391 lines
14 KiB
C
391 lines
14 KiB
C
/*++
|
||
|
||
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;
|
||
}
|
||
|