NT4/private/ntos/tdi/tcpip/tcp/dgram.c
2020-09-30 17:12:29 +02:00

991 lines
26 KiB
C

/********************************************************************/
/** Microsoft LAN Manager **/
/** Copyright(c) Microsoft Corp., 1990-1993 **/
/********************************************************************/
/* :ts=4 */
//** DGRAM.C - Common datagram protocol code.
//
// This file contains the code common to both UDP and Raw IP.
//
#include "oscfg.h"
#include "ndis.h"
#include "cxport.h"
#include "ip.h"
#include "tdi.h"
#include "tdistat.h"
#ifdef VXD
#include "tdivxd.h"
#endif
#ifdef NT
#include "tdint.h"
#include "tdistat.h"
#endif
#include "queue.h"
#include "addr.h"
#include "dgram.h"
#include "tlcommon.h"
#include "info.h"
#define NO_TCP_DEFS 1
#include "tcpdeb.h"
#ifdef NT
#ifdef POOL_TAGGING
#ifdef ExAllocatePool
#undef ExAllocatePool
#endif
#define ExAllocatePool(type, size) ExAllocatePoolWithTag(type, size, 'dPCT')
#ifndef CTEAllocMem
#error "CTEAllocMem is not already defined - will override tagging"
#else
#undef CTEAllocMem
#endif
#define CTEAllocMem(size) ExAllocatePoolWithTag(NonPagedPool, size, 'dPCT')
#endif // POOL_TAGGING
#endif // NT
#define NUM_DG_HEADERS 5
#ifdef NT
#define DG_MAX_HDRS 0xffff
#else
#define DG_MAX_HDRS 100
#endif
ulong DGCurrentSendFree = 0;
ulong DGMaxSendFree = DG_MAX_HDRS;
EXTERNAL_LOCK(AddrObjTableLock)
DGSendReq *DGSendReqFree;
DEFINE_LOCK_STRUCTURE(DGSendReqLock)
#ifndef NT
DGRcvReq *DGRcvReqFree;
#else
SLIST_HEADER DGRcvReqFree;
#endif
DEFINE_LOCK_STRUCTURE(DGRcvReqFreeLock)
#ifdef DEBUG
uint NumSendReq = 0;
uint NumRcvReq = 0;
#endif
// Information for maintaining the DG Header structures and
// pending queue.
uint DGHeaderSize;
PNDIS_BUFFER DGHeaderList;
Queue DGHeaderPending;
Queue DGDelayed;
CTEEvent DGDelayedEvent;
extern IPInfo LocalNetInfo;
typedef struct DGHdrBPoolEntry {
struct DGHdrBPoolEntry *uhe_next;
NDIS_HANDLE uhe_handle;
uchar *uhe_buffer;
} DGHdrBPoolEntry;
DGHdrBPoolEntry *DGHdrBPoolList = NULL;
//
// All of the init code can be discarded.
//
#ifdef NT
#ifdef ALLOC_PRAGMA
int InitDG(uint MaxHeaderSize);
#pragma alloc_text(INIT, InitDG)
#endif // ALLOC_PRAGMA
#endif
#ifdef CHICAGO
extern int RegisterAddrChangeHndlr(void *Handler, uint Add);
extern void AddrChange(IPAddr Addr, IPMask Mask, void *Context,
uint Added);
#endif
//* GrowDGHeaderList - Try to grow the DG header list.
//
// Called when we run out of buffers on the DG header list, and need
// to grow it. We look to see if we're already at the maximum size, and
// if not we'll allocate the need structures and free them to the list.
// This routine must be called with the SendReq lock held.
//
// Input: Nothing.
//
// Returns: A pointer to a new DG header buffer if we have one, or NULL.
//
PNDIS_BUFFER
GrowDGHeaderList(void)
{
DGHdrBPoolEntry *NewEntry;
NDIS_STATUS Status;
uint HeaderSize;
uchar *DGSendHP;
uint i;
PNDIS_BUFFER Buffer;
PNDIS_BUFFER ReturnBuffer = NULL;
if (DGCurrentSendFree < DGMaxSendFree) {
// Still room to grow the list.
NewEntry = CTEAllocMem(sizeof(DGHdrBPoolEntry));
if (NewEntry == NULL) {
// Couldn't get the memory.
return NULL;
}
NdisAllocateBufferPool(&Status, &NewEntry->uhe_handle,
NUM_DG_HEADERS);
if (Status != NDIS_STATUS_SUCCESS) {
// Couldn't get a new set of buffers. Fail.
CTEFreeMem(NewEntry);
return NULL;
}
HeaderSize = DGHeaderSize + LocalNetInfo.ipi_hsize;
DGSendHP = CTEAllocMem(HeaderSize * NUM_DG_HEADERS);
if (DGSendHP == NULL) {
NdisFreeBufferPool(NewEntry->uhe_handle);
CTEFreeMem(NewEntry);
return NULL;
}
NewEntry->uhe_buffer = DGSendHP;
for (i = 0; i < NUM_DG_HEADERS; i++) {
NdisAllocateBuffer(&Status, &Buffer, NewEntry->uhe_handle,
DGSendHP + (i * HeaderSize), HeaderSize);
if (Status != NDIS_STATUS_SUCCESS) {
NdisFreeBufferPool(NewEntry->uhe_handle);
CTEFreeMem(NewEntry);
CTEFreeMem(DGSendHP);
return NULL;
}
if (i != 0)
FreeDGHeader(Buffer);
else
ReturnBuffer = Buffer;
}
DGCurrentSendFree += NUM_DG_HEADERS;
NewEntry->uhe_next = DGHdrBPoolList;
DGHdrBPoolList = NewEntry;
} else {
// At the limit already.
ReturnBuffer = NULL;
}
return ReturnBuffer;
}
//* GetDGHeader - Get a DG header buffer.
//
// The get header buffer routine. Called with the SendReqLock held.
//
// Input: Nothing.
//
// Output: A pointer to an NDIS buffer, or NULL.
//
_inline PNDIS_BUFFER
GetDGHeader(void)
{
PNDIS_BUFFER NewBuffer;
NewBuffer = DGHeaderList;
if (NewBuffer != NULL)
DGHeaderList = NDIS_BUFFER_LINKAGE(NewBuffer);
else
NewBuffer = GrowDGHeaderList();
return NewBuffer;
}
//* FreeDGHeader - Free a DG header buffer.
//
// The free header buffer routine. Called with the SendReqLock held.
//
// Input: Buffer to be freed.
//
// Output: Nothing.
//
void
FreeDGHeader(PNDIS_BUFFER FreedBuffer)
{
NDIS_BUFFER_LINKAGE(FreedBuffer) = DGHeaderList;
DGHeaderList = FreedBuffer;
}
//* PutPendingQ - Put an address object on the pending queue.
//
// Called when we've experienced a header buffer out of resources condition,
// and want to queue an AddrObj for later processing. We put the specified
// address object on the DGHeaderPending queue, set the OOR flag and clear
// the 'send request' flag. It is invariant in the system that the send
// request flag and the OOR flag are not set at the same time.
//
// This routine assumes that the caller holds the DGSendReqLock and the
// lock on the particular AddrObj.
//
// Input: QueueingAO - Pointer to address object to be queued.
//
// Returns: Nothing.
//
void
PutPendingQ(AddrObj *QueueingAO)
{
CTEStructAssert(QueueingAO, ao);
if (!AO_OOR(QueueingAO)) {
CLEAR_AO_REQUEST(QueueingAO, AO_SEND);
SET_AO_OOR(QueueingAO);
ENQUEUE(&DGHeaderPending, &QueueingAO->ao_pendq);
}
}
//* GetDGSendReq - Get a DG send request.
//
// Called when someone wants to allocate a DG send request. We assume
// the send request lock is held when we are called.
//
// Note: This routine and the corresponding free routine might
// be good candidates for inlining.
//
// Input: Nothing.
//
// Returns: Pointer to the SendReq, or NULL if none.
//
DGSendReq *
GetDGSendReq()
{
DGSendReq *NewReq;
NewReq = DGSendReqFree;
if (NewReq != NULL) {
CTEStructAssert(NewReq, dsr);
DGSendReqFree = (DGSendReq *)NewReq->dsr_q.q_next;
} else {
// Couldn't get a request, grow it. This is one area where we'll try
// to allocate memory with a lock held. Because of this, we've
// got to be careful about where we call this routine from.
NewReq = CTEAllocMem(sizeof(DGSendReq));
if (NewReq != NULL) {
#ifdef DEBUG
NewReq->dsr_sig = dsr_signature;
NumSendReq++;
#endif
}
}
return NewReq;
}
//* FreeDGSendReq - Free a DG send request.
//
// Called when someone wants to free a DG send request. It's assumed
// that the caller holds the SendRequest lock.
//
// Input: SendReq - SendReq to be freed.
//
// Returns: Nothing.
//
void
FreeDGSendReq(DGSendReq *SendReq)
{
CTEStructAssert(SendReq, dsr);
*(DGSendReq **)&SendReq->dsr_q.q_next = DGSendReqFree;
DGSendReqFree = SendReq;
}
//* GetDGRcvReq - Get a DG receive request.
//
// Called when we need to get a DG receive request.
//
// Input: Nothing.
//
// Returns: Pointer to new request, or NULL if none.
//
DGRcvReq *
GetDGRcvReq()
{
DGRcvReq *NewReq;
#ifdef VXD
NewReq = DGRcvReqFree;
if (NewReq != NULL) {
CTEStructAssert(NewReq, drr);
DGRcvReqFree = (DGRcvReq *)NewReq->drr_q.q_next;
} else {
// Couldn't get a request, grow it.
NewReq = CTEAllocMem(sizeof(DGRcvReq));
if (NewReq != NULL) {
#ifdef DEBUG
NewReq->drr_sig = drr_signature;
NumRcvReq++;
#endif
}
}
#endif // VXD
#ifdef NT
PSINGLE_LIST_ENTRY BufferLink;
Queue *QueuePtr;
BufferLink = ExInterlockedPopEntrySList(
&DGRcvReqFree,
&DGRcvReqFreeLock
);
if (BufferLink != NULL) {
QueuePtr = STRUCT_OF(Queue, BufferLink, q_next);
NewReq = STRUCT_OF(DGRcvReq, QueuePtr, drr_q);
CTEStructAssert(NewReq, drr);
}
else {
// Couldn't get a request, grow it.
NewReq = CTEAllocMem(sizeof(DGRcvReq));
if (NewReq != NULL) {
#ifdef DEBUG
NewReq->drr_sig = drr_signature;
ExInterlockedAddUlong(&NumRcvReq, 1, &DGRcvReqFreeLock);
#endif
}
}
#endif // NT
return NewReq;
}
//* FreeDGRcvReq - Free a DG rcv request.
//
// Called when someone wants to free a DG rcv request.
//
// Input: RcvReq - RcvReq to be freed.
//
// Returns: Nothing.
//
void
FreeDGRcvReq(DGRcvReq *RcvReq)
{
#ifdef VXD
CTEStructAssert(RcvReq, drr);
*(DGRcvReq **)&RcvReq->drr_q.q_next = DGRcvReqFree;
DGRcvReqFree = RcvReq;
#endif // VXD
#ifdef NT
PSINGLE_LIST_ENTRY BufferLink;
CTEStructAssert(RcvReq, drr);
BufferLink = STRUCT_OF(SINGLE_LIST_ENTRY, &(RcvReq->drr_q.q_next), Next);
ExInterlockedPushEntrySList(
&DGRcvReqFree,
BufferLink,
&DGRcvReqFreeLock
);
#endif // NT
}
//* DGDelayedEventProc - Handle a delayed event.
//
// This is the delayed event handler, used for out-of-resources conditions
// on AddrObjs. We pull from the delayed queue, and is the addr obj is
// not already busy we'll send the datagram.
//
// Input: Event - Pointer to the event structure.
// Context - Nothing.
//
// Returns: Nothing
//
void
DGDelayedEventProc(CTEEvent *Event, void *Context)
{
CTELockHandle HeaderHandle, AOHandle;
AddrObj *SendingAO;
DGSendProc SendProc;
CTEGetLock(&DGSendReqLock, &HeaderHandle);
while (!EMPTYQ(&DGDelayed)) {
DEQUEUE(&DGDelayed, SendingAO, AddrObj, ao_pendq);
CTEStructAssert(SendingAO, ao);
CTEGetLock(&SendingAO->ao_lock, &AOHandle);
CLEAR_AO_OOR(SendingAO);
if (!AO_BUSY(SendingAO)) {
DGSendReq *SendReq;
if (!EMPTYQ(&SendingAO->ao_sendq)) {
DEQUEUE(&SendingAO->ao_sendq, SendReq, DGSendReq, dsr_q);
CTEStructAssert(SendReq, dsr);
CTEAssert(SendReq->dsr_header != NULL);
SendingAO->ao_usecnt++;
SendProc = SendingAO->ao_dgsend;
CTEFreeLock(&SendingAO->ao_lock, AOHandle);
CTEFreeLock(&DGSendReqLock, HeaderHandle);
(*SendProc)(SendingAO, SendReq);
DEREF_AO(SendingAO);
CTEGetLock(&DGSendReqLock, &HeaderHandle);
} else {
CTEAssert(FALSE);
CTEFreeLock(&SendingAO->ao_lock, AOHandle);
}
} else {
SET_AO_REQUEST(SendingAO, AO_SEND);
CTEFreeLock(&SendingAO->ao_lock, AOHandle);
}
}
CTEFreeLock(&DGSendReqLock, HeaderHandle);
}
//* DGSendComplete - DG send complete handler.
//
// This is the routine called by IP when a send completes. We
// take the context passed back as a pointer to a SendRequest
// structure, and complete the caller's send.
//
// Input: Context - Context we gave on send (really a
// SendRequest structure).
// BufferChain - Chain of buffers sent.
//
// Returns: Nothing.
void
DGSendComplete(void *Context, PNDIS_BUFFER BufferChain)
{
DGSendReq *FinishedSR = (DGSendReq *)Context;
CTELockHandle HeaderHandle, AOHandle;
CTEReqCmpltRtn Callback; // Completion routine.
PVOID CallbackContext; // User context.
ushort SentSize;
AddrObj *AO;
CTEStructAssert(FinishedSR, dsr);
CTEGetLock(&DGSendReqLock, &HeaderHandle);
Callback = FinishedSR->dsr_rtn;
CallbackContext = FinishedSR->dsr_context;
SentSize = FinishedSR->dsr_size;
// If there's nothing on the header pending queue, just free the
// header buffer. Otherwise pull from the pending queue, give him the
// resource, and schedule an event to deal with him.
if (EMPTYQ(&DGHeaderPending)) {
FreeDGHeader(BufferChain);
} else {
DEQUEUE(&DGHeaderPending, AO, AddrObj, ao_pendq);
CTEStructAssert(AO, ao);
CTEGetLock(&AO->ao_lock, &AOHandle);
if (!EMPTYQ(&AO->ao_sendq)) {
DGSendReq *SendReq;
PEEKQ(&AO->ao_sendq, SendReq, DGSendReq, dsr_q);
SendReq->dsr_header = BufferChain; // Give him this buffer.
ENQUEUE(&DGDelayed, &AO->ao_pendq);
CTEFreeLock(&AO->ao_lock, AOHandle);
CTEScheduleEvent(&DGDelayedEvent, NULL);
} else {
// On the pending queue, but no sends!
DEBUGCHK;
CLEAR_AO_OOR(AO);
CTEFreeLock(&AO->ao_lock, AOHandle);
}
}
FreeDGSendReq(FinishedSR);
CTEFreeLock(&DGSendReqLock, HeaderHandle);
if (Callback != NULL)
(*Callback)(CallbackContext, TDI_SUCCESS, (uint)SentSize);
}
#ifdef NT
//
// NT supports cancellation of DG send/receive requests.
//
#define TCP_DEBUG_SEND_DGRAM 0x00000100
#define TCP_DEBUG_RECEIVE_DGRAM 0x00000200
extern ULONG TCPDebug;
VOID
TdiCancelSendDatagram(
AddrObj *SrcAO,
PVOID Context
)
{
CTELockHandle lockHandle;
DGSendReq *sendReq = NULL;
Queue *qentry;
BOOLEAN found = FALSE;
CTEStructAssert(SrcAO, ao);
CTEGetLock(&SrcAO->ao_lock, &lockHandle);
// Search the send list for the specified request.
for ( qentry = QNEXT(&(SrcAO->ao_sendq));
qentry != &(SrcAO->ao_sendq);
qentry = QNEXT(qentry)
) {
sendReq = STRUCT_OF(DGSendReq, qentry, dsr_q);
CTEStructAssert(sendReq, dsr);
if (sendReq->dsr_context == Context) {
//
// Found it. Dequeue
//
REMOVEQ(qentry);
found = TRUE;
IF_TCPDBG(TCP_DEBUG_SEND_DGRAM) {
TCPTRACE((
"TdiCancelSendDatagram: Dequeued item %lx\n",
Context
));
}
break;
}
}
CTEFreeLock(&SrcAO->ao_lock, lockHandle);
if (found) {
//
// Complete the request and free its resources.
//
(*sendReq->dsr_rtn)(sendReq->dsr_context, (uint) TDI_CANCELLED, 0);
CTEGetLock(&DGSendReqLock, &lockHandle);
if (sendReq->dsr_header != NULL) {
FreeDGHeader(sendReq->dsr_header);
}
FreeDGSendReq(sendReq);
CTEFreeLock(&DGSendReqLock, lockHandle);
}
} // TdiCancelSendDatagram
VOID
TdiCancelReceiveDatagram(
AddrObj *SrcAO,
PVOID Context
)
{
CTELockHandle lockHandle;
DGRcvReq *rcvReq = NULL;
Queue *qentry;
BOOLEAN found = FALSE;
CTEStructAssert(SrcAO, ao);
CTEGetLock(&SrcAO->ao_lock, &lockHandle);
// Search the send list for the specified request.
for ( qentry = QNEXT(&(SrcAO->ao_rcvq));
qentry != &(SrcAO->ao_rcvq);
qentry = QNEXT(qentry)
) {
rcvReq = STRUCT_OF(DGRcvReq, qentry, drr_q);
CTEStructAssert(rcvReq, drr);
if (rcvReq->drr_context == Context) {
//
// Found it. Dequeue
//
REMOVEQ(qentry);
found = TRUE;
IF_TCPDBG(TCP_DEBUG_SEND_DGRAM) {
TCPTRACE((
"TdiCancelReceiveDatagram: Dequeued item %lx\n",
Context
));
}
break;
}
}
CTEFreeLock(&SrcAO->ao_lock, lockHandle);
if (found) {
//
// Complete the request and free its resources.
//
(*rcvReq->drr_rtn)(rcvReq->drr_context, (uint) TDI_CANCELLED, 0);
FreeDGRcvReq(rcvReq);
}
} // TdiCancelReceiveDatagram
#endif // NT
//** TdiSendDatagram - TDI send datagram function.
//
// This is the user interface to the send datagram function. The
// caller specified a request structure, a connection info
// structure containing the address, and data to be sent.
// This routine gets a DG Send request structure to manage the
// send, fills the structure in, and calls DGSend to deal with
// it.
//
// Input: Request - Pointer to request structure.
// ConnInfo - Pointer to ConnInfo structure which points to
// remote address.
// DataSize - Size in bytes of data to be sent.
// BytesSent - Pointer to where to return size sent.
// Buffer - Pointer to buffer chain.
//
// Returns: Status of attempt to send.
//
TDI_STATUS
TdiSendDatagram(PTDI_REQUEST Request, PTDI_CONNECTION_INFORMATION ConnInfo,
uint DataSize, uint *BytesSent, PNDIS_BUFFER Buffer)
{
AddrObj *SrcAO; // Pointer to AddrObj for src.
DGSendReq *SendReq; // Pointer to send req for this request.
CTELockHandle Handle, SRHandle; // Lock handles for the AO and the
// send request.
TDI_STATUS ReturnValue;
DGSendProc SendProc;
// First, get a send request. We do this first because of MP issues
// if we port this to NT. We need to take the SendRequest lock before
// we take the AddrObj lock, to prevent deadlock and also because
// GetDGSendReq might yield, and the state of the AddrObj might
// change on us, so we don't want to yield after we've validated
// it.
CTEGetLock(&DGSendReqLock, &SRHandle);
SendReq = GetDGSendReq();
// Now get the lock on the AO, and make sure it's valid. We do this
// to make sure we return the correct error code.
#ifdef VXD
SrcAO = GetIndexedAO((uint)Request->Handle.AddressHandle);
if (SrcAO != NULL) {
#else
SrcAO = Request->Handle.AddressHandle;
#endif
CTEStructAssert(SrcAO, ao);
CTEGetLock(&SrcAO->ao_lock, &Handle);
if (AO_VALID(SrcAO)) {
// Make sure the size is reasonable.
if (DataSize <= SrcAO->ao_maxdgsize) {
// The AddrObj is valid. Now fill the address into the send request,
// if we've got one. If this works, we'll continue with the
// send.
if (SendReq != NULL) { // Got a send request.
if (GetAddress(ConnInfo->RemoteAddress, &SendReq->dsr_addr,
&SendReq->dsr_port)) {
SendReq->dsr_rtn = Request->RequestNotifyObject;
SendReq->dsr_context = Request->RequestContext;
SendReq->dsr_buffer = Buffer;
SendReq->dsr_size = (ushort)DataSize;
// We've filled in the send request. If the AO isn't
// already busy, try to get a DG header buffer and send
// this. If the AO is busy, or we can't get a buffer, queue
// until later. We try to get the header buffer here, as
// an optimazation to avoid having to retake the lock.
if (!AO_OOR(SrcAO)) { // AO isn't out of resources
if (!AO_BUSY(SrcAO)) { // or or busy
if ((SendReq->dsr_header = GetDGHeader()) != NULL) {
REF_AO(SrcAO); // Lock out exclusive
// activities.
SendProc = SrcAO->ao_dgsend;
CTEFreeLock(&SrcAO->ao_lock, Handle);
CTEFreeLock(&DGSendReqLock, SRHandle);
// Allright, just send it.
(*SendProc)(SrcAO, SendReq);
// See if any pending requests occured during
// the send. If so, call the request handler.
DEREF_AO(SrcAO);
return TDI_PENDING;
} else {
// We couldn't get a header buffer. Put this
// guy on the pending queue, and then fall
// through to the 'queue request' code.
PutPendingQ(SrcAO);
}
} else {
// AO is busy, set request for later
SET_AO_REQUEST(SrcAO, AO_SEND);
}
}
// AO is busy, or out of resources. Queue the send request
// for later.
SendReq->dsr_header = NULL;
ENQUEUE(&SrcAO->ao_sendq, &SendReq->dsr_q);
SendReq = NULL;
ReturnValue = TDI_PENDING;
}
else {
// The remote address was invalid.
ReturnValue = TDI_BAD_ADDR;
}
}
else {
// Send request was null, return no resources.
ReturnValue = TDI_NO_RESOURCES;
}
}
else {
// Buffer was too big, return an error.
ReturnValue = TDI_BUFFER_TOO_BIG;
}
}
else {
// The addr object is invalid, possibly because it's deleting.
ReturnValue = TDI_ADDR_INVALID;
}
CTEFreeLock(&SrcAO->ao_lock, Handle);
#ifdef VXD
}
else {
ReturnValue = TDI_ADDR_INVALID;
}
#endif
if (SendReq != NULL)
FreeDGSendReq(SendReq);
CTEFreeLock(&DGSendReqLock, SRHandle);
return TDI_ADDR_INVALID;
}
//** TdiReceiveDatagram - TDI receive datagram function.
//
// This is the user interface to the receive datagram function. The
// caller specifies a request structure, a connection info
// structure that acts as a filter on acceptable datagrams, a connection
// info structure to be filled in, and other parameters. We get a DGRcvReq
// structure, fill it in, and hang it on the AddrObj, where it will be removed
// later by incomig datagram handler.
//
// Input: Request - Pointer to request structure.
// ConnInfo - Pointer to ConnInfo structure which points to
// remote address.
// ReturnInfo - Pointer to ConnInfo structure to be filled in.
// RcvSize - Total size in bytes receive buffer.
// BytesRcvd - Pointer to where to return size received.
// Buffer - Pointer to buffer chain.
//
// Returns: Status of attempt to receive.
//
TDI_STATUS
TdiReceiveDatagram(PTDI_REQUEST Request, PTDI_CONNECTION_INFORMATION ConnInfo,
PTDI_CONNECTION_INFORMATION ReturnInfo, uint RcvSize, uint *BytesRcvd,
PNDIS_BUFFER Buffer)
{
AddrObj *RcvAO; // AddrObj that is receiving.
DGRcvReq *RcvReq; // Receive request structure.
CTELockHandle AOHandle;
uchar AddrValid;
RcvReq = GetDGRcvReq();
#ifdef VXD
RcvAO = GetIndexedAO((uint)Request->Handle.AddressHandle);
if (RcvAO != NULL) {
CTEStructAssert(RcvAO, ao);
#else
RcvAO = Request->Handle.AddressHandle;
CTEStructAssert(RcvAO, ao);
#endif
CTEGetLock(&RcvAO->ao_lock, &AOHandle);
if (AO_VALID(RcvAO)) {
IF_TCPDBG(TCP_DEBUG_RAW) {
TCPTRACE(("posting receive on AO %lx\n", RcvAO));
}
if (RcvReq != NULL) {
if (ConnInfo != NULL && ConnInfo->RemoteAddressLength != 0)
AddrValid = GetAddress(ConnInfo->RemoteAddress,
&RcvReq->drr_addr, &RcvReq->drr_port);
else {
AddrValid = TRUE;
RcvReq->drr_addr = NULL_IP_ADDR;
RcvReq->drr_port = 0;
}
if (AddrValid) {
// Everything'd valid. Fill in the receive request and queue it.
RcvReq->drr_conninfo = ReturnInfo;
RcvReq->drr_rtn = Request->RequestNotifyObject;
RcvReq->drr_context = Request->RequestContext;
RcvReq->drr_buffer = Buffer;
RcvReq->drr_size = RcvSize;
ENQUEUE(&RcvAO->ao_rcvq, &RcvReq->drr_q);
CTEFreeLock(&RcvAO->ao_lock, AOHandle);
return TDI_PENDING;
} else {
// Have an invalid filter address.
CTEFreeLock(&RcvAO->ao_lock, AOHandle);
FreeDGRcvReq(RcvReq);
return TDI_BAD_ADDR;
}
} else {
// Couldn't get a receive request.
CTEFreeLock(&RcvAO->ao_lock, AOHandle);
return TDI_NO_RESOURCES;
}
} else {
// The AddrObj isn't valid.
CTEFreeLock(&RcvAO->ao_lock, AOHandle);
}
#ifdef VXD
}
#endif
// The AddrObj is invalid or non-existent.
if (RcvReq != NULL)
FreeDGRcvReq(RcvReq);
return TDI_ADDR_INVALID;
}
#pragma BEGIN_INIT
//* InitDG - Initialize the DG stuff.
//
// Called during init time to initalize the DG code. We initialize
// our locks and request lists.
//
// Input: MaxHeaderSize - The maximum size of a datagram transport header,
// not including the IP header.
//
// Returns: True if we succeed, False if we fail.
//
int
InitDG(uint MaxHeaderSize)
{
PNDIS_BUFFER Buffer;
CTELockHandle Handle;
DGHeaderSize = MaxHeaderSize;
CTEInitLock(&DGSendReqLock);
CTEInitLock(&DGRcvReqFreeLock);
DGSendReqFree = NULL;
#ifndef NT
DGRcvReqFree = NULL;
#else
ExInitializeSListHead(&DGRcvReqFree);
#endif
CTEGetLock(&DGSendReqLock, &Handle);
Buffer = GrowDGHeaderList();
if (Buffer != NULL) {
FreeDGHeader(Buffer);
CTEFreeLock(&DGSendReqLock, Handle);
} else {
CTEFreeLock(&DGSendReqLock, Handle);
return FALSE;
}
INITQ(&DGHeaderPending);
INITQ(&DGDelayed);
CTEInitEvent(&DGDelayedEvent, DGDelayedEventProc);
return TRUE;
}
#pragma END_INIT