diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/tdi/tcpip/tcp/dgram.c | 990 |
1 files changed, 990 insertions, 0 deletions
diff --git a/private/ntos/tdi/tcpip/tcp/dgram.c b/private/ntos/tdi/tcpip/tcp/dgram.c new file mode 100644 index 000000000..c0ada18c5 --- /dev/null +++ b/private/ntos/tdi/tcpip/tcp/dgram.c @@ -0,0 +1,990 @@ +/********************************************************************/ +/** 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 |