931 lines
26 KiB
C
931 lines
26 KiB
C
/*++
|
||
|
||
Copyright (c) 1989-1993 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
frame.c
|
||
|
||
Abstract:
|
||
|
||
This module contains code which creates and sends various
|
||
types of frames.
|
||
|
||
Environment:
|
||
|
||
Kernel mode
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
|
||
|
||
VOID
|
||
NbiSendNameFrame(
|
||
IN PADDRESS Address OPTIONAL,
|
||
IN UCHAR NameTypeFlag,
|
||
IN UCHAR DataStreamType,
|
||
IN PIPX_LOCAL_TARGET LocalTarget OPTIONAL,
|
||
IN NB_CONNECTIONLESS UNALIGNED * ReqFrame OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine allocates and sends a name frame on the
|
||
specified address. It handles add name, name in use, and
|
||
delete name frames.
|
||
|
||
Arguments:
|
||
|
||
Address - The address on which the frame is sent. This will
|
||
be NULL if we are responding to a request to the
|
||
broadcast address.
|
||
|
||
NameTypeFlag - The name type flag to use.
|
||
|
||
DataStreamType - The type of the command.
|
||
|
||
LocalTarget - If specified, the local target to use for the
|
||
send (if not, it will be broadcast).
|
||
|
||
ReqFrame - If specified, the request frame for which this
|
||
response is being sent. The reqframe contains the
|
||
destination ipx address and the netbios name.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PSLIST_ENTRY s;
|
||
PNB_SEND_RESERVED Reserved;
|
||
PNDIS_PACKET Packet;
|
||
NB_CONNECTIONLESS UNALIGNED * Header;
|
||
NDIS_STATUS NdisStatus;
|
||
IPX_LOCAL_TARGET TempLocalTarget;
|
||
PDEVICE Device = NbiDevice;
|
||
|
||
//
|
||
// Allocate a packet from the pool.
|
||
//
|
||
|
||
s = NbiPopSendPacket(Device, FALSE);
|
||
|
||
//
|
||
// If we can't allocate a frame, that is OK, since
|
||
// it is connectionless anyway.
|
||
//
|
||
|
||
if (s == NULL) {
|
||
return;
|
||
}
|
||
|
||
Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
|
||
Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
|
||
|
||
CTEAssert (Reserved->SendInProgress == FALSE);
|
||
Reserved->SendInProgress = TRUE;
|
||
Reserved->u.SR_NF.Address = Address; // may be NULL
|
||
Reserved->Type = SEND_TYPE_NAME_FRAME;
|
||
|
||
//
|
||
// Frame that are not sent to a specific address are
|
||
// sent to all valid NIC IDs.
|
||
//
|
||
|
||
if (!ARGUMENT_PRESENT(LocalTarget)) {
|
||
Reserved->u.SR_NF.NameTypeFlag = NameTypeFlag;
|
||
Reserved->u.SR_NF.DataStreamType = DataStreamType;
|
||
}
|
||
|
||
//
|
||
// Fill in the IPX header -- the default header has the broadcast
|
||
// address on net 0 as the destination IPX address.
|
||
//
|
||
|
||
Header = (NB_CONNECTIONLESS UNALIGNED *)
|
||
(&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
|
||
RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
|
||
if (ARGUMENT_PRESENT(ReqFrame)) {
|
||
RtlCopyMemory((PVOID)&Header->IpxHeader.DestinationNetwork, (PVOID)ReqFrame->IpxHeader.SourceNetwork, 12);
|
||
}
|
||
Header->IpxHeader.PacketLength[0] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) / 256;
|
||
Header->IpxHeader.PacketLength[1] = (sizeof(IPX_HEADER)+sizeof(NB_NAME_FRAME)) % 256;
|
||
|
||
if (ARGUMENT_PRESENT(LocalTarget)) {
|
||
Header->IpxHeader.PacketType = 0x04;
|
||
} else {
|
||
Header->IpxHeader.PacketType = (UCHAR)(Device->Internet ? 0x014 : 0x04);
|
||
}
|
||
|
||
//
|
||
// Now fill in the Netbios header.
|
||
//
|
||
|
||
RtlZeroMemory (Header->NameFrame.RoutingInfo, 32);
|
||
Header->NameFrame.ConnectionControlFlag = 0x00;
|
||
Header->NameFrame.DataStreamType = DataStreamType;
|
||
Header->NameFrame.NameTypeFlag = NameTypeFlag;
|
||
|
||
//
|
||
// DataStreamType2 is the same as DataStreamType except for
|
||
// name in use frames where it is set to the add name type.
|
||
//
|
||
|
||
Header->NameFrame.DataStreamType2 = (UCHAR)
|
||
((DataStreamType != NB_CMD_NAME_IN_USE) ? DataStreamType : NB_CMD_ADD_NAME);
|
||
|
||
RtlCopyMemory(
|
||
Header->NameFrame.Name,
|
||
Address ? Address->NetbiosAddress.NetbiosName : ReqFrame->NameFrame.Name,
|
||
16);
|
||
|
||
if (Address) {
|
||
NbiReferenceAddress (Address, AREF_NAME_FRAME);
|
||
} else {
|
||
NbiReferenceDevice (Device, DREF_NAME_FRAME);
|
||
}
|
||
|
||
//
|
||
// Now send the frame (because it is all in the first segment,
|
||
// IPX will adjust the length of the buffer correctly).
|
||
//
|
||
|
||
if (!ARGUMENT_PRESENT(LocalTarget)) {
|
||
LocalTarget = &BroadcastTarget;
|
||
}
|
||
|
||
NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(IPX_HEADER) +
|
||
sizeof(NB_NAME_FRAME));
|
||
if ((NdisStatus =
|
||
(*Device->Bind.SendHandler)(
|
||
LocalTarget,
|
||
Packet,
|
||
sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME),
|
||
sizeof(IPX_HEADER) + sizeof(NB_NAME_FRAME))) != STATUS_PENDING) {
|
||
|
||
NbiSendComplete(
|
||
Packet,
|
||
NdisStatus);
|
||
|
||
}
|
||
|
||
} /* NbiSendNameFrame */
|
||
|
||
|
||
VOID
|
||
NbiSendSessionInitialize(
|
||
IN PCONNECTION Connection
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine allocates and sends a session initialize
|
||
frame for the specified connection.
|
||
|
||
Arguments:
|
||
|
||
Connection - The connection on which the frame is sent.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PSLIST_ENTRY s;
|
||
PNB_SEND_RESERVED Reserved;
|
||
PNDIS_PACKET Packet;
|
||
NB_CONNECTION UNALIGNED * Header;
|
||
NDIS_STATUS NdisStatus;
|
||
PNB_SESSION_INIT SessionInitMemory;
|
||
PNDIS_BUFFER SessionInitBuffer;
|
||
PDEVICE Device = NbiDevice;
|
||
|
||
//
|
||
// Allocate a packet from the pool.
|
||
//
|
||
|
||
s = NbiPopSendPacket(Device, FALSE);
|
||
|
||
//
|
||
// If we can't allocate a frame, that is OK, since
|
||
// it is connectionless anyway.
|
||
//
|
||
|
||
if (s == NULL) {
|
||
return;
|
||
}
|
||
|
||
|
||
//
|
||
// Allocate a buffer for the extra portion of the
|
||
// session initialize.
|
||
//
|
||
|
||
SessionInitMemory = (PNB_SESSION_INIT)NbiAllocateMemory(sizeof(NB_SESSION_INIT), MEMORY_CONNECTION, "Session Initialize");
|
||
if (!SessionInitMemory) {
|
||
ExInterlockedPushEntrySList(
|
||
&Device->SendPacketList,
|
||
s,
|
||
&NbiGlobalPoolInterlock);
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Allocate an NDIS buffer to map the extra buffer.
|
||
//
|
||
|
||
NdisAllocateBuffer(
|
||
&NdisStatus,
|
||
&SessionInitBuffer,
|
||
Device->NdisBufferPoolHandle,
|
||
SessionInitMemory,
|
||
sizeof(NB_SESSION_INIT));
|
||
|
||
if (NdisStatus != NDIS_STATUS_SUCCESS) {
|
||
NbiFreeMemory (SessionInitMemory, sizeof(NB_SESSION_INIT), MEMORY_CONNECTION, "Session Initialize");
|
||
ExInterlockedPushEntrySList(
|
||
&Device->SendPacketList,
|
||
s,
|
||
&NbiGlobalPoolInterlock);
|
||
return;
|
||
}
|
||
|
||
Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
|
||
Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
|
||
|
||
CTEAssert (Reserved->SendInProgress == FALSE);
|
||
Reserved->SendInProgress = TRUE;
|
||
Reserved->Type = SEND_TYPE_SESSION_INIT;
|
||
|
||
//
|
||
// Fill in the IPX header -- the default header has the broadcast
|
||
// address on net 0 as the destination IPX address.
|
||
//
|
||
|
||
Header = (NB_CONNECTION UNALIGNED *)
|
||
(&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
|
||
RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
|
||
|
||
Header->IpxHeader.PacketLength[0] = (sizeof(NB_CONNECTION)+sizeof(NB_SESSION_INIT)) / 256;
|
||
Header->IpxHeader.PacketLength[1] = (sizeof(NB_CONNECTION)+sizeof(NB_SESSION_INIT)) % 256;
|
||
|
||
Header->IpxHeader.PacketType = 0x04;
|
||
|
||
//
|
||
// Now fill in the Netbios header.
|
||
//
|
||
|
||
if (Device->Extensions) {
|
||
Header->Session.ConnectionControlFlag = NB_CONTROL_SEND_ACK | NB_CONTROL_NEW_NB;
|
||
} else {
|
||
Header->Session.ConnectionControlFlag = NB_CONTROL_SEND_ACK;
|
||
}
|
||
Header->Session.DataStreamType = NB_CMD_SESSION_DATA;
|
||
Header->Session.SourceConnectionId = Connection->LocalConnectionId;
|
||
Header->Session.DestConnectionId = 0xffff;
|
||
Header->Session.SendSequence = 0;
|
||
Header->Session.TotalDataLength = sizeof(NB_SESSION_INIT);
|
||
Header->Session.Offset = 0;
|
||
Header->Session.DataLength = sizeof(NB_SESSION_INIT);
|
||
Header->Session.ReceiveSequence = 0;
|
||
if (Device->Extensions) {
|
||
Header->Session.ReceiveSequenceMax = 1; // low estimate for the moment
|
||
} else {
|
||
Header->Session.BytesReceived = 0;
|
||
}
|
||
|
||
RtlCopyMemory (SessionInitMemory->SourceName, Connection->AddressFile->Address->NetbiosAddress.NetbiosName, 16);
|
||
RtlCopyMemory (SessionInitMemory->DestinationName, Connection->RemoteName, 16);
|
||
|
||
SessionInitMemory->MaximumDataSize = (USHORT)Connection->MaximumPacketSize;
|
||
SessionInitMemory->StartTripTime = (USHORT)
|
||
((Device->InitialRetransmissionTime * (Device->KeepAliveCount+1)) / 500);
|
||
SessionInitMemory->MaximumPacketTime = SessionInitMemory->StartTripTime + 12;
|
||
|
||
//
|
||
// Should we ref the connection? It doesn't really matter which we do.
|
||
//
|
||
|
||
NbiReferenceDevice (Device, DREF_SESSION_INIT);
|
||
|
||
NdisChainBufferAtBack (Packet, SessionInitBuffer);
|
||
|
||
|
||
//
|
||
// Now send the frame, IPX will adjust the length of the
|
||
// first buffer correctly.
|
||
//
|
||
|
||
NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
|
||
|
||
if ((NdisStatus =
|
||
(*Device->Bind.SendHandler)(
|
||
&Connection->LocalTarget,
|
||
Packet,
|
||
sizeof(NB_CONNECTION) + sizeof(NB_SESSION_INIT),
|
||
sizeof(NB_CONNECTION))) != STATUS_PENDING) {
|
||
|
||
NbiSendComplete(
|
||
Packet,
|
||
NdisStatus);
|
||
|
||
}
|
||
|
||
} /* NbiSendSessionInitialize */
|
||
|
||
|
||
VOID
|
||
NbiSendSessionInitAck(
|
||
IN PCONNECTION Connection,
|
||
IN PUCHAR ExtraData,
|
||
IN ULONG ExtraDataLength,
|
||
IN CTELockHandle * LockHandle OPTIONAL
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine allocates and sends a session initialize ack
|
||
frame for the specified connection. If extra data was
|
||
specified in the session initialize frame it is echoed
|
||
back to the remote.
|
||
|
||
Arguments:
|
||
|
||
Connection - The connection on which the frame is sent.
|
||
|
||
ExtraData - Any extra data (after the SESSION_INIT buffer)
|
||
in the frame.
|
||
|
||
ExtraDataLength - THe length of the extra data.
|
||
|
||
LockHandle - If specified, indicates the connection lock
|
||
is held and should be released. This is for cases
|
||
where the ExtraData is in memory which may be freed
|
||
once the connection lock is released.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PSLIST_ENTRY s;
|
||
PNB_SEND_RESERVED Reserved;
|
||
PNDIS_PACKET Packet;
|
||
NB_CONNECTION UNALIGNED * Header;
|
||
NDIS_STATUS NdisStatus;
|
||
ULONG SessionInitBufferLength;
|
||
PNB_SESSION_INIT SessionInitMemory;
|
||
PNDIS_BUFFER SessionInitBuffer;
|
||
PDEVICE Device = NbiDevice;
|
||
|
||
//
|
||
// Allocate a packet from the pool.
|
||
//
|
||
|
||
s = NbiPopSendPacket(Device, FALSE);
|
||
|
||
//
|
||
// If we can't allocate a frame, that is OK, since
|
||
// it is connectionless anyway.
|
||
//
|
||
|
||
if (s == NULL) {
|
||
if (ARGUMENT_PRESENT(LockHandle)) {
|
||
NB_FREE_LOCK (&Connection->Lock, *LockHandle);
|
||
}
|
||
return;
|
||
}
|
||
|
||
|
||
//
|
||
// Allocate a buffer for the extra portion of the
|
||
// session initialize.
|
||
//
|
||
|
||
SessionInitBufferLength = sizeof(NB_SESSION_INIT) + ExtraDataLength;
|
||
SessionInitMemory = (PNB_SESSION_INIT)NbiAllocateMemory(SessionInitBufferLength, MEMORY_CONNECTION, "Session Initialize");
|
||
if (!SessionInitMemory) {
|
||
ExInterlockedPushEntrySList(
|
||
&Device->SendPacketList,
|
||
s,
|
||
&NbiGlobalPoolInterlock);
|
||
if (ARGUMENT_PRESENT(LockHandle)) {
|
||
NB_FREE_LOCK (&Connection->Lock, *LockHandle);
|
||
}
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Save the extra data, now we can free the lock.
|
||
//
|
||
|
||
if (ExtraDataLength != 0) {
|
||
RtlCopyMemory (SessionInitMemory+1, ExtraData, ExtraDataLength);
|
||
}
|
||
if (ARGUMENT_PRESENT(LockHandle)) {
|
||
NB_FREE_LOCK (&Connection->Lock, *LockHandle);
|
||
}
|
||
|
||
//
|
||
// Allocate an NDIS buffer to map the extra buffer.
|
||
//
|
||
|
||
NdisAllocateBuffer(
|
||
&NdisStatus,
|
||
&SessionInitBuffer,
|
||
Device->NdisBufferPoolHandle,
|
||
SessionInitMemory,
|
||
SessionInitBufferLength);
|
||
|
||
if (NdisStatus != NDIS_STATUS_SUCCESS) {
|
||
NbiFreeMemory (SessionInitMemory, SessionInitBufferLength, MEMORY_CONNECTION, "Session Initialize");
|
||
ExInterlockedPushEntrySList(
|
||
&Device->SendPacketList,
|
||
s,
|
||
&NbiGlobalPoolInterlock);
|
||
return;
|
||
}
|
||
|
||
Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
|
||
Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
|
||
|
||
CTEAssert (Reserved->SendInProgress == FALSE);
|
||
Reserved->SendInProgress = TRUE;
|
||
Reserved->Type = SEND_TYPE_SESSION_INIT;
|
||
|
||
//
|
||
// Fill in the IPX header -- the default header has the broadcast
|
||
// address on net 0 as the destination IPX address.
|
||
//
|
||
|
||
Header = (NB_CONNECTION UNALIGNED *)
|
||
(&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
|
||
RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
|
||
|
||
Header->IpxHeader.PacketLength[0] = (UCHAR)((sizeof(NB_CONNECTION)+SessionInitBufferLength) / 256);
|
||
Header->IpxHeader.PacketLength[1] = (UCHAR)((sizeof(NB_CONNECTION)+SessionInitBufferLength) % 256);
|
||
|
||
Header->IpxHeader.PacketType = 0x04;
|
||
|
||
//
|
||
// Now fill in the Netbios header.
|
||
//
|
||
|
||
if (Connection->NewNetbios) {
|
||
Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM | NB_CONTROL_NEW_NB;
|
||
} else {
|
||
Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM;
|
||
}
|
||
// Bug#: 158998: We can have a situation where the seqno wont be zero
|
||
// if u get a (late) session init frame during active session
|
||
// CTEAssert (Connection->CurrentSend.SendSequence == 0);
|
||
// CTEAssert (Connection->ReceiveSequence == 1);
|
||
if (Connection->ReceiveSequence != 1)
|
||
{
|
||
DbgPrint("NwlnkNb.NbiSendSessionInitAck: Connection=<%p>: ReceiveSequence=<%d> != 1\n",
|
||
Connection, Connection->ReceiveSequence);
|
||
}
|
||
Header->Session.DataStreamType = NB_CMD_SESSION_DATA;
|
||
Header->Session.SourceConnectionId = Connection->LocalConnectionId;
|
||
Header->Session.DestConnectionId = Connection->RemoteConnectionId;
|
||
Header->Session.SendSequence = 0;
|
||
Header->Session.TotalDataLength = (USHORT)SessionInitBufferLength;
|
||
Header->Session.Offset = 0;
|
||
Header->Session.DataLength = (USHORT)SessionInitBufferLength;
|
||
Header->Session.ReceiveSequence = 1;
|
||
if (Connection->NewNetbios) {
|
||
Header->Session.ReceiveSequenceMax = Connection->LocalRcvSequenceMax;
|
||
} else {
|
||
Header->Session.BytesReceived = 0;
|
||
}
|
||
|
||
RtlCopyMemory (SessionInitMemory->SourceName, Connection->AddressFile->Address->NetbiosAddress.NetbiosName, 16);
|
||
RtlCopyMemory (SessionInitMemory->DestinationName, Connection->RemoteName, 16);
|
||
|
||
SessionInitMemory->MaximumDataSize = (USHORT)Connection->MaximumPacketSize;
|
||
SessionInitMemory->StartTripTime = (USHORT)
|
||
((Device->InitialRetransmissionTime * (Device->KeepAliveCount+1)) / 500);
|
||
SessionInitMemory->MaximumPacketTime = SessionInitMemory->StartTripTime + 12;
|
||
|
||
//
|
||
// Should we ref the connection? It doesn't really matter which we do.
|
||
//
|
||
|
||
NbiReferenceDevice (Device, DREF_SESSION_INIT);
|
||
|
||
NdisChainBufferAtBack (Packet, SessionInitBuffer);
|
||
|
||
|
||
//
|
||
// Now send the frame, IPX will adjust the length of the
|
||
// first buffer correctly.
|
||
//
|
||
|
||
NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
|
||
if ((NdisStatus =
|
||
(*Device->Bind.SendHandler)(
|
||
&Connection->LocalTarget,
|
||
Packet,
|
||
sizeof(NB_CONNECTION) + SessionInitBufferLength,
|
||
sizeof(NB_CONNECTION))) != STATUS_PENDING) {
|
||
|
||
NbiSendComplete(
|
||
Packet,
|
||
NdisStatus);
|
||
|
||
}
|
||
|
||
} /* NbiSendSessionInitAck */
|
||
|
||
|
||
VOID
|
||
NbiSendDataAck(
|
||
IN PCONNECTION Connection,
|
||
IN NB_ACK_TYPE AckType
|
||
IN NB_LOCK_HANDLE_PARAM (LockHandle)
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine allocates and sends a data ack frame.
|
||
|
||
THIS ROUTINE IS CALLED WITH THE LOCK HANDLE HELD AND
|
||
RETURNS WITH IT RELEASED.
|
||
|
||
Arguments:
|
||
|
||
Connection - The connection on which the frame is sent.
|
||
|
||
AckType - Indicates if this is a query to the remote,
|
||
a response to a received probe, or a request to resend.
|
||
|
||
LockHandle - The handle with which Connection->Lock was acquired.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PSLIST_ENTRY s;
|
||
PNB_SEND_RESERVED Reserved;
|
||
PNDIS_PACKET Packet;
|
||
NB_CONNECTION UNALIGNED * Header;
|
||
PDEVICE Device = NbiDevice;
|
||
|
||
//
|
||
// Allocate a packet from the pool.
|
||
//
|
||
|
||
s = NbiPopSendPacket(Device, FALSE);
|
||
|
||
//
|
||
// If we can't allocate a frame, try for the connection
|
||
// packet. If that's not available, that's OK since data
|
||
// acks are connectionless anyway.
|
||
//
|
||
|
||
if (s == NULL) {
|
||
|
||
if (!Connection->SendPacketInUse) {
|
||
|
||
Connection->SendPacketInUse = TRUE;
|
||
Packet = PACKET(&Connection->SendPacket);
|
||
Reserved = (PNB_SEND_RESERVED)(Packet->ProtocolReserved);
|
||
|
||
} else {
|
||
|
||
NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
|
||
return;
|
||
}
|
||
|
||
} else {
|
||
|
||
Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
|
||
Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
|
||
|
||
}
|
||
|
||
CTEAssert (Reserved->SendInProgress == FALSE);
|
||
Reserved->SendInProgress = TRUE;
|
||
Reserved->Type = SEND_TYPE_SESSION_NO_DATA;
|
||
Reserved->u.SR_CO.Connection = Connection;
|
||
Reserved->u.SR_CO.PacketLength = sizeof(NB_CONNECTION);
|
||
|
||
//
|
||
// Fill in the IPX header -- the default header has the broadcast
|
||
// address on net 0 as the destination IPX address.
|
||
//
|
||
|
||
Header = (NB_CONNECTION UNALIGNED *)
|
||
(&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
|
||
RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
|
||
|
||
Header->IpxHeader.PacketLength[0] = sizeof(NB_CONNECTION) / 256;
|
||
Header->IpxHeader.PacketLength[1] = sizeof(NB_CONNECTION) % 256;
|
||
|
||
Header->IpxHeader.PacketType = 0x04;
|
||
|
||
//
|
||
// Now fill in the Netbios header.
|
||
//
|
||
|
||
switch (AckType) {
|
||
case NbiAckQuery: Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM | NB_CONTROL_SEND_ACK; break;
|
||
case NbiAckResponse: Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM; break;
|
||
case NbiAckResend: Header->Session.ConnectionControlFlag = NB_CONTROL_SYSTEM | NB_CONTROL_RESEND; break;
|
||
}
|
||
Header->Session.DataStreamType = NB_CMD_SESSION_DATA;
|
||
Header->Session.SourceConnectionId = Connection->LocalConnectionId;
|
||
Header->Session.DestConnectionId = Connection->RemoteConnectionId;
|
||
Header->Session.SendSequence = Connection->CurrentSend.SendSequence;
|
||
Header->Session.TotalDataLength = (USHORT)Connection->CurrentSend.MessageOffset;
|
||
Header->Session.Offset = 0;
|
||
Header->Session.DataLength = 0;
|
||
|
||
#if 0
|
||
//
|
||
// These are set by NbiAssignSequenceAndSend.
|
||
//
|
||
|
||
Header->Session.ReceiveSequence = Connection->ReceiveSequence;
|
||
Header->Session.BytesReceived = (USHORT)Connection->CurrentReceive.MessageOffset;
|
||
#endif
|
||
|
||
NbiReferenceConnectionSync(Connection, CREF_FRAME);
|
||
|
||
//
|
||
// Set this so we will accept a probe from a remote without
|
||
// the send ack bit on. However if we receive such a request
|
||
// we turn this flag off until we get something else from the
|
||
// remote.
|
||
//
|
||
|
||
Connection->IgnoreNextDosProbe = FALSE;
|
||
|
||
Connection->ReceivesWithoutAck = 0;
|
||
|
||
//
|
||
// This frees the lock. IPX will adjust the length of
|
||
// the first buffer correctly.
|
||
//
|
||
|
||
NbiAssignSequenceAndSend(
|
||
Connection,
|
||
Packet
|
||
NB_LOCK_HANDLE_ARG(LockHandle));
|
||
|
||
} /* NbiSendDataAck */
|
||
|
||
|
||
VOID
|
||
NbiSendSessionEnd(
|
||
IN PCONNECTION Connection
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine allocates and sends a session end
|
||
frame for the specified connection.
|
||
|
||
Arguments:
|
||
|
||
Connection - The connection on which the frame is sent.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PSLIST_ENTRY s;
|
||
PNB_SEND_RESERVED Reserved;
|
||
PNDIS_PACKET Packet;
|
||
NB_CONNECTION UNALIGNED * Header;
|
||
NDIS_STATUS NdisStatus;
|
||
PDEVICE Device = NbiDevice;
|
||
|
||
//
|
||
// Allocate a packet from the pool.
|
||
//
|
||
|
||
s = NbiPopSendPacket(Device, FALSE);
|
||
|
||
//
|
||
// If we can't allocate a frame, that is OK, since
|
||
// it is connectionless anyway.
|
||
//
|
||
|
||
if (s == NULL) {
|
||
return;
|
||
}
|
||
|
||
Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
|
||
Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
|
||
|
||
CTEAssert (Reserved->SendInProgress == FALSE);
|
||
Reserved->SendInProgress = TRUE;
|
||
Reserved->Type = SEND_TYPE_SESSION_NO_DATA;
|
||
Reserved->u.SR_CO.Connection = Connection;
|
||
|
||
//
|
||
// Fill in the IPX header -- the default header has the broadcast
|
||
// address on net 0 as the destination IPX address.
|
||
//
|
||
|
||
Header = (NB_CONNECTION UNALIGNED *)
|
||
(&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
|
||
RtlCopyMemory((PVOID)&Header->IpxHeader, &Connection->RemoteHeader, sizeof(IPX_HEADER));
|
||
|
||
Header->IpxHeader.PacketLength[0] = sizeof(NB_CONNECTION) / 256;
|
||
Header->IpxHeader.PacketLength[1] = sizeof(NB_CONNECTION) % 256;
|
||
|
||
Header->IpxHeader.PacketType = 0x04;
|
||
|
||
//
|
||
// Now fill in the Netbios header. We don't advance the
|
||
// send pointer, since it is the last frame of the session
|
||
// and we want it to stay the same in the case of resends.
|
||
//
|
||
|
||
Header->Session.ConnectionControlFlag = NB_CONTROL_SEND_ACK;
|
||
Header->Session.DataStreamType = NB_CMD_SESSION_END;
|
||
Header->Session.SourceConnectionId = Connection->LocalConnectionId;
|
||
Header->Session.DestConnectionId = Connection->RemoteConnectionId;
|
||
Header->Session.SendSequence = Connection->CurrentSend.SendSequence;
|
||
Header->Session.TotalDataLength = 0;
|
||
Header->Session.Offset = 0;
|
||
Header->Session.DataLength = 0;
|
||
Header->Session.ReceiveSequence = Connection->ReceiveSequence;
|
||
if (Connection->NewNetbios) {
|
||
Header->Session.ReceiveSequenceMax = Connection->LocalRcvSequenceMax;
|
||
} else {
|
||
Header->Session.BytesReceived = 0;
|
||
}
|
||
|
||
NbiReferenceConnection (Connection, CREF_FRAME);
|
||
|
||
//
|
||
// Now send the frame, IPX will adjust the length of the
|
||
// first buffer correctly.
|
||
//
|
||
|
||
NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
|
||
if ((NdisStatus =
|
||
(*Device->Bind.SendHandler)(
|
||
&Connection->LocalTarget,
|
||
Packet,
|
||
sizeof(NB_CONNECTION),
|
||
sizeof(NB_CONNECTION))) != STATUS_PENDING) {
|
||
|
||
NbiSendComplete(
|
||
Packet,
|
||
NdisStatus);
|
||
|
||
}
|
||
|
||
} /* NbiSendSessionEnd */
|
||
|
||
|
||
VOID
|
||
NbiSendSessionEndAck(
|
||
IN TDI_ADDRESS_IPX UNALIGNED * RemoteAddress,
|
||
IN PIPX_LOCAL_TARGET LocalTarget,
|
||
IN NB_SESSION UNALIGNED * SessionEnd
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine allocates and sends a session end
|
||
frame. Generally it is sent on a connection but we
|
||
are not tied to that, to allow us to respond to
|
||
session ends from unknown remotes.
|
||
|
||
Arguments:
|
||
|
||
RemoteAddress - The remote IPX address.
|
||
|
||
LocalTarget - The local target of the remote.
|
||
|
||
SessionEnd - The received session end frame.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PSLIST_ENTRY s;
|
||
PNB_SEND_RESERVED Reserved;
|
||
PNDIS_PACKET Packet;
|
||
NB_CONNECTION UNALIGNED * Header;
|
||
NDIS_STATUS NdisStatus;
|
||
PDEVICE Device = NbiDevice;
|
||
|
||
//
|
||
// Allocate a packet from the pool.
|
||
//
|
||
|
||
s = NbiPopSendPacket(Device, FALSE);
|
||
|
||
//
|
||
// If we can't allocate a frame, that is OK, since
|
||
// it is connectionless anyway.
|
||
//
|
||
|
||
if (s == NULL) {
|
||
return;
|
||
}
|
||
|
||
Reserved = CONTAINING_RECORD (s, NB_SEND_RESERVED, PoolLinkage);
|
||
Packet = CONTAINING_RECORD (Reserved, NDIS_PACKET, ProtocolReserved[0]);
|
||
|
||
CTEAssert (Reserved->SendInProgress == FALSE);
|
||
Reserved->SendInProgress = TRUE;
|
||
Reserved->Type = SEND_TYPE_SESSION_NO_DATA;
|
||
Reserved->u.SR_CO.Connection = NULL;
|
||
|
||
//
|
||
// Fill in the IPX header -- the default header has the broadcast
|
||
// address on net 0 as the destination IPX address.
|
||
//
|
||
|
||
Header = (NB_CONNECTION UNALIGNED *)
|
||
(&Reserved->Header[Device->Bind.IncludedHeaderOffset]);
|
||
RtlCopyMemory((PVOID)&Header->IpxHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
|
||
RtlCopyMemory(&Header->IpxHeader.DestinationNetwork, (PVOID)RemoteAddress, 12);
|
||
|
||
Header->IpxHeader.PacketLength[0] = (sizeof(NB_CONNECTION)) / 256;
|
||
Header->IpxHeader.PacketLength[1] = (sizeof(NB_CONNECTION)) % 256;
|
||
|
||
Header->IpxHeader.PacketType = 0x04;
|
||
|
||
//
|
||
// Now fill in the Netbios header.
|
||
//
|
||
|
||
Header->Session.ConnectionControlFlag = 0x00;
|
||
Header->Session.DataStreamType = NB_CMD_SESSION_END_ACK;
|
||
Header->Session.SourceConnectionId = SessionEnd->DestConnectionId;
|
||
Header->Session.DestConnectionId = SessionEnd->SourceConnectionId;
|
||
Header->Session.SendSequence = SessionEnd->ReceiveSequence;
|
||
Header->Session.TotalDataLength = 0;
|
||
Header->Session.Offset = 0;
|
||
Header->Session.DataLength = 0;
|
||
if (SessionEnd->BytesReceived != 0) { // Will this detect new netbios?
|
||
Header->Session.ReceiveSequence = SessionEnd->SendSequence + 1;
|
||
Header->Session.ReceiveSequenceMax = SessionEnd->SendSequence + 3;
|
||
} else {
|
||
Header->Session.ReceiveSequence = SessionEnd->SendSequence;
|
||
Header->Session.BytesReceived = 0;
|
||
}
|
||
|
||
NbiReferenceDevice (Device, DREF_FRAME);
|
||
|
||
//
|
||
// Now send the frame, IPX will adjust the length of the
|
||
// first buffer correctly.
|
||
//
|
||
|
||
NdisAdjustBufferLength(NB_GET_NBHDR_BUFF(Packet), sizeof(NB_CONNECTION));
|
||
if ((NdisStatus =
|
||
(*Device->Bind.SendHandler)(
|
||
LocalTarget,
|
||
Packet,
|
||
sizeof(NB_CONNECTION),
|
||
sizeof(NB_CONNECTION))) != STATUS_PENDING) {
|
||
|
||
NbiSendComplete(
|
||
Packet,
|
||
NdisStatus);
|
||
|
||
}
|
||
|
||
} /* NbiSendSessionEndAck */
|
||
|