/*++ Copyright (c) 1990 Microsoft Corporation Module Name: bowtdi.c Abstract: This module implements all of the routines that interface with the TDI transport for NT Author: Larry Osterman (LarryO) 21-Jun-1990 Revision History: 21-Jun-1990 LarryO Created --*/ #include "precomp.h" #include #include #pragma hdrstop NTSTATUS BowserHandleIpxDomainAnnouncement( IN PTRANSPORT Transport, IN PSMB_IPX_NAME_PACKET NamePacket, IN PBROWSE_ANNOUNCE_PACKET_1 DomainAnnouncement, IN DWORD RequestLength, IN ULONG ReceiveFlags ); #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE4BROW, BowserHandleIpxDomainAnnouncement) #endif NTSTATUS BowserIpxDatagramHandler ( IN PVOID TdiEventContext, IN LONG SourceAddressLength, IN PVOID SourceAddress, IN LONG OptionsLength, IN PVOID Options, IN ULONG ReceiveDatagramFlags, IN ULONG BytesIndicated, IN ULONG BytesAvailable, OUT ULONG *BytesTaken, IN PVOID Tsdu, OUT PIRP *IoRequestPacket ) { PVOID DatagramData; PINTERNAL_TRANSACTION InternalTransaction = NULL; ULONG DatagramDataSize; PTRANSPORT Transport = TdiEventContext; MAILSLOTTYPE Opcode; PSMB_IPX_NAME_PACKET NamePacket = Tsdu; PSMB_HEADER Smb = (PSMB_HEADER)(NamePacket+1); PCHAR ComputerName; PCHAR DomainName; PTRANSPORT_NAME TransportName = Transport->ComputerName; ULONG SmbLength = BytesIndicated - sizeof(SMB_IPX_NAME_PACKET); if (BytesAvailable > Transport->DatagramSize) { return STATUS_REQUEST_NOT_ACCEPTED; } if (BytesIndicated <= sizeof(SMB_IPX_NAME_PACKET)) { return STATUS_REQUEST_NOT_ACCEPTED; } // // If we're not fully initialized yet, // simply ignore the packet. // if (Transport->ComputerName == NULL ) { return STATUS_REQUEST_NOT_ACCEPTED; } ComputerName = ((PTA_NETBIOS_ADDRESS)(Transport->ComputerName->TransportAddress.Buffer))->Address[0].Address->NetbiosName; DomainName = Transport->DomainInfo->DomNetbiosDomainName; // // It's not for us, ignore the announcement. // if (NamePacket->NameType == SMB_IPX_NAME_TYPE_MACHINE) { // Mailslot messages are always sent as TYPE_MACHINE even when they're // to the DomainName (so allow both). if (!RtlEqualMemory(ComputerName, NamePacket->Name, SMB_IPX_NAME_LENGTH) && !RtlEqualMemory(DomainName, NamePacket->Name, SMB_IPX_NAME_LENGTH)) { return STATUS_REQUEST_NOT_ACCEPTED; } } else if (NamePacket->NameType == SMB_IPX_NAME_TYPE_WORKKGROUP) { if (!RtlEqualMemory(DomainName, NamePacket->Name, SMB_IPX_NAME_LENGTH)) { return STATUS_REQUEST_NOT_ACCEPTED; } } else if (NamePacket->NameType != SMB_IPX_NAME_TYPE_BROWSER) { return STATUS_REQUEST_NOT_ACCEPTED; } // // Classify the incoming packet according to it's type. Depending on // the type, either process it as: // // 1) A server announcement // 2) An incoming mailslot // Opcode = BowserClassifyIncomingDatagram(Smb, SmbLength, &DatagramData, &DatagramDataSize); if (Opcode == MailslotTransaction) { // // BowserHandleMailslotTransaction will always receive the indicated bytes // expecting to find the SMB. Tell the TDI driver we've already consumed // the IPX_NAME_PACKET to keep that assumption constant. // *BytesTaken = sizeof(SMB_IPX_NAME_PACKET); return BowserHandleMailslotTransaction( Transport->ComputerName, NamePacket->SourceName, 0, // No IP address sizeof(SMB_IPX_NAME_PACKET), // SMB offset into TSDU ReceiveDatagramFlags, BytesIndicated, BytesAvailable, BytesTaken, Tsdu, IoRequestPacket ); } else if (Opcode == Illegal) { // // This might be illegal because it's a short packet. In that // case, handle it as if it were a short packet and deal with any // other failures when we have the whole packet. // if (BytesAvailable != BytesIndicated) { return BowserHandleShortBrowserPacket(Transport->ComputerName, TdiEventContext, SourceAddressLength, SourceAddress, OptionsLength, Options, ReceiveDatagramFlags, BytesAvailable, BytesTaken, IoRequestPacket, BowserIpxDatagramHandler ); } BowserLogIllegalDatagram( Transport->ComputerName, Smb, (USHORT)(SmbLength & 0xffff), NamePacket->SourceName, ReceiveDatagramFlags); return STATUS_REQUEST_NOT_ACCEPTED; } else { // PTA_NETBIOS_ADDRESS NetbiosAddress = SourceAddress; if (BowserDatagramHandlerTable[Opcode] == NULL) { return STATUS_SUCCESS; } // // If this isn't the full packet, post a receive for it and // handle it when we finally complete the receive. // if (BytesIndicated != BytesAvailable) { return BowserHandleShortBrowserPacket(Transport->ComputerName, TdiEventContext, SourceAddressLength, SourceAddress, OptionsLength, Options, ReceiveDatagramFlags, BytesAvailable, BytesTaken, IoRequestPacket, BowserIpxDatagramHandler ); } InternalTransaction = DatagramData; // // If this is a workgroup announcement (a server announcement for another // workgroup), handle it specially - regardless of the opcode, it's // really a workgroup announcement. // if (NamePacket->NameType == SMB_IPX_NAME_TYPE_BROWSER) { if (Opcode == LocalMasterAnnouncement ) { NTSTATUS status; // // If we're processing these announcements, then handle this // as a domain announcement. // if (Transport->MasterBrowser && Transport->MasterBrowser->ProcessHostAnnouncements) { status = BowserHandleIpxDomainAnnouncement(Transport, NamePacket, (PBROWSE_ANNOUNCE_PACKET_1)&InternalTransaction->Union.Announcement, SmbLength-(ULONG)((PCHAR)&InternalTransaction->Union.Announcement - (PCHAR)Smb), ReceiveDatagramFlags); } else { status = STATUS_REQUEST_NOT_ACCEPTED; } // // If this request isn't for our domain, we're done with it, if // it's for our domain, then we need to do some more work. // if (!RtlEqualMemory(DomainName, NamePacket->Name, SMB_IPX_NAME_LENGTH)) { return status; } } else { // // This isn't a master announcement, so ignore it. // return STATUS_REQUEST_NOT_ACCEPTED; } } // // Figure out which transportname is appropriate for the request: // // There are basically 3 choices: // // ComputeName (The default) // MasterBrowser (if this is a server announcement) // PrimaryDomain (if this is a request announcement) // Election (if this is a local master announcement) if ((Opcode == WkGroupAnnouncement) || (Opcode == HostAnnouncement)) { if (Transport->MasterBrowser == NULL || !Transport->MasterBrowser->ProcessHostAnnouncements) { return STATUS_REQUEST_NOT_ACCEPTED; } else { TransportName = Transport->MasterBrowser; } } else if (Opcode == AnnouncementRequest) { TransportName = Transport->PrimaryDomain; } else if (Opcode == LocalMasterAnnouncement) { if (Transport->BrowserElection != NULL) { TransportName = Transport->BrowserElection; } else { return STATUS_REQUEST_NOT_ACCEPTED; } } ASSERT (DatagramDataSize == (SmbLength - ((PCHAR)InternalTransaction - (PCHAR)Smb))); ASSERT (FIELD_OFFSET(INTERNAL_TRANSACTION, Union.Announcement) == FIELD_OFFSET(INTERNAL_TRANSACTION, Union.BrowseAnnouncement)); ASSERT (FIELD_OFFSET(INTERNAL_TRANSACTION, Union.Announcement) == FIELD_OFFSET(INTERNAL_TRANSACTION, Union.RequestElection)); ASSERT (FIELD_OFFSET(INTERNAL_TRANSACTION, Union.Announcement) == FIELD_OFFSET(INTERNAL_TRANSACTION, Union.BecomeBackup)); ASSERT (FIELD_OFFSET(INTERNAL_TRANSACTION, Union.Announcement) == FIELD_OFFSET(INTERNAL_TRANSACTION, Union.GetBackupListRequest)); ASSERT (FIELD_OFFSET(INTERNAL_TRANSACTION, Union.Announcement) == FIELD_OFFSET(INTERNAL_TRANSACTION, Union.GetBackupListResp)); ASSERT (FIELD_OFFSET(INTERNAL_TRANSACTION, Union.Announcement) == FIELD_OFFSET(INTERNAL_TRANSACTION, Union.ResetState)); ASSERT (FIELD_OFFSET(INTERNAL_TRANSACTION, Union.Announcement) == FIELD_OFFSET(INTERNAL_TRANSACTION, Union.MasterAnnouncement)); return BowserDatagramHandlerTable[Opcode](TransportName, &InternalTransaction->Union.Announcement, SmbLength-(ULONG)((PCHAR)&InternalTransaction->Union.Announcement - (PCHAR)Smb), BytesTaken, SourceAddress, SourceAddressLength, &NamePacket->SourceName, SMB_IPX_NAME_LENGTH, ReceiveDatagramFlags); } return STATUS_SUCCESS; UNREFERENCED_PARAMETER(OptionsLength); UNREFERENCED_PARAMETER(Options); UNREFERENCED_PARAMETER(ReceiveDatagramFlags); } NTSTATUS BowserHandleIpxDomainAnnouncement( IN PTRANSPORT Transport, IN PSMB_IPX_NAME_PACKET NamePacket, IN PBROWSE_ANNOUNCE_PACKET_1 DomainAnnouncement, IN DWORD RequestLength, IN ULONG ReceiveFlags ) /*++ Routine Description: This routine will process receive datagram indication messages, and process them as appropriate. Arguments: IN PTRANSPORT Transport - The transport provider for this request. IN PSMB_IPX_NAME_PACKET NamePacket - The name packet for this request. Return Value: NTSTATUS - Status of operation. --*/ { PVIEW_BUFFER ViewBuffer; DISCARDABLE_CODE(BowserDiscardableCodeSection); #ifdef ENABLE_PSEUDO_BROWSER if ( BowserData.PseudoServerLevel == BROWSER_PSEUDO ) { // no-op for black hole server return STATUS_SUCCESS; } #endif ExInterlockedAddLargeStatistic(&BowserStatistics.NumberOfDomainAnnouncements, 1); ViewBuffer = BowserAllocateViewBuffer(); // // If we are unable to allocate a view buffer, ditch this datagram on // the floor. // if (ViewBuffer == NULL) { return STATUS_REQUEST_NOT_ACCEPTED; } BowserCopyOemComputerName(ViewBuffer->ServerName, NamePacket->Name, SMB_IPX_NAME_LENGTH, ReceiveFlags); BowserCopyOemComputerName(ViewBuffer->ServerComment, NamePacket->SourceName, SMB_IPX_NAME_LENGTH, ReceiveFlags); if ( DomainAnnouncement->Type & SV_TYPE_NT ) { ViewBuffer->ServerType = SV_TYPE_DOMAIN_ENUM | SV_TYPE_NT; } else { ViewBuffer->ServerType = SV_TYPE_DOMAIN_ENUM; } ASSERT (Transport->MasterBrowser != NULL); ViewBuffer->TransportName = Transport->MasterBrowser; ViewBuffer->ServerVersionMajor = DomainAnnouncement->VersionMajor; ViewBuffer->ServerVersionMinor = DomainAnnouncement->VersionMinor; ViewBuffer->ServerPeriodicity = (USHORT)((SmbGetUlong(&DomainAnnouncement->Periodicity) + 999) / 1000); BowserReferenceTransportName(Transport->MasterBrowser); BowserReferenceTransport( Transport ); ExInitializeWorkItem(&ViewBuffer->Overlay.WorkHeader, BowserProcessDomainAnnouncement, ViewBuffer); BowserQueueDelayedWorkItem( &ViewBuffer->Overlay.WorkHeader ); return STATUS_SUCCESS; }