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

1719 lines
50 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. receive.c
  5. Abstract:
  6. This module implements the routines needed to process TDI receive
  7. indication requests.
  8. Author:
  9. Larry Osterman (larryo) 6-May-1991
  10. Revision History:
  11. 6-May-1991 LarryO
  12. Created
  13. --*/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. //
  17. // Keep track of the number of datagram queued to worker threads.
  18. // Keep a separate count of critical versus non-critical to ensure non-critical
  19. // datagrams don't starve critical ones.
  20. //
  21. LONG BowserPostedDatagramCount;
  22. LONG BowserPostedCriticalDatagramCount;
  23. #define BOWSER_MAX_POSTED_DATAGRAMS 100
  24. #define INCLUDE_SMB_TRANSACTION
  25. typedef struct _PROCESS_MASTER_ANNOUNCEMENT_CONTEXT {
  26. WORK_QUEUE_ITEM WorkItem;
  27. PTRANSPORT Transport;
  28. ULONG ServerType;
  29. ULONG ServerElectionVersion;
  30. UCHAR MasterName[NETBIOS_NAME_LEN];
  31. ULONG MasterAddressLength;
  32. UCHAR Buffer[1];
  33. } PROCESS_MASTER_ANNOUNCEMENT_CONTEXT, *PPROCESS_MASTER_ANNOUNCEMENT_CONTEXT;
  34. typedef struct _ILLEGAL_DATAGRAM_CONTEXT {
  35. WORK_QUEUE_ITEM WorkItem;
  36. PTRANSPORT_NAME TransportName;
  37. NTSTATUS EventStatus;
  38. USHORT BufferSize;
  39. UCHAR SenderName[max(NETBIOS_NAME_LEN, SMB_IPX_NAME_LENGTH)];
  40. UCHAR Buffer[1];
  41. } ILLEGAL_DATAGRAM_CONTEXT, *PILLEGAL_DATAGRAM_CONTEXT;
  42. VOID
  43. BowserLogIllegalDatagramWorker(
  44. IN PVOID Ctx
  45. );
  46. VOID
  47. BowserProcessMasterAnnouncement(
  48. IN PVOID Ctx
  49. );
  50. DATAGRAM_HANDLER(
  51. HandleLocalMasterAnnouncement
  52. );
  53. DATAGRAM_HANDLER(
  54. HandleAnnounceRequest
  55. );
  56. NTSTATUS
  57. CompleteReceiveMailslot (
  58. IN PDEVICE_OBJECT TransportDevice,
  59. IN PIRP Irp,
  60. IN PVOID Context
  61. );
  62. NTSTATUS
  63. CompleteShortBrowserPacket (
  64. IN PDEVICE_OBJECT TransportDevice,
  65. IN PIRP Irp,
  66. IN PVOID Ctx
  67. );
  68. #ifdef ALLOC_PRAGMA
  69. #pragma alloc_text(PAGE, BowserLogIllegalDatagramWorker)
  70. #pragma alloc_text(PAGE, BowserProcessMasterAnnouncement)
  71. #endif
  72. PDATAGRAM_HANDLER
  73. BowserDatagramHandlerTable[] = {
  74. NULL, // 0 - Illegal (no opcode for this).
  75. BowserHandleServerAnnouncement, // 1 - HostAnnouncement
  76. HandleAnnounceRequest, // 2 - AnnouncementRequest
  77. NULL, // 3 - InterrogateInfoRequest
  78. NULL, // 4 - RelogonRequest
  79. NULL, // 5
  80. NULL, // 6
  81. NULL, // 7
  82. BowserHandleElection, // 8 - Election
  83. BowserGetBackupListRequest, // 9 - GetBackupListReq
  84. BowserGetBackupListResponse, // a - GetBackupListResp
  85. BowserHandleBecomeBackup, // b - BecomeBackupServer
  86. BowserHandleDomainAnnouncement, // c - WkGroupAnnouncement,
  87. BowserMasterAnnouncement, // d - MasterAnnouncement,
  88. BowserResetState, // e - ResetBrowserState
  89. HandleLocalMasterAnnouncement // f - LocalMasterAnnouncement
  90. };
  91. NTSTATUS
  92. BowserTdiReceiveDatagramHandler (
  93. IN PVOID TdiEventContext, // the event context
  94. IN LONG SourceAddressLength, // length of the originator of the datagram
  95. IN PVOID SourceAddress, // string describing the originator of the datagram
  96. IN LONG OptionsLength, // options for the receive
  97. IN PVOID Options, //
  98. IN ULONG ReceiveDatagramFlags, //
  99. IN ULONG BytesIndicated, // number of bytes this indication
  100. IN ULONG BytesAvailable, // number of bytes in complete Tsdu
  101. OUT ULONG *BytesTaken, // number of bytes used
  102. IN PVOID Tsdu, // pointer describing this TSDU, typically a lump of bytes
  103. OUT PIRP *IoRequestPacket // TdiReceive IRP if MORE_PROCESSING_REQUIRED.
  104. )
  105. /*++
  106. Routine Description:
  107. This routine will process receive datagram indication messages, and
  108. process them as appropriate.
  109. Arguments:
  110. IN PVOID TdiEventContext - the event context
  111. IN int SourceAddressLength - length of the originator of the datagram
  112. IN PVOID SourceAddress, - string describing the originator of the datagram
  113. IN int OptionsLength, - options for the receive
  114. IN PVOID Options, -
  115. IN ULONG BytesIndicated, - number of bytes this indication
  116. IN ULONG BytesAvailable, - number of bytes in complete Tsdu
  117. OUT ULONG *BytesTaken, - number of bytes used
  118. IN PVOID Tsdu, - pointer describing this TSDU, typically a lump of bytes
  119. OUT PIRP *IoRequestPacket - TdiReceive IRP if MORE_PROCESSING_REQUIRED.
  120. Return Value:
  121. NTSTATUS - Status of operation.
  122. --*/
  123. {
  124. PVOID DatagramData;
  125. PINTERNAL_TRANSACTION InternalTransaction = NULL;
  126. ULONG DatagramDataSize;
  127. PTRANSPORT_NAME TransportName = TdiEventContext;
  128. MAILSLOTTYPE Opcode;
  129. PTA_NETBIOS_ADDRESS NetbiosAddress = SourceAddress;
  130. if (BytesAvailable > ((PTRANSPORT_NAME)TdiEventContext)->Transport->DatagramSize) {
  131. return STATUS_REQUEST_NOT_ACCEPTED;
  132. }
  133. ASSERT (SourceAddressLength <= sizeof(TA_NETBIOS_ADDRESS));
  134. //
  135. // Classify the incoming packet according to it's type. Depending on
  136. // the type, either process it as:
  137. //
  138. // 1) A server announcement
  139. // 2) An incoming mailslot
  140. // 3) A relogon request
  141. //
  142. Opcode = BowserClassifyIncomingDatagram(Tsdu, BytesIndicated,
  143. &DatagramData,
  144. &DatagramDataSize);
  145. if (Opcode == MailslotTransaction) {
  146. return BowserHandleMailslotTransaction(
  147. TransportName,
  148. NetbiosAddress->Address[0].Address->NetbiosName,
  149. 0, // SMB offset into TSDU
  150. ReceiveDatagramFlags,
  151. BytesIndicated,
  152. BytesAvailable,
  153. BytesTaken,
  154. Tsdu,
  155. IoRequestPacket );
  156. } else if (Opcode == Illegal) {
  157. BowserLogIllegalDatagram(TdiEventContext,
  158. Tsdu,
  159. (USHORT)(BytesIndicated & 0xffff),
  160. NetbiosAddress->Address[0].Address->NetbiosName,
  161. ReceiveDatagramFlags);
  162. return STATUS_REQUEST_NOT_ACCEPTED;
  163. } else {
  164. if (BowserDatagramHandlerTable[Opcode] == NULL) {
  165. return STATUS_SUCCESS;
  166. }
  167. //
  168. // If this isn't the full packet, post a receive for it and
  169. // handle it when we finally complete the receive.
  170. //
  171. if (BytesIndicated < BytesAvailable) {
  172. return BowserHandleShortBrowserPacket(TransportName,
  173. TdiEventContext,
  174. SourceAddressLength,
  175. SourceAddress,
  176. OptionsLength,
  177. Options,
  178. ReceiveDatagramFlags,
  179. BytesAvailable,
  180. BytesTaken,
  181. IoRequestPacket,
  182. BowserTdiReceiveDatagramHandler
  183. );
  184. }
  185. InternalTransaction = DatagramData;
  186. if (((Opcode == WkGroupAnnouncement) ||
  187. (Opcode == HostAnnouncement)) && !TransportName->ProcessHostAnnouncements) {
  188. return STATUS_REQUEST_NOT_ACCEPTED;
  189. }
  190. ASSERT (DatagramDataSize == (BytesIndicated - ((PCHAR)InternalTransaction - (PCHAR)Tsdu)));
  191. ASSERT (FIELD_OFFSET(INTERNAL_TRANSACTION, Union.Announcement) == FIELD_OFFSET(INTERNAL_TRANSACTION, Union.BrowseAnnouncement));
  192. ASSERT (FIELD_OFFSET(INTERNAL_TRANSACTION, Union.Announcement) == FIELD_OFFSET(INTERNAL_TRANSACTION, Union.RequestElection));
  193. ASSERT (FIELD_OFFSET(INTERNAL_TRANSACTION, Union.Announcement) == FIELD_OFFSET(INTERNAL_TRANSACTION, Union.BecomeBackup));
  194. ASSERT (FIELD_OFFSET(INTERNAL_TRANSACTION, Union.Announcement) == FIELD_OFFSET(INTERNAL_TRANSACTION, Union.GetBackupListRequest));
  195. ASSERT (FIELD_OFFSET(INTERNAL_TRANSACTION, Union.Announcement) == FIELD_OFFSET(INTERNAL_TRANSACTION, Union.GetBackupListResp));
  196. ASSERT (FIELD_OFFSET(INTERNAL_TRANSACTION, Union.Announcement) == FIELD_OFFSET(INTERNAL_TRANSACTION, Union.ResetState));
  197. ASSERT (FIELD_OFFSET(INTERNAL_TRANSACTION, Union.Announcement) == FIELD_OFFSET(INTERNAL_TRANSACTION, Union.MasterAnnouncement));
  198. return BowserDatagramHandlerTable[Opcode](TdiEventContext,
  199. &InternalTransaction->Union.Announcement,
  200. BytesIndicated-((PCHAR)&InternalTransaction->Union.Announcement - (PCHAR)Tsdu),
  201. BytesTaken,
  202. SourceAddress,
  203. SourceAddressLength,
  204. NetbiosAddress->Address[0].Address->NetbiosName,
  205. NETBIOS_NAME_LEN,
  206. ReceiveDatagramFlags);
  207. }
  208. return STATUS_SUCCESS;
  209. UNREFERENCED_PARAMETER(OptionsLength);
  210. UNREFERENCED_PARAMETER(Options);
  211. UNREFERENCED_PARAMETER(ReceiveDatagramFlags);
  212. }
  213. VOID
  214. BowserLogIllegalDatagram(
  215. IN PTRANSPORT_NAME TransportName,
  216. IN PVOID IncomingBuffer,
  217. IN USHORT BufferSize,
  218. IN PCHAR ClientName,
  219. IN ULONG ReceiveFlags
  220. )
  221. {
  222. KIRQL OldIrql;
  223. NTSTATUS ErrorStatus = STATUS_SUCCESS;
  224. ExInterlockedAddLargeStatistic(&BowserStatistics.NumberOfIllegalDatagrams, 1);
  225. ACQUIRE_SPIN_LOCK(&BowserTimeSpinLock, &OldIrql);
  226. if (BowserIllegalDatagramCount > 0) {
  227. BowserIllegalDatagramCount -= 1;
  228. ErrorStatus = EVENT_BOWSER_ILLEGAL_DATAGRAM;
  229. } else if (!BowserIllegalDatagramThreshold) {
  230. BowserIllegalDatagramThreshold = TRUE;
  231. ErrorStatus = EVENT_BOWSER_ILLEGAL_DATAGRAM_THRESHOLD;
  232. }
  233. RELEASE_SPIN_LOCK(&BowserTimeSpinLock, OldIrql);
  234. // if (!memcmp(TransportName->Transport->ComputerName->Name->NetbiosName.Address[0].Address->NetbiosName, ClientAddress->Address[0].Address->NetbiosName, CNLEN)) {
  235. // DbgBreakPoint();
  236. // }
  237. if (ErrorStatus != STATUS_SUCCESS) {
  238. PILLEGAL_DATAGRAM_CONTEXT Context = NULL;
  239. Context = ALLOCATE_POOL(NonPagedPool, sizeof(ILLEGAL_DATAGRAM_CONTEXT)+BufferSize, POOL_ILLEGALDGRAM);
  240. if (Context != NULL) {
  241. Context->EventStatus = ErrorStatus;
  242. Context->TransportName = TransportName;
  243. Context->BufferSize = BufferSize;
  244. TdiCopyLookaheadData(&Context->Buffer, IncomingBuffer, BufferSize, 0);
  245. BowserCopyOemComputerName( Context->SenderName,
  246. ClientName,
  247. sizeof(Context->SenderName),
  248. ReceiveFlags);
  249. ExInitializeWorkItem(&Context->WorkItem, BowserLogIllegalDatagramWorker, Context);
  250. ExQueueWorkItem(&Context->WorkItem, DelayedWorkQueue);
  251. }
  252. }
  253. }
  254. VOID
  255. BowserCopyOemComputerName(
  256. PCHAR OutputComputerName,
  257. PCHAR NetbiosName,
  258. ULONG NetbiosNameLength,
  259. IN ULONG ReceiveFlags
  260. )
  261. {
  262. ULONG i;
  263. //
  264. // Since this routine can be called at indication time, we need to use
  265. // TdiCopyLookaheadData
  266. //
  267. TdiCopyLookaheadData(OutputComputerName, NetbiosName, NetbiosNameLength, ReceiveFlags);
  268. for (i = NetbiosNameLength-2; i ; i -= 1) {
  269. if ((OutputComputerName[i] != ' ') &&
  270. (OutputComputerName[i] != '\0')) {
  271. OutputComputerName[i+1] = '\0';
  272. break;
  273. }
  274. }
  275. }
  276. VOID
  277. BowserLogIllegalDatagramWorker(
  278. IN PVOID Ctx
  279. )
  280. {
  281. PILLEGAL_DATAGRAM_CONTEXT Context = Ctx;
  282. NTSTATUS EventContext = Context->EventStatus;
  283. LPWSTR TransportNamePointer = &Context->TransportName->Transport->PagedTransport->TransportName.Buffer[(sizeof(L"\\Device\\") / sizeof(WCHAR))-1];
  284. LPWSTR NamePointer = Context->TransportName->PagedTransportName->Name->Name.Buffer;
  285. UNICODE_STRING ClientNameU;
  286. OEM_STRING ClientNameO;
  287. NTSTATUS Status;
  288. PAGED_CODE();
  289. RtlInitAnsiString(&ClientNameO, Context->SenderName);
  290. Status = RtlOemStringToUnicodeString(&ClientNameU, &ClientNameO, TRUE);
  291. if (!NT_SUCCESS(Status)) {
  292. BowserWriteErrorLogEntry(EVENT_BOWSER_NAME_CONVERSION_FAILED, Status, ClientNameO.Buffer, ClientNameO.Length, 0);
  293. return;
  294. }
  295. BowserWriteErrorLogEntry(EventContext, STATUS_REQUEST_NOT_ACCEPTED,
  296. Context->Buffer,
  297. Context->BufferSize,
  298. 3, ClientNameU.Buffer,
  299. NamePointer,
  300. TransportNamePointer);
  301. RtlFreeUnicodeString(&ClientNameU);
  302. FREE_POOL(Context);
  303. }
  304. CHAR BowserMinimumDatagramSize[] = {
  305. (CHAR)0xff, // 0 - Illegal (no opcode for this).
  306. (CHAR)FIELD_OFFSET(INTERNAL_TRANSACTION, Union.Announcement.NameComment), // HostAnnouncement
  307. (CHAR)0xff, // AnnouncementRequest
  308. (CHAR)0xff, // InterrogateInfoRequest
  309. (CHAR)0xff, // RelogonRequest
  310. (CHAR)0xff, // 5
  311. (CHAR)0xff, // 6
  312. (CHAR)0xff, // 7
  313. (CHAR)FIELD_OFFSET(INTERNAL_TRANSACTION, Union.RequestElection.ServerName),// Election
  314. (CHAR)FIELD_OFFSET(INTERNAL_TRANSACTION, Union.GetBackupListRequest.Token),// GetBackupListReq
  315. (CHAR)FIELD_OFFSET(INTERNAL_TRANSACTION, Union.GetBackupListResp.Token), // GetBackupListResp
  316. (CHAR)FIELD_OFFSET(INTERNAL_TRANSACTION, Union.BecomeBackup.BrowserToPromote), // BecomeBackupServer
  317. (CHAR)FIELD_OFFSET(INTERNAL_TRANSACTION, Union.BrowseAnnouncement.Comment), // WkGroupAnnouncement,
  318. (CHAR)FIELD_OFFSET(INTERNAL_TRANSACTION, Union.ResetState.Options), // ResetBrowserState
  319. (CHAR)FIELD_OFFSET(INTERNAL_TRANSACTION, Union.MasterAnnouncement.MasterName), // MasterAnnouncement,
  320. (CHAR)FIELD_OFFSET(INTERNAL_TRANSACTION, Union.Announcement.NameComment) // LocalMasterAnnouncement
  321. };
  322. MAILSLOTTYPE
  323. BowserClassifyIncomingDatagram(
  324. IN PVOID Buffer,
  325. IN ULONG BufferLength,
  326. OUT PVOID *DatagramData,
  327. OUT PULONG DatagramDataSize
  328. )
  329. /*++
  330. Routine Description:
  331. This routine will classify an incoming datagram into its type - either
  332. Illegal, ServerAnnouncement, MailslotRequest, or RelogonRequest.
  333. Arguments:
  334. IN PVOID Buffer, - pointer describing this TSDU, typically a lump of bytes
  335. IN ULONG BufferLength - number of bytes in complete Tsdu
  336. Return Value:
  337. NTSTATUS - Status of operation.
  338. --*/
  339. {
  340. PSMB_HEADER Header = Buffer;
  341. PSMB_TRANSACT_MAILSLOT Transaction = (PSMB_TRANSACT_MAILSLOT) (Header+1);
  342. PSZ MailslotName = Transaction->Buffer;
  343. PINTERNAL_TRANSACTION InternalTransaction;
  344. BOOLEAN MailslotLanman = FALSE;
  345. BOOLEAN MailslotBrowse = FALSE;
  346. ULONG i;
  347. ULONG MaxMailslotNameLength;
  348. ASSERT (sizeof(BowserMinimumDatagramSize) == MaximumMailslotType);
  349. //
  350. // We only know things that start with an SMB header.
  351. //
  352. if ((BufferLength < sizeof(SMB_HEADER)) ||
  353. (SmbGetUlong(((PULONG )Header->Protocol)) != (ULONG)SMB_HEADER_PROTOCOL) ||
  354. //
  355. // All mailslots and server announcements go via the transaction SMB
  356. // protocol.
  357. //
  358. (Header->Command != SMB_COM_TRANSACTION) ||
  359. //
  360. // The buffer has to be big enough to hold a mailslot transaction.
  361. //
  362. (BufferLength <= (FIELD_OFFSET(SMB_TRANSACT_MAILSLOT, Buffer) + sizeof(SMB_HEADER)) + SMB_MAILSLOT_PREFIX_LENGTH) ||
  363. //
  364. // The word count for a transaction SMB is 17 (14+3 setup words).
  365. //
  366. (Transaction->WordCount != 17) ||
  367. //
  368. // There must be 3 setup words.
  369. //
  370. (Transaction->SetupWordCount != 3) ||
  371. // //
  372. // // Mailslot and server announcements expect no response.
  373. // //
  374. //
  375. // (!(SmbGetUshort(&Transaction->Flags) & SMB_TRANSACTION_NO_RESPONSE)) ||
  376. //
  377. // There are no parameter bytes for a mailslot write.
  378. //
  379. (SmbGetUshort(&Transaction->TotalParameterCount) != 0) ||
  380. //
  381. // This must be a mailslot write command.
  382. //
  383. (SmbGetUshort(&Transaction->Opcode) != TRANS_MAILSLOT_WRITE) ||
  384. //
  385. // And it must be a second class mailslot write.
  386. //
  387. (SmbGetUshort(&Transaction->Class) != 2) ||
  388. _strnicmp(MailslotName, SMB_MAILSLOT_PREFIX,
  389. min(SMB_MAILSLOT_PREFIX_LENGTH,
  390. BufferLength-((PCHAR)Buffer-(PCHAR)MailslotName)))) {
  391. return Illegal;
  392. }
  393. //
  394. // Ensure there's a zero byte in the mailslotname
  395. //
  396. MaxMailslotNameLength =
  397. min( MAXIMUM_FILENAME_LENGTH-7, // \Device
  398. BufferLength-((PCHAR)Buffer-(PCHAR)MailslotName));
  399. for ( i = SMB_MAILSLOT_PREFIX_LENGTH; i < MaxMailslotNameLength; i++ ) {
  400. if ( MailslotName[i] == '\0' ) {
  401. break;
  402. }
  403. }
  404. if ( i == MaxMailslotNameLength ) {
  405. return Illegal;
  406. }
  407. //
  408. // We now know this is a mailslot of some kind. Now check what type
  409. // of mailslot it is.
  410. //
  411. *DatagramData = (((PCHAR )Header) + SmbGetUshort(&Transaction->DataOffset));
  412. //
  413. // There are two special mailslot names we understand, \MAILSLOT\LANMAN,
  414. // and \MAILSLOT\BROWSE
  415. //
  416. if (_strnicmp(MailslotName, MAILSLOT_LANMAN_NAME, min(sizeof(MAILSLOT_LANMAN_NAME)-1, BufferLength-((PCHAR)Buffer-(PCHAR)MailslotName)))) {
  417. if (_strnicmp(MailslotName, MAILSLOT_BROWSER_NAME, min(sizeof(MAILSLOT_BROWSER_NAME)-1, BufferLength-((PCHAR)Buffer-(PCHAR)MailslotName)))) {
  418. return MailslotTransaction;
  419. } else {
  420. MailslotBrowse = TRUE;
  421. }
  422. } else {
  423. MailslotLanman = TRUE;
  424. }
  425. //
  426. // This mailslot write is to the special mailslot \MAILSLOT\LANMAN (or \MAILSLOT\MSBROWSE).
  427. //
  428. //
  429. // Make sure that the datagram is at least long enough to contain a type.
  430. //
  431. InternalTransaction = *DatagramData;
  432. *DatagramDataSize = (BufferLength - ((PCHAR)InternalTransaction - (PCHAR)Buffer));
  433. if (InternalTransaction->Type >= MaximumMailslotType) {
  434. return Illegal;
  435. }
  436. if (((LONG)*DatagramDataSize) < BowserMinimumDatagramSize[InternalTransaction->Type]) {
  437. return Illegal;
  438. }
  439. // //
  440. // // Figure out what type of mailslot it is by looking at the
  441. // // data in the message.
  442. // //
  443. //
  444. //
  445. // //
  446. // // Depending on which special mailslot this is, certain types of requests
  447. // // are illegal.
  448. // //
  449. // switch (InternalTransaction->Type) {
  450. // case InterrogateInfoRequest:
  451. // case RelogonRequest:
  452. // if (MailslotBrowse) {
  453. // return Illegal;
  454. // }
  455. // break;
  456. //
  457. // case GetBackupListReq:
  458. // case GetBackupListResp:
  459. // case BecomeBackupServer:
  460. // case WkGroupAnnouncement:
  461. // case MasterAnnouncement:
  462. // case Election:
  463. // if (MailslotLanman) {
  464. // return Illegal;
  465. // }
  466. // break;
  467. // }
  468. //
  469. //
  470. // The type of this request is the first UCHAR inside the transaction
  471. // data.
  472. //
  473. return (MAILSLOTTYPE )InternalTransaction->Type;
  474. }
  475. DATAGRAM_HANDLER(
  476. HandleLocalMasterAnnouncement
  477. )
  478. /*++
  479. Routine Description:
  480. This routine will process receive datagram indication messages, and
  481. process them as appropriate.
  482. Arguments:
  483. IN PTRANSPORT Transport - The transport provider for this request.
  484. IN ULONG BytesAvailable - number of bytes in complete Tsdu
  485. IN PHOST_ANNOUNCE_PACKET_1 HostAnnouncement - the server announcement.
  486. IN ULONG BytesAvailable - The number of bytes in the announcement.
  487. OUT ULONG *BytesTaken - number of bytes used
  488. IN UCHAR Opcode - the mailslot write opcode.
  489. Return Value:
  490. NTSTATUS - Status of operation.
  491. --*/
  492. {
  493. PPROCESS_MASTER_ANNOUNCEMENT_CONTEXT Context = NULL;
  494. PBROWSE_ANNOUNCE_PACKET_1 BrowseAnnouncement = Buffer;
  495. if (BytesAvailable < FIELD_OFFSET(BROWSE_ANNOUNCE_PACKET_1, Comment)) {
  496. return(STATUS_REQUEST_NOT_ACCEPTED);
  497. }
  498. Context = ALLOCATE_POOL(NonPagedPool, sizeof(PROCESS_MASTER_ANNOUNCEMENT_CONTEXT) + SourceAddressLength, POOL_MASTERANNOUNCE);
  499. //
  500. // If we couldn't allocate the pool from non paged pool, just give up,
  501. // the master will announce within 15 minutes anyway.
  502. //
  503. if (Context == NULL) {
  504. return STATUS_SUCCESS;
  505. }
  506. ExInitializeWorkItem(&Context->WorkItem, BowserProcessMasterAnnouncement, Context);
  507. BowserReferenceTransport( TransportName->Transport );
  508. Context->Transport = TransportName->Transport;
  509. Context->ServerType = SmbGetUlong(&BrowseAnnouncement->Type);
  510. Context->ServerElectionVersion = SmbGetUlong(&BrowseAnnouncement->CommentPointer);
  511. RtlCopyMemory(Context->MasterName, BrowseAnnouncement->ServerName, sizeof(Context->MasterName)-1);
  512. Context->MasterName[sizeof(Context->MasterName)-1] = '\0';
  513. Context->MasterAddressLength = SourceAddressLength;
  514. TdiCopyLookaheadData(Context->Buffer, SourceAddress, SourceAddressLength, ReceiveFlags);
  515. ExQueueWorkItem(&Context->WorkItem, DelayedWorkQueue);
  516. //
  517. // If we are not processing host announcements for this
  518. // transport, ignore this request.
  519. //
  520. if (!TransportName->ProcessHostAnnouncements) {
  521. return STATUS_REQUEST_NOT_ACCEPTED;
  522. }
  523. DISCARDABLE_CODE( BowserDiscardableCodeSection );
  524. return BowserHandleServerAnnouncement(TransportName,
  525. Buffer,
  526. BytesAvailable,
  527. BytesTaken,
  528. SourceAddress,
  529. SourceAddressLength,
  530. SourceName,
  531. SourceNameLength,
  532. ReceiveFlags);
  533. }
  534. VOID
  535. BowserProcessMasterAnnouncement(
  536. IN PVOID Ctx
  537. )
  538. /*++
  539. Routine Description:
  540. This routine will process browser master announcements.
  541. Arguments:
  542. IN PVOID Context - Context block containing master name.
  543. Return Value:
  544. None.
  545. --*/
  546. {
  547. PPROCESS_MASTER_ANNOUNCEMENT_CONTEXT Context = Ctx;
  548. PTRANSPORT Transport = Context->Transport;
  549. UNICODE_STRING MasterName;
  550. OEM_STRING AnsiMasterName;
  551. WCHAR MasterNameBuffer[LM20_CNLEN+1];
  552. PAGED_CODE();
  553. try {
  554. NTSTATUS Status;
  555. PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport;
  556. LOCK_TRANSPORT(Transport);
  557. MasterName.Buffer = MasterNameBuffer;
  558. MasterName.MaximumLength = sizeof(MasterNameBuffer);
  559. //
  560. // If we are currently running an election, ignore this announcement.
  561. //
  562. if (Transport->ElectionState == RunningElection) {
  563. try_return(NOTHING);
  564. }
  565. RtlInitAnsiString(&AnsiMasterName, Context->MasterName);
  566. Status = RtlOemStringToUnicodeString(&MasterName, &AnsiMasterName, FALSE);
  567. if (!NT_SUCCESS(Status)) {
  568. BowserWriteErrorLogEntry(EVENT_BOWSER_NAME_CONVERSION_FAILED, Status, AnsiMasterName.Buffer, AnsiMasterName.Length, 0);
  569. try_return(NOTHING);
  570. }
  571. //
  572. // We've found our master - stop our timers - there's a master,
  573. // and any find masters we have outstanding will be completed.
  574. //
  575. PagedTransport->ElectionCount = 0;
  576. Transport->ElectionState = Idle;
  577. BowserStopTimer(&Transport->ElectionTimer);
  578. BowserStopTimer(&Transport->FindMasterTimer);
  579. //
  580. // If this address doesn't match the address we have for the master,
  581. // then use the new address.
  582. //
  583. if (Context->MasterAddressLength != PagedTransport->MasterBrowserAddress.Length ||
  584. !RtlEqualMemory(PagedTransport->MasterBrowserAddress.Buffer, Context->Buffer, Context->MasterAddressLength)) {
  585. ASSERT (Context->MasterAddressLength <= PagedTransport->MasterBrowserAddress.MaximumLength);
  586. if (Context->MasterAddressLength <= PagedTransport->MasterBrowserAddress.MaximumLength) {
  587. PagedTransport->MasterBrowserAddress.Length = (USHORT)Context->MasterAddressLength;
  588. RtlCopyMemory(PagedTransport->MasterBrowserAddress.Buffer, Context->Buffer, Context->MasterAddressLength);
  589. }
  590. }
  591. //
  592. // We got a master announcement from someone else. Remember the
  593. // transport address of the master.
  594. //
  595. if (!RtlEqualUnicodeString(&Transport->ComputerName->PagedTransportName->Name->Name, &MasterName, TRUE)) {
  596. BOOLEAN sendElection = FALSE;
  597. //
  598. // If we're a master, and we receive this from someone else,
  599. // stop being a master and force an election.
  600. //
  601. if (PagedTransport->Role == Master) {
  602. BowserStatistics.NumberOfDuplicateMasterAnnouncements += 1;
  603. BowserWriteErrorLogEntry(EVENT_BOWSER_OTHER_MASTER_ON_NET,
  604. STATUS_SUCCESS,
  605. NULL,
  606. 0,
  607. 2,
  608. MasterName.Buffer,
  609. &Transport->PagedTransport->TransportName.Buffer[(sizeof(L"\\Device\\") / sizeof(WCHAR))-1]);
  610. if (!(PagedTransport->Flags & ELECT_LOST_LAST_ELECTION)) {
  611. //
  612. // If we're the PDC, and we didn't lose the last election (ie.
  613. // we SHOULD be the browse master),then send a dummy election
  614. // packet to get the other guy to shut up.
  615. //
  616. if (BowserData.IsPrimaryDomainController) {
  617. sendElection = TRUE;
  618. //
  619. // If we're not an NTAS machine, or if we just lost the
  620. // last election, or if the guy announcing is a DC of some
  621. // kind, stop being the master and reset our state.
  622. //
  623. } else if (!BowserData.IsLanmanNt ||
  624. (Context->ServerType & (SV_TYPE_DOMAIN_BAKCTRL | SV_TYPE_DOMAIN_CTRL))) {
  625. //
  626. // If we're not the PDC, then we want to simply inform
  627. // the browser service that someone else is the master
  628. // and let things sort themselves out when it's done.
  629. //
  630. BowserResetStateForTransport(Transport, RESET_STATE_STOP_MASTER);
  631. }
  632. } else {
  633. //
  634. // If we lost the last election, then we want to shut down
  635. // the browser regardless of what state the other browser
  636. // is in.
  637. //
  638. BowserResetStateForTransport(Transport, RESET_STATE_STOP_MASTER);
  639. }
  640. }
  641. //
  642. // If this guy is a WfW machine, we must force an election to move
  643. // mastery off of the WfW machine.
  644. //
  645. if (Context->ServerType & SV_TYPE_WFW) {
  646. sendElection = TRUE;
  647. }
  648. //
  649. // If this guy is running an older version of the browser than we are,
  650. // and we didn't lose last election,
  651. // then force an election to try to become master.
  652. //
  653. // We check to see if we lost the last election to prevent us from
  654. // constantly forcing an election when the older version is still
  655. // a better browse master than we are.
  656. //
  657. if ((Context->ServerElectionVersion >> 16) == 0xaa55 &&
  658. (Context->ServerElectionVersion & 0xffff) <
  659. (BROWSER_VERSION_MAJOR << 8) + BROWSER_VERSION_MINOR &&
  660. !(PagedTransport->Flags & ELECT_LOST_LAST_ELECTION)) {
  661. sendElection = TRUE;
  662. }
  663. //
  664. // if we're an NTAS server, and the guy announcing as a master
  665. // isn't an NTAS server, and we won the last election, force an
  666. // election. This will tend mastership towards DC's.
  667. //
  668. if (BowserData.IsLanmanNt &&
  669. !(PagedTransport->Flags & ELECT_LOST_LAST_ELECTION)) {
  670. if (BowserData.IsPrimaryDomainController) {
  671. //
  672. // If we're the PDC and we didn't send the announcement,
  673. // force an election.
  674. //
  675. sendElection = TRUE;
  676. } else if (!(Context->ServerType & (SV_TYPE_DOMAIN_BAKCTRL | SV_TYPE_DOMAIN_CTRL))) {
  677. //
  678. // Otherwise, if the guy who announced isn't a DC, and we
  679. // are, force an election.
  680. //
  681. sendElection = TRUE;
  682. }
  683. }
  684. if (sendElection) {
  685. //
  686. // Send a dummy election packet. This will cause the
  687. // othe browser to stop being the master and will
  688. // allow the correct machine to become the master.
  689. //
  690. BowserSendElection(&Transport->PrimaryDomain->PagedTransportName->Name->Name,
  691. BrowserElection,
  692. Transport,
  693. FALSE);
  694. }
  695. //
  696. // We know who the master is, complete any find master request
  697. // outstanding now.
  698. //
  699. BowserCompleteFindMasterRequests(Transport, &MasterName, STATUS_SUCCESS);
  700. } else {
  701. if (PagedTransport->Role == Master) {
  702. BowserCompleteFindMasterRequests(Transport, &MasterName, STATUS_MORE_PROCESSING_REQUIRED);
  703. } else {
  704. //
  705. // If the transport is disabled,
  706. // we know this transport isn't really the master,
  707. // this datagram is probably just a datagram leaked from another
  708. // enabled transport on the same wire.
  709. //
  710. if ( !PagedTransport->DisabledTransport ) {
  711. BowserWriteErrorLogEntry(EVENT_BOWSER_NON_MASTER_MASTER_ANNOUNCE,
  712. STATUS_SUCCESS,
  713. NULL,
  714. 0,
  715. 1,
  716. MasterName.Buffer);
  717. //
  718. // Make sure that the service realizes it is out of sync
  719. // with the driver.
  720. //
  721. BowserResetStateForTransport(Transport, RESET_STATE_STOP_MASTER);
  722. }
  723. }
  724. }
  725. try_exit:NOTHING;
  726. } finally {
  727. UNLOCK_TRANSPORT(Transport);
  728. BowserDereferenceTransport( Transport );
  729. FREE_POOL(Context);
  730. }
  731. }
  732. NTSTATUS
  733. BowserHandleMailslotTransaction (
  734. IN PTRANSPORT_NAME TransportName,
  735. IN PCHAR ClientName,
  736. IN ULONG SmbOffset,
  737. IN DWORD ReceiveFlags,
  738. IN ULONG BytesIndicated,
  739. IN ULONG BytesAvailable,
  740. OUT ULONG *BytesTaken,
  741. IN PVOID Tsdu,
  742. OUT PIRP *Irp
  743. )
  744. /*++
  745. Routine Description:
  746. This routine will process receive datagram indication messages, and
  747. process them as appropriate.
  748. Arguments:
  749. TransportName - The transport name for this request.
  750. BytesAvailable - number of bytes in complete Tsdu
  751. Irp - I/O request packet used to complete the request
  752. SmbOffset - Offset from the beginning of the indicated data to the SMB
  753. BytesIndicated - Number of bytes currently available in the TSDU
  754. BytesTaken - Returns the number of bytes of TSDU already consumed
  755. Tsdu - The datagram itself.
  756. Return Value:
  757. NTSTATUS - Status of operation.
  758. --*/
  759. {
  760. PMAILSLOT_BUFFER Buffer;
  761. PDEVICE_OBJECT DeviceObject;
  762. PFILE_OBJECT FileObject;
  763. PTRANSPORT Transport = TransportName->Transport;
  764. ULONG BytesToReceive = BytesAvailable - SmbOffset;
  765. ASSERT (TransportName->Signature == STRUCTURE_SIGNATURE_TRANSPORTNAME);
  766. ASSERT (BytesAvailable <= TransportName->Transport->DatagramSize);
  767. //
  768. // We must ignore all mailslot requests coming to any names domains
  769. // other than the primary domain, the computer name, and the LanMan/NT
  770. // domain name.
  771. //
  772. if ((TransportName->NameType != ComputerName) &&
  773. (TransportName->NameType != AlternateComputerName) &&
  774. (TransportName->NameType != DomainName) &&
  775. (TransportName->NameType != PrimaryDomain) &&
  776. (TransportName->NameType != PrimaryDomainBrowser) ) {
  777. return STATUS_SUCCESS;
  778. }
  779. //
  780. // Now allocate a buffer to hold the data.
  781. //
  782. Buffer = BowserAllocateMailslotBuffer( TransportName, BytesToReceive );
  783. if (Buffer == NULL) {
  784. //
  785. // We couldn't allocate a buffer to hold the data - ditch the request.
  786. //
  787. return(STATUS_REQUEST_NOT_ACCEPTED);
  788. }
  789. ASSERT (Buffer->BufferSize >= BytesToReceive);
  790. KeQuerySystemTime( &Buffer->TimeReceived );
  791. //
  792. // Save away the name of the client
  793. // just in case the datagram turns out to be illegal.
  794. //
  795. TdiCopyLookaheadData(Buffer->ClientAddress, ClientName, max(NETBIOS_NAME_LEN, SMB_IPX_NAME_LENGTH), ReceiveFlags);
  796. //
  797. // If the entire datagram has been indicated (or already received as a short packet),
  798. // just copy the data into the Mailslot buffer directly.
  799. //
  800. if ( BytesAvailable == BytesIndicated ) {
  801. //
  802. // Copy the data into the mailslot buffer
  803. //
  804. Buffer->ReceiveLength = BytesToReceive;
  805. TdiCopyLookaheadData( Buffer->Buffer,
  806. ((LPBYTE)(Tsdu)) + SmbOffset,
  807. BytesToReceive,
  808. ReceiveFlags);
  809. //
  810. // Queue the request to the worker routine.
  811. //
  812. ExInitializeWorkItem(&Buffer->Overlay.WorkHeader,
  813. BowserProcessMailslotWrite,
  814. Buffer);
  815. ExQueueWorkItem(&Buffer->Overlay.WorkHeader, DelayedWorkQueue);
  816. return STATUS_SUCCESS;
  817. }
  818. //
  819. // We rely on the fact that the device object is NULL for
  820. // IPX transport names.
  821. //
  822. if (TransportName->DeviceObject == NULL) {
  823. ASSERT (Transport->IpxSocketDeviceObject != NULL);
  824. ASSERT (Transport->IpxSocketFileObject != NULL);
  825. ASSERT (TransportName->FileObject == NULL);
  826. DeviceObject = Transport->IpxSocketDeviceObject;
  827. FileObject = Transport->IpxSocketFileObject;
  828. } else {
  829. ASSERT (Transport->IpxSocketDeviceObject == NULL);
  830. ASSERT (Transport->IpxSocketFileObject == NULL);
  831. DeviceObject = TransportName->DeviceObject;
  832. FileObject = TransportName->FileObject;
  833. }
  834. //
  835. // Now allocate an IRP to hold the incoming mailslot.
  836. //
  837. *Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
  838. if (*Irp == NULL) {
  839. BowserFreeMailslotBufferHighIrql(Buffer);
  840. BowserStatistics.NumberOfFailedMailslotReceives += 1;
  841. return STATUS_REQUEST_NOT_ACCEPTED;
  842. }
  843. (*Irp)->MdlAddress = IoAllocateMdl(Buffer->Buffer, BytesToReceive, FALSE, FALSE, NULL);
  844. //
  845. // If we were unable to allocate the MDL, ditch the datagram.
  846. //
  847. if ((*Irp)->MdlAddress == NULL) {
  848. IoFreeIrp(*Irp);
  849. BowserFreeMailslotBufferHighIrql(Buffer);
  850. BowserStatistics.NumberOfFailedMailslotReceives += 1;
  851. return STATUS_REQUEST_NOT_ACCEPTED;
  852. }
  853. MmBuildMdlForNonPagedPool((*Irp)->MdlAddress);
  854. //
  855. // Build the receive datagram IRP.
  856. //
  857. TdiBuildReceiveDatagram((*Irp),
  858. DeviceObject,
  859. FileObject,
  860. CompleteReceiveMailslot,
  861. Buffer,
  862. (*Irp)->MdlAddress,
  863. BytesToReceive,
  864. NULL,
  865. NULL,
  866. 0);
  867. //
  868. // This gets kinda wierd.
  869. //
  870. // Since this IRP is going to be completed by the transport without
  871. // ever going to IoCallDriver, we have to update the stack location
  872. // to make the transports stack location the current stack location.
  873. //
  874. // Please note that this means that any transport provider that uses
  875. // IoCallDriver to re-submit it's requests at indication time will
  876. // break badly because of this code....
  877. //
  878. IoSetNextIrpStackLocation(*Irp);
  879. //
  880. // Indicate we've already handled everything before the SMB
  881. //
  882. *BytesTaken = SmbOffset;
  883. //
  884. // And return to the caller indicating we want to receive this stuff.
  885. //
  886. return STATUS_MORE_PROCESSING_REQUIRED;
  887. }
  888. NTSTATUS
  889. CompleteReceiveMailslot (
  890. IN PDEVICE_OBJECT TransportDevice,
  891. IN PIRP Irp,
  892. IN PVOID Context
  893. )
  894. /*++
  895. Routine Description:
  896. This routine handles completion of a mailslot write operation.
  897. Arguments:
  898. IN PDEVICE_OBJECT TransportDevice - Device object for transport.
  899. IN PIRP Irp - I/O request packet to complete.
  900. IN PVOID Context - Context for request (transport name).
  901. Return Value:
  902. NTSTATUS - Status of operation.
  903. --*/
  904. {
  905. PMAILSLOT_BUFFER Buffer = Context;
  906. NTSTATUS Status = Irp->IoStatus.Status;
  907. ASSERT (MmGetSystemAddressForMdl(Irp->MdlAddress) == Buffer->Buffer);
  908. //
  909. // Save away the number of bytes we received.
  910. //
  911. Buffer->ReceiveLength = Irp->IoStatus.Information;
  912. //
  913. // Release the MDL, we're done with it.
  914. //
  915. IoFreeMdl(Irp->MdlAddress);
  916. //
  917. // And free the IRP, we're done with it as well.
  918. //
  919. IoFreeIrp(Irp);
  920. if (NT_SUCCESS(Status)) {
  921. ExInitializeWorkItem(&Buffer->Overlay.WorkHeader,
  922. BowserProcessMailslotWrite,
  923. Buffer);
  924. ExQueueWorkItem(&Buffer->Overlay.WorkHeader, DelayedWorkQueue);
  925. } else {
  926. BowserStatistics.NumberOfFailedMailslotReceives += 1;
  927. BowserFreeMailslotBufferHighIrql(Buffer);
  928. }
  929. //
  930. // Short circuit I/O completion for this request.
  931. //
  932. return STATUS_MORE_PROCESSING_REQUIRED;
  933. UNREFERENCED_PARAMETER(TransportDevice);
  934. }
  935. typedef struct _SHORT_ANNOUNCEMENT_CONTEXT {
  936. PVOID EventContext;
  937. int SourceAddressLength;
  938. PVOID SourceAddress;
  939. int OptionsLength;
  940. PVOID Options;
  941. ULONG ReceiveDatagramFlags;
  942. PVOID Buffer;
  943. PTDI_IND_RECEIVE_DATAGRAM ReceiveDatagramHandler;
  944. CHAR Data[1];
  945. } SHORT_ANNOUNCEMENT_CONTEXT, *PSHORT_ANNOUNCEMENT_CONTEXT;
  946. NTSTATUS
  947. BowserHandleShortBrowserPacket(
  948. IN PTRANSPORT_NAME TransportName,
  949. IN PVOID EventContext,
  950. IN int SourceAddressLength,
  951. IN PVOID SourceAddress,
  952. IN int OptionsLength,
  953. IN PVOID Options,
  954. IN ULONG ReceiveDatagramFlags,
  955. IN ULONG BytesAvailable,
  956. IN ULONG *BytesTaken,
  957. IN PIRP *Irp,
  958. PTDI_IND_RECEIVE_DATAGRAM Handler
  959. )
  960. /*++
  961. Routine Description:
  962. This routine will process receive datagram indication messages, and
  963. process them as appropriate.
  964. Arguments:
  965. IN PTRANSPORT_NAME TransportName - The transport name for this request.
  966. IN ULONG BytesAvailable - number of bytes in complete Tsdu
  967. OUT PIRP *BytesTaken, - I/O request packet used to complete the request
  968. Return Value:
  969. NTSTATUS - Status of operation.
  970. --*/
  971. {
  972. PDEVICE_OBJECT DeviceObject;
  973. PFILE_OBJECT FileObject;
  974. PTRANSPORT Transport = TransportName->Transport;
  975. PSHORT_ANNOUNCEMENT_CONTEXT Context;
  976. ASSERT (TransportName->Signature == STRUCTURE_SIGNATURE_TRANSPORTNAME);
  977. ASSERT (BytesAvailable <= TransportName->Transport->DatagramSize);
  978. //
  979. // Now allocate a buffer to hold the data.
  980. //
  981. Context = ALLOCATE_POOL(NonPagedPool, sizeof(SHORT_ANNOUNCEMENT_CONTEXT) + SourceAddressLength + OptionsLength + BytesAvailable, POOL_SHORT_CONTEXT);
  982. if (Context == NULL) {
  983. //
  984. // We couldn't allocate a buffer to hold the data - ditch the request.
  985. //
  986. return(STATUS_REQUEST_NOT_ACCEPTED);
  987. }
  988. //
  989. // Save away the name of the client and which transport this was received
  990. // on just in case the datagram turns out to be illegal.
  991. //
  992. Context->SourceAddress = ((PCHAR)Context + FIELD_OFFSET(SHORT_ANNOUNCEMENT_CONTEXT, Data));
  993. Context->Options = ((PCHAR)Context + FIELD_OFFSET(SHORT_ANNOUNCEMENT_CONTEXT, Data) + SourceAddressLength);
  994. Context->Buffer = ((PCHAR)Context + FIELD_OFFSET(SHORT_ANNOUNCEMENT_CONTEXT, Data) + SourceAddressLength + OptionsLength);
  995. TdiCopyLookaheadData(Context->SourceAddress, SourceAddress, SourceAddressLength, ReceiveDatagramFlags);
  996. Context->SourceAddressLength = SourceAddressLength;
  997. TdiCopyLookaheadData(Context->Options, Options, OptionsLength, ReceiveDatagramFlags);
  998. Context->OptionsLength = OptionsLength;
  999. Context->ReceiveDatagramFlags = ReceiveDatagramFlags;
  1000. Context->EventContext = EventContext;
  1001. Context->ReceiveDatagramHandler = Handler;
  1002. //
  1003. // We rely on the fact that the device object is NULL for
  1004. // IPX transport names.
  1005. //
  1006. if (TransportName->DeviceObject == NULL) {
  1007. ASSERT (Transport->IpxSocketDeviceObject != NULL);
  1008. ASSERT (Transport->IpxSocketFileObject != NULL);
  1009. ASSERT (TransportName->FileObject == NULL);
  1010. DeviceObject = Transport->IpxSocketDeviceObject;
  1011. FileObject = Transport->IpxSocketFileObject;
  1012. } else {
  1013. ASSERT (Transport->IpxSocketDeviceObject == NULL);
  1014. ASSERT (Transport->IpxSocketFileObject == NULL);
  1015. DeviceObject = TransportName->DeviceObject;
  1016. FileObject = TransportName->FileObject;
  1017. }
  1018. //
  1019. // Now allocate an IRP to hold the incoming mailslot.
  1020. //
  1021. *Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
  1022. if (*Irp == NULL) {
  1023. FREE_POOL(Context);
  1024. BowserStatistics.NumberOfFailedMailslotReceives += 1;
  1025. return STATUS_REQUEST_NOT_ACCEPTED;
  1026. }
  1027. (*Irp)->MdlAddress = IoAllocateMdl(Context->Buffer, BytesAvailable, FALSE, FALSE, NULL);
  1028. //
  1029. // If we were unable to allocate the MDL, ditch the datagram.
  1030. //
  1031. if ((*Irp)->MdlAddress == NULL) {
  1032. IoFreeIrp(*Irp);
  1033. FREE_POOL(Context);
  1034. BowserStatistics.NumberOfFailedMailslotReceives += 1;
  1035. return STATUS_REQUEST_NOT_ACCEPTED;
  1036. }
  1037. MmBuildMdlForNonPagedPool((*Irp)->MdlAddress);
  1038. //
  1039. // Build the receive datagram IRP.
  1040. //
  1041. TdiBuildReceiveDatagram((*Irp),
  1042. DeviceObject,
  1043. FileObject,
  1044. CompleteShortBrowserPacket,
  1045. Context,
  1046. (*Irp)->MdlAddress,
  1047. BytesAvailable,
  1048. NULL,
  1049. NULL,
  1050. 0);
  1051. //
  1052. // This gets kinda wierd.
  1053. //
  1054. // Since this IRP is going to be completed by the transport without
  1055. // ever going to IoCallDriver, we have to update the stack location
  1056. // to make the transports stack location the current stack location.
  1057. //
  1058. // Please note that this means that any transport provider that uses
  1059. // IoCallDriver to re-submit it's requests at indication time will
  1060. // break badly because of this code....
  1061. //
  1062. IoSetNextIrpStackLocation(*Irp);
  1063. *BytesTaken = 0;
  1064. //
  1065. // And return to the caller indicating we want to receive this stuff.
  1066. //
  1067. return STATUS_MORE_PROCESSING_REQUIRED;
  1068. }
  1069. NTSTATUS
  1070. CompleteShortBrowserPacket (
  1071. IN PDEVICE_OBJECT TransportDevice,
  1072. IN PIRP Irp,
  1073. IN PVOID Ctx
  1074. )
  1075. /*++
  1076. Routine Description:
  1077. This routine handles completion of a mailslot write operation.
  1078. Arguments:
  1079. IN PDEVICE_OBJECT TransportDevice - Device object for transport.
  1080. IN PIRP Irp - I/O request packet to complete.
  1081. IN PVOID Context - Context for request (transport name).
  1082. Return Value:
  1083. NTSTATUS - Status of operation.
  1084. --*/
  1085. {
  1086. PSHORT_ANNOUNCEMENT_CONTEXT Context = Ctx;
  1087. NTSTATUS Status = Irp->IoStatus.Status;
  1088. ULONG ReceiveLength;
  1089. ULONG BytesTaken;
  1090. //
  1091. // Save away the number of bytes we received.
  1092. //
  1093. ReceiveLength = Irp->IoStatus.Information;
  1094. //
  1095. // Release the MDL, we're done with it.
  1096. //
  1097. IoFreeMdl(Irp->MdlAddress);
  1098. //
  1099. // And free the IRP, we're done with it as well.
  1100. //
  1101. IoFreeIrp(Irp);
  1102. if (NT_SUCCESS(Status)) {
  1103. Status = Context->ReceiveDatagramHandler(Context->EventContext,
  1104. Context->SourceAddressLength,
  1105. Context->SourceAddress,
  1106. Context->OptionsLength,
  1107. Context->Options,
  1108. Context->ReceiveDatagramFlags,
  1109. ReceiveLength,
  1110. ReceiveLength,
  1111. &BytesTaken,
  1112. Context->Buffer,
  1113. &Irp);
  1114. ASSERT (Status != STATUS_MORE_PROCESSING_REQUIRED);
  1115. }
  1116. FREE_POOL(Context);
  1117. //
  1118. // Short circuit I/O completion for this request.
  1119. //
  1120. return STATUS_MORE_PROCESSING_REQUIRED;
  1121. UNREFERENCED_PARAMETER(TransportDevice);
  1122. }
  1123. DATAGRAM_HANDLER(
  1124. HandleAnnounceRequest
  1125. )
  1126. /*++
  1127. Routine Description:
  1128. This routine will process receive datagram indication messages for announce
  1129. requests.
  1130. Arguments:
  1131. None.
  1132. Return Value:
  1133. NTSTATUS - Status of operation.
  1134. --*/
  1135. {
  1136. //BUGBUG We should be able to make transport->ElectionState pagable.
  1137. //
  1138. // If we're running an election, ignore announce requests.
  1139. //
  1140. if (TransportName->Transport->ElectionState != RunningElection) {
  1141. if ((TransportName->NameType == BrowserElection) ||
  1142. (TransportName->NameType == MasterBrowser) ||
  1143. (TransportName->NameType == PrimaryDomain)) {
  1144. //
  1145. // This one's easy - simply set the servers announcement event to the
  1146. // signalled state. If the server is running, this will force an
  1147. // announcement
  1148. //
  1149. KeSetEvent(BowserServerAnnouncementEvent, IO_NETWORK_INCREMENT, FALSE);
  1150. } else if (TransportName->NameType == DomainAnnouncement) {
  1151. //
  1152. // BUGBUG NEED TO HANDLE REQUEST ANNOUNCEMENT OF DOMAIN
  1153. // REQUEST.
  1154. //
  1155. }
  1156. }
  1157. return STATUS_SUCCESS;
  1158. }
  1159. NTSTATUS
  1160. BowserPostDatagramToWorkerThread(
  1161. IN PTRANSPORT_NAME TransportName,
  1162. IN PVOID Datagram,
  1163. IN ULONG Length,
  1164. OUT PULONG BytesTaken,
  1165. IN PVOID OriginatorsAddress,
  1166. IN ULONG OriginatorsAddressLength,
  1167. IN PVOID OriginatorsName,
  1168. IN ULONG OriginatorsNameLength,
  1169. IN PWORKER_THREAD_ROUTINE Handler,
  1170. IN POOL_TYPE PoolType,
  1171. IN WORK_QUEUE_TYPE QueueType,
  1172. IN ULONG ReceiveFlags,
  1173. IN BOOLEAN PostToRdrWorkerThread
  1174. )
  1175. /*++
  1176. Routine Description:
  1177. Queue a datagram to a worker thread.
  1178. This routine increment the reference count on the Transport and TransportName.
  1179. The Handler routine is expected to dereference them.
  1180. Arguments:
  1181. Many.
  1182. Return Value:
  1183. NTSTATUS - Status of operation.
  1184. --*/
  1185. {
  1186. PPOST_DATAGRAM_CONTEXT Context;
  1187. PTA_NETBIOS_ADDRESS NetbiosAddress = OriginatorsAddress;
  1188. ASSERT (NetbiosAddress->TAAddressCount == 1);
  1189. ASSERT ((NetbiosAddress->Address[0].AddressType == TDI_ADDRESS_TYPE_NETBIOS) ||
  1190. (NetbiosAddress->Address[0].AddressType == TDI_ADDRESS_TYPE_IPX));
  1191. Context = ALLOCATE_POOL(PoolType, sizeof(POST_DATAGRAM_CONTEXT) + Length + OriginatorsAddressLength, POOL_POSTDG_CONTEXT);
  1192. if (Context == NULL) {
  1193. return STATUS_REQUEST_NOT_ACCEPTED;
  1194. }
  1195. Context->TransportName = TransportName;
  1196. Context->Buffer = ((PCHAR)(Context+1))+OriginatorsAddressLength;
  1197. Context->BytesAvailable = Length;
  1198. TdiCopyLookaheadData(Context->Buffer, Datagram, Length, ReceiveFlags);
  1199. Context->ClientAddressLength = OriginatorsAddressLength;
  1200. TdiCopyLookaheadData(Context->TdiClientAddress, OriginatorsAddress, OriginatorsAddressLength, ReceiveFlags);
  1201. //
  1202. // Copy over the client name into the buffer.
  1203. //
  1204. Context->ClientNameLength = NETBIOS_NAME_LEN;
  1205. BowserCopyOemComputerName(Context->ClientName,
  1206. OriginatorsName,
  1207. OriginatorsNameLength,
  1208. ReceiveFlags);
  1209. *BytesTaken = Length;
  1210. ExInitializeWorkItem(&Context->WorkItem, Handler, Context);
  1211. if ( QueueType == CriticalWorkQueue ) {
  1212. //
  1213. // Ensure we've not consumed too much memory
  1214. //
  1215. InterlockedIncrement( &BowserPostedCriticalDatagramCount );
  1216. if ( BowserPostedCriticalDatagramCount > BOWSER_MAX_POSTED_DATAGRAMS ) {
  1217. InterlockedDecrement( &BowserPostedCriticalDatagramCount );
  1218. FREE_POOL( Context );
  1219. return STATUS_REQUEST_NOT_ACCEPTED;
  1220. }
  1221. //
  1222. // Reference the Transport and TransportName to ensure they aren't deleted. The
  1223. // Handler routine is expected to dereference them.
  1224. //
  1225. BowserReferenceTransportName(TransportName);
  1226. BowserReferenceTransport( TransportName->Transport );
  1227. //
  1228. // Queue the workitem.
  1229. //
  1230. BowserQueueCriticalWorkItem( &Context->WorkItem );
  1231. } else {
  1232. //
  1233. // Ensure we've not consumed too much memory
  1234. //
  1235. InterlockedIncrement( &BowserPostedDatagramCount );
  1236. if ( BowserPostedDatagramCount > BOWSER_MAX_POSTED_DATAGRAMS ) {
  1237. InterlockedDecrement( &BowserPostedDatagramCount );
  1238. FREE_POOL( Context );
  1239. return STATUS_REQUEST_NOT_ACCEPTED;
  1240. }
  1241. //
  1242. // Reference the Transport and TransportName to ensure they aren't deleted. The
  1243. // Handler routine is expected to dereference them.
  1244. //
  1245. BowserReferenceTransportName(TransportName);
  1246. BowserReferenceTransport( TransportName->Transport );
  1247. //
  1248. // Queue the workitem.
  1249. //
  1250. ExQueueWorkItem(&Context->WorkItem, QueueType);
  1251. }
  1252. return STATUS_SUCCESS;
  1253. }