windows-nt/Source/XPSP1/NT/net/atm/rawwan/sys/send.c
2020-09-26 16:20:57 +08:00

615 lines
11 KiB
C

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
D:\nt\private\ntos\tdi\rawwan\core\send.c
Abstract:
Routines for sending data, including TDI entry points and
NDIS completions.
Revision History:
Who When What
-------- -------- ----------------------------------------------
arvindm 05-16-97 Created
Notes:
--*/
#include <precomp.h>
#define _FILENUMBER 'DNES'
#if STATS
ULONG SendPktsOk = 0;
ULONG SendBytesOk = 0;
ULONG SendPktsFail = 0;
ULONG SendBytesFail = 0;
#endif // STATS
RWAN_STATUS
RWanInitSend(
VOID
)
/*++
Routine Description:
Initialize our send side structures. All we need to do is to allocate
an NDIS packet pool.
Arguments:
None
Return Value:
RWAN_STATUS_SUCCESS if we initialized successfully, RWAN_STATUS_RESOURCES
if we couldn't allocate what we need.
--*/
{
NDIS_STATUS Status;
NdisAllocatePacketPoolEx(
&Status,
&RWanSendPacketPool,
RWAN_INITIAL_SEND_PACKET_COUNT,
RWAN_OVERFLOW_SEND_PACKET_COUNT,
0
);
return ((Status == NDIS_STATUS_SUCCESS)? RWAN_STATUS_SUCCESS: RWAN_STATUS_RESOURCES);
}
VOID
RWanShutdownSend(
VOID
)
/*++
Routine Description:
Free up our send resources.
Arguments:
None
Return Value:
None
--*/
{
if (RWanSendPacketPool != NULL)
{
NdisFreePacketPool(RWanSendPacketPool);
RWanSendPacketPool = NULL;
}
return;
}
TDI_STATUS
RWanTdiSendData(
IN PTDI_REQUEST pTdiRequest,
IN USHORT SendFlags,
IN UINT SendLength,
IN PNDIS_BUFFER pSendBuffer
)
/*++
Routine Description:
This is the TDI Entry point for sending connection-oriented data.
The Connection Object is identified by its context buried in the
TDI Request.
If all is well with the specified Connection, we prepend an NDIS
packet to the buffer chain, and submit it to the miniport.
Arguments:
pTdiRequest - Pointer to the TDI Request containing the Send
SendFlags - Options associated with this Send
SendLength - Total data bytes in this Send
pSendBuffer - Pointer to buffer chain
Return Value:
TDI_STATUS - this is TDI_PENDING if we successfully submitted
a send request via NDIS, TDI_NO_RESOURCES if we failed to allocate
resources for the send, TDI_INVALID_CONNECTION if the specified
--*/
{
RWAN_CONN_ID ConnId;
PRWAN_TDI_CONNECTION pConnObject;
TDI_STATUS TdiStatus;
PRWAN_NDIS_VC pVc;
NDIS_HANDLE NdisVcHandle;
PNDIS_PACKET pNdisPacket;
PRWAN_SEND_REQUEST pSendReq;
NDIS_STATUS NdisStatus;
pNdisPacket = NULL;
do
{
//
// XXX: Should we check the length?
//
//
// Discard zero-length sends.
//
if (SendLength == 0)
{
TdiStatus = TDI_SUCCESS;
break;
}
//
// Fail expedited data.
// TBD - base this on the media-specific module.
//
if (SendFlags & TDI_SEND_EXPEDITED)
{
TdiStatus = STATUS_NOT_SUPPORTED; // No matching TDI status!
break;
}
pNdisPacket = RWanAllocateSendPacket();
if (pNdisPacket == NULL)
{
TdiStatus = TDI_NO_RESOURCES;
break;
}
ConnId = (RWAN_CONN_ID) PtrToUlong(pTdiRequest->Handle.ConnectionContext);
RWAN_ACQUIRE_CONN_TABLE_LOCK();
pConnObject = RWanGetConnFromId(ConnId);
RWAN_RELEASE_CONN_TABLE_LOCK();
if (pConnObject == NULL_PRWAN_TDI_CONNECTION)
{
TdiStatus = TDI_INVALID_CONNECTION;
break;
}
RWAN_ACQUIRE_CONN_LOCK(pConnObject);
if ((pConnObject->State != RWANS_CO_CONNECTED) ||
(RWAN_IS_BIT_SET(pConnObject->Flags, RWANF_CO_CLOSING)) ||
(RWAN_IS_BIT_SET(pConnObject->Flags, RWANF_CO_CLOSE_SCHEDULED)))
{
//
// Fix up the return status to get proper Winsock error
// codes back to the app.
//
RWANDEBUGP(DL_INFO, DC_DATA_TX,
("Send: bad state %d, pConnObject %x\n", pConnObject->State, pConnObject));
if ((pConnObject->State == RWANS_CO_DISCON_INDICATED) ||
(pConnObject->State == RWANS_CO_ASSOCIATED) ||
(pConnObject->State == RWANS_CO_DISCON_REQUESTED))
{
//
// AFD would like to see us send an Abort at this time.
//
PDisconnectEvent pDisconInd;
PVOID IndContext;
PVOID ConnectionHandle;
RWAN_ASSERT(pConnObject->pAddrObject != NULL);
pDisconInd = pConnObject->pAddrObject->pDisconInd;
IndContext = pConnObject->pAddrObject->DisconIndContext;
ConnectionHandle = pConnObject->ConnectionHandle;
RWAN_RELEASE_CONN_LOCK(pConnObject);
(*pDisconInd)(
IndContext,
ConnectionHandle,
0, // Disconnect Data Length
NULL, // Disconnect Data
0, // Disconnect Info Length
NULL, // Disconnect Info
TDI_DISCONNECT_ABORT
);
TdiStatus = TDI_CONNECTION_RESET;
}
else
{
RWAN_RELEASE_CONN_LOCK(pConnObject);
TdiStatus = TDI_INVALID_STATE;
}
break;
}
if (RWAN_IS_BIT_SET(pConnObject->Flags, RWANF_CO_LEAF))
{
//
// Allow sends only on the Root Connection object.
//
RWAN_RELEASE_CONN_LOCK(pConnObject);
TdiStatus = TDI_INVALID_CONNECTION;
break;
}
pVc = pConnObject->NdisConnection.pNdisVc;
RWAN_ASSERT(pVc != NULL_PRWAN_NDIS_VC);
RWAN_STRUCT_ASSERT(pVc, nvc);
NdisVcHandle = pVc->NdisVcHandle;
//
// Save context about this send.
//
pSendReq = RWAN_SEND_REQUEST_FROM_PACKET(pNdisPacket);
pSendReq->Request.pReqComplete = pTdiRequest->RequestNotifyObject;
pSendReq->Request.ReqContext = pTdiRequest->RequestContext;
//
// XXX: we save the send flags also - may not be needed?
//
if ((pVc->MaxSendSize != 0) &&
(SendLength > pVc->MaxSendSize))
{
RWANDEBUGP(DL_WARN, DC_DATA_TX,
("TdiSendData: Sending %d, which is more than %d\n",
SendLength, pVc->MaxSendSize));
#if HACK_SEND_SIZE
pSendReq->SendLength = pVc->MaxSendSize;
}
else
{
pSendReq->SendLength = SendLength;
#else
RWAN_RELEASE_CONN_LOCK(pConnObject);
TdiStatus = TDI_NO_RESOURCES;
break;
}
pSendReq->SendLength = SendLength;
#endif // HACK_SEND_SIZE
pVc->PendingPacketCount++;
RWAN_RELEASE_CONN_LOCK(pConnObject);
pSendReq->SendFlags = SendFlags;
RWANDEBUGP(DL_INFO, DC_DATA_TX,
("Send: VC %x [%d], %d bytes\n", pVc, pVc->MaxSendSize, SendLength));
//
// Attach the buffer chain to the Packet.
//
NdisChainBufferAtFront(pNdisPacket, pSendBuffer);
#if HACK_SEND_SIZE
if (pSendReq->SendLength != SendLength)
{
UINT TotalPacketLength;
//
// HACK: Recalculate total bytes and fix it.
//
NdisQueryPacket(
pNdisPacket,
NULL,
NULL,
NULL,
&TotalPacketLength
);
pNdisPacket->Private.TotalLength = pSendReq->SendLength;
DbgPrint("RWan: send: real length %d, sending length %d\n",
TotalPacketLength, pSendReq->SendLength);
}
#endif // HACK_SEND_SIZE
RWAND_LOG_PACKET(pVc, RWAND_DLOG_TX_START, pNdisPacket, pTdiRequest->RequestContext);
//
// And send it off.
//
NdisCoSendPackets(NdisVcHandle, &pNdisPacket, 1);
//
// Our CoSendComplete handler will be called to signify completion.
// So we return PENDING now.
//
TdiStatus = TDI_PENDING;
break;
}
while (FALSE);
if (TdiStatus != TDI_PENDING)
{
#if STATS
if (TdiStatus == TDI_SUCCESS)
{
INCR_STAT(&SendPktsOk);
ADD_STAT(&SendBytesOk, SendLength);
}
else
{
INCR_STAT(&SendPktsFail);
ADD_STAT(&SendBytesFail, SendLength);
}
#endif // STATS
//
// Clean up.
//
if (pNdisPacket != NULL)
{
RWanFreeSendPacket(pNdisPacket);
}
#if DBG
if (TdiStatus != TDI_SUCCESS)
{
RWANDEBUGP(DL_INFO, DC_DATA_TX,
("Send: Length %x, failing with status %x\n", SendLength, TdiStatus));
}
#endif
}
return (TdiStatus);
}
VOID
RWanNdisCoSendComplete(
IN NDIS_STATUS NdisStatus,
IN NDIS_HANDLE ProtocolVcContext,
IN PNDIS_PACKET pNdisPacket
)
/*++
Routine Description:
This is the NDIS Entry point indicating completion of a
packet send. We complete the TDI Send Request.
Arguments:
NdisStatus - Status of the NDIS Send.
ProtocolVcContext - Actually a pointer to our NDIS VC structure
pNdisPacket - Packet that has been sent.
Return Value:
None
--*/
{
PRWAN_NDIS_VC pVc;
PRWAN_SEND_REQUEST pSendReq;
PRWAN_TDI_CONNECTION pConnObject;
TDI_STATUS TdiStatus;
pVc = (PRWAN_NDIS_VC)ProtocolVcContext;
RWAN_STRUCT_ASSERT(pVc, nvc);
#if STATS
{
PNDIS_BUFFER pNdisBuffer;
PVOID FirstBufferVa;
UINT FirstBufferLength;
UINT TotalLength;
NdisGetFirstBufferFromPacket(
pNdisPacket,
&pNdisBuffer,
&FirstBufferVa,
&FirstBufferLength,
&TotalLength
);
if (NdisStatus == NDIS_STATUS_SUCCESS)
{
INCR_STAT(&SendPktsOk);
ADD_STAT(&SendBytesOk, TotalLength);
}
else
{
INCR_STAT(&SendPktsFail);
ADD_STAT(&SendBytesFail, TotalLength);
}
}
#endif // STATS
if (NdisStatus == NDIS_STATUS_SUCCESS)
{
TdiStatus = TDI_SUCCESS;
}
else
{
TdiStatus = RWanNdisToTdiStatus(NdisStatus);
RWANDEBUGP(DL_INFO, DC_DATA_TX,
("CoSendComp: Failing Pkt %x, NDIS Status %x, TDI Status %x\n",
pNdisPacket, NdisStatus, TdiStatus));
}
pSendReq = RWAN_SEND_REQUEST_FROM_PACKET(pNdisPacket);
RWAND_LOG_PACKET(pVc, RWAND_DLOG_TX_END, pNdisPacket, pSendReq->Request.ReqContext);
//
// Complete the TDI Send.
//
(*pSendReq->Request.pReqComplete)(
pSendReq->Request.ReqContext,
TdiStatus,
((TdiStatus == TDI_SUCCESS) ? pSendReq->SendLength: 0)
);
//
// Free the NDIS Packet structure.
//
RWanFreeSendPacket(pNdisPacket);
//
// Update the Connection object.
//
pConnObject = pVc->pConnObject;
if (pConnObject != NULL)
{
RWAN_ASSERT(pConnObject->NdisConnection.pNdisVc == pVc);
RWAN_ACQUIRE_CONN_LOCK(pConnObject);
pVc->PendingPacketCount--; // Send complete
if ((pVc->PendingPacketCount == 0) &&
(RWAN_IS_BIT_SET(pVc->Flags, RWANF_VC_NEEDS_CLOSE)))
{
RWanStartCloseCall(pConnObject, pVc);
}
else
{
RWAN_RELEASE_CONN_LOCK(pConnObject);
}
}
//
// else we are aborting this connection.
//
#if DBG
else
{
RWANDEBUGP(DL_WARN, DC_DATA_TX,
("SendComp: VC %x, ConnObj is NULL\n", pVc));
}
#endif // DBG
return;
}
PNDIS_PACKET
RWanAllocateSendPacket(
VOID
)
/*++
Routine Description:
Allocate and return an NDIS packet to prepare a send.
Arguments:
None
Return Value:
Pointer to allocate packet if successful, else NULL.
--*/
{
PNDIS_PACKET pSendPacket;
NDIS_STATUS Status;
NdisAllocatePacket(
&Status,
&pSendPacket,
RWanSendPacketPool
);
if (Status != NDIS_STATUS_SUCCESS)
{
pSendPacket = NULL;
}
return (pSendPacket);
}
VOID
RWanFreeSendPacket(
IN PNDIS_PACKET pSendPacket
)
/*++
Routine Description:
Free an NDIS_PACKET used for a send.
Arguments:
pSendPacket - Points to packet to be freed.
Return Value:
None
--*/
{
RWAN_ASSERT(pSendPacket != NULL);
NdisFreePacket(pSendPacket);
}
VOID
RWanNdisSendComplete(
IN NDIS_HANDLE ProtocolBindingContext,
IN PNDIS_PACKET pNdisPacket,
IN NDIS_STATUS Status
)
/*++
Routine Description:
Dummy handler for connection-less send completes.
Arguments:
Return Value:
None
--*/
{
//
// We don't do connection-less sends yet.
//
RWAN_ASSERT(FALSE);
return;
}