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

1825 lines
56 KiB

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