|
|
/*++
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 <isnkrnl.h>
#include <smbipx.h>
#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; }
|