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.

1730 lines
44 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. mailslot.c
  5. Abstract:
  6. This module implements the routines needed to process incoming mailslot
  7. requests.
  8. Author:
  9. Larry Osterman (larryo) 18-Oct-1991
  10. Revision History:
  11. 18-Oct-1991 larryo
  12. Created
  13. --*/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. #include <netlogon.h>
  17. #define _INC_WINDOWS 1
  18. #include <winsock2.h>
  19. // Free list of 512-byte buffers.
  20. LIST_ENTRY
  21. BowserMailslotBufferList = {0};
  22. KSPIN_LOCK
  23. BowserMailslotSpinLock = {0};
  24. // Largest "typical" datagram size
  25. #define BOWSER_MAX_DATAGRAM_SIZE 512
  26. // Total number of mailslot buffers currently allocated.
  27. LONG
  28. BowserNumberOfMailslotBuffers = {0};
  29. // Number of 512-byte buffers currently allocated.
  30. LONG
  31. BowserNumberOfMaxSizeMailslotBuffers = {0};
  32. // Number of 512-byte buffers currently in the free list.
  33. LONG
  34. BowserNumberOfFreeMailslotBuffers = {0};
  35. #if DBG
  36. ULONG
  37. BowserMailslotCacheHitCount = 0;
  38. ULONG
  39. BowserMailslotCacheMissCount = 0;
  40. #endif // DBG
  41. //
  42. // Variables describing bowser support for handling netlogon mailslot messages and
  43. // PNP messages to Netlogon service or BrowserService.
  44. typedef struct _BROWSER_PNP_STATE {
  45. // Queue of mailslot messages.
  46. LIST_ENTRY MailslotMessageQueue;
  47. // Maximum queue length
  48. ULONG MaxMessageCount;
  49. // Current queue length
  50. ULONG CurrentMessageCount;
  51. // Queue of IRPs used to read the queues
  52. IRP_QUEUE IrpQueue;
  53. // Queue of PNP events
  54. LIST_ENTRY PnpQueue;
  55. } BROWSER_PNP_STATE, *PBROWSER_PNP_STATE;
  56. //
  57. // There is one BROWSER_PNP_STATE for the Netlogon service and one for the
  58. // Browser service.
  59. //
  60. BROWSER_PNP_STATE BowserPnp[BOWSER_PNP_COUNT];
  61. //
  62. // Queue of PNP notifications to netlogon or browser service
  63. //
  64. typedef struct _BR_PNP_MESSAGE {
  65. LIST_ENTRY Next; // List of all queued entries.
  66. NETLOGON_PNP_OPCODE NlPnpOpcode; // Operation to be notified
  67. ULONG TransportFlags; // Flags describing transport
  68. UNICODE_STRING TransportName; // Transport operation happened on
  69. UNICODE_STRING HostedDomainName; // Hosted domain operation happened on
  70. } BR_PNP_MESSAGE, *PBR_PNP_MESSAGE;
  71. //
  72. // Forwards for the alloc_text
  73. //
  74. NTSTATUS
  75. BowserNetlogonCopyMessage(
  76. IN PIRP Irp,
  77. IN PMAILSLOT_BUFFER MailslotBuffer
  78. );
  79. NTSTATUS
  80. BowserCopyPnp(
  81. IN PIRP Irp,
  82. IN NETLOGON_PNP_OPCODE NlPnpOpcode,
  83. IN PUNICODE_STRING HostedDomainName,
  84. IN PUNICODE_STRING TransportName,
  85. IN ULONG TransportFlags
  86. );
  87. VOID
  88. BowserTrimMessageQueue (
  89. PBROWSER_PNP_STATE BrPnp
  90. );
  91. BOOLEAN
  92. BowserProcessNetlogonMailslotWrite(
  93. IN PMAILSLOT_BUFFER MailslotBuffer
  94. );
  95. #ifdef ALLOC_PRAGMA
  96. #pragma alloc_text(PAGE5NETLOGON, BowserNetlogonCopyMessage)
  97. #pragma alloc_text(PAGE4BROW, BowserCopyPnp)
  98. #pragma alloc_text(PAGE4BROW, BowserTrimMessageQueue)
  99. #pragma alloc_text(PAGE5NETLOGON, BowserNetlogonDeleteTransportFromMessageQueue )
  100. #pragma alloc_text(PAGE5NETLOGON, BowserProcessNetlogonMailslotWrite)
  101. #pragma alloc_text(PAGE4BROW, BowserSendPnp)
  102. #pragma alloc_text(PAGE4BROW, BowserEnablePnp )
  103. #pragma alloc_text(PAGE4BROW, BowserReadPnp )
  104. #pragma alloc_text(PAGE, BowserProcessMailslotWrite)
  105. #pragma alloc_text(PAGE4BROW, BowserFreeMailslotBuffer)
  106. #pragma alloc_text(INIT, BowserpInitializeMailslot)
  107. #pragma alloc_text(PAGE, BowserpUninitializeMailslot)
  108. #endif
  109. NTSTATUS
  110. BowserNetlogonCopyMessage(
  111. IN PIRP Irp,
  112. IN PMAILSLOT_BUFFER MailslotBuffer
  113. )
  114. /*++
  115. Routine Description:
  116. This routine copies the data from the specified MailslotBuffer into the
  117. IRP for the netlogon request.
  118. This routine unconditionally frees the passed in Mailslot Buffer.
  119. Arguments:
  120. Irp - IRP for the IOCTL from the netlogon service.
  121. MailslotBuffer - Buffer describing the mailslot message.
  122. Return Value:
  123. Status of the operation.
  124. The caller should complete the I/O operation with this status code.
  125. --*/
  126. {
  127. NTSTATUS Status;
  128. PSMB_HEADER SmbHeader;
  129. PSMB_TRANSACT_MAILSLOT MailslotSmb;
  130. PUCHAR MailslotData;
  131. OEM_STRING MailslotNameA;
  132. UNICODE_STRING MailslotNameU;
  133. UNICODE_STRING TransportName;
  134. UNICODE_STRING DestinationName;
  135. USHORT DataCount;
  136. PNETLOGON_MAILSLOT NetlogonMailslot;
  137. PUCHAR Where;
  138. PIO_STACK_LOCATION IrpSp;
  139. BowserReferenceDiscardableCode( BowserNetlogonDiscardableCodeSection );
  140. DISCARDABLE_CODE( BowserNetlogonDiscardableCodeSection );
  141. //
  142. // Extract the name of the mailslot and address/size of mailslot message
  143. // from SMB.
  144. //
  145. SmbHeader = (PSMB_HEADER )MailslotBuffer->Buffer;
  146. MailslotSmb = (PSMB_TRANSACT_MAILSLOT)(SmbHeader+1);
  147. MailslotData = (((PCHAR )SmbHeader) + SmbGetUshort(&MailslotSmb->DataOffset));
  148. RtlInitString(&MailslotNameA, MailslotSmb->Buffer );
  149. DataCount = SmbGetUshort(&MailslotSmb->DataCount);
  150. //
  151. // Get the name of the transport and netbios name the mailslot message arrived on.
  152. //
  153. TransportName =
  154. MailslotBuffer->TransportName->Transport->PagedTransport->TransportName;
  155. DestinationName =
  156. MailslotBuffer->TransportName->PagedTransportName->Name->Name;
  157. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  158. try {
  159. //
  160. // Convert mailslot name to unicode for return.
  161. //
  162. Status = RtlOemStringToUnicodeString(&MailslotNameU, &MailslotNameA, TRUE);
  163. if (!NT_SUCCESS(Status)) {
  164. BowserLogIllegalName( Status, MailslotNameA.Buffer, MailslotNameA.Length );
  165. MailslotNameU.Buffer = NULL;
  166. try_return( NOTHING );
  167. }
  168. //
  169. // Ensure the data fits in the user's output buffer.
  170. //
  171. if ( IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  172. sizeof(NETLOGON_MAILSLOT) + // Header structure
  173. DataCount + // Actual mailslot message
  174. sizeof(DWORD) + // alignment for socket address
  175. sizeof(SOCKADDR_IN) + // Client Socket Address
  176. sizeof(WCHAR) + // alignment of unicode strings
  177. TransportName.Length + // TransportName
  178. sizeof(WCHAR) + // zero terminator
  179. MailslotNameU.Length + // Mailslot name
  180. sizeof(WCHAR) + // zero terminator
  181. DestinationName.Length + // Destination name
  182. sizeof(WCHAR) ) { // zero terminator
  183. try_return( Status = STATUS_BUFFER_TOO_SMALL );
  184. }
  185. //
  186. // Get the address of Netlogon's buffer and fill in common portion.
  187. //
  188. NetlogonMailslot = MmGetSystemAddressForMdl( Irp->MdlAddress );
  189. if ( NULL == NetlogonMailslot ) {
  190. try_return( Status = STATUS_NO_MEMORY );
  191. }
  192. if (!POINTER_IS_ALIGNED( NetlogonMailslot, ALIGN_DWORD) ) {
  193. try_return( Status = STATUS_INVALID_PARAMETER );
  194. }
  195. Where = (PUCHAR) (NetlogonMailslot+1);
  196. NetlogonMailslot->TimeReceived = MailslotBuffer->TimeReceived;
  197. //
  198. // Copy the datagram to the buffer
  199. //
  200. NetlogonMailslot->MailslotMessageSize = DataCount;
  201. NetlogonMailslot->MailslotMessageOffset = (ULONG)(Where - (PUCHAR)NetlogonMailslot);
  202. RtlCopyMemory( Where, MailslotData, DataCount );
  203. Where += DataCount;
  204. //
  205. // Copy Client IpAddress to buffer.
  206. //
  207. if ( MailslotBuffer->ClientIpAddress != 0 ) {
  208. PSOCKADDR_IN SockAddrIn;
  209. *Where = 0;
  210. *(Where+1) = 0;
  211. *(Where+2) = 0;
  212. Where = ROUND_UP_POINTER( Where, ALIGN_DWORD );
  213. NetlogonMailslot->ClientSockAddrSize = sizeof(SOCKADDR_IN);
  214. NetlogonMailslot->ClientSockAddrOffset = (ULONG)(Where - (PUCHAR)NetlogonMailslot);
  215. SockAddrIn = (PSOCKADDR_IN) Where;
  216. RtlZeroMemory( SockAddrIn, sizeof(SOCKADDR_IN) );
  217. SockAddrIn->sin_family = AF_INET;
  218. SockAddrIn->sin_addr.S_un.S_addr = MailslotBuffer->ClientIpAddress;
  219. Where += sizeof(SOCKADDR_IN);
  220. } else {
  221. NetlogonMailslot->ClientSockAddrSize = 0;
  222. NetlogonMailslot->ClientSockAddrOffset = 0;
  223. }
  224. //
  225. // Copy the transport name to the buffer
  226. //
  227. *Where = 0;
  228. Where = ROUND_UP_POINTER( Where, ALIGN_WCHAR );
  229. NetlogonMailslot->TransportNameSize = TransportName.Length;
  230. NetlogonMailslot->TransportNameOffset = (ULONG)(Where - (PUCHAR)NetlogonMailslot);
  231. RtlCopyMemory( Where, TransportName.Buffer, TransportName.Length );
  232. Where += TransportName.Length;
  233. *((PWCH)Where) = L'\0';
  234. Where += sizeof(WCHAR);
  235. //
  236. // Copy the mailslot name to the buffer
  237. //
  238. NetlogonMailslot->MailslotNameSize = MailslotNameU.Length;
  239. NetlogonMailslot->MailslotNameOffset = (ULONG)(Where - (PUCHAR)NetlogonMailslot);
  240. RtlCopyMemory( Where, MailslotNameU.Buffer, MailslotNameU.Length );
  241. Where += MailslotNameU.Length;
  242. *((PWCH)Where) = L'\0';
  243. Where += sizeof(WCHAR);
  244. //
  245. // Copy the destination netbios name to the buffer
  246. //
  247. NetlogonMailslot->DestinationNameSize = DestinationName.Length;
  248. NetlogonMailslot->DestinationNameOffset = (ULONG)(Where - (PUCHAR)NetlogonMailslot);
  249. RtlCopyMemory( Where, DestinationName.Buffer, DestinationName.Length );
  250. Where += DestinationName.Length;
  251. *((PWCH)Where) = L'\0';
  252. Where += sizeof(WCHAR);
  253. Status = STATUS_SUCCESS;
  254. try_exit:NOTHING;
  255. } finally {
  256. //
  257. // Free Locally allocated buffers
  258. //
  259. RtlFreeUnicodeString(&MailslotNameU);
  260. //
  261. // Always free the incoming mailslot message
  262. //
  263. BowserFreeMailslotBuffer( MailslotBuffer );
  264. }
  265. BowserDereferenceDiscardableCode( BowserNetlogonDiscardableCodeSection );
  266. return Status;
  267. }
  268. NTSTATUS
  269. BowserCopyPnp(
  270. IN PIRP Irp,
  271. IN NETLOGON_PNP_OPCODE NlPnpOpcode,
  272. IN PUNICODE_STRING HostedDomainName,
  273. IN PUNICODE_STRING TransportName,
  274. IN ULONG TransportFlags
  275. )
  276. /*++
  277. Routine Description:
  278. This routine copies the data for a PNP notification into the
  279. IRP for the I/O request.
  280. Arguments:
  281. Irp - IRP for the IOCTL from the service.
  282. NlPnpOpcode - Opcode describing the event being notified.
  283. HostedDomainName - Name of the hosted domain this event applies to
  284. TransportName - Name of transport being affected.
  285. TransportFlags - Flags describing the transport
  286. Return Value:
  287. Status of the operation.
  288. The caller should complete the I/O operation with this status code.
  289. --*/
  290. {
  291. NTSTATUS Status;
  292. PNETLOGON_MAILSLOT NetlogonMailslot;
  293. PUCHAR Where;
  294. PIO_STACK_LOCATION IrpSp;
  295. BowserReferenceDiscardableCode( BowserDiscardableCodeSection );
  296. DISCARDABLE_CODE( BowserDiscardableCodeSection );
  297. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  298. try {
  299. //
  300. // Ensure the data fits in the user's output buffer.
  301. //
  302. if ( IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
  303. sizeof(NETLOGON_MAILSLOT) + // Header structure
  304. TransportName->Length + sizeof(WCHAR) + // TransportName
  305. HostedDomainName->Length + sizeof(WCHAR) + // DomainName
  306. 1 ) { // possible rounding requirement
  307. try_return( Status = STATUS_BUFFER_TOO_SMALL );
  308. }
  309. //
  310. // Get the address of service's buffer and fill in common portion.
  311. //
  312. NetlogonMailslot = MmGetSystemAddressForMdl( Irp->MdlAddress );
  313. if ( NULL == NetlogonMailslot ) {
  314. try_return( Status = STATUS_NO_MEMORY );
  315. }
  316. if (!POINTER_IS_ALIGNED( NetlogonMailslot, ALIGN_DWORD) ) {
  317. try_return( Status = STATUS_INVALID_PARAMETER );
  318. }
  319. RtlZeroMemory( NetlogonMailslot, sizeof(NETLOGON_MAILSLOT));
  320. //
  321. // Copy the opcode
  322. //
  323. NetlogonMailslot->MailslotNameOffset = NlPnpOpcode;
  324. //
  325. // Copy the transport flags.
  326. //
  327. NetlogonMailslot->MailslotMessageOffset = TransportFlags;
  328. //
  329. // Copy the transport name to the buffer
  330. //
  331. Where = (PUCHAR) (NetlogonMailslot+1);
  332. *Where = 0;
  333. Where = ROUND_UP_POINTER( Where, ALIGN_WCHAR );
  334. NetlogonMailslot->TransportNameSize = TransportName->Length;
  335. NetlogonMailslot->TransportNameOffset = (ULONG)(Where - (PUCHAR)NetlogonMailslot);
  336. RtlCopyMemory( Where, TransportName->Buffer, TransportName->Length );
  337. Where += TransportName->Length;
  338. *((PWCH)Where) = L'\0';
  339. Where += sizeof(WCHAR);
  340. //
  341. // Copy the hosted domain name to the buffer
  342. //
  343. NetlogonMailslot->DestinationNameSize = HostedDomainName->Length;
  344. NetlogonMailslot->DestinationNameOffset = (ULONG)(Where - (PUCHAR)NetlogonMailslot);
  345. RtlCopyMemory( Where, HostedDomainName->Buffer, HostedDomainName->Length );
  346. Where += HostedDomainName->Length;
  347. *((PWCH)Where) = L'\0';
  348. Where += sizeof(WCHAR);
  349. Status = STATUS_SUCCESS;
  350. try_exit:NOTHING;
  351. } finally {
  352. BowserDereferenceDiscardableCode( BowserDiscardableCodeSection );
  353. }
  354. return Status;
  355. }
  356. VOID
  357. BowserTrimMessageQueue (
  358. PBROWSER_PNP_STATE BrPnp
  359. )
  360. /*++
  361. Routine Description:
  362. This routines ensures there are not too many mailslot messages in
  363. the message queue. Any excess messages are deleted.
  364. Arguments:
  365. BrPnp - Indicates which message queue to trim
  366. Return Value:
  367. None.
  368. --*/
  369. {
  370. KIRQL OldIrql;
  371. dprintf(DPRT_NETLOGON, ("Bowser: trim message queue to %ld\n", BrPnp->MaxMessageCount ));
  372. //
  373. //
  374. BowserReferenceDiscardableCode( BowserDiscardableCodeSection );
  375. DISCARDABLE_CODE( BowserDiscardableCodeSection );
  376. //
  377. // If too many messages are queued,
  378. // delete the oldest messages.
  379. //
  380. ACQUIRE_SPIN_LOCK(&BowserMailslotSpinLock, &OldIrql);
  381. while ( BrPnp->CurrentMessageCount > BrPnp->MaxMessageCount){
  382. PLIST_ENTRY Entry;
  383. PMAILSLOT_BUFFER MailslotBuffer;
  384. Entry = RemoveHeadList(&BrPnp->MailslotMessageQueue);
  385. BrPnp->CurrentMessageCount--;
  386. MailslotBuffer = CONTAINING_RECORD(Entry, MAILSLOT_BUFFER, Overlay.NextBuffer);
  387. RELEASE_SPIN_LOCK(&BowserMailslotSpinLock, OldIrql);
  388. BowserFreeMailslotBuffer( MailslotBuffer );
  389. ACQUIRE_SPIN_LOCK(&BowserMailslotSpinLock, &OldIrql);
  390. }
  391. //
  392. // If absolutely no queued messages are allowed,
  393. // delete the queued PNP messages, too.
  394. // (Either netlogon or the bowser is shutting down.)
  395. //
  396. if ( BrPnp->MaxMessageCount == 0 ) {
  397. while ( !IsListEmpty(&BrPnp->PnpQueue) ) {
  398. PLIST_ENTRY ListEntry;
  399. PBR_PNP_MESSAGE PnpMessage;
  400. ListEntry = RemoveHeadList(&BrPnp->PnpQueue);
  401. PnpMessage = CONTAINING_RECORD(ListEntry, BR_PNP_MESSAGE, Next);
  402. RELEASE_SPIN_LOCK(&BowserMailslotSpinLock, OldIrql);
  403. FREE_POOL(PnpMessage);
  404. ACQUIRE_SPIN_LOCK(&BowserMailslotSpinLock, &OldIrql);
  405. }
  406. }
  407. RELEASE_SPIN_LOCK(&BowserMailslotSpinLock, OldIrql);
  408. BowserDereferenceDiscardableCode( BowserDiscardableCodeSection );
  409. }
  410. VOID
  411. BowserNetlogonDeleteTransportFromMessageQueue (
  412. PTRANSPORT Transport
  413. )
  414. /*++
  415. Routine Description:
  416. This routines removes queued mailslot messages that arrived on the specified
  417. transport.
  418. Arguments:
  419. Transport - Transport who's mailslot messages are to be deleted.
  420. Return Value:
  421. None.
  422. --*/
  423. {
  424. KIRQL OldIrql;
  425. PLIST_ENTRY ListEntry;
  426. PBROWSER_PNP_STATE BrPnp=&BowserPnp[NETLOGON_PNP];
  427. dprintf(DPRT_NETLOGON, ("Bowser: remove messages queued by transport %lx\n", Transport ));
  428. //
  429. //
  430. BowserReferenceDiscardableCode( BowserNetlogonDiscardableCodeSection );
  431. DISCARDABLE_CODE( BowserNetlogonDiscardableCodeSection );
  432. //
  433. // Loop through all of the queued messages.
  434. //
  435. ACQUIRE_SPIN_LOCK(&BowserMailslotSpinLock, &OldIrql);
  436. for ( ListEntry = BrPnp->MailslotMessageQueue.Flink;
  437. ListEntry != &BrPnp->MailslotMessageQueue;
  438. ) {
  439. PMAILSLOT_BUFFER MailslotBuffer;
  440. //
  441. // If the message wasn't queued by this transport,
  442. // go on to the next entry.
  443. //
  444. MailslotBuffer = CONTAINING_RECORD(ListEntry, MAILSLOT_BUFFER, Overlay.NextBuffer);
  445. if ( MailslotBuffer->TransportName->Transport != Transport ) {
  446. ListEntry = ListEntry->Flink;
  447. //
  448. // Otherwise,
  449. // delete the entry.
  450. //
  451. } else {
  452. dprintf(DPRT_ALWAYS, ("Bowser: removing message %lx queued by transport %lx\n", MailslotBuffer, Transport ));
  453. RemoveEntryList( ListEntry );
  454. BrPnp->CurrentMessageCount--;
  455. RELEASE_SPIN_LOCK(&BowserMailslotSpinLock, OldIrql);
  456. BowserFreeMailslotBuffer( MailslotBuffer );
  457. ACQUIRE_SPIN_LOCK(&BowserMailslotSpinLock, &OldIrql);
  458. //
  459. // Start over at the beginning of the list since we dropped the spinlock.
  460. //
  461. ListEntry = BrPnp->MailslotMessageQueue.Flink;
  462. }
  463. }
  464. RELEASE_SPIN_LOCK(&BowserMailslotSpinLock, OldIrql);
  465. BowserDereferenceDiscardableCode( BowserNetlogonDiscardableCodeSection );
  466. }
  467. BOOLEAN
  468. BowserProcessNetlogonMailslotWrite(
  469. IN PMAILSLOT_BUFFER MailslotBuffer
  470. )
  471. /*++
  472. Routine Description:
  473. This routine checks to see if the described mailslot message is destined
  474. to the Netlogon service and if the Bowser is currently handling such
  475. messages
  476. Arguments:
  477. MailslotBuffer - Buffer describing the mailslot message.
  478. Return Value:
  479. TRUE - iff the mailslot message was successfully queued to the netlogon
  480. service.
  481. --*/
  482. {
  483. KIRQL OldIrql;
  484. NTSTATUS Status;
  485. PSMB_HEADER SmbHeader;
  486. PSMB_TRANSACT_MAILSLOT MailslotSmb;
  487. BOOLEAN TrimIt;
  488. BOOLEAN ReturnValue;
  489. PBROWSER_PNP_STATE BrPnp=&BowserPnp[NETLOGON_PNP];
  490. PIRP Irp;
  491. BowserReferenceDiscardableCode( BowserNetlogonDiscardableCodeSection );
  492. DISCARDABLE_CODE( BowserNetlogonDiscardableCodeSection );
  493. //
  494. // If this message isn't destined to the Netlogon service,
  495. // just return.
  496. //
  497. SmbHeader = (PSMB_HEADER )MailslotBuffer->Buffer;
  498. MailslotSmb = (PSMB_TRANSACT_MAILSLOT)(SmbHeader+1);
  499. if ( _stricmp( MailslotSmb->Buffer, NETLOGON_LM_MAILSLOT_A ) != 0 &&
  500. _stricmp( MailslotSmb->Buffer, NETLOGON_NT_MAILSLOT_A ) != 0 ) {
  501. ReturnValue = FALSE;
  502. //
  503. // The mailslot message is destined to netlogon.
  504. //
  505. } else {
  506. //
  507. // Check to ensure we're queuing messages to Netlogon
  508. //
  509. ACQUIRE_SPIN_LOCK(&BowserMailslotSpinLock, &OldIrql);
  510. if ( BrPnp->MaxMessageCount == 0 ) {
  511. RELEASE_SPIN_LOCK(&BowserMailslotSpinLock, OldIrql);
  512. ReturnValue = FALSE;
  513. //
  514. // Queueing to netlogon is enabled.
  515. //
  516. } else {
  517. //
  518. // If there already is an IRP from netlogon queued,
  519. // return this mailslot message to netlogon now.
  520. //
  521. // This routine locks BowserIrpQueueSpinLock so watch the spin lock
  522. // locking order.
  523. //
  524. ReturnValue = TRUE;
  525. Irp = BowserDequeueQueuedIrp( &BrPnp->IrpQueue );
  526. if ( Irp != NULL ) {
  527. ASSERT( IsListEmpty( &BrPnp->MailslotMessageQueue ) );
  528. dprintf(DPRT_NETLOGON, ("Bowser: found already queued netlogon IRP\n"));
  529. RELEASE_SPIN_LOCK(&BowserMailslotSpinLock, OldIrql);
  530. Status = BowserNetlogonCopyMessage( Irp, MailslotBuffer );
  531. BowserCompleteRequest( Irp, Status );
  532. } else {
  533. //
  534. // Queue the mailslot message for netlogon to pick up later.
  535. //
  536. InsertTailList( &BrPnp->MailslotMessageQueue,
  537. &MailslotBuffer->Overlay.NextBuffer);
  538. BrPnp->CurrentMessageCount++;
  539. TrimIt =
  540. (BrPnp->CurrentMessageCount > BrPnp->MaxMessageCount);
  541. RELEASE_SPIN_LOCK(&BowserMailslotSpinLock, OldIrql);
  542. //
  543. // If there are too many messages queued,
  544. // trim entries from the front.
  545. //
  546. if ( TrimIt ) {
  547. BowserTrimMessageQueue(BrPnp);
  548. }
  549. }
  550. }
  551. }
  552. BowserDereferenceDiscardableCode( BowserNetlogonDiscardableCodeSection );
  553. return ReturnValue;
  554. }
  555. VOID
  556. BowserSendPnp(
  557. IN NETLOGON_PNP_OPCODE NlPnpOpcode,
  558. IN PUNICODE_STRING HostedDomainName OPTIONAL,
  559. IN PUNICODE_STRING TransportName OPTIONAL,
  560. IN ULONG TransportFlags
  561. )
  562. /*++
  563. Routine Description:
  564. This routine sends a PNP notification to the Netlogon service.
  565. Arguments:
  566. NlPnpOpcode - Opcode describing the event being notified.
  567. HostedDomainName - Hosted domain name
  568. NULL - if the operation affects all hosted domains
  569. TransportName - Name of transport being affected.
  570. NULL - if the operation affects all transports
  571. TransportFlags - Flags describing the transport
  572. Return Value:
  573. None.
  574. --*/
  575. {
  576. KIRQL OldIrql;
  577. NTSTATUS Status;
  578. PIRP Irp;
  579. PBR_PNP_MESSAGE PnpMessage = NULL;
  580. PBROWSER_PNP_STATE BrPnp;
  581. UNICODE_STRING NullUnicodeString = { 0, 0, NULL };
  582. BowserReferenceDiscardableCode( BowserDiscardableCodeSection );
  583. DISCARDABLE_CODE( BowserDiscardableCodeSection );
  584. //
  585. // Initialization.
  586. //
  587. if ( TransportName == NULL ) {
  588. TransportName = &NullUnicodeString;
  589. }
  590. if ( HostedDomainName == NULL ) {
  591. HostedDomainName = &NullUnicodeString;
  592. }
  593. //
  594. // Send the PNP message to each service that wants it.
  595. //
  596. for ( BrPnp=&BowserPnp[0];
  597. BrPnp<&BowserPnp[BOWSER_PNP_COUNT];
  598. BrPnp++) {
  599. //
  600. // If this service doesn't want notification,
  601. // skip it.
  602. //
  603. if ( BrPnp->MaxMessageCount == 0 ) {
  604. continue;
  605. }
  606. //
  607. // Preallocate the buffer since we can't do it under the spinlock.
  608. //
  609. if ( PnpMessage == NULL ) {
  610. PnpMessage = ALLOCATE_POOL( NonPagedPool,
  611. sizeof(BR_PNP_MESSAGE) +
  612. TransportName->Length +
  613. HostedDomainName->Length,
  614. POOL_NETLOGON_BUFFER);
  615. //
  616. // Copy the parameters into the newly allocated buffer.
  617. //
  618. if ( PnpMessage != NULL ) {
  619. LPBYTE Where;
  620. PnpMessage->NlPnpOpcode = NlPnpOpcode;
  621. PnpMessage->TransportFlags = TransportFlags;
  622. Where = (LPBYTE)(PnpMessage + 1);
  623. // Copy the TransportName
  624. PnpMessage->TransportName.MaximumLength =
  625. PnpMessage->TransportName.Length = TransportName->Length;
  626. PnpMessage->TransportName.Buffer = (LPWSTR) Where;
  627. RtlCopyMemory( Where,
  628. TransportName->Buffer,
  629. TransportName->Length );
  630. Where += TransportName->Length;
  631. // Copy the HostedDomainName
  632. PnpMessage->HostedDomainName.MaximumLength =
  633. PnpMessage->HostedDomainName.Length = HostedDomainName->Length;
  634. PnpMessage->HostedDomainName.Buffer = (LPWSTR) Where;
  635. RtlCopyMemory( Where,
  636. HostedDomainName->Buffer,
  637. HostedDomainName->Length );
  638. Where += HostedDomainName->Length;
  639. }
  640. }
  641. //
  642. // Check to ensure we're queuing messages to this service.
  643. //
  644. ACQUIRE_SPIN_LOCK(&BowserMailslotSpinLock, &OldIrql);
  645. if ( BrPnp->MaxMessageCount == 0 ) {
  646. RELEASE_SPIN_LOCK(&BowserMailslotSpinLock, OldIrql);
  647. //
  648. // Queueing to service is enabled.
  649. //
  650. } else {
  651. //
  652. // If there already is an IRP from the service queued,
  653. // return this PNP message to the service now.
  654. //
  655. // This routine locks BowserIrpQueueSpinLock so watch the spin lock
  656. // locking order.
  657. //
  658. Irp = BowserDequeueQueuedIrp( &BrPnp->IrpQueue );
  659. if ( Irp != NULL ) {
  660. ASSERT( IsListEmpty( &BrPnp->MailslotMessageQueue ) );
  661. dprintf(DPRT_NETLOGON, ("Bowser: found already queued netlogon IRP\n"));
  662. RELEASE_SPIN_LOCK(&BowserMailslotSpinLock, OldIrql);
  663. Status = BowserCopyPnp( Irp, NlPnpOpcode, HostedDomainName, TransportName, TransportFlags );
  664. BowserCompleteRequest( Irp, Status );
  665. } else {
  666. //
  667. // Queue the mailslot message for the service to pick up later.
  668. // (Drop notification on the floor if there is no memory.)
  669. //
  670. if ( PnpMessage != NULL ) {
  671. InsertTailList( &BrPnp->PnpQueue, &PnpMessage->Next );
  672. PnpMessage = NULL;
  673. }
  674. RELEASE_SPIN_LOCK(&BowserMailslotSpinLock, OldIrql);
  675. }
  676. }
  677. }
  678. //
  679. // Free the PnpMessage buffer if we didn't need it.
  680. //
  681. if ( PnpMessage != NULL ) {
  682. FREE_POOL(PnpMessage);
  683. }
  684. BowserDereferenceDiscardableCode( BowserDiscardableCodeSection );
  685. return;
  686. }
  687. NTSTATUS
  688. BowserEnablePnp (
  689. IN PLMDR_REQUEST_PACKET InputBuffer,
  690. IN ULONG ServiceIndex
  691. )
  692. /*++
  693. Routine Description:
  694. This routine processes an IOCTL from the netlogon service to enable or
  695. disable the queueing of netlogon mailslot messages.
  696. Arguments:
  697. InputBuffer - Specifies the number of mailslot messages to queue.
  698. Zero disables queuing.
  699. ServiceIndex - Index of service to set queue size for.
  700. Return Value:
  701. Status of operation.
  702. Please note that this IRP is cancelable.
  703. --*/
  704. {
  705. KIRQL OldIrql;
  706. NTSTATUS Status;
  707. ULONG MaxMessageCount;
  708. PBROWSER_PNP_STATE BrPnp=&BowserPnp[ServiceIndex];
  709. BowserReferenceDiscardableCode( BowserDiscardableCodeSection );
  710. DISCARDABLE_CODE( BowserDiscardableCodeSection );
  711. try {
  712. MaxMessageCount = InputBuffer->Parameters.NetlogonMailslotEnable.MaxMessageCount;
  713. dprintf(DPRT_NETLOGON,
  714. ("NtDeviceIoControlFile: Netlogon enable %ld\n",
  715. MaxMessageCount ));
  716. //
  717. // Set the new size of the message queue
  718. //
  719. ACQUIRE_SPIN_LOCK(&BowserMailslotSpinLock, &OldIrql);
  720. BrPnp->MaxMessageCount = MaxMessageCount;
  721. RELEASE_SPIN_LOCK(&BowserMailslotSpinLock, OldIrql);
  722. //
  723. // Trim the message queue to the new size.
  724. //
  725. BowserTrimMessageQueue(BrPnp);
  726. try_return(Status = STATUS_SUCCESS);
  727. try_exit:NOTHING;
  728. } finally {
  729. BowserDereferenceDiscardableCode( BowserDiscardableCodeSection );
  730. }
  731. return Status;
  732. }
  733. NTSTATUS
  734. BowserReadPnp (
  735. IN PIRP Irp,
  736. IN ULONG OutputBufferLength,
  737. IN ULONG ServiceIndex
  738. )
  739. /*++
  740. Routine Description:
  741. This routine processes an IOCTL from the netlogon service to get the next
  742. mailslot message.
  743. Arguments:
  744. Irp - I/O request packet describing request.
  745. ServiceIndex - Index of service to set queue size for.
  746. Return Value:
  747. Status of operation.
  748. Please note that this IRP is cancelable.
  749. --*/
  750. {
  751. KIRQL OldIrql;
  752. NTSTATUS Status;
  753. PBROWSER_PNP_STATE BrPnp=&BowserPnp[ServiceIndex];
  754. //
  755. // If this is Netlogon,
  756. // page in BowserNetlogonCopyMessage.
  757. //
  758. if ( ServiceIndex == NETLOGON_PNP ) {
  759. BowserReferenceDiscardableCode( BowserNetlogonDiscardableCodeSection );
  760. DISCARDABLE_CODE( BowserNetlogonDiscardableCodeSection );
  761. }
  762. //
  763. // Reference the discardable code of this routine and
  764. // BowserQueueNonBufferRequestReferenced()
  765. //
  766. BowserReferenceDiscardableCode( BowserDiscardableCodeSection );
  767. DISCARDABLE_CODE( BowserDiscardableCodeSection );
  768. //
  769. // Ensure service has asked the browser to queue messages
  770. //
  771. ACQUIRE_SPIN_LOCK(&BowserMailslotSpinLock, &OldIrql);
  772. if ( BrPnp->MaxMessageCount == 0 ) {
  773. dprintf(DPRT_NETLOGON, ("Bowser called from Netlogon when not enabled\n"));
  774. RELEASE_SPIN_LOCK(&BowserMailslotSpinLock, OldIrql);
  775. Status = STATUS_NOT_SUPPORTED;
  776. //
  777. // If there already is a PNP message queued,
  778. // just return it to netlogon immediately.
  779. //
  780. } else if ( !IsListEmpty( &BrPnp->PnpQueue )) {
  781. PBR_PNP_MESSAGE PnpMessage;
  782. PLIST_ENTRY ListEntry;
  783. dprintf(DPRT_NETLOGON, ("Bowser found netlogon PNP message already queued\n"));
  784. ListEntry = RemoveHeadList(&BrPnp->PnpQueue);
  785. PnpMessage = CONTAINING_RECORD(ListEntry, BR_PNP_MESSAGE, Next);
  786. RELEASE_SPIN_LOCK(&BowserMailslotSpinLock, OldIrql);
  787. Status = BowserCopyPnp( Irp,
  788. PnpMessage->NlPnpOpcode,
  789. &PnpMessage->HostedDomainName,
  790. &PnpMessage->TransportName,
  791. PnpMessage->TransportFlags );
  792. FREE_POOL(PnpMessage);
  793. //
  794. // If there already is a mailslot message queued,
  795. // just return it to netlogon immediately.
  796. //
  797. } else if ( ServiceIndex == NETLOGON_PNP &&
  798. !IsListEmpty( &BrPnp->MailslotMessageQueue )) {
  799. PMAILSLOT_BUFFER MailslotBuffer;
  800. PLIST_ENTRY ListEntry;
  801. dprintf(DPRT_NETLOGON, ("Bowser found netlogon mailslot message already queued\n"));
  802. ListEntry = RemoveHeadList(&BrPnp->MailslotMessageQueue);
  803. BrPnp->CurrentMessageCount--;
  804. MailslotBuffer = CONTAINING_RECORD(ListEntry, MAILSLOT_BUFFER, Overlay.NextBuffer);
  805. RELEASE_SPIN_LOCK(&BowserMailslotSpinLock, OldIrql);
  806. Status = BowserNetlogonCopyMessage( Irp, MailslotBuffer );
  807. //
  808. // Otherwise, save this IRP until a mailslot message arrives.
  809. // This routine locks BowserIrpQueueSpinLock so watch the spin lock
  810. // locking order.
  811. //
  812. } else {
  813. dprintf(DPRT_NETLOGON, ("Bowser: queue netlogon mailslot irp\n"));
  814. Status = BowserQueueNonBufferRequestReferenced(
  815. Irp,
  816. &BrPnp->IrpQueue,
  817. BowserCancelQueuedRequest );
  818. RELEASE_SPIN_LOCK(&BowserMailslotSpinLock, OldIrql);
  819. }
  820. if ( ServiceIndex == NETLOGON_PNP ) {
  821. BowserDereferenceDiscardableCode( BowserNetlogonDiscardableCodeSection );
  822. }
  823. BowserDereferenceDiscardableCode( BowserDiscardableCodeSection );
  824. return Status;
  825. }
  826. VOID
  827. BowserProcessMailslotWrite(
  828. IN PVOID Context
  829. )
  830. /*++
  831. Routine Description:
  832. This routine performs all the task time operations to perform a mailslot
  833. write.
  834. It will open the mailslot, write the specified data into the mailslot,
  835. and close the mailslot.
  836. Arguments:
  837. IN PWORK_HEADER WorkHeader - Specifies the mailslot buffer holding the
  838. mailslot write
  839. Return Value:
  840. None.
  841. --*/
  842. {
  843. PSMB_HEADER SmbHeader;
  844. PSMB_TRANSACT_MAILSLOT MailslotSmb;
  845. PMAILSLOT_BUFFER MailslotBuffer = Context;
  846. PUCHAR MailslotData;
  847. HANDLE MailslotHandle = NULL;
  848. OBJECT_ATTRIBUTES ObjAttr;
  849. OEM_STRING MailslotNameA;
  850. UNICODE_STRING MailslotNameU;
  851. IO_STATUS_BLOCK IoStatusBlock;
  852. CHAR MailslotName[MAXIMUM_FILENAME_LENGTH+1];
  853. NTSTATUS Status;
  854. ULONG DataCount;
  855. ULONG TotalDataCount;
  856. PAGED_CODE();
  857. ASSERT (MailslotBuffer->Signature == STRUCTURE_SIGNATURE_MAILSLOT_BUFFER);
  858. SmbHeader = (PSMB_HEADER )MailslotBuffer->Buffer;
  859. ASSERT (SmbHeader->Command == SMB_COM_TRANSACTION);
  860. MailslotSmb = (PSMB_TRANSACT_MAILSLOT)(SmbHeader+1);
  861. ASSERT (MailslotSmb->WordCount == 17);
  862. ASSERT (MailslotSmb->Class == 2);
  863. MailslotData = (((PCHAR )SmbHeader) + SmbGetUshort(&MailslotSmb->DataOffset));
  864. DataCount = (ULONG)SmbGetUshort(&MailslotSmb->DataCount);
  865. TotalDataCount = (ULONG)SmbGetUshort(&MailslotSmb->TotalDataCount);
  866. //
  867. // Verify that all of the data was received and that the indicated data doesn't
  868. // overflow the received buffer.
  869. //
  870. if (TotalDataCount != DataCount ||
  871. (MailslotData > MailslotBuffer->Buffer + MailslotBuffer->ReceiveLength) ||
  872. (DataCount + SmbGetUshort(&MailslotSmb->DataOffset) > MailslotBuffer->ReceiveLength )) {
  873. BowserLogIllegalDatagram(MailslotBuffer->TransportName,
  874. SmbHeader,
  875. (USHORT)MailslotBuffer->ReceiveLength,
  876. MailslotBuffer->ClientAddress,
  877. 0);
  878. BowserFreeMailslotBuffer(MailslotBuffer);
  879. return;
  880. }
  881. MailslotNameU.MaximumLength = MAXIMUM_FILENAME_LENGTH*sizeof(WCHAR)+sizeof(WCHAR);
  882. #define DEVICE_PREFIX_LENGTH 7
  883. strcpy(MailslotName, "\\Device");
  884. strncpy( MailslotName+DEVICE_PREFIX_LENGTH,
  885. MailslotSmb->Buffer,
  886. sizeof(MailslotName)-DEVICE_PREFIX_LENGTH);
  887. MailslotName[sizeof(MailslotName)-1] = '\0';
  888. RtlInitString(&MailslotNameA, MailslotName);
  889. //
  890. // Handle netlogon mailslot messages specially.
  891. // Don't call the discardable code at all if netlogon isn't running
  892. //
  893. if ( BowserPnp[NETLOGON_PNP].MaxMessageCount != 0 &&
  894. BowserProcessNetlogonMailslotWrite( MailslotBuffer ) ) {
  895. return;
  896. }
  897. //
  898. // Write the mailslot message to the mailslot
  899. //
  900. try {
  901. Status = RtlOemStringToUnicodeString(&MailslotNameU, &MailslotNameA, TRUE);
  902. if (!NT_SUCCESS(Status)) {
  903. BowserLogIllegalName( Status, MailslotNameA.Buffer, MailslotNameA.Length );
  904. try_return(NOTHING);
  905. }
  906. InitializeObjectAttributes(&ObjAttr,
  907. &MailslotNameU,
  908. OBJ_CASE_INSENSITIVE,
  909. NULL,
  910. NULL);
  911. Status = NtCreateFile(&MailslotHandle, // Handle
  912. GENERIC_WRITE | SYNCHRONIZE,
  913. &ObjAttr, // Object Attributes
  914. &IoStatusBlock, // Final I/O status block
  915. NULL, // Allocation Size
  916. FILE_ATTRIBUTE_NORMAL, // Normal attributes
  917. FILE_SHARE_READ|FILE_SHARE_WRITE,// Sharing attributes
  918. FILE_OPEN, // Create disposition
  919. 0, // CreateOptions
  920. NULL, // EA Buffer
  921. 0); // EA Length
  922. RtlFreeUnicodeString(&MailslotNameU);
  923. //
  924. // If the mailslot doesn't exist, ditch the request -
  925. //
  926. if (!NT_SUCCESS(Status)) {
  927. BowserStatistics.NumberOfFailedMailslotOpens += 1;
  928. try_return(NOTHING);
  929. }
  930. //
  931. // Now that the mailslot is opened, write the mailslot data into
  932. // the mailslot.
  933. //
  934. Status = NtWriteFile(MailslotHandle,
  935. NULL,
  936. NULL,
  937. NULL,
  938. &IoStatusBlock,
  939. MailslotData,
  940. DataCount,
  941. NULL,
  942. NULL);
  943. if (!NT_SUCCESS(Status)) {
  944. BowserStatistics.NumberOfFailedMailslotWrites += 1;
  945. } else {
  946. BowserStatistics.NumberOfMailslotWrites += 1;
  947. }
  948. try_exit:NOTHING;
  949. } finally {
  950. //
  951. // If we opened the mailslot, close it.
  952. //
  953. if (MailslotHandle != NULL) {
  954. ZwClose(MailslotHandle);
  955. }
  956. //
  957. // Free the mailslot buffer holding this mailslot.
  958. //
  959. BowserFreeMailslotBuffer(MailslotBuffer);
  960. }
  961. }
  962. PMAILSLOT_BUFFER
  963. BowserAllocateMailslotBuffer(
  964. IN PTRANSPORT_NAME TransportName,
  965. IN ULONG RequestedBufferSize
  966. )
  967. /*++
  968. Routine Description:
  969. This routine will allocate a mailslot buffer from the mailslot buffer pool.
  970. If it is unable to allocate a buffer, it will allocate the buffer from
  971. non-paged pool (up to the maximum configured by the user).
  972. Arguments:
  973. TransportName - The transport name for this request.
  974. RequestedBufferSize - Minimum size of buffer to allocate.
  975. Return Value:
  976. MAILSLOT_BUFFER - The allocated buffer.
  977. --*/
  978. {
  979. KIRQL OldIrql;
  980. PMAILSLOT_BUFFER Buffer = NULL;
  981. ULONG BufferSize;
  982. BOOLEAN AllocatingMaxBuffer = FALSE;
  983. //
  984. // If the request fits into a cached buffer,
  985. // and there is a cache buffer available,
  986. // use it.
  987. //
  988. ACQUIRE_SPIN_LOCK(&BowserMailslotSpinLock, &OldIrql);
  989. if ( RequestedBufferSize <= BOWSER_MAX_DATAGRAM_SIZE &&
  990. !IsListEmpty(&BowserMailslotBufferList)) {
  991. PMAILSLOT_BUFFER Buffer;
  992. PLIST_ENTRY Entry;
  993. Entry = RemoveHeadList(&BowserMailslotBufferList);
  994. BowserNumberOfFreeMailslotBuffers --;
  995. Buffer = CONTAINING_RECORD(Entry, MAILSLOT_BUFFER, Overlay.NextBuffer);
  996. #if DBG
  997. BowserMailslotCacheHitCount++;
  998. #endif // DBG
  999. RELEASE_SPIN_LOCK(&BowserMailslotSpinLock, OldIrql);
  1000. Buffer->TransportName = TransportName;
  1001. BowserReferenceTransportName(TransportName);
  1002. BowserReferenceTransport( TransportName->Transport );
  1003. return Buffer;
  1004. }
  1005. //
  1006. // If we've got too many buffers allocated,
  1007. // don't allocate any more.
  1008. //
  1009. // BowserData.NumberOfMailslotBuffers is the maximum number we're allowed to have
  1010. // in the cache at once. It defaults to 3.
  1011. //
  1012. // BrPnp[NETLOGON].MaxMessageCount is the number of buffers the netlogon service may
  1013. // have queued at any one point in time. It may be zero when netlogon isn't
  1014. // running or if we're running on a non-DC. On DC's it defaults to 500.
  1015. //
  1016. // Add 50, to ensure we don't limit it by too much.
  1017. //
  1018. if ( (ULONG)BowserNumberOfMailslotBuffers >=
  1019. max( (ULONG)BowserData.NumberOfMailslotBuffers, BowserPnp[NETLOGON_PNP].MaxMessageCount+50 )) {
  1020. BowserStatistics.NumberOfMissedMailslotDatagrams += 1;
  1021. BowserNumberOfMissedMailslotDatagrams += 1;
  1022. RELEASE_SPIN_LOCK(&BowserMailslotSpinLock, OldIrql);
  1023. return NULL;
  1024. }
  1025. //
  1026. // The first few buffers we allocate should be maximum size so we can keep a preallocated
  1027. // cache of huge buffers.
  1028. //
  1029. if ( BowserNumberOfMaxSizeMailslotBuffers < BowserData.NumberOfMailslotBuffers &&
  1030. RequestedBufferSize <= BOWSER_MAX_DATAGRAM_SIZE ) {
  1031. BufferSize = FIELD_OFFSET(MAILSLOT_BUFFER, Buffer) + BOWSER_MAX_DATAGRAM_SIZE;
  1032. AllocatingMaxBuffer = TRUE;
  1033. BowserNumberOfMaxSizeMailslotBuffers += 1;
  1034. } else {
  1035. BufferSize = FIELD_OFFSET(MAILSLOT_BUFFER, Buffer) + RequestedBufferSize;
  1036. }
  1037. BowserNumberOfMailslotBuffers += 1;
  1038. ASSERT ( (BufferSize - FIELD_OFFSET(MAILSLOT_BUFFER, Buffer)) <= 0xffff);
  1039. #if DBG
  1040. BowserMailslotCacheMissCount++;
  1041. #endif // DBG
  1042. RELEASE_SPIN_LOCK(&BowserMailslotSpinLock, OldIrql);
  1043. Buffer = ALLOCATE_POOL(NonPagedPool, BufferSize, POOL_MAILSLOT_BUFFER);
  1044. //
  1045. // If we couldn't allocate the buffer from non paged pool, give up.
  1046. //
  1047. if (Buffer == NULL) {
  1048. ACQUIRE_SPIN_LOCK(&BowserMailslotSpinLock, &OldIrql);
  1049. ASSERT (BowserNumberOfMailslotBuffers);
  1050. BowserNumberOfMailslotBuffers -= 1;
  1051. if ( AllocatingMaxBuffer ) {
  1052. BowserNumberOfMaxSizeMailslotBuffers -= 1;
  1053. }
  1054. RELEASE_SPIN_LOCK(&BowserMailslotSpinLock, OldIrql);
  1055. BowserStatistics.NumberOfFailedMailslotAllocations += 1;
  1056. //
  1057. // Since we couldn't allocate this buffer, we've effectively missed
  1058. // this mailslot request.
  1059. //
  1060. BowserStatistics.NumberOfMissedMailslotDatagrams += 1;
  1061. BowserNumberOfMissedMailslotDatagrams += 1;
  1062. return NULL;
  1063. }
  1064. Buffer->Signature = STRUCTURE_SIGNATURE_MAILSLOT_BUFFER;
  1065. Buffer->Size = FIELD_OFFSET(MAILSLOT_BUFFER, Buffer);
  1066. Buffer->BufferSize = BufferSize - FIELD_OFFSET(MAILSLOT_BUFFER, Buffer);
  1067. Buffer->TransportName = TransportName;
  1068. BowserReferenceTransportName(TransportName);
  1069. BowserReferenceTransport( TransportName->Transport );
  1070. return Buffer;
  1071. }
  1072. VOID
  1073. BowserFreeMailslotBuffer(
  1074. IN PMAILSLOT_BUFFER Buffer
  1075. )
  1076. /*++
  1077. Routine Description:
  1078. This routine will return a mailslot buffer to the view buffer pool.
  1079. If the buffer was allocated from must-succeed pool, it is freed back
  1080. to pool. In addition, if the buffer is smaller than the current
  1081. max view buffer size, we free it.
  1082. Arguments:
  1083. IN PVIEW_BUFFER Buffer - Supplies the buffer to free
  1084. Return Value:
  1085. None.
  1086. --*/
  1087. {
  1088. KIRQL OldIrql;
  1089. PTRANSPORT Transport;
  1090. BowserReferenceDiscardableCode( BowserDiscardableCodeSection );
  1091. DISCARDABLE_CODE( BowserDiscardableCodeSection );
  1092. Transport = Buffer->TransportName->Transport;
  1093. (VOID) BowserDereferenceTransportName( Buffer->TransportName );
  1094. BowserDereferenceTransport( Transport);
  1095. ACQUIRE_SPIN_LOCK(&BowserMailslotSpinLock, &OldIrql);
  1096. //
  1097. // Also, if a new transport was added that is larger than this buffer,
  1098. // we want to free the buffer.
  1099. //
  1100. //
  1101. // If we have more mailslot buffers than the size of our lookaside list,
  1102. // free it, don't stick it on our lookaside list.
  1103. //
  1104. if (Buffer->BufferSize != BOWSER_MAX_DATAGRAM_SIZE ||
  1105. BowserNumberOfFreeMailslotBuffers > BowserData.NumberOfMailslotBuffers) {
  1106. //
  1107. // Since we're returning this buffer to pool, we shouldn't count it
  1108. // against our total number of mailslot buffers.
  1109. //
  1110. BowserNumberOfMailslotBuffers -= 1;
  1111. ASSERT (BowserNumberOfMailslotBuffers >= 0);
  1112. RELEASE_SPIN_LOCK(&BowserMailslotSpinLock, OldIrql);
  1113. FREE_POOL(Buffer);
  1114. BowserDereferenceDiscardableCode( BowserDiscardableCodeSection );
  1115. return;
  1116. }
  1117. InsertTailList(&BowserMailslotBufferList, &Buffer->Overlay.NextBuffer);
  1118. BowserNumberOfFreeMailslotBuffers ++;
  1119. RELEASE_SPIN_LOCK(&BowserMailslotSpinLock, OldIrql);
  1120. BowserDereferenceDiscardableCode( BowserDiscardableCodeSection );
  1121. }
  1122. VOID
  1123. BowserFreeMailslotBufferHighIrql(
  1124. IN PMAILSLOT_BUFFER Buffer
  1125. )
  1126. /*++
  1127. Routine Description:
  1128. This routine will return a mailslot buffer to the view buffer pool if the
  1129. caller is at raised irql.
  1130. Arguments:
  1131. Buffer - Supplies the buffer to free
  1132. Return Value:
  1133. None.
  1134. --*/
  1135. {
  1136. //
  1137. // Queue the request to a worker routine.
  1138. //
  1139. ExInitializeWorkItem(&Buffer->Overlay.WorkHeader,
  1140. (PWORKER_THREAD_ROUTINE) BowserFreeMailslotBuffer,
  1141. Buffer);
  1142. BowserQueueDelayedWorkItem( &Buffer->Overlay.WorkHeader );
  1143. }
  1144. VOID
  1145. BowserpInitializeMailslot (
  1146. VOID
  1147. )
  1148. /*++
  1149. Routine Description:
  1150. This routine will allocate a transport descriptor and bind the bowser
  1151. to the transport.
  1152. Arguments:
  1153. None
  1154. Return Value:
  1155. None
  1156. --*/
  1157. {
  1158. PBROWSER_PNP_STATE BrPnp;
  1159. KeInitializeSpinLock(&BowserMailslotSpinLock);
  1160. InitializeListHead(&BowserMailslotBufferList);
  1161. for ( BrPnp=&BowserPnp[0];
  1162. BrPnp<&BowserPnp[BOWSER_PNP_COUNT];
  1163. BrPnp++) {
  1164. InitializeListHead(&BrPnp->MailslotMessageQueue);
  1165. InitializeListHead(&BrPnp->PnpQueue);
  1166. BowserInitializeIrpQueue( &BrPnp->IrpQueue );
  1167. }
  1168. }
  1169. VOID
  1170. BowserpUninitializeMailslot (
  1171. VOID
  1172. )
  1173. /*++
  1174. Routine Description:
  1175. Arguments:
  1176. None
  1177. Return Value:
  1178. None
  1179. --*/
  1180. {
  1181. PBROWSER_PNP_STATE BrPnp;
  1182. PAGED_CODE();
  1183. //
  1184. // Trim the netlogon message queue to zero entries.
  1185. //
  1186. for ( BrPnp=&BowserPnp[0];
  1187. BrPnp<&BowserPnp[BOWSER_PNP_COUNT];
  1188. BrPnp++) {
  1189. BrPnp->MaxMessageCount = 0;
  1190. BowserTrimMessageQueue(BrPnp);
  1191. BowserUninitializeIrpQueue( &BrPnp->IrpQueue );
  1192. }
  1193. //
  1194. // Free the mailslot buffers.
  1195. while (!IsListEmpty(&BowserMailslotBufferList)) {
  1196. PLIST_ENTRY Entry;
  1197. PMAILSLOT_BUFFER Buffer;
  1198. Entry = RemoveHeadList(&BowserMailslotBufferList);
  1199. Buffer = CONTAINING_RECORD(Entry, MAILSLOT_BUFFER, Overlay.NextBuffer);
  1200. FREE_POOL(Buffer);
  1201. }
  1202. }