windows-nt/Source/XPSP1/NT/net/netbeui/sys/framesnd.c

2529 lines
62 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*++
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.
//
// 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 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.\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.\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.\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);
if (DeviceContext->NdisBindingHandle) {
NdisSend (
&NdisStatus,
(NDIS_HANDLE)DeviceContext->NdisBindingHandle,
RawFrame->NdisPacket);
}
else {
NdisStatus = STATUS_INVALID_DEVICE_STATE;
}
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 {
#ifndef NO_STRESS_BUG
Address->SendFlags |= ADDRESS_FLAGS_SENT_TO_NDIS;
Address->SendFlags &= ~ADDRESS_FLAGS_RETD_BY_NDIS;
#endif
if (Address->Provider->NdisBindingHandle) {
NdisSend (
&NdisStatus,
(NDIS_HANDLE)Address->Provider->NdisBindingHandle,
Address->UIFrame->NdisPacket);
}
else {
NdisStatus = STATUS_INVALID_DEVICE_STATE;
}
}
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");
}
#ifndef NO_STRESS_BUG
Address->SendFlags |= ADDRESS_FLAGS_RETD_BY_NDIS;
#endif
//
// 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);
#ifndef NO_STRESS_BUG
Address->SendFlags &= ~ADDRESS_FLAGS_SENT_TO_NDIS;
Address->SendFlags &= ~ADDRESS_FLAGS_RETD_BY_NDIS;
#endif
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 */