summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/isnp/nb/frame.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/tdi/isnp/nb/frame.c')
-rw-r--r--private/ntos/tdi/isnp/nb/frame.c1095
1 files changed, 1095 insertions, 0 deletions
diff --git a/private/ntos/tdi/isnp/nb/frame.c b/private/ntos/tdi/isnp/nb/frame.c
new file mode 100644
index 000000000..bbc14fd56
--- /dev/null
+++ b/private/ntos/tdi/isnp/nb/frame.c
@@ -0,0 +1,1095 @@
+/*++
+
+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
+
+#if defined(_PNP_POWER)
+
+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.
+
+--*/
+
+{
+ PSINGLE_LIST_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 */
+#else
+
+VOID
+NbiSendNameFrame(
+ IN PADDRESS Address OPTIONAL,
+ IN UCHAR NameTypeFlag,
+ IN UCHAR DataStreamType,
+ IN PIPX_LOCAL_TARGET LocalTarget OPTIONAL,
+ IN TDI_ADDRESS_IPX UNALIGNED * DestAddress 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).
+
+ DestAddress - If specified, the destination IPX address to
+ use for the send (if not, it will be broadcast on net 0).
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSINGLE_LIST_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.CurrentNicId = 1;
+ Reserved->u.SR_NF.NameTypeFlag = NameTypeFlag;
+ Reserved->u.SR_NF.DataStreamType = DataStreamType;
+ } else {
+ Reserved->u.SR_NF.CurrentNicId = 0;
+ }
+
+ //
+ // 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(DestAddress)) {
+ RtlCopyMemory((PVOID)&Header->IpxHeader.DestinationNetwork, (PVOID)DestAddress, 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 : NetbiosBroadcastName,
+ 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)) {
+ TempLocalTarget.NicId = 1; // BUGBUG: What if 1 isn't valid?
+ RtlCopyMemory (TempLocalTarget.MacAddress, BroadcastAddress, 6);
+ LocalTarget = &TempLocalTarget;
+ }
+
+ 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 */
+#endif _PNP_POWER
+
+
+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.
+
+--*/
+
+{
+ PSINGLE_LIST_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);
+
+ //
+ // BUGBUG: What exactly should I put here?
+ //
+
+ SessionInitMemory->MaximumDataSize = (USHORT)Connection->MaximumPacketSize;
+ SessionInitMemory->StartTripTime = (USHORT)
+ ((Device->InitialRetransmissionTime * (Device->KeepAliveCount+1)) / 500);
+ SessionInitMemory->MaximumPacketTime = SessionInitMemory->StartTripTime + 12;
+
+ //
+ // BUGBUG: 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.
+
+--*/
+
+{
+ PSINGLE_LIST_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] = (sizeof(NB_CONNECTION)+SessionInitBufferLength) / 256;
+ Header->IpxHeader.PacketLength[1] = (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;
+ }
+ CTEAssert (Connection->CurrentSend.SendSequence == 0);
+ CTEAssert (Connection->ReceiveSequence == 1);
+ 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);
+
+ //
+ // BUGBUG: What exactly should I put here?
+ //
+
+ SessionInitMemory->MaximumDataSize = (USHORT)Connection->MaximumPacketSize;
+ SessionInitMemory->StartTripTime = (USHORT)
+ ((Device->InitialRetransmissionTime * (Device->KeepAliveCount+1)) / 500);
+ SessionInitMemory->MaximumPacketTime = SessionInitMemory->StartTripTime + 12;
+
+ //
+ // BUGBUG: 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.
+
+--*/
+
+{
+ PSINGLE_LIST_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.
+
+--*/
+
+{
+ PSINGLE_LIST_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.
+
+--*/
+
+{
+ PSINGLE_LIST_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) { // BUGBUG: 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 */
+