diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/tdi/nbf/framesnd.c | 2504 |
1 files changed, 2504 insertions, 0 deletions
diff --git a/private/ntos/tdi/nbf/framesnd.c b/private/ntos/tdi/nbf/framesnd.c new file mode 100644 index 000000000..e4c356d99 --- /dev/null +++ b/private/ntos/tdi/nbf/framesnd.c @@ -0,0 +1,2504 @@ +/*++ + +Copyright (c) 1989, 1990, 1991 Microsoft Corporation + +Module Name: + + framesnd.c + +Abstract: + + This module contains routines which build and send NetBIOS Frames Protocol + frames and data link frames for other modules. These routines call on the + ones in FRAMECON.C to do the construction work. + +Author: + + David Beaver (dbeaver) 1-July-1991 + +Environment: + + Kernel mode + +Revision History: + +--*/ + +#include "precomp.h" +#pragma hdrstop + +#if DBG +ULONG NbfSendsIssued = 0; +ULONG NbfSendsCompletedInline = 0; +ULONG NbfSendsCompletedOk = 0; +ULONG NbfSendsCompletedFail = 0; +ULONG NbfSendsPended = 0; +ULONG NbfSendsCompletedAfterPendOk = 0; +ULONG NbfSendsCompletedAfterPendFail = 0; + +ULONG NbfPacketPanic = 0; +#endif + + +NTSTATUS +NbfSendAddNameQuery( + IN PTP_ADDRESS Address + ) + +/*++ + +Routine Description: + + This routine sends a ADD_NAME_QUERY frame to register the specified + address. + +Arguments: + + Address - Pointer to a transport address object. + + +Return Value: + + none. + +--*/ + +{ + NTSTATUS Status; + PDEVICE_CONTEXT DeviceContext; + PTP_UI_FRAME RawFrame; + PUCHAR SingleSR; + UINT SingleSRLength; + UINT HeaderLength; + + DeviceContext = Address->Provider; + + + // + // Allocate a UI frame from the pool. + // + + Status = NbfCreateConnectionlessFrame (DeviceContext, &RawFrame); + if (!NT_SUCCESS (Status)) { // couldn't make frame. + return STATUS_INSUFFICIENT_RESOURCES; + } + + IF_NBFDBG (NBF_DEBUG_FRAMESND) { + NbfPrint3 ("NbfSendAddNameQuery: Sending Frame: %lx, NdisPacket: %lx MacHeader: %lx\n", + RawFrame, RawFrame->NdisPacket, RawFrame->Header); + } + + + // + // Build the MAC header. ADD_NAME_QUERY frames go out as + // single-route source routing. + // + + MacReturnSingleRouteSR( + &DeviceContext->MacInfo, + &SingleSR, + &SingleSRLength); + + MacConstructHeader ( + &DeviceContext->MacInfo, + RawFrame->Header, + DeviceContext->NetBIOSAddress.Address, + DeviceContext->LocalAddress.Address, + sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS), + SingleSR, + SingleSRLength, + &HeaderLength); + + + // + // Build the DLC UI frame header. + // + + NbfBuildUIFrameHeader(&RawFrame->Header[HeaderLength]); + HeaderLength += sizeof(DLC_FRAME); + + + // + // Build the appropriate Netbios header based on the type + // of the address. + // + + if ((Address->Flags & ADDRESS_FLAGS_GROUP) != 0) { + + ConstructAddGroupNameQuery ( + (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]), + 0, // correlator we don't use. + Address->NetworkName->NetbiosName); + + } else { + + ConstructAddNameQuery ( + (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]), + 0, // correlator we don't use. + Address->NetworkName->NetbiosName); + + } + + HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS); + + + // + // Munge the packet length and send the it. + // + + NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength); + + NbfSendUIFrame ( + DeviceContext, + RawFrame, + FALSE); // no loopback (MC frame). + + return STATUS_SUCCESS; +} /* NbfSendAddNameQuery */ + + +VOID +NbfSendNameQuery( + IN PTP_CONNECTION Connection, + IN BOOLEAN SourceRoutingOptional + ) + +/*++ + +Routine Description: + + This routine sends a NAME_QUERY frame of the appropriate type given the + state of the specified connection. + +Arguments: + + Connection - Pointer to a transport connection object. + + SourceRoutingOptional - TRUE if source routing should be removed if + we are configured that way. + +Return Value: + + none. + +--*/ + +{ + NTSTATUS Status; + PDEVICE_CONTEXT DeviceContext; + PTP_ADDRESS Address; + PTP_UI_FRAME RawFrame; + PUCHAR NameQuerySR; + UINT NameQuerySRLength; + PUCHAR NameQueryAddress; + UINT HeaderLength; + UCHAR Lsn; + UCHAR NameType; + + Address = Connection->AddressFile->Address; + DeviceContext = Address->Provider; + + + // + // Allocate a UI frame from the pool. + // + + Status = NbfCreateConnectionlessFrame(DeviceContext, &RawFrame); + if (!NT_SUCCESS (Status)) { // couldn't make frame. + return; + } + + IF_NBFDBG (NBF_DEBUG_FRAMESND) { + NbfPrint2 ("NbfSendNameQuery: Sending Frame: %lx, NdisPacket: %lx\n", + RawFrame, RawFrame->NdisPacket); + } + + + // + // Build the MAC header. + // + + if (((Connection->Flags2 & CONNECTION_FLAGS2_WAIT_NR) != 0) && + ((Connection->Flags2 & CONNECTION_FLAGS2_GROUP_LSN) == 0)) { + + // + // This is the second find name to a unique name; this + // means that we already have a link and we can send this + // frame directed to it. + // + + ASSERT (Connection->Link != NULL); + + MacReturnSourceRouting( + &DeviceContext->MacInfo, + Connection->Link->Header, + &NameQuerySR, + &NameQuerySRLength); + + NameQueryAddress = Connection->Link->HardwareAddress.Address; + + } else { + + // + // Standard NAME_QUERY frames go out as + // single-route source routing, except if + // it is optional and we are configured + // that way. + // + + if (SourceRoutingOptional && + Connection->Provider->MacInfo.QueryWithoutSourceRouting) { + + NameQuerySR = NULL; + NameQuerySRLength = 0; + + } else { + + MacReturnSingleRouteSR( + &DeviceContext->MacInfo, + &NameQuerySR, + &NameQuerySRLength); + + } + + NameQueryAddress = DeviceContext->NetBIOSAddress.Address; + + } + + MacConstructHeader ( + &DeviceContext->MacInfo, + RawFrame->Header, + NameQueryAddress, + DeviceContext->LocalAddress.Address, + sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS), + NameQuerySR, + NameQuerySRLength, + &HeaderLength); + + + // + // Build the DLC UI frame header. + // + + NbfBuildUIFrameHeader(&RawFrame->Header[HeaderLength]); + HeaderLength += sizeof(DLC_FRAME); + + + // + // Build the Netbios header. + // + + Lsn = (UCHAR)((Connection->Flags2 & CONNECTION_FLAGS2_WAIT_NR_FN) ? + NAME_QUERY_LSN_FIND_NAME : Connection->Lsn); + + NameType = (UCHAR)((Connection->AddressFile->Address->Flags & ADDRESS_FLAGS_GROUP) ? + NETBIOS_NAME_TYPE_GROUP : NETBIOS_NAME_TYPE_UNIQUE); + + ConstructNameQuery ( + (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]), + NameType, // type of our name. + Lsn, // calculated, above. + (USHORT)Connection->ConnectionId, // corr. in 1st NAME_RECOGNIZED. + Address->NetworkName->NetbiosName, // NetBIOS name of sender. + Connection->CalledAddress.NetbiosName); // NetBIOS name of receiver. + + HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS); + + + // + // Munge the packet length and send the it. + // + + NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength); + + NbfSendUIFrame ( + DeviceContext, + RawFrame, + FALSE); // no loopback (MC frame) + +} /* NbfSendNameQuery */ + + +VOID +NbfSendNameRecognized( + IN PTP_ADDRESS Address, + IN UCHAR LocalSessionNumber, // LSN assigned to session. + IN PNBF_HDR_CONNECTIONLESS Header, + IN PHARDWARE_ADDRESS SourceAddress, + IN PUCHAR SourceRouting, + IN UINT SourceRoutingLength + ) + +/*++ + +Routine Description: + + This routine sends a NAME_RECOGNIZED frame of the appropriate type + in response to the NAME_QUERY pointed to by Header. + +Arguments: + + Address - Pointer to a transport address object. + + LocalSessionNumber - The LSN to use in the frame. + + Header - Pointer to the connectionless NetBIOS header of the + NAME_QUERY frame. + + SourceAddress - Pointer to the source hardware address in the received + frame. + + SourceRoutingInformation - Pointer to source routing information, if any. + +Return Value: + + none. + +--*/ + +{ + NTSTATUS Status; + PDEVICE_CONTEXT DeviceContext; + PTP_UI_FRAME RawFrame; + UINT HeaderLength; + PUCHAR ReplySR; + UINT ReplySRLength; + UCHAR TempSR[MAX_SOURCE_ROUTING]; + UCHAR NameType; + + DeviceContext = Address->Provider; + + + // + // Allocate a UI frame from the pool. + // + + Status = NbfCreateConnectionlessFrame (DeviceContext, &RawFrame); + if (!NT_SUCCESS (Status)) { // couldn't make frame. + return; + } + + IF_NBFDBG (NBF_DEBUG_FRAMESND) { + NbfPrint2 ("NbfSendNameRecognized: Sending Frame: %lx, NdisPacket: %lx\n", + RawFrame, RawFrame->NdisPacket); + } + + + // + // Build the MAC header. NAME_RECOGNIZED frames go out as + // directed source routing unless configured for general-route. + // + + if (DeviceContext->MacInfo.AllRoutesNameRecognized) { + + MacReturnGeneralRouteSR( + &DeviceContext->MacInfo, + &ReplySR, + &ReplySRLength); + + } else { + + if (SourceRouting != NULL) { + + RtlCopyMemory( + TempSR, + SourceRouting, + SourceRoutingLength); + + MacCreateNonBroadcastReplySR( + &DeviceContext->MacInfo, + TempSR, + SourceRoutingLength, + &ReplySR); + + ReplySRLength = SourceRoutingLength; + + } else { + + ReplySR = NULL; + } + } + + + MacConstructHeader ( + &DeviceContext->MacInfo, + RawFrame->Header, + SourceAddress->Address, + DeviceContext->LocalAddress.Address, + sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS), + ReplySR, + ReplySRLength, + &HeaderLength); + + + // + // Build the DLC UI frame header. + // + + NbfBuildUIFrameHeader(&RawFrame->Header[HeaderLength]); + HeaderLength += sizeof(DLC_FRAME); + + + // + // Build the Netbios header. + // + + NameType = (UCHAR)((Address->Flags & ADDRESS_FLAGS_GROUP) ? + NETBIOS_NAME_TYPE_GROUP : NETBIOS_NAME_TYPE_UNIQUE); + + ConstructNameRecognized ( // build a good response. + (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]), + NameType, // type of local name. + LocalSessionNumber, // return our LSN. + RESPONSE_CORR(Header), // new xmit corr. + 0, // our response correlator (unused). + Header->DestinationName, // our NetBIOS name. + Header->SourceName); // his NetBIOS name. + + // + // BUGBUG: Use Address->NetworkName->Address[0].Address[0].NetbiosName + // instead of Header->DestinationName? + // + + HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS); + + + // + // Munge the packet length and send the it. + // + + NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength); + + NbfSendUIFrame ( + DeviceContext, + RawFrame, + FALSE); // no loopback (MC frame) + +} /* NbfSendNameRecognized */ + + +VOID +NbfSendNameInConflict( + IN PTP_ADDRESS Address, + IN PUCHAR ConflictingName + ) + +/*++ + +Routine Description: + + This routine sends a NAME_IN_CONFLICT frame. + +Arguments: + + Address - Pointer to a transport address object. + + ConflictingName - The NetBIOS name which is in conflict. + +Return Value: + + none. + +--*/ + +{ + NTSTATUS Status; + PDEVICE_CONTEXT DeviceContext; + PTP_UI_FRAME RawFrame; + UINT HeaderLength; + PUCHAR SingleSR; + UINT SingleSRLength; + + DeviceContext = Address->Provider; + + + // + // Allocate a UI frame from the pool. + // + + Status = NbfCreateConnectionlessFrame (DeviceContext, &RawFrame); + if (!NT_SUCCESS (Status)) { // couldn't make frame. + return; + } + + IF_NBFDBG (NBF_DEBUG_FRAMESND) { + NbfPrint2 ("NbfSendNameRecognized: Sending Frame: %lx, NdisPacket: %lx\n", + RawFrame, RawFrame->NdisPacket); + } + + + // + // Build the MAC header. ADD_NAME_QUERY frames go out as + // single-route source routing. + // + + MacReturnSingleRouteSR( + &DeviceContext->MacInfo, + &SingleSR, + &SingleSRLength); + + MacConstructHeader ( + &DeviceContext->MacInfo, + RawFrame->Header, + DeviceContext->NetBIOSAddress.Address, + DeviceContext->LocalAddress.Address, + sizeof (DLC_FRAME) + sizeof (NBF_HDR_CONNECTIONLESS), + SingleSR, + SingleSRLength, + &HeaderLength); + + + // + // Build the DLC UI frame header. + // + + NbfBuildUIFrameHeader(&RawFrame->Header[HeaderLength]); + HeaderLength += sizeof(DLC_FRAME); + + + // + // Build the Netbios header. + // + + ConstructNameInConflict ( + (PNBF_HDR_CONNECTIONLESS)&(RawFrame->Header[HeaderLength]), + ConflictingName, // his NetBIOS name. + DeviceContext->ReservedNetBIOSAddress); // our reserved NetBIOS name. + + HeaderLength += sizeof(NBF_HDR_CONNECTIONLESS); + + + // + // Munge the packet length and send the it. + // + + NbfSetNdisPacketLength(RawFrame->NdisPacket, HeaderLength); + + NbfSendUIFrame ( + DeviceContext, + RawFrame, + FALSE); // no loopback (MC frame) + +} /* NbfSendNameInConflict */ + + +VOID +NbfSendSessionInitialize( + IN PTP_CONNECTION Connection + ) + +/*++ + +Routine Description: + + This routine sends a SESSION_INITIALIZE frame on the specified connection. + + NOTE: THIS ROUTINE MUST BE CALLED AT DPC LEVEL. + +Arguments: + + Connection - Pointer to a transport connection object. + + +Return Value: + + none. + +--*/ + +{ + NTSTATUS Status; + PTP_PACKET Packet; + PDEVICE_CONTEXT DeviceContext; + PTP_LINK Link; + + NbfReferenceConnection("send Session Initialize", Connection, CREF_FRAME_SEND); + + DeviceContext = Connection->Provider; + Link = Connection->Link; + Status = NbfCreatePacket (DeviceContext, Connection->Link, &Packet); + + if (!NT_SUCCESS (Status)) { // if we couldn't make frame. +#if DBG + if (NbfPacketPanic) { + PANIC ("NbfSendSessionInitialize: NbfCreatePacket failed.\n"); + } +#endif + NbfWaitPacket (Connection, CONNECTION_FLAGS_SEND_SI); + NbfDereferenceConnection("Couldn't get SI packet", Connection, CREF_FRAME_SEND); + return; + } + + + // + // Initialize the Netbios header. + // + + ConstructSessionInitialize ( + (PNBF_HDR_CONNECTION)&(Packet->Header[Link->HeaderLength + sizeof(DLC_I_FRAME)]), + SESSION_INIT_OPTIONS_20 | SESSION_INIT_NO_ACK | + SESSION_INIT_OPTIONS_LF, // supported options BUGBUG: Set LF correctly. + (USHORT)(Connection->Link->MaxFrameSize - sizeof(NBF_HDR_CONNECTION) - sizeof(DLC_I_FRAME)), + // maximum frame size/this session. + Connection->NetbiosHeader.TransmitCorrelator, // correlator from NAME_RECOGNIZED. + 0, // correlator for expected SESSION_CONFIRM. + Connection->Lsn, // our local session number. + Connection->Rsn); // his session number (our RSN). + + // + // Now send the packet on the connection via the link. If there are + // conditions on the link which make it impossible to send the packet, + // then the packet will be queued to the WackQ, and then timeouts will + // restart the link. This is acceptable when the traffic level is so + // high that we encounter this condition. + // + + // + // Set this so NbfDestroyPacket will dereference the connection. + // + + Packet->Owner = Connection; + Packet->Action = PACKET_ACTION_CONNECTION; + + Packet->NdisIFrameLength = + Link->HeaderLength + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION); + + MacModifyHeader( + &DeviceContext->MacInfo, + Packet->Header, + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION)); + + NbfSetNdisPacketLength( + Packet->NdisPacket, + Packet->NdisIFrameLength); + + ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock); + + Status = SendOnePacket (Connection, Packet, FALSE, NULL); // fire and forget. + + if (Status == STATUS_LINK_FAILED) { + NbfDereferencePacket (Packet); // destroy the packet. + } + + return; +} /* NbfSendSessionInitialize */ + + +VOID +NbfSendSessionConfirm( + IN PTP_CONNECTION Connection + ) + +/*++ + +Routine Description: + + This routine sends a SESSION_CONFIRM frame on the specified connection. + +Arguments: + + Connection - Pointer to a transport connection object. + + +Return Value: + + none. + +--*/ + +{ + NTSTATUS Status; + PTP_PACKET Packet; + PDEVICE_CONTEXT DeviceContext; + PTP_LINK Link; + + NbfReferenceConnection("send Session Confirm", Connection, CREF_FRAME_SEND); + + DeviceContext = Connection->Provider; + Link = Connection->Link; + Status = NbfCreatePacket (DeviceContext, Connection->Link, &Packet); + + if (!NT_SUCCESS (Status)) { // if we couldn't make frame. +#if DBG + if (NbfPacketPanic) { + PANIC ("NbfSendSessionConfirm: NbfCreatePacket failed.\n"); + } +#endif + NbfWaitPacket (Connection, CONNECTION_FLAGS_SEND_SC); + NbfDereferenceConnection("Couldn't get SC packet", Connection, CREF_FRAME_SEND); + return; + } + + + // + // Initialize the Netbios header. + // + + ConstructSessionConfirm ( + (PNBF_HDR_CONNECTION)&(Packet->Header[Link->HeaderLength + sizeof(DLC_I_FRAME)]), + SESSION_CONFIRM_OPTIONS_20 | SESSION_CONFIRM_NO_ACK, // supported options. + (USHORT)(Connection->Link->MaxFrameSize - sizeof(NBF_HDR_CONNECTION) - sizeof(DLC_I_FRAME)), + // maximum frame size/this session. + Connection->NetbiosHeader.TransmitCorrelator, // correlator from NAME_RECOGNIZED. + Connection->Lsn, // our local session number. + Connection->Rsn); // his session number (our RSN). + + // + // Now send the packet on the connection via the link. If there are + // conditions on the link which make it impossible to send the packet, + // then the packet will be queued to the WackQ, and then timeouts will + // restart the link. This is acceptable when the traffic level is so + // high that we encounter this condition. + // + + // + // Set this so NbfDestroyPacket will dereference the connection. + // + + Packet->Owner = Connection; + Packet->Action = PACKET_ACTION_CONNECTION; + + Packet->NdisIFrameLength = + Link->HeaderLength + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION); + + MacModifyHeader( + &DeviceContext->MacInfo, + Packet->Header, + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION)); + + NbfSetNdisPacketLength( + Packet->NdisPacket, + Packet->NdisIFrameLength); + + ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock); + + Status = SendOnePacket (Connection, Packet, FALSE, NULL); // fire and forget. + + if (Status == STATUS_LINK_FAILED) { + NbfDereferencePacket (Packet); // destroy the packet. + } + + return; +} /* NbfSendSessionConfirm */ + + +VOID +NbfSendSessionEnd( + IN PTP_CONNECTION Connection, + IN BOOLEAN Abort + ) + +/*++ + +Routine Description: + + This routine sends a SESSION_END frame on the specified connection. + +Arguments: + + Connection - Pointer to a transport connection object. + + Abort - Boolean set to TRUE if the connection is abnormally terminating. + +Return Value: + + none. + +--*/ + +{ + NTSTATUS Status; + PTP_PACKET Packet; + PDEVICE_CONTEXT DeviceContext; + PTP_LINK Link; + + NbfReferenceConnection("send Session End", Connection, CREF_FRAME_SEND); + + DeviceContext = Connection->Provider; + Link = Connection->Link; + + Status = NbfCreatePacket (DeviceContext, Connection->Link, &Packet); + + if (!NT_SUCCESS (Status)) { // if we couldn't make frame. +#if DBG + if (NbfPacketPanic) { + PANIC ("NbfSendSessionEnd: NbfCreatePacket failed.\n"); + } +#endif + NbfWaitPacket (Connection, CONNECTION_FLAGS_SEND_SE); + NbfDereferenceConnection("Couldn't get SE packet", Connection, CREF_FRAME_SEND); + return; + } + + // + // The following statements instruct the packet destructor to run + // down this connection when the packet is acknowleged. + // + + Packet->Owner = Connection; + Packet->Action = PACKET_ACTION_END; + + + // + // Initialize the Netbios header. + // + + ConstructSessionEnd ( + (PNBF_HDR_CONNECTION)&(Packet->Header[Link->HeaderLength + sizeof(DLC_I_FRAME)]), + (USHORT)(Abort ? // reason for termination. + SESSION_END_REASON_ABEND : + SESSION_END_REASON_HANGUP), + Connection->Lsn, // our local session number. + Connection->Rsn); // his session number (our RSN). + + // + // Now send the packet on the connection via the link. If there are + // conditions on the link which make it impossible to send the packet, + // then the packet will be queued to the WackQ, and then timeouts will + // restart the link. This is acceptable when the traffic level is so + // high that we encounter this condition. + // + // Note that we force an ack for this packet, as we want to make sure we + // run down the connection and link correctly. + // + + Packet->NdisIFrameLength = + Link->HeaderLength + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION); + + MacModifyHeader( + &DeviceContext->MacInfo, + Packet->Header, + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION)); + + NbfSetNdisPacketLength( + Packet->NdisPacket, + Packet->NdisIFrameLength); + + ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock); + + Status = SendOnePacket (Connection, Packet, TRUE, NULL); // fire and forget. + + if (Status == STATUS_LINK_FAILED) { + NbfDereferencePacket (Packet); // destroy the packet. + } + + return; +} /* NbfSendSessionEnd */ + + +VOID +NbfSendNoReceive( + IN PTP_CONNECTION Connection + ) + +/*++ + +Routine Description: + + This routine sends a NO_RECEIVE frame on the specified connection. + +Arguments: + + Connection - Pointer to a transport connection object. + + +Return Value: + + none. + +--*/ + +{ + NTSTATUS Status; + PTP_PACKET Packet; + PDEVICE_CONTEXT DeviceContext; + PTP_LINK Link; + USHORT MessageBytesToAck; + + NbfReferenceConnection("send No Receive", Connection, CREF_FRAME_SEND); + + DeviceContext = Connection->Provider; + Link = Connection->Link; + Status = NbfCreatePacket (DeviceContext, Connection->Link, &Packet); + + if (!NT_SUCCESS (Status)) { // if we couldn't make frame. +#if DBG + if (NbfPacketPanic) { + PANIC ("NbfSendNoReceive: NbfCreatePacket failed.\n"); + } +#endif + NbfDereferenceConnection("Couldn't get NR packet", Connection, CREF_FRAME_SEND); + return; + } + + + ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock); + + MessageBytesToAck = (USHORT) + (Connection->MessageBytesReceived + Connection->MessageInitAccepted - Connection->MessageBytesAcked); + Connection->Flags |= CONNECTION_FLAGS_W_RESYNCH; + + // + // Initialize the Netbios header. + // + + ConstructNoReceive ( + (PNBF_HDR_CONNECTION)&(Packet->Header[Link->HeaderLength + sizeof(DLC_I_FRAME)]), + (USHORT)0, // options + MessageBytesToAck, // number of bytes accepted. + Connection->Lsn, // our local session number. + Connection->Rsn); // his session number (our RSN). + + // + // Now send the packet on the connection via the link. If there are + // conditions on the link which make it impossible to send the packet, + // then the packet will be queued to the WackQ, and then timeouts will + // restart the link. This is acceptable when the traffic level is so + // high that we encounter this condition. + // + + // + // Set this so NbfDestroyPacket will dereference the connection. + // + + Packet->Owner = Connection; + Packet->Action = PACKET_ACTION_CONNECTION; + + Packet->NdisIFrameLength = + Link->HeaderLength + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION); + + MacModifyHeader( + &DeviceContext->MacInfo, + Packet->Header, + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION)); + + NbfSetNdisPacketLength( + Packet->NdisPacket, + Packet->NdisIFrameLength); + + Status = SendOnePacket (Connection, Packet, FALSE, NULL); // fire and forget. + + if (Status != STATUS_LINK_FAILED) { + ExInterlockedAddUlong( + &Connection->MessageBytesAcked, + MessageBytesToAck, + Connection->LinkSpinLock); + } else { + NbfDereferencePacket (Packet); // destroy the packet. + } + + return; +} /* NbfSendNoReceive */ + + +VOID +NbfSendReceiveContinue( + IN PTP_CONNECTION Connection + ) + +/*++ + +Routine Description: + + This routine sends a RECEIVE_CONTINUE frame on the specified connection. + +Arguments: + + Connection - Pointer to a transport connection object. + + +Return Value: + + none. + +--*/ + +{ + NTSTATUS Status; + PTP_PACKET Packet; + PDEVICE_CONTEXT DeviceContext; + PTP_LINK Link; + USHORT MessageBytesToAck; + + NbfReferenceConnection("send Receive Continue", Connection, CREF_FRAME_SEND); + + DeviceContext = Connection->Provider; + Link = Connection->Link; + Status = NbfCreatePacket (DeviceContext, Connection->Link, &Packet); + + if (!NT_SUCCESS (Status)) { // if we couldn't make frame. +#if DBG + if (NbfPacketPanic) { + PANIC ("NbfSendReceiveContinue: NbfCreatePacket failed.\n"); + } +#endif + NbfWaitPacket (Connection, CONNECTION_FLAGS_SEND_RC); + NbfDereferenceConnection("Couldn't get RC packet", Connection, CREF_FRAME_SEND); + return; + } + + // + // Save this variable now since it is what we are implicitly ack'ing. + // + + ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock); + MessageBytesToAck = (USHORT) + (Connection->MessageBytesReceived + Connection->MessageInitAccepted - Connection->MessageBytesAcked); + + // + // Initialize the Netbios header. + // + + ConstructReceiveContinue ( + (PNBF_HDR_CONNECTION)&(Packet->Header[Link->HeaderLength + sizeof(DLC_I_FRAME)]), + Connection->NetbiosHeader.TransmitCorrelator, // correlator from DFM + Connection->Lsn, // our local session number. + Connection->Rsn); // his session number (our RSN). + + // + // Now send the packet on the connection via the link. If there are + // conditions on the link which make it impossible to send the packet, + // then the packet will be queued to the WackQ, and then timeouts will + // restart the link. This is acceptable when the traffic level is so + // high that we encounter this condition. + // + + // + // Set this so NbfDestroyPacket will dereference the connection. + // + + Packet->Owner = Connection; + Packet->Action = PACKET_ACTION_CONNECTION; + + Packet->NdisIFrameLength = + Link->HeaderLength + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION); + + MacModifyHeader( + &DeviceContext->MacInfo, + Packet->Header, + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION)); + + NbfSetNdisPacketLength( + Packet->NdisPacket, + Packet->NdisIFrameLength); + + Status = SendOnePacket (Connection, Packet, FALSE, NULL); // fire and forget. + + if (Status != STATUS_LINK_FAILED) { + ExInterlockedAddUlong( + &Connection->MessageBytesAcked, + MessageBytesToAck, + Connection->LinkSpinLock); + } else { + NbfDereferencePacket (Packet); // destroy the packet. + } + + return; +} /* NbfSendReceiveContinue */ + + +VOID +NbfSendReceiveOutstanding( + IN PTP_CONNECTION Connection + ) + +/*++ + +Routine Description: + + This routine sends a RECEIVE_OUTSTANDING frame on the specified connection. + +Arguments: + + Connection - Pointer to a transport connection object. + + +Return Value: + + none. + +--*/ + +{ + NTSTATUS Status; + PTP_PACKET Packet; + PDEVICE_CONTEXT DeviceContext; + PTP_LINK Link; + USHORT MessageBytesToAck; + + NbfReferenceConnection("send Receive Outstanding", Connection, CREF_FRAME_SEND); + + DeviceContext = Connection->Provider; + Link = Connection->Link; + Status = NbfCreatePacket (DeviceContext, Connection->Link, &Packet); + + if (!NT_SUCCESS (Status)) { // if we couldn't make frame. +#if DBG + if (NbfPacketPanic) { + PANIC ("NbfSendReceiveOutstanding: NbfCreatePacket failed.\n"); + } +#endif + NbfWaitPacket (Connection, CONNECTION_FLAGS_SEND_RO); + NbfDereferenceConnection("Couldn't get RO packet", Connection, CREF_FRAME_SEND); + return; + } + + + ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock); + + MessageBytesToAck = (USHORT) + (Connection->MessageBytesReceived + Connection->MessageInitAccepted - Connection->MessageBytesAcked); + Connection->Flags |= CONNECTION_FLAGS_W_RESYNCH; + + // + // Initialize the Netbios header. + // + + ConstructReceiveOutstanding ( + (PNBF_HDR_CONNECTION)&(Packet->Header[Link->HeaderLength + sizeof(DLC_I_FRAME)]), + MessageBytesToAck, // number of bytes accepted. + Connection->Lsn, // our local session number. + Connection->Rsn); // his session number (our RSN). + + + // + // Now send the packet on the connection via the link. If there are + // conditions on the link which make it impossible to send the packet, + // then the packet will be queued to the WackQ, and then timeouts will + // restart the link. This is acceptable when the traffic level is so + // high that we encounter this condition. + // + + // + // Set this so NbfDestroyPacket will dereference the connection. + // + + Packet->Owner = Connection; + Packet->Action = PACKET_ACTION_CONNECTION; + + Packet->NdisIFrameLength = + Link->HeaderLength + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION); + + MacModifyHeader( + &DeviceContext->MacInfo, + Packet->Header, + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION)); + + NbfSetNdisPacketLength( + Packet->NdisPacket, + Packet->NdisIFrameLength); + + Status = SendOnePacket (Connection, Packet, FALSE, NULL); // fire and forget. + + if (Status != STATUS_LINK_FAILED) { + ExInterlockedAddUlong( + &Connection->MessageBytesAcked, + MessageBytesToAck, + Connection->LinkSpinLock); + } else { + NbfDereferencePacket (Packet); // destroy the packet. + } + + return; +} /* NbfSendReceiveOutstanding */ + + +VOID +NbfSendDataAck( + IN PTP_CONNECTION Connection + ) + +/*++ + +Routine Description: + + This routine sends a DATA_ACK frame on the specified connection. + +Arguments: + + Connection - Pointer to a transport connection object. + + +Return Value: + + none. + +--*/ + +{ + NTSTATUS Status; + PTP_PACKET Packet; + PDEVICE_CONTEXT DeviceContext; + PTP_LINK Link; + + NbfReferenceConnection("send Data Ack", Connection, CREF_FRAME_SEND); + + DeviceContext = Connection->Provider; + Link = Connection->Link; + Status = NbfCreatePacket (DeviceContext, Connection->Link, &Packet); + + if (!NT_SUCCESS (Status)) { // if we couldn't make frame. +#if DBG + if (NbfPacketPanic) { + PANIC ("NbfSendDataAck: NbfCreatePacket failed.\n"); + } +#endif + NbfWaitPacket (Connection, CONNECTION_FLAGS_SEND_DA); + NbfDereferenceConnection("Couldn't get DA packet", Connection, CREF_FRAME_SEND); + return; + } + + + // + // Initialize the Netbios header. + // + + ConstructDataAck ( + (PNBF_HDR_CONNECTION)&(Packet->Header[Link->HeaderLength + sizeof(DLC_I_FRAME)]), + Connection->NetbiosHeader.TransmitCorrelator, // correlator from DATA_ONLY_LAST. + Connection->Lsn, // our local session number. + Connection->Rsn); // his session number (our RSN). + + // + // Now send the packet on the connection via the link. If there are + // conditions on the link which make it impossible to send the packet, + // then the packet will be queued to the WackQ, and then timeouts will + // restart the link. This is acceptable when the traffic level is so + // high that we encounter this condition. Note that Data Ack will be + // seeing this condition frequently when send windows close after large + // sends. + // + + // + // Set this so NbfDestroyPacket will dereference the connection. + // + + Packet->Owner = Connection; + Packet->Action = PACKET_ACTION_CONNECTION; + + Packet->NdisIFrameLength = + Link->HeaderLength + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION); + + MacModifyHeader( + &DeviceContext->MacInfo, + Packet->Header, + sizeof(DLC_I_FRAME) + sizeof(NBF_HDR_CONNECTION)); + + NbfSetNdisPacketLength( + Packet->NdisPacket, + Packet->NdisIFrameLength); + + ACQUIRE_DPC_SPIN_LOCK (Connection->LinkSpinLock); + + Status = SendOnePacket (Connection, Packet, FALSE, NULL); // fire and forget. + + if (Status == STATUS_LINK_FAILED) { + NbfDereferencePacket (Packet); // destroy the packet. + } + + return; +} /* NbfSendDataAck */ + + +VOID +NbfSendDm( + IN PTP_LINK Link, + IN BOOLEAN PollFinal + ) + +/*++ + +Routine Description: + + This routine sends a DM-r/x DLC frame on the specified link. + + NOTE: This routine is called with the link spinlock held, + and returns with it released. IT MUST BE CALLED AT DPC + LEVEL. + +Arguments: + + Link - Pointer to a transport link object. + + PollFinal - TRUE if poll/final bit should be set. + +Return Value: + + none. + +--*/ + +{ + NTSTATUS Status; + PTP_PACKET RawFrame; + PDLC_U_FRAME DlcHeader; // S-format frame alias. + + Status = NbfCreatePacket (Link->Provider, Link, &RawFrame); + if (NT_SUCCESS (Status)) { + + RawFrame->Owner = NULL; + RawFrame->Action = PACKET_ACTION_NULL; + + // + // set the packet length correctly (Note that the NDIS_BUFFER + // gets returned to the proper length in NbfDestroyPacket) + // + + MacModifyHeader(&Link->Provider->MacInfo, RawFrame->Header, sizeof(DLC_FRAME)); + NbfSetNdisPacketLength (RawFrame->NdisPacket, Link->HeaderLength + sizeof(DLC_FRAME)); + + // + // Format LLC DM-r/x header. + // + + DlcHeader = (PDLC_U_FRAME)&(RawFrame->Header[Link->HeaderLength]); + DlcHeader->Dsap = DSAP_NETBIOS_OVER_LLC; + DlcHeader->Ssap = DSAP_NETBIOS_OVER_LLC | DLC_SSAP_RESPONSE; + DlcHeader->Command = (UCHAR)(DLC_CMD_DM | (PollFinal ? DLC_U_PF : 0)); + + // + // This releases the spin lock. + // + + SendControlPacket (Link, RawFrame); + + } else { + RELEASE_DPC_SPIN_LOCK(&Link->SpinLock); +#if DBG + if (NbfPacketPanic) { + PANIC ("NbfSendDm: packet not sent.\n"); + } +#endif + } +} /* NbfSendDm */ + + +VOID +NbfSendUa( + IN PTP_LINK Link, + IN BOOLEAN PollFinal + ) + +/*++ + +Routine Description: + + This routine sends a UA-r/x DLC frame on the specified link. + + NOTE: This routine is called with the link spinlock held, + and returns with it released. IT MUST BE CALLED AT DPC + LEVEL. + +Arguments: + + Link - Pointer to a transport link object. + + PollFinal - TRUE if poll/final bit should be set. + + OldIrql - The IRQL at which Link->SpinLock was acquired. + +Return Value: + + none. + +--*/ + +{ + NTSTATUS Status; + PTP_PACKET RawFrame; + PDLC_U_FRAME DlcHeader; // U-format frame alias. + + Status = NbfCreatePacket (Link->Provider, Link, &RawFrame); + if (NT_SUCCESS (Status)) { + + RawFrame->Owner = NULL; + RawFrame->Action = PACKET_ACTION_NULL; + + // + // set the packet length correctly (Note that the NDIS_BUFFER + // gets returned to the proper length in NbfDestroyPacket) + // + + MacModifyHeader(&Link->Provider->MacInfo, RawFrame->Header, sizeof(DLC_FRAME)); + NbfSetNdisPacketLength (RawFrame->NdisPacket, Link->HeaderLength + sizeof(DLC_FRAME)); + + // Format LLC UA-r/x header. + // + + DlcHeader = (PDLC_U_FRAME)&(RawFrame->Header[Link->HeaderLength]); + DlcHeader->Dsap = DSAP_NETBIOS_OVER_LLC; + DlcHeader->Ssap = DSAP_NETBIOS_OVER_LLC | DLC_SSAP_RESPONSE; + DlcHeader->Command = (UCHAR)(DLC_CMD_UA | (PollFinal ? DLC_U_PF : 0)); + + // + // This releases the spin lock. + // + + SendControlPacket (Link, RawFrame); + + } else { + RELEASE_DPC_SPIN_LOCK(&Link->SpinLock); +#if DBG + if (NbfPacketPanic) { + PANIC ("NbfSendUa: packet not sent.\n"); + } +#endif + } +} /* NbfSendUa */ + + +VOID +NbfSendSabme( + IN PTP_LINK Link, + IN BOOLEAN PollFinal + ) + +/*++ + +Routine Description: + + This routine sends a SABME-c/x DLC frame on the specified link. + + NOTE: This routine is called with the link spinlock held, + and returns with it released. + +Arguments: + + Link - Pointer to a transport link object. + + PollFinal - TRUE if poll/final bit should be set. + +Return Value: + + none. + +--*/ + +{ + NTSTATUS Status; + PLIST_ENTRY p; + PTP_PACKET RawFrame, packet; + PDLC_U_FRAME DlcHeader; // S-format frame alias. + + Status = NbfCreatePacket (Link->Provider, Link, &RawFrame); + if (NT_SUCCESS (Status)) { + + RawFrame->Owner = NULL; + RawFrame->Action = PACKET_ACTION_NULL; + + // + // set the packet length correctly (Note that the NDIS_BUFFER + // gets returned to the proper length in NbfDestroyPacket) + // + + MacModifyHeader(&Link->Provider->MacInfo, RawFrame->Header, sizeof(DLC_FRAME)); + NbfSetNdisPacketLength (RawFrame->NdisPacket, Link->HeaderLength + sizeof(DLC_FRAME)); + + // + // Format LLC SABME-c/x header. + // + + DlcHeader = (PDLC_U_FRAME)&(RawFrame->Header[Link->HeaderLength]); + DlcHeader->Dsap = DSAP_NETBIOS_OVER_LLC; + DlcHeader->Ssap = DSAP_NETBIOS_OVER_LLC; + DlcHeader->Command = (UCHAR)(DLC_CMD_SABME | (PollFinal ? DLC_U_PF : 0)); + + // + // Set up so that T1 will be started when the send + // completes. + // + + if (PollFinal) { + if (Link->Provider->MacInfo.MediumAsync) { + RawFrame->NdisIFrameLength = Link->HeaderLength + sizeof(DLC_S_FRAME); + RawFrame->Link = Link; + NbfReferenceLink ("Sabme/p", Link, LREF_START_T1); + } else { + StartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME)); + } + } + + // + // This releases the spin lock. + // + + SendControlPacket (Link, RawFrame); + + // + // Reset the link state based on having sent this packet.. + // Note that a SABME can be sent under some conditions on an existing + // link. If it is, it means we want to reset this link to a known state. + // We'll do that; note that that involves ditching any packets outstanding + // on the link. + // + + ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); + Link->NextSend = 0; + Link->LastAckReceived = 0; + Link->NextReceive = 0; // expect next packet to be sequence 0 + Link->NextReceive = 0; + Link->LastAckSent = 0; + Link->NextReceive = 0; + Link->LastAckSent = 0; + + while (!IsListEmpty (&Link->WackQ)) { + p = RemoveHeadList (&Link->WackQ); + RELEASE_DPC_SPIN_LOCK (&Link->SpinLock); + packet = CONTAINING_RECORD (p, TP_PACKET, Linkage); + NbfDereferencePacket (packet); + ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); + } + + RELEASE_DPC_SPIN_LOCK (&Link->SpinLock); + } else { + if (PollFinal) { + StartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME)); + } + RELEASE_DPC_SPIN_LOCK(&Link->SpinLock); +#if DBG + if (NbfPacketPanic) { + PANIC ("NbfSendSabme: packet not sent.\n"); + } +#endif + } +} /* NbfSendSabme */ + + +VOID +NbfSendDisc( + IN PTP_LINK Link, + IN BOOLEAN PollFinal + ) + +/*++ + +Routine Description: + + This routine sends a DISC-c/x DLC frame on the specified link. + +Arguments: + + Link - Pointer to a transport link object. + + PollFinal - TRUE if poll/final bit should be set. + +Return Value: + + none. + +--*/ + +{ + NTSTATUS Status; + PTP_PACKET RawFrame; + PDLC_U_FRAME DlcHeader; // S-format frame alias. + KIRQL oldirql; + + KeRaiseIrql (DISPATCH_LEVEL, &oldirql); + + Status = NbfCreatePacket (Link->Provider, Link, &RawFrame); + if (NT_SUCCESS (Status)) { + + RawFrame->Owner = NULL; + RawFrame->Action = PACKET_ACTION_NULL; + + // + // set the packet length correctly (Note that the NDIS_BUFFER + // gets returned to the proper length in NbfDestroyPacket) + // + + MacModifyHeader(&Link->Provider->MacInfo, RawFrame->Header, sizeof(DLC_FRAME)); + NbfSetNdisPacketLength (RawFrame->NdisPacket, Link->HeaderLength + sizeof(DLC_FRAME)); + + // + // Format LLC DISC-c/x header. + // + + DlcHeader = (PDLC_U_FRAME)&(RawFrame->Header[Link->HeaderLength]); + DlcHeader->Dsap = DSAP_NETBIOS_OVER_LLC; + DlcHeader->Ssap = DSAP_NETBIOS_OVER_LLC; + DlcHeader->Command = (UCHAR)(DLC_CMD_DISC | (PollFinal ? DLC_U_PF : 0)); + + ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); + + // + // This releases the spin lock. + // + + SendControlPacket (Link, RawFrame); + + } else { +#if DBG + if (NbfPacketPanic) { + PANIC ("NbfSendDisc: packet not sent.\n"); + } +#endif + } + + KeLowerIrql (oldirql); + +} /* NbfSendDisc */ + + +VOID +NbfSendRr( + IN PTP_LINK Link, + IN BOOLEAN Command, + IN BOOLEAN PollFinal + ) + +/*++ + +Routine Description: + + This routine sends a RR-x/x DLC frame on the specified link. + + NOTE: This routine is called with the link spinlock held, + and returns with it released. THIS ROUTINE MUST BE CALLED + AT DPC LEVEL. + +Arguments: + + Link - Pointer to a transport link object. + + Command - TRUE if command bit should be set. + + PollFinal - TRUE if poll/final bit should be set. + +Return Value: + + none. + +--*/ + +{ + NTSTATUS Status; + PTP_PACKET RawFrame; + PDLC_S_FRAME DlcHeader; // S-format frame alias. + + Status = NbfCreateRrPacket (Link->Provider, Link, &RawFrame); + if (NT_SUCCESS (Status)) { + + RawFrame->Owner = NULL; + + // + // RawFrame->Action will be set to PACKET_ACTION_RR if + // NbfCreateRrPacket got a packet from the RrPacketPool + // and PACKET_ACTION_NULL if it got one from the regular + // pool. + // + + // + // set the packet length correctly (Note that the NDIS_BUFFER + // gets returned to the proper length in NbfDestroyPacket) + // + + MacModifyHeader(&Link->Provider->MacInfo, RawFrame->Header, sizeof(DLC_S_FRAME)); + NbfSetNdisPacketLength (RawFrame->NdisPacket, Link->HeaderLength + sizeof(DLC_S_FRAME)); + + // + // Format LLC RR-x/x header. + // + + DlcHeader = (PDLC_S_FRAME)&(RawFrame->Header[Link->HeaderLength]); + DlcHeader->Dsap = DSAP_NETBIOS_OVER_LLC; + DlcHeader->Ssap = (UCHAR)(DSAP_NETBIOS_OVER_LLC | (Command ? 0 : DLC_SSAP_RESPONSE)); + DlcHeader->Command = DLC_CMD_RR; + DlcHeader->RcvSeq = (UCHAR)(PollFinal ? DLC_S_PF : 0); + + // + // If this is a command frame (which will always be a + // poll with the current code) set up so that T1 will + // be started when the send completes. + // + + if (Command) { + if (Link->Provider->MacInfo.MediumAsync) { + RawFrame->NdisIFrameLength = Link->HeaderLength + sizeof(DLC_S_FRAME); + RawFrame->Link = Link; + NbfReferenceLink ("Rr/p", Link, LREF_START_T1); + } else { + StartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME)); + } + } + + // + // This puts Link->NextReceive into DlcHeader->RcvSeq + // and releases the spinlock. + // + + SendControlPacket (Link, RawFrame); + + } else { + if (Command) { + StartT1 (Link, Link->HeaderLength + sizeof(DLC_S_FRAME)); + } + RELEASE_DPC_SPIN_LOCK(&Link->SpinLock); +#if DBG + if (NbfPacketPanic) { + PANIC ("NbfSendRr: packet not sent.\n"); + } +#endif + } +} /* NbfSendRr */ + +#if 0 + +// +// These functions are not currently called, so they are commented +// out. +// + + +VOID +NbfSendRnr( + IN PTP_LINK Link, + IN BOOLEAN Command, + IN BOOLEAN PollFinal + ) + +/*++ + +Routine Description: + + This routine sends a RNR-x/x DLC frame on the specified link. + +Arguments: + + Link - Pointer to a transport link object. + + Command - TRUE if command bit should be set. + + PollFinal - TRUE if poll/final bit should be set. + +Return Value: + + none. + +--*/ + +{ + NTSTATUS Status; + PTP_PACKET RawFrame; + PDLC_S_FRAME DlcHeader; // S-format frame alias. + KIRQL oldirql; + + KeRaiseIrql (DISPATCH_LEVEL, &oldirql); + + Status = NbfCreatePacket (Link->Provider, Link, &RawFrame); + if (NT_SUCCESS (Status)) { + + RawFrame->Owner = NULL; + RawFrame->Action = PACKET_ACTION_NULL; + + // + // set the packet length correctly (Note that the NDIS_BUFFER + // gets returned to the proper length in NbfDestroyPacket) + // + + MacModifyHeader(&Link->Provider->MacInfo, RawFrame->Header, sizeof(DLC_S_FRAME)); + NbfSetNdisPacketLength (RawFrame->NdisPacket, Link->HeaderLength + sizeof(DLC_S_FRAME)); + + // + // Format LLC RR-x/x header. + // + + DlcHeader = (PDLC_S_FRAME)&(RawFrame->Header[Link->HeaderLength]); + DlcHeader->Dsap = DSAP_NETBIOS_OVER_LLC; + DlcHeader->Ssap = (UCHAR)(DSAP_NETBIOS_OVER_LLC | (Command ? 0 : DLC_SSAP_RESPONSE)); + DlcHeader->Command = DLC_CMD_RNR; + DlcHeader->RcvSeq = (UCHAR)(PollFinal ? DLC_S_PF : 0); + + ACQUIRE_DPC_SPIN_LOCK (&Link->SpinLock); + + // + // This puts Link->NextReceive into DlcHeader->RcvSeq + // and releases the spin lock. + // + + SendControlPacket (Link, RawFrame); + + } else { +#if DBG + if (NbfPacketPanic) { + PANIC ("NbfSendRnr: packet not sent.\n"); + } +#endif + } + KeLowerIrql (oldirql); +} /* NbfSendRnr */ + + +VOID +NbfSendTest( + IN PTP_LINK Link, + IN BOOLEAN Command, + IN BOOLEAN PollFinal, + IN PMDL Psdu + ) + +/*++ + +Routine Description: + + This routine sends a TEST-x/x DLC frame on the specified link. + +Arguments: + + Link - Pointer to a transport link object. + + Command - TRUE if command bit should be set. + + PollFinal - TRUE if poll/final bit should be set. + + Psdu - Pointer to an MDL chain describing received TEST-c frame's storage. + +Return Value: + + none. + +--*/ + +{ + Link, Command, PollFinal, Psdu; // prevent compiler warnings + + PANIC ("NbfSendTest: Entered (BUGBUG).\n"); +} /* NbfSendTest */ + + +VOID +NbfSendFrmr( + IN PTP_LINK Link, + IN BOOLEAN PollFinal + ) + +/*++ + +Routine Description: + + This routine sends a FRMR-r/x DLC frame on the specified link. + +Arguments: + + Link - Pointer to a transport link object. + + PollFinal - TRUE if poll/final bit should be set. + +Return Value: + + none. + +--*/ + +{ + Link, PollFinal; // prevent compiler warnings + + IF_NBFDBG (NBF_DEBUG_FRAMESND) { + NbfPrint0 ("NbfSendFrmr: Entered (BUGBUG).\n"); + } +} /* NbfSendFrmr */ + +#endif + + +VOID +NbfSendXid( + IN PTP_LINK Link, + IN BOOLEAN Command, + IN BOOLEAN PollFinal + ) + +/*++ + +Routine Description: + + This routine sends an XID-x/x DLC frame on the specified link. + + NOTE: This routine is called with the link spinlock held, + and returns with it released. + +Arguments: + + Link - Pointer to a transport link object. + + Command - TRUE if command bit should be set. + + PollFinal - TRUE if poll/final bit should be set. + +Return Value: + + none. + +--*/ + +{ + Link, Command, PollFinal; // prevent compiler warnings + + RELEASE_DPC_SPIN_LOCK(&Link->SpinLock); + PANIC ("NbfSendXid: Entered (BUGBUG).\n"); +} /* NbfSendXid */ + + +VOID +NbfSendRej( + IN PTP_LINK Link, + IN BOOLEAN Command, + IN BOOLEAN PollFinal + ) + +/*++ + +Routine Description: + + This routine sends a REJ-x/x DLC frame on the specified link. + + NOTE: This function is called with Link->SpinLock held and + returns with it released. THIS MUST BE CALLED AT DPC LEVEL. + +Arguments: + + Link - Pointer to a transport link object. + + Command - TRUE if command bit should be set. + + PollFinal - TRUE if poll/final bit should be set. + +Return Value: + + none. + +--*/ + +{ + NTSTATUS Status; + PTP_PACKET RawFrame; + PDLC_S_FRAME DlcHeader; // S-format frame alias. + + IF_NBFDBG (NBF_DEBUG_FRAMESND) { + NbfPrint0 ("NbfSendRej: Entered.\n"); + } + + Status = NbfCreatePacket (Link->Provider, Link, &RawFrame); + if (NT_SUCCESS (Status)) { + + RawFrame->Owner = NULL; + RawFrame->Action = PACKET_ACTION_NULL; + + // + // set the packet length correctly (Note that the NDIS_BUFFER + // gets returned to the proper length in NbfDestroyPacket) + // + + MacModifyHeader(&Link->Provider->MacInfo, RawFrame->Header, sizeof(DLC_S_FRAME)); + NbfSetNdisPacketLength (RawFrame->NdisPacket, Link->HeaderLength + sizeof(DLC_S_FRAME)); + + // + // Format LLC REJ-x/x header. + // + + DlcHeader = (PDLC_S_FRAME)&(RawFrame->Header[Link->HeaderLength]); + DlcHeader->Dsap = DSAP_NETBIOS_OVER_LLC; + DlcHeader->Ssap = (UCHAR)(DSAP_NETBIOS_OVER_LLC | (Command ? 0 : DLC_SSAP_RESPONSE)); + DlcHeader->Command = DLC_CMD_REJ; + DlcHeader->RcvSeq = (UCHAR)(PollFinal ? DLC_S_PF : 0); + + // + // This puts Link->NextReceive into DlcHeader->RcvSeq + // and releases the spin lock. + // + + SendControlPacket (Link, RawFrame); + + } else { + RELEASE_DPC_SPIN_LOCK(&Link->SpinLock); +#if DBG + if (NbfPacketPanic) { + PANIC ("NbfSendRej: packet not sent.\n"); + } +#endif + } +} /* NbfSendRej */ + + +NTSTATUS +NbfCreateConnectionlessFrame( + PDEVICE_CONTEXT DeviceContext, + PTP_UI_FRAME *RawFrame + ) + +/*++ + +Routine Description: + + This routine allocates a connectionless frame (either from the local + device context pool or out of non-paged pool). + +Arguments: + + DeviceContext - Pointer to our device context to charge the frame to. + + RawFrame - Pointer to a place where we will return a pointer to the + allocated frame. + +Return Value: + + NTSTATUS - status of operation. + +--*/ + +{ + KIRQL oldirql; + PTP_UI_FRAME UIFrame; + PLIST_ENTRY p; + + IF_NBFDBG (NBF_DEBUG_FRAMESND) { + NbfPrint0 ("NbfCreateConnectionlessFrame: Entered.\n"); + } + + // + // Make sure that structure padding hasn't happened. + // + + ASSERT (sizeof(NBF_HDR_CONNECTIONLESS) == 44); + + p = ExInterlockedRemoveHeadList ( + &DeviceContext->UIFramePool, + &DeviceContext->Interlock); + + if (p == NULL) { +#if DBG + if (NbfPacketPanic) { + PANIC ("NbfCreateConnectionlessFrame: PANIC! no more UI frames in pool!\n"); + } +#endif + ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql); + ++DeviceContext->UIFrameExhausted; + RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql); + return STATUS_INSUFFICIENT_RESOURCES; + } + + UIFrame = (PTP_UI_FRAME) CONTAINING_RECORD (p, TP_UI_FRAME, Linkage); + + *RawFrame = UIFrame; + + return STATUS_SUCCESS; +} /* NbfCreateConnectionlessFrame */ + + +VOID +NbfDestroyConnectionlessFrame( + PDEVICE_CONTEXT DeviceContext, + PTP_UI_FRAME RawFrame + ) + +/*++ + +Routine Description: + + This routine destroys a connectionless frame by either returning it + to the device context's pool or to the system's non-paged pool. + +Arguments: + + DeviceContext - Pointer to our device context to return the frame to. + + RawFrame - Pointer to a frame to be returned. + +Return Value: + + none. + +--*/ + +{ + PNDIS_BUFFER HeaderBuffer; + PNDIS_BUFFER NdisBuffer; + + IF_NBFDBG (NBF_DEBUG_FRAMESND) { + NbfPrint0 ("NbfDestroyConnectionlessFrame: Entered.\n"); + } + + // + // Strip off and unmap the buffers describing data and header. + // + + NdisUnchainBufferAtFront (RawFrame->NdisPacket, &HeaderBuffer); + + // data buffers get thrown away + + NdisUnchainBufferAtFront (RawFrame->NdisPacket, &NdisBuffer); + while (NdisBuffer != NULL) { + NdisFreeBuffer (NdisBuffer); + NdisUnchainBufferAtFront (RawFrame->NdisPacket, &NdisBuffer); + } + + NDIS_BUFFER_LINKAGE(HeaderBuffer) = (PNDIS_BUFFER)NULL; + + // + // If this UI frame has some transport-created data, + // free the buffer now. + // + + if (RawFrame->DataBuffer) { + ExFreePool (RawFrame->DataBuffer); + RawFrame->DataBuffer = NULL; + } + + NdisChainBufferAtFront (RawFrame->NdisPacket, HeaderBuffer); + + ExInterlockedInsertTailList ( + &DeviceContext->UIFramePool, + &RawFrame->Linkage, + &DeviceContext->Interlock); + +} /* NbfDestroyConnectionlessFrame */ + + +VOID +NbfSendUIFrame( + PDEVICE_CONTEXT DeviceContext, + PTP_UI_FRAME RawFrame, + IN BOOLEAN Loopback + ) + +/*++ + +Routine Description: + + This routine sends a connectionless frame by calling the physical + provider's Send service. When the request completes, or if the service + does not return successfully, then the frame is deallocated. + +Arguments: + + DeviceContext - Pointer to our device context. + + RawFrame - Pointer to a connectionless frame to be sent. + + Loopback - A boolean flag set to TRUE if the source hardware address + of the packet should be set to zeros. + + SourceRoutingInformation - Pointer to optional source routing information. + +Return Value: + + None. + +--*/ + +{ + NDIS_STATUS NdisStatus; + PUCHAR DestinationAddress; + + UNREFERENCED_PARAMETER(Loopback); + +#if DBG + IF_NBFDBG (NBF_DEBUG_FRAMESND) { + NbfPrint2 ("NbfSendUIFrame: Entered, RawFrame: %lx NdisPacket %lx\n", + RawFrame, RawFrame->NdisPacket); + DbgPrint ("NbfSendUIFrame: MacHeader: %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x \n", + RawFrame->Header[0], + RawFrame->Header[1], + RawFrame->Header[2], + RawFrame->Header[3], + RawFrame->Header[4], + RawFrame->Header[5], + RawFrame->Header[6], + RawFrame->Header[7], + RawFrame->Header[8], + RawFrame->Header[9], + RawFrame->Header[10], + RawFrame->Header[11], + RawFrame->Header[12], + RawFrame->Header[13]); + } +#endif + + // + // Send the packet. + // + +#if DBG + NbfSendsIssued++; +#endif + + // + // Loopback will be FALSE for multicast frames or other + // frames that we know are not directly addressed to + // our hardware address. + // + + if (Loopback) { + + // + // See if this frame should be looped back. + // + + MacReturnDestinationAddress( + &DeviceContext->MacInfo, + RawFrame->Header, + &DestinationAddress); + + if (RtlEqualMemory( + DestinationAddress, + DeviceContext->LocalAddress.Address, + DeviceContext->MacInfo.AddressLength)) { + + NbfInsertInLoopbackQueue( + DeviceContext, + RawFrame->NdisPacket, + LOOPBACK_UI_FRAME + ); + + NdisStatus = NDIS_STATUS_PENDING; + + goto NoNdisSend; + + } + + } + + INCREMENT_COUNTER (DeviceContext, PacketsSent); + + NdisSend ( + &NdisStatus, + (NDIS_HANDLE)DeviceContext->NdisBindingHandle, + RawFrame->NdisPacket); + +NoNdisSend: + + if (NdisStatus != NDIS_STATUS_PENDING) { + +#if DBG + if (NdisStatus == NDIS_STATUS_SUCCESS) { + NbfSendsCompletedOk++; + } else { + NbfSendsCompletedFail++; + IF_NBFDBG (NBF_DEBUG_FRAMESND) { + NbfPrint1 ("NbfSendUIFrame: NdisSend failed, status other Pending or Complete: %s.\n", + NbfGetNdisStatus(NdisStatus)); + } + } +#endif + + NbfDestroyConnectionlessFrame (DeviceContext, RawFrame); + + } else { + +#if DBG + NbfSendsPended++; +#endif + } + +} /* NbfSendUIFrame */ + + +VOID +NbfSendUIMdlFrame( + PTP_ADDRESS Address + ) + +/*++ + +Routine Description: + + This routine sends a connectionless frame by calling the NbfSendUIFrame. + It is intended that this routine be used for sending datagrams and + braodcast datagrams. + + The datagram to be sent is described in the NDIS packet contained + in the Address. When the send completes, the send completion handler + returns the NDIS buffer describing the datagram to the buffer pool and + marks the address ndis packet as usable again. Thus, all datagram and + UI frames are sequenced through the address they are sent on. + +Arguments: + + Address - pointer to the address from which to send this datagram. + + SourceRoutingInformation - Pointer to optional source routing information. + +Return Value: + + None. + +--*/ + +{ +// NTSTATUS Status; + NDIS_STATUS NdisStatus; + PDEVICE_CONTEXT DeviceContext; + PUCHAR DestinationAddress; + + IF_NBFDBG (NBF_DEBUG_FRAMESND) { + NbfPrint0 ("NbfSendUIMdlFrame: Entered.\n"); + } + + + // + // Send the packet. + // + + DeviceContext = Address->Provider; + + INCREMENT_COUNTER (DeviceContext, PacketsSent); + + MacReturnDestinationAddress( + &DeviceContext->MacInfo, + Address->UIFrame->Header, + &DestinationAddress); + + if (RtlEqualMemory( + DestinationAddress, + DeviceContext->LocalAddress.Address, + DeviceContext->MacInfo.AddressLength)) { + + // + // This packet is sent to ourselves; we should loop it + // back. + // + + NbfInsertInLoopbackQueue( + DeviceContext, + Address->UIFrame->NdisPacket, + LOOPBACK_UI_FRAME + ); + + NdisStatus = NDIS_STATUS_PENDING; + + } else { + + NdisSend ( + &NdisStatus, + (NDIS_HANDLE)Address->Provider->NdisBindingHandle, + Address->UIFrame->NdisPacket); + + } + + if (NdisStatus != NDIS_STATUS_PENDING) { + + NbfSendDatagramCompletion (Address, Address->UIFrame->NdisPacket, NdisStatus); + +#if DBG + if (NdisStatus != NDIS_STATUS_SUCCESS) { // This is an error, trickle it up + IF_NBFDBG (NBF_DEBUG_FRAMESND) { + NbfPrint1 ("NbfSendUIMdlFrame: NdisSend failed, status other Pending or Complete: %s.\n", + NbfGetNdisStatus(NdisStatus)); + } + } +#endif + } + +} /* NbfSendUIMdlFrame */ + + +VOID +NbfSendDatagramCompletion( + IN PTP_ADDRESS Address, + IN PNDIS_PACKET NdisPacket, + IN NDIS_STATUS NdisStatus + ) + +/*++ + +Routine Description: + + This routine is called as an I/O completion handler at the time a + NbfSendUIMdlFrame send request is completed. Because this handler is only + associated with NbfSendUIMdlFrame, and because NbfSendUIMdlFrame is only + used with datagrams and broadcast datagrams, we know that the I/O being + completed is a datagram. Here we complete the in-progress datagram, and + start-up the next one if there is one. + +Arguments: + + Address - Pointer to a transport address on which the datagram + is queued. + + NdisPacket - pointer to the NDIS packet describing this request. + +Return Value: + + none. + +--*/ + +{ + PIRP Irp; + PLIST_ENTRY p; + KIRQL oldirql; + PNDIS_BUFFER HeaderBuffer; + + NdisPacket; // prevent compiler warnings. + + IF_NBFDBG (NBF_DEBUG_FRAMESND) { + NbfPrint0 ("NbfSendDatagramCompletion: Entered.\n"); + } + + + // + // Dequeue the current request and return it to the client. Release + // our hold on the send datagram queue. + // + // *** There may be no current request, if the one that was queued + // was aborted or timed out. If this is the case, we added a + // special reference to the address, so we still want to deref + // when we are done (I don't think this is true - adb 3/22/93). + // + + ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql); + p = RemoveHeadList (&Address->SendDatagramQueue); + + if (p != &Address->SendDatagramQueue) { + + RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql); + + Irp = CONTAINING_RECORD (p, IRP, Tail.Overlay.ListEntry); + + IF_NBFDBG (NBF_DEBUG_FRAMESND) { + NbfPrint0 ("NbfDestroyConnectionlessFrame: Entered.\n"); + } + + // + // Strip off and unmap the buffers describing data and header. + // + + NdisUnchainBufferAtFront (Address->UIFrame->NdisPacket, &HeaderBuffer); + + // drop the rest of the packet + + NdisReinitializePacket (Address->UIFrame->NdisPacket); + + NDIS_BUFFER_LINKAGE(HeaderBuffer) = (PNDIS_BUFFER)NULL; + NdisChainBufferAtFront (Address->UIFrame->NdisPacket, HeaderBuffer); + + // + // Ignore NdisStatus; datagrams always "succeed". The Information + // field was filled in when we queued the datagram. + // + + Irp->IoStatus.Status = STATUS_SUCCESS; + IoCompleteRequest (Irp, IO_NETWORK_INCREMENT); + + ACQUIRE_SPIN_LOCK (&Address->SpinLock, &oldirql); + Address->Flags &= ~ADDRESS_FLAGS_SEND_IN_PROGRESS; + RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql); + + // + // Send more datagrams on the Address if possible. + // + + NbfSendDatagramsOnAddress (Address); // do more datagrams. + + } else { + + ASSERT (FALSE); + + Address->Flags &= ~ADDRESS_FLAGS_SEND_IN_PROGRESS; + RELEASE_SPIN_LOCK (&Address->SpinLock, oldirql); + + } + + NbfDereferenceAddress ("Complete datagram", Address, AREF_REQUEST); + +} /* NbfSendDatagramCompletion */ |