windows-nt/Source/XPSP1/NT/net/rras/ipx/sap/netio.c
2020-09-26 16:20:57 +08:00

472 lines
12 KiB
C

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
net\routing\ipx\sap\netio.c
Abstract:
This module handles network io for sap agent
Author:
Vadim Eydelman 05-15-1995
Revision History:
--*/
#include "sapp.h"
// Queues and synchronization associated with net io
typedef struct _IO_QUEUES {
HANDLE IQ_AdptHdl; // Handle to SAP socket port
HANDLE IQ_RecvEvent; // Event signalled when recv completes
#if DBG
LIST_ENTRY IQ_SentPackets; // Packets that are being sent
LIST_ENTRY IQ_RcvdPackets; // Packets that are being received
#endif
CRITICAL_SECTION IQ_Lock; // Queue data protection
} IO_QUEUES, *PIO_QUEUES;
IO_QUEUES IOQueues;
VOID CALLBACK
IoCompletionProc (
DWORD error,
DWORD cbTransferred,
LPOVERLAPPED ovlp
);
VOID CALLBACK
SendCompletionProc (
DWORD status,
DWORD cbSent,
PIO_PARAM_BLOCK sreq
);
VOID CALLBACK
RecvCompletionProc (
DWORD status,
DWORD cbSent,
PIO_PARAM_BLOCK rreq
);
DWORD
CreateIOQueue (
HANDLE *RecvEvent
) {
DWORD status;
InitializeCriticalSection (&IOQueues.IQ_Lock);
#if DBG
InitializeListHead (&IOQueues.IQ_SentPackets);
InitializeListHead (&IOQueues.IQ_RcvdPackets);
#endif
IOQueues.IQ_AdptHdl = INVALID_HANDLE_VALUE;
IOQueues.IQ_RecvEvent = CreateEvent (NULL,
FALSE, // auto-reset (reset by recv operation
// and when thread is signalled (it may
// not post new request if limit is
// exceded)
FALSE, // not signalled
NULL);
if (IOQueues.IQ_RecvEvent!=NULL) {
INT i;
*RecvEvent = IOQueues.IQ_RecvEvent;
return NO_ERROR;
}
else {
status = GetLastError ();
Trace (DEBUG_FAILURES,
"Failed to create recv comp event (gle:%ld)", status);
}
DeleteCriticalSection (&IOQueues.IQ_Lock);
return status;
}
VOID
DeleteIOQueue (
VOID
) {
CloseHandle (IOQueues.IQ_RecvEvent);
DeleteCriticalSection (&IOQueues.IQ_Lock);
}
DWORD
StartIO (
VOID
) {
DWORD status=NO_ERROR;
EnterCriticalSection (&IOQueues.IQ_Lock);
if (IOQueues.IQ_AdptHdl==INVALID_HANDLE_VALUE) {
USHORT sockNum;
IpxSockCpy (&sockNum, IPX_SAP_SOCKET);
Trace (DEBUG_NET_IO, "Creating socket port.");
IOQueues.IQ_AdptHdl = CreateSocketPort (sockNum);
if (IOQueues.IQ_AdptHdl!=INVALID_HANDLE_VALUE) {
status = NO_ERROR;
if (! BindIoCompletionCallback(
IOQueues.IQ_AdptHdl,
IoCompletionProc,
0))
{
status = GetLastError();
}
if (status==NO_ERROR) {
BOOL res;
LeaveCriticalSection (&IOQueues.IQ_Lock);
res = SetEvent (IOQueues.IQ_RecvEvent);
ASSERTMSG ("Could not set recv event ", res);
return NO_ERROR;
}
else {
status = GetLastError ();
Trace (DEBUG_FAILURES,
"Failed to create completion port (gle:%ld)", status);
}
DeleteSocketPort (IOQueues.IQ_AdptHdl);
IOQueues.IQ_AdptHdl = INVALID_HANDLE_VALUE;
}
else {
status = GetLastError ();
Trace (DEBUG_FAILURES,
"Failed to create adapter port (gle:%ld)", status);
IF_LOG (EVENTLOG_ERROR_TYPE) {
RouterLogErrorA (RouterEventLogHdl,
ROUTERLOG_IPXSAP_SAP_SOCKET_IN_USE,
0, NULL, status);
}
}
}
LeaveCriticalSection (&IOQueues.IQ_Lock);
return status;
}
VOID
StopIO (
VOID
) {
EnterCriticalSection (&IOQueues.IQ_Lock);
if (IOQueues.IQ_AdptHdl!=INVALID_HANDLE_VALUE) {
DWORD status;
HANDLE Port = IOQueues.IQ_AdptHdl;
IOQueues.IQ_AdptHdl = INVALID_HANDLE_VALUE;
LeaveCriticalSection (&IOQueues.IQ_Lock);
Trace (DEBUG_NET_IO, "Deleting socket port.");
DeleteSocketPort (Port);
}
else
LeaveCriticalSection (&IOQueues.IQ_Lock);
}
/*++
*******************************************************************
I o C o m p l e t i o n P r o c
Routine Description:
Called on completion of each io request
Arguments:
error - result of io
cbTransferred - number of bytes actually sent
ovlp - overlapped structure associated with io request
Return Value:
None
*******************************************************************
--*/
VOID CALLBACK
IoCompletionProc (
DWORD error,
DWORD cbTransferred,
LPOVERLAPPED ovlp
) {
PIO_PARAM_BLOCK req = CONTAINING_RECORD (ovlp, IO_PARAM_BLOCK, ovlp);
// Get actual parameters adjusted by the adapter dll
IpxAdjustIoCompletionParams (ovlp, &cbTransferred, &error);
(*req->comp)(error, cbTransferred, req);
}
/*++
*******************************************************************
E n q u e u e S e n d R e q u e s t
Routine Description:
Sets adapter id field in request io param block and enqueues
send request to adapter's driver.
Arguments:
sreq - io parameter block, the following fields must be set:
intf - pointer to interface external data
buffer - pointer to buffer that contains data to be sent
cbBuffer - count of bytes of data in the buffer
Return Value:
None
*******************************************************************
--*/
VOID
EnqueueSendRequest (
PIO_PARAM_BLOCK sreq
) {
DWORD status;
sreq->status = ERROR_IO_PENDING;
sreq->ovlp.hEvent = NULL;
sreq->comp = SendCompletionProc;
#if DBG
EnterCriticalSection (&IOQueues.IQ_Lock);
InsertTailList (&IOQueues.IQ_SentPackets, &sreq->link);
LeaveCriticalSection (&IOQueues.IQ_Lock);
#endif
status = IpxSendPacket (IOQueues.IQ_AdptHdl,
sreq->adpt,
sreq->buffer,
sreq->cbBuffer,
&sreq->rsvd,
&sreq->ovlp,
NULL
);
// If request failed and thus completion routine won't be called
// we'll simulate completion ourselves so that request won't get
// lost
if (status!=NO_ERROR)
SendCompletionProc (status, 0, sreq);
}
/*++
*******************************************************************
S e n d C o m p l e t i o n P r o c
Routine Description:
Called on completion for each sent packet.
Sets fields of send request io param block and enqueues it to
completion queue.
Arguments:
status - result of io
cbSent - number of bytes actually sent
context - context associated with send request (IO_PARAM_BLOCK)
Return Value:
None
*******************************************************************
--*/
VOID CALLBACK
SendCompletionProc (
DWORD status,
DWORD cbSent,
PIO_PARAM_BLOCK sreq
) {
BOOL res;
BOOL releaseSend = FALSE;
sreq->compTime = GetTickCount ();
sreq->status = status;
if (status!=NO_ERROR) {
#define dstPtr (sreq->buffer+FIELD_OFFSET (SAP_BUFFER, Dst.Network))
Trace (DEBUG_FAILURES, "Error %d while sending to"
" %02x%02x%02x%02x:%02x%02x%02x%02x%02x%02x:%02x%02x"
" on adapter %d.", status,
*dstPtr, *(dstPtr+1), *(dstPtr+2), *(dstPtr+3),
*(dstPtr+4), *(dstPtr+5), *(dstPtr+6), *(dstPtr+7), *(dstPtr+8), *(dstPtr+9),
*(dstPtr+10), *(dstPtr+11),
sreq->adpt);
#undef dstPtr
}
sreq->cbBuffer = cbSent;
#if DBG
// Maintain queue of posted requests
EnterCriticalSection (&IOQueues.IQ_Lock);
RemoveEntryList (&sreq->link);
LeaveCriticalSection (&IOQueues.IQ_Lock);
#endif
ProcessCompletedIORequest (sreq);
}
/*++
*******************************************************************
E n q u e u e R e c v R e q u e s t
Routine Description:
Enqueues recv request to be posted to the network driver.
Arguments:
rreq - io parameter block, the following fields must be set:
buffer - pointer to buffer to receive data
cbBuffer - size of the buffer
Return Value:
TRUE - need more recv requests (number of posted requests is below
low water mark)
FALSE - no more requests needed.
*******************************************************************
--*/
VOID
EnqueueRecvRequest (
PIO_PARAM_BLOCK rreq
) {
DWORD status;
rreq->status = ERROR_IO_PENDING;
rreq->adpt = INVALID_ADAPTER_INDEX;
rreq->ovlp.hEvent = IOQueues.IQ_RecvEvent;
rreq->comp = RecvCompletionProc;
#if DBG
EnterCriticalSection (&IOQueues.IQ_Lock);
InsertTailList (&IOQueues.IQ_RcvdPackets, &rreq->link);
LeaveCriticalSection (&IOQueues.IQ_Lock);
#endif
status = IpxRecvPacket (IOQueues.IQ_AdptHdl,
rreq->buffer,
rreq->cbBuffer,
&rreq->rsvd,
&rreq->ovlp,
NULL
);
if (status==NO_ERROR) {
NOTHING;
}
else {
Trace (DEBUG_FAILURES, "Error %d while posting receive packet", status);
// If request failed and thus completion routine won't be called
// we'll simulate completion ourselves so that request won't get
// lost
RecvCompletionProc (status, 0, rreq);
}
}
/*++
*******************************************************************
R e c v C o m p l e t i o n P r o c
Routine Description:
Called on completion of each received packet.
Sets fields of recv request io param block and enqueues it to
completion queue.
Arguments:
status - result of io
cbSent - number of bytes actually sent
context - context associated with send request (IO_PARAM_BLOCK)
Return Value:
None
*******************************************************************
--*/
VOID CALLBACK
RecvCompletionProc (
DWORD status,
DWORD cbRecvd,
PIO_PARAM_BLOCK rreq
) {
BOOL completed=TRUE;
rreq->adpt = GetNicId (&rreq->rsvd);
rreq->compTime = GetTickCount ();
rreq->cbBuffer = cbRecvd;
rreq->status = status;
if (status!=NO_ERROR)
Trace (DEBUG_FAILURES, "Error %d while receiving packet on adapter %d.",
status, rreq->adpt);
#if DBG
EnterCriticalSection (&IOQueues.IQ_Lock);
RemoveEntryList (&rreq->link);
LeaveCriticalSection (&IOQueues.IQ_Lock);
#endif
ProcessCompletedIORequest (rreq);
}
/*++
*******************************************************************
D u m p P a c k e t
Routine Description:
Dumps IPX SAP packet fields to stdio
Arguments:
Packet - pointer to IPX SAP packet
count - size of the packet
Return Value:
None
*******************************************************************
--*/
/*
#if DBG
VOID
DumpPacket (
PSAP_BUFFER packet,
DWORD count
) {
SS_PRINTF(("Length : %d.", GETUSHORT (&packet->Length)));
SS_PRINTF(("Packet type : %02X.", packet->PacketType));
SS_PRINTF(("Dest. net : %02X%02X%02X%02X.",
packet->Dst.Net[0],
packet->Dst.Net[1],
packet->Dst.Net[2],
packet->Dst.Net[3]));
SS_PRINTF(("Dest. node : %02X%02X%02X%02X%02X%02X.",
packet->Dst.Node[0],
packet->Dst.Node[1],
packet->Dst.Node[2],
packet->Dst.Node[3],
packet->Dst.Node[4],
packet->Dst.Node[5]));
SS_PRINTF(("Dest. socket : %04X.", GETUSHORT (&packet->Dst.Socket)));
SS_PRINTF(("Src. net : %02X%02X%02X%02X.",
packet->Src.Net[0],
packet->Src.Net[1],
packet->Src.Net[2],
packet->Src.Net[3]));
SS_PRINTF(("Src. node : %02X%02X%02X%02X%02X%02X.",
packet->Src.Node[0],
packet->Src.Node[1],
packet->Src.Node[2],
packet->Src.Node[3],
packet->Src.Node[4],
packet->Src.Node[5]));
SS_PRINTF(("Src. socket : %04X.", GETUSHORT (&packet->Src.Socket)));
if (count>=(DWORD)FIELD_OFFSET(SAP_BUFFER, Entries[0])) {
INT j;
SS_PRINTF(("SAP Operation : %d.", GETUSHORT (&packet->Operation)));
for (j=0; (j<7) && (count>=(DWORD)FIELD_OFFSET (SAP_BUFFER, Entries[j+1])); j++) {
SS_PRINTF(("Server type : %04X.", GETUSHORT (&packet->Entries[j].Type)));
SS_PRINTF(("Server name : %.48s.", packet->Entries[j].Name));
SS_PRINTF(("Server net : %02X%02X%02X%02X.",
packet->Entries[j].Network[0],
packet->Entries[j].Network[1],
packet->Entries[j].Network[2],
packet->Entries[j].Network[3]));
SS_PRINTF(("Server node : %02X%02X%02X%02X%02X%02X.",
packet->Entries[j].Node[0],
packet->Entries[j].Node[1],
packet->Entries[j].Node[2],
packet->Entries[j].Node[3],
packet->Entries[j].Node[4],
packet->Entries[j].Node[5]));
SS_PRINTF(("Server socket : %02X%02X.",
packet->Entries[j].Socket[0],
packet->Entries[j].Socket[1]));
SS_PRINTF(("Server hops : %d.", GETUSHORT (&packet->Entries[j].HopCount)));
}
if ((j==0) && (count>=(DWORD)FIELD_OFFSET (SAP_BUFFER, Entries[0].Name)))
SS_PRINTF(("Server type : %04X.", GETUSHORT (&packet->Entries[0].Type)));
}
}
#endif
*/