summaryrefslogtreecommitdiffstats
path: root/private/ntos/tdi/nbf/framesnd.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--private/ntos/tdi/nbf/framesnd.c2504
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 */