diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/tdi/isn/nb/frame.c | 1096 |
1 files changed, 1096 insertions, 0 deletions
diff --git a/private/ntos/tdi/isn/nb/frame.c b/private/ntos/tdi/isn/nb/frame.c new file mode 100644 index 000000000..49846a177 --- /dev/null +++ b/private/ntos/tdi/isn/nb/frame.c @@ -0,0 +1,1096 @@ +/*++ + +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 */ + |