mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2424 lines
74 KiB
2424 lines
74 KiB
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
net\routing\ipx\sap\workers.c
|
|
|
|
Abstract:
|
|
|
|
This module implement all SAP agent work items
|
|
|
|
Author:
|
|
|
|
Vadim Eydelman 05-15-1995
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#include "sapp.h"
|
|
|
|
|
|
// Max number of pending recv work items
|
|
LONG MaxUnprocessedRequests=SAP_MAX_UNPROCESSED_REQUESTS_DEF;
|
|
|
|
// Minimum number of queued recv requests
|
|
LONG MinPendingRequests = SAP_MIN_REQUESTS_DEF;
|
|
|
|
|
|
// How often to check on pending triggered update
|
|
ULONG TriggeredUpdateCheckInterval=SAP_TRIGGERED_UPDATE_CHECK_INTERVAL_DEF;
|
|
|
|
// How many requests to send if no response received within check interval
|
|
ULONG MaxTriggeredUpdateRequests=SAP_MAX_TRIGGERED_UPDATE_REQUESTS_DEF;
|
|
|
|
// Whether to respond for internal servers that are not registered with SAP
|
|
// through the API calls (for standalone service only)
|
|
ULONG RespondForInternalServers=SAP_RESPOND_FOR_INTERNAL_DEF;
|
|
|
|
// Delay in response to general reguests for specific server type
|
|
// if local servers are included in the packet
|
|
ULONG DelayResponseToGeneral=SAP_DELAY_RESPONSE_TO_GENERAL_DEF;
|
|
|
|
// Delay in sending change broadcasts if packet is not full
|
|
ULONG DelayChangeBroadcast=SAP_DELAY_CHANGE_BROADCAST_DEF;
|
|
|
|
UCHAR IPX_BCAST_NODE[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
|
UCHAR IPX_SAP_SOCKET[2] = {0x04, 0x52};
|
|
UCHAR IPX_INVALID_NET[4] = {0};
|
|
UCHAR IPX_INVALID_NODE[6] = {0};
|
|
|
|
#define SetupIpxSapPacket(packet,oper,net,node,sock) \
|
|
(packet)->PacketType = IPX_SAP_PACKET_TYPE; \
|
|
PUTUSHORT (oper, &(packet)->Operation); \
|
|
IpxNetCpy ((packet)->Dst.Network, net); \
|
|
IpxNodeCpy ((packet)->Dst.Node, node); \
|
|
IpxSockCpy ((packet)->Dst.Socket, sock);
|
|
|
|
typedef struct _WORKER_QUEUE {
|
|
LONG WQ_WorkerCount;
|
|
LONG WQ_RequestQuota;
|
|
LONG WQ_RequestExtra;
|
|
LIST_ENTRY WQ_Queue;
|
|
HANDLE WQ_Heap;
|
|
HANDLE WQ_DoneEvent;
|
|
HANDLE WQ_RecvEvent;
|
|
} WORKER_QUEUE, *PWORKER_QUEUE;
|
|
|
|
WORKER_QUEUE WorkerQueue;
|
|
|
|
// Work item that obtains and processes SAP requests
|
|
typedef struct _REQ_ITEM {
|
|
IO_WORKER iow;
|
|
SAP_BUFFER packet;
|
|
} REQ_ITEM, *PREQ_ITEM;
|
|
|
|
|
|
// Work item that generates responses for SAP general requests
|
|
typedef struct _RESP_ITEM {
|
|
PINTERFACE_DATA intf;
|
|
USHORT svrType; // Type of servers requested
|
|
BOOLEAN bcast; // Is destination a broadcast
|
|
// address ?
|
|
HANDLE hEnum; // Enumeration handle to keep
|
|
// track of sent servers
|
|
IO_WORKER iow;
|
|
TIMER_WORKER tmw;
|
|
SAP_BUFFER packet;
|
|
} RESP_ITEM, *PRESP_ITEM;
|
|
|
|
// Work item that generates responses for SAP GETNEAREST requests
|
|
typedef struct _GNEAR_ITEM {
|
|
PINTERFACE_DATA intf;
|
|
IO_WORKER iow;
|
|
SAP_BUFFER packet;
|
|
} GNEAR_ITEM, *PGNEAR_ITEM;
|
|
|
|
// Work item that sends SAP general requests
|
|
typedef struct _SREQ_ITEM {
|
|
PINTERFACE_DATA intf;
|
|
IO_WORKER iow;
|
|
SAP_BUFFER packet;
|
|
} SREQ_ITEM, *PSREQ_ITEM;
|
|
|
|
|
|
// Work item that generates periodic and change broadcasts
|
|
typedef struct _BCAST_ITEM {
|
|
IO_WORKER iow;
|
|
TIMER_WORKER tmw;
|
|
PINTERFACE_DATA intf;
|
|
DWORD nextBcast; // Time (windows time in msec) for
|
|
// next broadcast
|
|
INT delayedSvrCount; // Number of servers already
|
|
// in the packet that were delayed because
|
|
// packet wasn't full
|
|
DWORD delayedSendTime; // Time until packet was delayed
|
|
// because it wasn't full
|
|
HANDLE chngEnum; // Enumeration hadnle that keeps
|
|
// track of chnagd servers
|
|
HANDLE perdEnum; // Enumeration handle that keeps
|
|
// track of servers during periodic
|
|
// broadcasts
|
|
SAP_BUFFER packet;
|
|
} BCAST_ITEM, *PBCAST_ITEM;
|
|
|
|
// Work item that gets and processes LPC requests
|
|
typedef struct _LPC_ITEM {
|
|
LPC_WORKER lpcw;
|
|
NWSAP_REQUEST_MESSAGE request;
|
|
} LPC_ITEM, *PLPC_ITEM;
|
|
|
|
typedef struct _TREQ_ITEM {
|
|
IO_WORKER iow;
|
|
TIMER_WORKER tmw;
|
|
AR_PARAM_BLOCK ar;
|
|
PINTERFACE_DATA intf;
|
|
ULONG pktCount;
|
|
ULONG resend;
|
|
ULONG listenSave;
|
|
ULONG intervalSave;
|
|
SAP_BUFFER packet;
|
|
} TREQ_ITEM, *PTREQ_ITEM;
|
|
|
|
|
|
typedef union _WORK_ITEM {
|
|
REQ_ITEM req;
|
|
LPC_ITEM lpc;
|
|
BCAST_ITEM bcast;
|
|
SREQ_ITEM sreq;
|
|
TREQ_ITEM treq;
|
|
GNEAR_ITEM gnear;
|
|
RESP_ITEM resp;
|
|
} WORK_ITEM, *PWORK_ITEM;
|
|
|
|
|
|
// Parameter block passed to enumeration call back filter procedures
|
|
typedef struct _GR_FILTER_PARAMS {
|
|
INT svrIdx; // Index of server info in SAP packet
|
|
BOOLEAN localSvr; // Local server included in the packet
|
|
USHORT localHopCount; // Hop count used to track servers local
|
|
// to the interface that may prevent use from broad-
|
|
// casting info of same server obtained on different
|
|
// interface
|
|
PINTERFACE_DATA intf; // Pointer to interface data
|
|
PSAP_BUFFER packet; // Packet to be filled
|
|
} GR_FILTER_PARAMS, *PGR_FILTER_PARAMS;
|
|
|
|
typedef struct _GN_FILTER_PARAMS {
|
|
BOOLEAN found; // flag indicating the one server was found
|
|
USHORT localHopCount; // Hop count used to track servers local
|
|
// to the interface that may prevent use from broad-
|
|
// casting info of same server obtained on different
|
|
// interface
|
|
PINTERFACE_DATA intf; // Pointer to interface data
|
|
PSAP_BUFFER packet; // Packet to be filled
|
|
} GN_FILTER_PARAMS, *PGN_FILTER_PARAMS;
|
|
|
|
// Parameters used to construct a list of servers that
|
|
// need their internal network information updated.
|
|
typedef struct _SERVER_INTERNAL_UPDATE_NODE {
|
|
ULONG InterfaceIndex;
|
|
ULONG Protocol;
|
|
PUCHAR AdvertisingNode;
|
|
INT Flags;
|
|
IPX_SERVER_ENTRY_P Server;
|
|
struct _SERVER_INTERNAL_UPDATE_NODE * pNext;
|
|
} SERVER_INTERNAL_UPDATE_NODE;
|
|
|
|
#define AllocateWorker(worker,type) \
|
|
((worker=(type *)HeapAlloc(WorkerQueue.WQ_Heap, 0, sizeof (WORK_ITEM))) \
|
|
? InterlockedIncrement (&WorkerQueue.WQ_WorkerCount) \
|
|
: 0)
|
|
|
|
#define DeallocateWorker(worker) { \
|
|
HeapFree (WorkerQueue.WQ_Heap, 0, worker); \
|
|
if (InterlockedDecrement (&WorkerQueue.WQ_WorkerCount)<0) { \
|
|
BOOL res = SetEvent (WorkerQueue.WQ_DoneEvent); \
|
|
ASSERTERRMSG ("Can't set workers done event ", res); \
|
|
} \
|
|
}
|
|
|
|
|
|
// Local prototypes
|
|
VOID APIENTRY
|
|
ProcessReqItem (
|
|
PVOID worker
|
|
);
|
|
VOID APIENTRY
|
|
ProcessRespIOItem (
|
|
PVOID worker
|
|
);
|
|
VOID APIENTRY
|
|
ProcessRespTMItem (
|
|
PVOID worker
|
|
);
|
|
VOID APIENTRY
|
|
ProcessGnearItem (
|
|
PVOID worker
|
|
);
|
|
VOID APIENTRY
|
|
ProcessBcastIOItem (
|
|
PVOID worker
|
|
);
|
|
VOID APIENTRY
|
|
ProcessBcastTMItem (
|
|
PVOID worker
|
|
);
|
|
VOID APIENTRY
|
|
ProcessShutItem (
|
|
PVOID worker
|
|
);
|
|
VOID APIENTRY
|
|
ProcessSreqItem (
|
|
PVOID worker
|
|
);
|
|
VOID APIENTRY
|
|
ProcessSreqItem (
|
|
PVOID worker
|
|
);
|
|
VOID APIENTRY
|
|
ProcessLPCItem (
|
|
PVOID worker
|
|
);
|
|
VOID APIENTRY
|
|
ProcessTreqIOItem (
|
|
PVOID worker
|
|
);
|
|
VOID APIENTRY
|
|
ProcessTreqTMItem (
|
|
PVOID worker
|
|
);
|
|
VOID APIENTRY
|
|
FreeTreqItem (
|
|
PAR_PARAM_BLOCK rslt
|
|
);
|
|
|
|
/*++
|
|
*******************************************************************
|
|
I n i t i a l i z e W o r k e r s
|
|
|
|
Routine Description:
|
|
Initialize heap to be used for allocation of work items
|
|
Arguments:
|
|
None
|
|
Return Value:
|
|
NO_ERROR - heap was initialized OK
|
|
other - operation failed (windows error code)
|
|
|
|
*******************************************************************
|
|
--*/
|
|
DWORD
|
|
InitializeWorkers (
|
|
HANDLE RecvEvent
|
|
) {
|
|
DWORD status;
|
|
|
|
if (MaxUnprocessedRequests<(MinPendingRequests*11/10)) {
|
|
MaxUnprocessedRequests = MinPendingRequests*11/10;
|
|
Trace (DEBUG_FAILURES,
|
|
"Set "SAP_MAX_UNPROCESSED_REQUESTS_STR" to %d (10%% above "
|
|
SAP_MIN_REQUESTS_STR")", MaxUnprocessedRequests);
|
|
}
|
|
|
|
WorkerQueue.WQ_WorkerCount = 0;
|
|
WorkerQueue.WQ_RequestQuota = MaxUnprocessedRequests;
|
|
WorkerQueue.WQ_RequestExtra = -MinPendingRequests;
|
|
WorkerQueue.WQ_DoneEvent = NULL;
|
|
WorkerQueue.WQ_RecvEvent = RecvEvent;
|
|
WorkerQueue.WQ_Heap = HeapCreate (0, 0, 0);
|
|
if (WorkerQueue.WQ_Heap!=NULL) {
|
|
return NO_ERROR;
|
|
}
|
|
else {
|
|
status = GetLastError ();
|
|
Trace (DEBUG_FAILURES,
|
|
"File: %s, line %ld. Could not allocate worker's heap (gle:%ld).",
|
|
__FILE__, __LINE__, status);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
/*++
|
|
*******************************************************************
|
|
S h u t d o w n W o r k e r s
|
|
|
|
Routine Description:
|
|
Stops new worker creation and signals event when all
|
|
workers are deleted
|
|
Arguments:
|
|
doneEvent - event to be signalled when all workers are deleted
|
|
Return Value:
|
|
None
|
|
|
|
*******************************************************************
|
|
--*/
|
|
VOID
|
|
ShutdownWorkers (
|
|
IN HANDLE doneEvent
|
|
) {
|
|
WorkerQueue.WQ_DoneEvent = doneEvent;
|
|
|
|
if (InterlockedDecrement (&WorkerQueue.WQ_WorkerCount)<0) {
|
|
BOOL res = SetEvent (WorkerQueue.WQ_DoneEvent);
|
|
ASSERTERRMSG ("Can't set workers done event ", res);
|
|
}
|
|
}
|
|
|
|
/*++
|
|
*******************************************************************
|
|
D e l e t e W o r k e r s
|
|
|
|
Routine Description:
|
|
Deletes heap used for work items (and thus all work items as well)
|
|
Arguments:
|
|
None
|
|
Return Value:
|
|
None
|
|
|
|
*******************************************************************
|
|
--*/
|
|
VOID
|
|
DeleteWorkers (
|
|
void
|
|
) {
|
|
ASSERT (WorkerQueue.WQ_WorkerCount==-1);
|
|
HeapDestroy (WorkerQueue.WQ_Heap);
|
|
}
|
|
|
|
|
|
/*++
|
|
*******************************************************************
|
|
H o p C o u n t F i l t e r
|
|
|
|
Routine Description:
|
|
Server enumeration callback proc that filters out servers with high hop
|
|
(<=15 for same interface, <15 for rest)
|
|
Arguments:
|
|
CBParam - enumeration callback parameter (param block above)
|
|
Server, InterfaceIndex, Protocol, AdvertisingNode, Flags - server info
|
|
Return Value:
|
|
TRUE (to stop enumeration) when sap packet gets filled up,
|
|
FALSE otherwise
|
|
*******************************************************************
|
|
--*/
|
|
BOOL
|
|
HopCountFilter (
|
|
IN LPVOID CBParam,
|
|
IN PIPX_SERVER_ENTRY_P Server,
|
|
IN ULONG InterfaceIndex,
|
|
IN ULONG Protocol,
|
|
IN PUCHAR AdvertisingNode,
|
|
IN INT Flags
|
|
) {
|
|
#define params ((PGR_FILTER_PARAMS)CBParam)
|
|
|
|
ASSERTMSG ("To many servers ", params->svrIdx<IPX_SAP_MAX_ENTRY);
|
|
|
|
if ((InterfaceIndex!=INTERNAL_INTERFACE_INDEX)
|
|
|| (IpxNetCmp (Server->Network, IPX_INVALID_NET)!=0)
|
|
&& ((Protocol==IPX_PROTOCOL_LOCAL)
|
|
|| Routing
|
|
|| RespondForInternalServers)) {
|
|
if ((Server->HopCount<IPX_MAX_HOP_COUNT-1)
|
|
|| ((InterfaceIndex==params->intf->index)
|
|
&& (Server->HopCount<IPX_MAX_HOP_COUNT)) ) {
|
|
if ((params->intf->filterOut==SAP_DONT_FILTER)
|
|
|| ((params->intf->filterOut==SAP_FILTER_PERMIT)
|
|
&& Filter (FILTER_TYPE_SUPPLY,
|
|
params->intf->index, Server->Type, Server->Name))
|
|
|| ((params->intf->filterOut==SAP_FILTER_DENY)
|
|
&& !Filter (FILTER_TYPE_SUPPLY,
|
|
params->intf->index, Server->Type, Server->Name))) {
|
|
IpxServerCpy (¶ms->packet->Entries[params->svrIdx], Server);
|
|
PUTUSHORT (Server->Type, ¶ms->packet->Entries[params->svrIdx].Type);
|
|
if (InterfaceIndex==params->intf->index) {
|
|
PUTUSHORT (Server->HopCount,
|
|
¶ms->packet->Entries[params->svrIdx].HopCount);
|
|
}
|
|
else {
|
|
|
|
PUTUSHORT (Server->HopCount+1,
|
|
¶ms->packet->Entries[params->svrIdx].HopCount);
|
|
}
|
|
params->svrIdx += 1;
|
|
if (InterfaceIndex==INTERNAL_INTERFACE_INDEX)
|
|
params->localSvr = TRUE;
|
|
// Trace (DEBUG_ENTRIES, "\tAdding server, type: %04x, name: %.48s, hops: %d.",
|
|
// Server->Type, Server->Name, Server->HopCount);
|
|
if (params->svrIdx>=IPX_SAP_MAX_ENTRY)
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
#undef params
|
|
return FALSE;
|
|
}
|
|
|
|
/*++
|
|
*******************************************************************
|
|
S p l i t H o r i z o n H o p C o u n t F i l t e r
|
|
|
|
Routine Description:
|
|
Server enumeration callback proc that filters out servers with high hop
|
|
(<15) and applies split horizon algorithm based on interface index
|
|
Arguments:
|
|
CBParam - enumeration callback parameter (param block above)
|
|
Server, InterfaceIndex, Protocol, AdvertisingNode, Flags - server info
|
|
Return Value:
|
|
TRUE (to stop enumeration) when sap packet gets filled up,
|
|
FALSE otherwise
|
|
*******************************************************************
|
|
--*/
|
|
BOOL
|
|
SplitHorizonHopCountFilter (
|
|
IN LPVOID CBParam,
|
|
IN OUT PIPX_SERVER_ENTRY_P Server,
|
|
IN ULONG InterfaceIndex,
|
|
IN ULONG Protocol,
|
|
IN PUCHAR AdvertisingNode,
|
|
IN INT Flags
|
|
) {
|
|
#define params ((PGR_FILTER_PARAMS)CBParam)
|
|
ASSERTMSG ("To many servers ", params->svrIdx<IPX_SAP_MAX_ENTRY);
|
|
if (Flags & SDB_MAIN_NODE_FLAG) {
|
|
// Only send entries that are not received through local interface
|
|
// and that do not have entry with equal hop count on local interface
|
|
if (((InterfaceIndex!=INTERNAL_INTERFACE_INDEX)
|
|
|| (IpxNetCmp (Server->Network, IPX_INVALID_NET)!=0)
|
|
&& ((Protocol==IPX_PROTOCOL_LOCAL)
|
|
|| Routing
|
|
|| RespondForInternalServers))
|
|
&& (InterfaceIndex!=params->intf->index)
|
|
&& (Server->HopCount<params->localHopCount)
|
|
&& ((params->intf->filterOut==SAP_DONT_FILTER)
|
|
|| ((params->intf->filterOut==SAP_FILTER_PERMIT)
|
|
&& Filter (FILTER_TYPE_SUPPLY,
|
|
params->intf->index, Server->Type, Server->Name))
|
|
|| ((params->intf->filterOut==SAP_FILTER_DENY)
|
|
&& !Filter (FILTER_TYPE_SUPPLY,
|
|
params->intf->index, Server->Type, Server->Name)))) {
|
|
IpxServerCpy (¶ms->packet->Entries[params->svrIdx], Server);
|
|
PUTUSHORT (Server->Type,
|
|
¶ms->packet->Entries[params->svrIdx].Type);
|
|
PUTUSHORT (Server->HopCount+1,
|
|
¶ms->packet->Entries[params->svrIdx].HopCount);
|
|
if (InterfaceIndex==INTERNAL_INTERFACE_INDEX)
|
|
params->localSvr = TRUE;
|
|
params->svrIdx += 1;
|
|
// Trace (DEBUG_ENTRIES, "\tAdding server, type: %04x, name: %.48s, hops: %d.",
|
|
// Server->Type, Server->Name, Server->HopCount);
|
|
if (params->svrIdx>=IPX_SAP_MAX_ENTRY)
|
|
return TRUE;
|
|
}
|
|
// Make sure we won't send deleted servers
|
|
params->localHopCount = IPX_MAX_HOP_COUNT-1;
|
|
}
|
|
else if (InterfaceIndex==params->intf->index) {
|
|
params->localHopCount = Server->HopCount; // Remember hop count of entry
|
|
// on local interface
|
|
// Trace (DEBUG_ENTRIES, "\tBackup server entry, type: %04x, name: %.48s, hops: %d.",
|
|
// Server->Type, Server->Name, Server->HopCount);
|
|
}
|
|
|
|
#undef params
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
/*++
|
|
*******************************************************************
|
|
S p l i t H o r i z o n F i l t e r
|
|
|
|
Routine Description:
|
|
Server enumeration callback proc that applies split horizon algorithm
|
|
based on interface index to filter out enumerated servers
|
|
Arguments:
|
|
CBParam - enumeration callback parameter (param block above)
|
|
Server, InterfaceIndex, Protocol, AdvertisingNode, Flags - server info
|
|
Return Value:
|
|
TRUE (to stop enumeration) when sap packet gets filled up,
|
|
FALSE otherwise
|
|
*******************************************************************
|
|
--*/
|
|
BOOL
|
|
SplitHorizonFilter (
|
|
IN LPVOID CBParam,
|
|
IN OUT PIPX_SERVER_ENTRY_P Server,
|
|
IN ULONG InterfaceIndex,
|
|
IN ULONG Protocol,
|
|
IN PUCHAR AdvertisingNode,
|
|
IN INT Flags
|
|
) {
|
|
#define params ((PGR_FILTER_PARAMS)CBParam)
|
|
|
|
ASSERTMSG ("To many servers ", params->svrIdx<IPX_SAP_MAX_ENTRY);
|
|
if (Flags&SDB_MAIN_NODE_FLAG) {
|
|
// Only send entries that are not received through local interface
|
|
// and that do not have entry with equal hop count on local interface
|
|
if ( (((InterfaceIndex==INTERNAL_INTERFACE_INDEX)
|
|
&& (IpxNetCmp (Server->Network, IPX_INVALID_NET)!=0)
|
|
&& ((Protocol==IPX_PROTOCOL_LOCAL)
|
|
|| Routing
|
|
|| RespondForInternalServers))
|
|
|| (InterfaceIndex!=params->intf->index))
|
|
&& (Server->HopCount<params->localHopCount)
|
|
&& ((params->intf->filterOut==SAP_DONT_FILTER)
|
|
|| ((params->intf->filterOut==SAP_FILTER_PERMIT)
|
|
&& Filter (FILTER_TYPE_SUPPLY,
|
|
params->intf->index, Server->Type, Server->Name))
|
|
|| ((params->intf->filterOut==SAP_FILTER_DENY)
|
|
&& !Filter (FILTER_TYPE_SUPPLY,
|
|
params->intf->index, Server->Type, Server->Name))) ){
|
|
IpxServerCpy (¶ms->packet->Entries[params->svrIdx], Server);
|
|
PUTUSHORT (Server->Type,
|
|
¶ms->packet->Entries[params->svrIdx].Type);
|
|
if ((Server->HopCount<IPX_MAX_HOP_COUNT)
|
|
&& !(Flags&SDB_DISABLED_NODE_FLAG)) {
|
|
PUTUSHORT (Server->HopCount+1,
|
|
¶ms->packet->Entries[params->svrIdx].HopCount);
|
|
}
|
|
else {
|
|
PUTUSHORT (IPX_MAX_HOP_COUNT,
|
|
¶ms->packet->Entries[params->svrIdx].HopCount);
|
|
}
|
|
if (InterfaceIndex==INTERNAL_INTERFACE_INDEX)
|
|
params->localSvr = TRUE;
|
|
params->svrIdx += 1;
|
|
// Trace (DEBUG_ENTRIES, "\tAdding server, type: %04x, name: %.48s, hops: %d.",
|
|
// Server->Type, Server->Name, Server->HopCount);
|
|
if (params->svrIdx>=IPX_SAP_MAX_ENTRY)
|
|
return TRUE;
|
|
}
|
|
params->localHopCount = IPX_MAX_HOP_COUNT+1;
|
|
}
|
|
else if ((InterfaceIndex==params->intf->index)
|
|
&& !(Flags&SDB_DISABLED_NODE_FLAG)) {
|
|
params->localHopCount = Server->HopCount;
|
|
// Trace (DEBUG_ENTRIES,"\tBackup server entry, type: %04x, name: %.48s, hops: %d.",
|
|
// Server->Type, Server->Name, Server->HopCount);
|
|
}
|
|
|
|
#undef params
|
|
return FALSE;
|
|
}
|
|
|
|
/*++
|
|
*******************************************************************
|
|
S p l i t H o r i z o n F i l t e r
|
|
|
|
Routine Description:
|
|
Server enumeration callback proc that applies split horizon algorithm
|
|
based on interface index to filter out enumerated servers
|
|
and only gets deleted servers (HopCount=16)
|
|
Arguments:
|
|
CBParam - enumeration callback parameter (param block above)
|
|
Server, InterfaceIndex, Protocol, AdvertisingNode, Flags - server info
|
|
Return Value:
|
|
TRUE (to stop enumeration) when sap packet gets filled up,
|
|
FALSE otherwise
|
|
*******************************************************************
|
|
--*/
|
|
BOOL
|
|
SplitHorizonDeletedFilter (
|
|
IN LPVOID CBParam,
|
|
IN OUT PIPX_SERVER_ENTRY_P Server,
|
|
IN ULONG InterfaceIndex,
|
|
IN ULONG Protocol,
|
|
IN PUCHAR AdvertisingNode,
|
|
IN INT Flags
|
|
) {
|
|
#define params ((PGR_FILTER_PARAMS)CBParam)
|
|
|
|
ASSERTMSG ("To many servers ", params->svrIdx<IPX_SAP_MAX_ENTRY);
|
|
if (Flags&SDB_MAIN_NODE_FLAG) {
|
|
// Only send entries that are not received through local interface
|
|
// and that do not have entry with equal hop count on local interface
|
|
if (((Server->HopCount>=IPX_MAX_HOP_COUNT)
|
|
|| (Flags&SDB_DISABLED_NODE_FLAG))
|
|
&& (((InterfaceIndex==INTERNAL_INTERFACE_INDEX)
|
|
&& (IpxNetCmp (Server->Network, IPX_INVALID_NET)!=0)
|
|
&& ((Protocol==IPX_PROTOCOL_LOCAL)
|
|
|| Routing
|
|
|| RespondForInternalServers))
|
|
|| (InterfaceIndex!=params->intf->index))
|
|
&& ((params->intf->filterOut==SAP_DONT_FILTER)
|
|
|| ((params->intf->filterOut==SAP_FILTER_PERMIT)
|
|
&& Filter (FILTER_TYPE_SUPPLY,
|
|
params->intf->index, Server->Type, Server->Name))
|
|
|| ((params->intf->filterOut==SAP_FILTER_DENY)
|
|
&& !Filter (FILTER_TYPE_SUPPLY,
|
|
params->intf->index, Server->Type, Server->Name))) ){
|
|
IpxServerCpy (¶ms->packet->Entries[params->svrIdx], Server);
|
|
PUTUSHORT (Server->Type,
|
|
¶ms->packet->Entries[params->svrIdx].Type);
|
|
PUTUSHORT (IPX_MAX_HOP_COUNT,
|
|
¶ms->packet->Entries[params->svrIdx].HopCount);
|
|
|
|
params->svrIdx += 1;
|
|
// Trace (DEBUG_ENTRIES, "\tAdding server, type: %04x, name: %.48s, hops: %d.",
|
|
// Server->Type, Server->Name, Server->HopCount);
|
|
if (params->svrIdx>=IPX_SAP_MAX_ENTRY)
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
#undef params
|
|
return FALSE;
|
|
}
|
|
|
|
/*++
|
|
*******************************************************************
|
|
G e t N e a r e s t F i l t e r
|
|
|
|
Routine Description:
|
|
Server enumeration callback proc that gets internal server if there is one or
|
|
server with lowest hop count not on the local interface
|
|
Arguments:
|
|
CBParam - enumeration callback parameter (param block above)
|
|
Server, InterfaceIndex, Protocol, AdvertisingNode, Flags - server info
|
|
Return Value:
|
|
TRUE (to stop enumeration) when it finds first internal server,
|
|
FALSE otherwise
|
|
*******************************************************************
|
|
--*/
|
|
BOOL
|
|
GetNearestFilter (
|
|
IN LPVOID CBParam,
|
|
IN OUT PIPX_SERVER_ENTRY_P Server,
|
|
IN ULONG InterfaceIndex,
|
|
IN ULONG Protocol,
|
|
IN PUCHAR AdvertisingNode,
|
|
IN INT Flags
|
|
) {
|
|
#define params ((PGN_FILTER_PARAMS)CBParam)
|
|
|
|
if (((InterfaceIndex==INTERNAL_INTERFACE_INDEX)
|
|
&& !(Flags&SDB_DONT_RESPOND_NODE_FLAG)
|
|
&& (IpxNetCmp (Server->Network, IPX_INVALID_NET)!=0)
|
|
&& ((Protocol==IPX_PROTOCOL_LOCAL)
|
|
|| Routing
|
|
|| RespondForInternalServers))
|
|
|| ((InterfaceIndex!=params->intf->index)
|
|
&& (Server->HopCount<params->localHopCount))) {
|
|
if ((params->intf->filterOut==SAP_DONT_FILTER)
|
|
|| ((params->intf->filterOut==SAP_FILTER_PERMIT)
|
|
&& Filter (FILTER_TYPE_SUPPLY,
|
|
params->intf->index, Server->Type, Server->Name))
|
|
|| ((params->intf->filterOut==SAP_FILTER_DENY)
|
|
&& !Filter (FILTER_TYPE_SUPPLY,
|
|
params->intf->index, Server->Type, Server->Name))) {
|
|
IpxServerCpy (¶ms->packet->Entries[0], Server);
|
|
PUTUSHORT (Server->Type, ¶ms->packet->Entries[0].Type);
|
|
PUTUSHORT (Server->HopCount+1,
|
|
¶ms->packet->Entries[0].HopCount);
|
|
// Trace (DEBUG_ENTRIES, "\tGetting server, type: %04x, name: %.48s, hops: %d.",
|
|
// Server->Type, Server->Name, Server->HopCount);
|
|
params->found = TRUE;
|
|
params->localHopCount = Server->HopCount;
|
|
if (InterfaceIndex==INTERNAL_INTERFACE_INDEX)
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
#undef params
|
|
return FALSE;
|
|
}
|
|
|
|
/*++
|
|
*******************************************************************
|
|
C o u n t S e r v e r s F i l t e r
|
|
|
|
Routine Description:
|
|
Server enumeration callback proc that count servers with which it
|
|
is called back
|
|
Arguments:
|
|
CBParam - pointer to counter
|
|
Server, InterfaceIndex, Protocol, AdvertisingNode, Flags - server info
|
|
Return Value:
|
|
FALSE to tell SDB to continue enumeration
|
|
*******************************************************************
|
|
--*/
|
|
BOOL
|
|
CountServersFilter (
|
|
IN LPVOID CBParam,
|
|
IN OUT PIPX_SERVER_ENTRY_P Server,
|
|
IN ULONG InterfaceIndex,
|
|
IN ULONG Protocol,
|
|
IN PUCHAR AdvertisingNode,
|
|
IN INT Flags
|
|
) {
|
|
#define count ((ULONG *)CBParam)
|
|
if (Protocol==IPX_PROTOCOL_SAP)
|
|
*count += 1;
|
|
return FALSE;
|
|
#undef count
|
|
}
|
|
|
|
|
|
VOID
|
|
AddRecvRequests (
|
|
LONG count
|
|
) {
|
|
InterlockedExchangeAdd (&WorkerQueue.WQ_RequestQuota, count);
|
|
if (InterlockedExchangeAdd (&WorkerQueue.WQ_RequestExtra, (-count))<count) {
|
|
BOOL res = SetEvent (WorkerQueue.WQ_RecvEvent);
|
|
ASSERTMSG ("Could not set recv event ", res);
|
|
}
|
|
else {
|
|
BOOL res = ResetEvent (WorkerQueue.WQ_RecvEvent);
|
|
ASSERTMSG ("Could not reset recv event ", res);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
RemoveRecvRequests (
|
|
LONG count
|
|
) {
|
|
InterlockedExchangeAdd (&WorkerQueue.WQ_RequestQuota, (-count));
|
|
if (InterlockedExchangeAdd (&WorkerQueue.WQ_RequestExtra, count)>(-count)) {
|
|
BOOL res = ResetEvent (WorkerQueue.WQ_RecvEvent);
|
|
ASSERTMSG ("Could not reset recv event ", res);
|
|
}
|
|
}
|
|
|
|
|
|
/*++
|
|
*******************************************************************
|
|
I n i t R e q I t e m
|
|
|
|
Routine Description:
|
|
Allocate and initialize IO request item
|
|
Enqueue the request
|
|
Arguments:
|
|
None
|
|
Return Value:
|
|
NO_ERROR - item was initialized and enqueued OK
|
|
other - operation failed (windows error code)
|
|
|
|
*******************************************************************
|
|
--*/
|
|
DWORD
|
|
InitReqItem (
|
|
VOID
|
|
) {
|
|
PREQ_ITEM reqItem;
|
|
|
|
do {
|
|
if (InterlockedDecrement (&WorkerQueue.WQ_RequestQuota)<0) {
|
|
InterlockedIncrement (&WorkerQueue.WQ_RequestQuota);
|
|
return NO_ERROR;
|
|
}
|
|
|
|
if (!AllocateWorker (reqItem, REQ_ITEM)) {
|
|
Trace (DEBUG_FAILURES,
|
|
"File: %s, line %ld. Could not allocate request item (gle:%ld).",
|
|
__FILE__, __LINE__, GetLastError ());
|
|
InterlockedIncrement (&WorkerQueue.WQ_RequestQuota);
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
reqItem->iow.worker = ProcessReqItem;
|
|
reqItem->iow.io.buffer = (PUCHAR)&reqItem->packet;
|
|
reqItem->iow.io.cbBuffer = sizeof (reqItem->packet);
|
|
Trace (DEBUG_REQ, "Generated receive request: %08lx.", reqItem);
|
|
EnqueueRecvRequest (&reqItem->iow.io);
|
|
}
|
|
while (InterlockedIncrement (&WorkerQueue.WQ_RequestExtra)<0);
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
/*++
|
|
*******************************************************************
|
|
P r o c e s s R e q I t e m
|
|
|
|
Routine Description:
|
|
Process received request
|
|
Arguments:
|
|
worker - pointer to work item to process
|
|
Return Value:
|
|
None
|
|
|
|
*******************************************************************
|
|
--*/
|
|
VOID APIENTRY
|
|
ProcessReqItem (
|
|
PVOID worker
|
|
) {
|
|
PREQ_ITEM reqItem = CONTAINING_RECORD (worker, REQ_ITEM, iow.worker);
|
|
INT i;
|
|
PINTERFACE_DATA intf;
|
|
LONG count;
|
|
|
|
Trace (DEBUG_REQ, "Processing received request item %08lx on adpt: %d.",
|
|
reqItem, reqItem->iow.io.adpt);
|
|
|
|
count = InterlockedDecrement (&WorkerQueue.WQ_RequestExtra);
|
|
|
|
if ((OperationalState==OPER_STATE_UP)
|
|
&& (reqItem->iow.io.status==NO_ERROR)) {
|
|
|
|
if (count<0) {
|
|
BOOL res = SetEvent (WorkerQueue.WQ_RecvEvent);
|
|
ASSERTMSG ("Failed to set recv event ", res);
|
|
}
|
|
|
|
intf = GetInterfaceReference (reqItem->iow.io.adpt);
|
|
if (intf!=NULL) {
|
|
PSAP_BUFFER packet = &reqItem->packet;
|
|
if ((IpxNodeCmp (packet->Src.Node, intf->adapter.LocalNode)!=0)
|
|
|| (IpxSockCmp (packet->Src.Socket, IPX_SAP_SOCKET)!=0)
|
|
|| (IpxNetCmp (packet->Src.Network, intf->adapter.Network)!=0)) {
|
|
InterlockedIncrement (&intf->stats.SapIfInputPackets);
|
|
packet->Length = GETUSHORT(&packet->Length);
|
|
if (packet->Length>reqItem->iow.io.cbBuffer)
|
|
packet->Length = (USHORT)reqItem->iow.io.cbBuffer;
|
|
|
|
if (reqItem->iow.io.status==NO_ERROR) {
|
|
if (packet->Length
|
|
>= (FIELD_OFFSET (SAP_BUFFER, Operation)
|
|
+sizeof(packet->Operation))) {
|
|
packet->Operation = GETUSHORT(&packet->Operation);
|
|
switch (packet->Operation) {
|
|
case SAP_GENERAL_REQ:
|
|
Trace (DEBUG_REQ, "\tGeneral request received for type: %04x.",
|
|
GETUSHORT (&packet->Entries[0].Type));
|
|
if (intf->info.Supply==ADMIN_STATE_ENABLED) {
|
|
PIPX_SERVER_ENTRY_P pEntry = packet->Entries;
|
|
if (packet->Length >= (FIELD_OFFSET (
|
|
SAP_BUFFER, Entries[0].Type)
|
|
+sizeof (pEntry->Type))) {
|
|
pEntry->Type = GETUSHORT (&pEntry->Type);
|
|
InitRespItem (intf,
|
|
pEntry->Type,
|
|
&packet->Src,
|
|
memcmp (
|
|
packet->Dst.Node,
|
|
IPX_BCAST_NODE,
|
|
sizeof (IPX_BCAST_NODE))
|
|
==0);
|
|
}
|
|
}
|
|
break;
|
|
case SAP_GENERAL_RESP:
|
|
Trace (DEBUG_REQ, "\tGeneral response received.");
|
|
if (intf->info.Listen==ADMIN_STATE_ENABLED) {
|
|
PIPX_SERVER_ENTRY_P pEntry = packet->Entries;
|
|
for (i=0; (i<IPX_SAP_MAX_ENTRY)
|
|
&& ((PUCHAR)&pEntry[1]-(PUCHAR)packet
|
|
<=packet->Length);
|
|
i++,pEntry++) {
|
|
pEntry->Type = GETUSHORT (&pEntry->Type);
|
|
if ((intf->filterIn==SAP_DONT_FILTER)
|
|
|| ((intf->filterIn==SAP_FILTER_PERMIT)
|
|
&& Filter (FILTER_TYPE_LISTEN,
|
|
intf->index,
|
|
pEntry->Type, pEntry->Name))
|
|
|| ((intf->filterIn==SAP_FILTER_DENY)
|
|
&& !Filter (FILTER_TYPE_LISTEN,
|
|
intf->index,
|
|
pEntry->Type, pEntry->Name))) {
|
|
if ((IpxNodeCmp (packet->Src.Node, intf->adapter.LocalNode)!=0)
|
|
|| (IpxNetCmp (packet->Src.Network, intf->adapter.Network)!=0)) {
|
|
USHORT Metric;
|
|
if (GetServerMetric (pEntry, &Metric)==NO_ERROR)
|
|
pEntry->HopCount = GETUSHORT (&pEntry->HopCount);
|
|
else
|
|
pEntry->HopCount = IPX_MAX_HOP_COUNT;
|
|
UpdateServer (
|
|
pEntry,
|
|
intf->index,
|
|
IPX_PROTOCOL_SAP,
|
|
(intf->info.PeriodicUpdateInterval!=MAXULONG)
|
|
? (intf->info.PeriodicUpdateInterval
|
|
*intf->info.AgeIntervalMultiplier)
|
|
: INFINITE,
|
|
packet->Src.Node,
|
|
0,
|
|
NULL
|
|
);
|
|
}
|
|
else {
|
|
if (GETUSHORT (&pEntry->HopCount)<IPX_MAX_HOP_COUNT)
|
|
pEntry->HopCount = 0;
|
|
else
|
|
pEntry->HopCount = IPX_MAX_HOP_COUNT;
|
|
IpxNetCpy (pEntry->Network, INTERNAL_IF_NET);
|
|
IpxNodeCpy (pEntry->Node, INTERNAL_IF_NODE);
|
|
UpdateServer (
|
|
pEntry,
|
|
INTERNAL_INTERFACE_INDEX,
|
|
IPX_PROTOCOL_SAP,
|
|
ServerAgingTimeout*60,
|
|
IPX_BCAST_NODE,
|
|
0,
|
|
NULL
|
|
);
|
|
}
|
|
// Trace (DEBUG_ENTRIES, "\tInserting server,"
|
|
// " type: %04x, hops: %d, name: %.48s.",
|
|
// pEntry->Type,
|
|
// pEntry->HopCount,
|
|
// pEntry->Name);
|
|
if (((intf->stats.SapIfOperState!=OPER_STATE_UP)
|
|
|| (OperationalState!=OPER_STATE_UP))
|
|
&& (IpxNetCmp (pEntry->Network, INTERNAL_IF_NET)!=0)) {
|
|
pEntry->HopCount = IPX_MAX_HOP_COUNT;
|
|
UpdateServer (
|
|
pEntry,
|
|
intf->index,
|
|
IPX_PROTOCOL_SAP,
|
|
INFINITE,
|
|
packet->Src.Node,
|
|
0,
|
|
NULL
|
|
);
|
|
break;
|
|
}
|
|
} // End if filter path
|
|
} // end for
|
|
|
|
} // end if Listening
|
|
break;
|
|
|
|
case SAP_GET_NEAREST_REQ:
|
|
Trace (DEBUG_REQ, "\tGet nearest server request received.");
|
|
if (intf->info.GetNearestServerReply==ADMIN_STATE_ENABLED) {
|
|
PIPX_SERVER_ENTRY_P pEntry = packet->Entries;
|
|
if (packet->Length >= (FIELD_OFFSET (
|
|
SAP_BUFFER, Entries[0].Type)
|
|
+sizeof (pEntry->Type))) {
|
|
pEntry->Type = GETUSHORT (&pEntry->Type);
|
|
InitGnearItem (intf, pEntry->Type, &packet->Src);
|
|
}
|
|
}
|
|
break;
|
|
case SAP_GET_NEAREST_RESP:
|
|
Trace (DEBUG_FAILURES, "\tGet nearest server response received"
|
|
" from %.2x%.2x%.2x%.2x.%.2x%.2x%.2x%.2x%.2x%.2x.%.2x%.2x"
|
|
" (I never ask for it).",
|
|
packet->Src.Network[0], packet->Src.Network[1],
|
|
packet->Src.Network[2], packet->Src.Network[3],
|
|
packet->Src.Node[0], packet->Src.Node[1],
|
|
packet->Src.Node[2], packet->Src.Node[3],
|
|
packet->Src.Node[4], packet->Src.Node[5],
|
|
packet->Src.Socket[0], packet->Src.Socket[1]);
|
|
break;
|
|
default:
|
|
Trace (DEBUG_FAILURES, "Packet with operation %d"
|
|
" from %.2x%.2x%.2x%.2x.%.2x%.2x%.2x%.2x%.2x%.2x.%.2x%.2x ignored.",
|
|
packet->Operation,
|
|
packet->Src.Network[0], packet->Src.Network[1],
|
|
packet->Src.Network[2], packet->Src.Network[3],
|
|
packet->Src.Node[0], packet->Src.Node[1],
|
|
packet->Src.Node[2], packet->Src.Node[3],
|
|
packet->Src.Node[4], packet->Src.Node[5],
|
|
packet->Src.Socket[0], packet->Src.Socket[1]);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
Trace (DEBUG_FAILURES, "File: %s, line %ld. Invalid packet.", __FILE__, __LINE__);
|
|
}
|
|
// else Receive failure - reported by io layer
|
|
}
|
|
// else Loopback packet
|
|
ReleaseInterfaceReference (intf);
|
|
}
|
|
// else Unknown interface - reported by io layer
|
|
|
|
if (InterlockedIncrement (&WorkerQueue.WQ_RequestExtra)<=0) {
|
|
Trace (DEBUG_REQ, "Requeing receive request item %08lx.", reqItem);
|
|
reqItem->iow.io.cbBuffer = sizeof (reqItem->packet);
|
|
EnqueueRecvRequest (&reqItem->iow.io);
|
|
return;
|
|
}
|
|
else
|
|
InterlockedDecrement (&WorkerQueue.WQ_RequestExtra);
|
|
}
|
|
// else Packet received with error or OperationalState is not UP
|
|
|
|
Trace (DEBUG_REQ, "Freeing receive request item %08lx.", reqItem);
|
|
InterlockedIncrement (&WorkerQueue.WQ_RequestQuota);
|
|
DeallocateWorker (reqItem);
|
|
}
|
|
|
|
VOID APIENTRY
|
|
SendResponse (
|
|
PRESP_ITEM respItem
|
|
) {
|
|
GR_FILTER_PARAMS params;
|
|
|
|
if (respItem->iow.io.status==NO_ERROR) {
|
|
Trace (DEBUG_RESP,
|
|
"Filling response item %08lx on interface: %d, for type: %04x.",
|
|
respItem,
|
|
respItem->intf->index,
|
|
respItem->svrType);
|
|
|
|
params.svrIdx = 0;
|
|
params.intf = respItem->intf;
|
|
params.packet = &respItem->packet;
|
|
params.localHopCount = IPX_MAX_HOP_COUNT-1;
|
|
params.localSvr = FALSE;
|
|
EnumerateServers (respItem->hEnum,
|
|
respItem->bcast
|
|
? SplitHorizonHopCountFilter // Bcast - use split horizon
|
|
: HopCountFilter, // Send all best servers (except duplicate entries
|
|
// on looped networks)
|
|
(LPVOID)¶ms);
|
|
|
|
respItem->iow.io.cbBuffer = FIELD_OFFSET (SAP_BUFFER, Entries[params.svrIdx]);
|
|
PUTUSHORT (respItem->iow.io.cbBuffer, &respItem->packet.Length);
|
|
respItem->iow.io.adpt = respItem->intf->adapter.AdapterIndex;
|
|
|
|
if ((params.svrIdx!=0)
|
|
&& (respItem->intf->stats.SapIfOperState==OPER_STATE_UP)
|
|
&& (OperationalState==OPER_STATE_UP)) {
|
|
EnqueueSendRequest (&respItem->iow.io);
|
|
return;
|
|
}
|
|
}
|
|
|
|
Trace (DEBUG_RESP,
|
|
"Freeing general response item %08lx for interface: %d.",
|
|
respItem, respItem->intf->index);
|
|
ReleaseInterfaceReference (respItem->intf);
|
|
DeleteListEnumerator (respItem->hEnum);
|
|
DeallocateWorker (respItem);
|
|
}
|
|
|
|
|
|
/*++
|
|
*******************************************************************
|
|
I n i t R e s p I t e m
|
|
|
|
Routine Description:
|
|
Allocate and initialize SAP response item
|
|
Calls ProcessRespIOItem to fill the packet and send it
|
|
Arguments:
|
|
intf - pointer to interface control block to send on
|
|
svrType - type of servers to put in response packet
|
|
dst - where to send the response packet
|
|
bcast - are we responding to broadcasted request
|
|
Return Value:
|
|
NO_ERROR - item was initialized and enqueued OK
|
|
other - operation failed (windows error code)
|
|
|
|
*******************************************************************
|
|
--*/
|
|
DWORD
|
|
InitRespItem (
|
|
PINTERFACE_DATA intf,
|
|
USHORT svrType,
|
|
PIPX_ADDRESS_BLOCK dst,
|
|
BOOL bcast
|
|
) {
|
|
PRESP_ITEM respItem;
|
|
DWORD status;
|
|
|
|
if (!AllocateWorker (respItem, RESP_ITEM)) {
|
|
Trace (DEBUG_FAILURES,
|
|
"File: %s, line %ld. Could not allocate response item (gle:%ld).",
|
|
__FILE__, __LINE__, GetLastError ());
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
AcquireInterfaceReference (intf); // Make sure interface block is locked
|
|
respItem->hEnum = CreateListEnumerator (
|
|
(svrType!=0xFFFF)
|
|
? SDB_TYPE_LIST_LINK // Just servers of one type
|
|
: SDB_HASH_TABLE_LINK, // All servers
|
|
svrType,
|
|
NULL,
|
|
(!Routing && bcast) // Respond with only local
|
|
// servers if not routing and
|
|
// request was a broadcast
|
|
? INTERNAL_INTERFACE_INDEX
|
|
: INVALID_INTERFACE_INDEX,
|
|
0xFFFFFFFF,
|
|
0); // All entries, so we can
|
|
// detect duplicate servers on looped networks
|
|
if (respItem->hEnum==NULL) {
|
|
status = GetLastError ();
|
|
ReleaseInterfaceReference (intf);
|
|
DeallocateWorker (respItem);
|
|
return status;
|
|
}
|
|
|
|
respItem->iow.worker = ProcessRespIOItem;
|
|
respItem->iow.io.buffer = (PUCHAR)&respItem->packet;
|
|
respItem->iow.io.status = NO_ERROR;
|
|
respItem->tmw.worker = ProcessRespTMItem;
|
|
respItem->tmw.tm.ExpirationCheckProc = NULL;
|
|
respItem->intf = intf;
|
|
SetupIpxSapPacket(&respItem->packet, SAP_GENERAL_RESP,
|
|
dst->Network, dst->Node, dst->Socket);
|
|
respItem->svrType = svrType;
|
|
respItem->bcast = (UCHAR)bcast;
|
|
|
|
Trace (DEBUG_RESP, "Generated general response item %08lx for interface %d.",
|
|
respItem, respItem->intf->index);
|
|
if (DelayResponseToGeneral>0) {
|
|
Trace (DEBUG_RESP,
|
|
"Delaying general response item %08lx for interface: %d.",
|
|
respItem, respItem->intf->index);
|
|
respItem->tmw.tm.dueTime = GetTickCount ()+DelayResponseToGeneral;
|
|
AddHRTimerRequest (&respItem->tmw.tm);
|
|
}
|
|
else
|
|
SendResponse (respItem);
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
|
|
/*++
|
|
*******************************************************************
|
|
P r o c e s s R e s p I O I t e m
|
|
|
|
Routine Description:
|
|
Generate and send response packet
|
|
Arguments:
|
|
worker - pointer to work item to process
|
|
Return Value:
|
|
None
|
|
|
|
*******************************************************************
|
|
--*/
|
|
VOID APIENTRY
|
|
ProcessRespIOItem (
|
|
PVOID worker
|
|
) {
|
|
PRESP_ITEM respItem = CONTAINING_RECORD (worker, RESP_ITEM, iow.worker);
|
|
|
|
Trace (DEBUG_RESP,
|
|
"Processing general response tm item %08lx on interface: %d.",
|
|
respItem, respItem->intf->index);
|
|
if (respItem->iow.io.status==NO_ERROR)
|
|
InterlockedIncrement (&respItem->intf->stats.SapIfOutputPackets);
|
|
|
|
if ( (respItem->intf->stats.SapIfOperState==OPER_STATE_UP)
|
|
&& (OperationalState==OPER_STATE_UP)) {
|
|
if (GetTickCount()-respItem->iow.io.compTime<IPX_SAP_INTERPACKET_GAP) {
|
|
respItem->tmw.tm.dueTime = respItem->iow.io.compTime
|
|
+ IPX_SAP_INTERPACKET_GAP;
|
|
AddHRTimerRequest (&respItem->tmw.tm);
|
|
}
|
|
else
|
|
SendResponse (respItem);
|
|
}
|
|
else {
|
|
Trace (DEBUG_RESP,
|
|
"Freeing general response item %08lx for interface: %d.",
|
|
respItem, respItem->intf->index);
|
|
ReleaseInterfaceReference (respItem->intf);
|
|
DeleteListEnumerator (respItem->hEnum);
|
|
DeallocateWorker (respItem);
|
|
}
|
|
}
|
|
|
|
|
|
VOID APIENTRY
|
|
ProcessRespTMItem (
|
|
PVOID worker
|
|
) {
|
|
PRESP_ITEM respItem = CONTAINING_RECORD (worker, RESP_ITEM, tmw.worker);
|
|
Trace (DEBUG_RESP,
|
|
"Processing general response tm item %08lx on interface: %d.",
|
|
respItem, respItem->intf->index);
|
|
if ( (respItem->intf->stats.SapIfOperState==OPER_STATE_UP)
|
|
&& (OperationalState==OPER_STATE_UP)) {
|
|
SendResponse (respItem);
|
|
}
|
|
else {
|
|
Trace (DEBUG_RESP,
|
|
"Freeing general response item %08lx for interface: %d.",
|
|
respItem, respItem->intf->index);
|
|
ReleaseInterfaceReference (respItem->intf);
|
|
DeleteListEnumerator (respItem->hEnum);
|
|
DeallocateWorker (respItem);
|
|
}
|
|
}
|
|
|
|
|
|
/*++
|
|
*******************************************************************
|
|
D e l e t e B c a s t I t e m
|
|
|
|
Routine Description:
|
|
Disposes of resources associated with broadcast work item
|
|
Arguments:
|
|
bcastItem - pointer to broadcast work item
|
|
Return Value:
|
|
None
|
|
*******************************************************************
|
|
--*/
|
|
VOID
|
|
DeleteBcastItem (
|
|
PBCAST_ITEM bcastItem
|
|
) {
|
|
Trace (DEBUG_BCAST, "Freeing broadcast item %08lx for interface: %d.",
|
|
bcastItem, bcastItem->intf->index);
|
|
if (bcastItem->chngEnum!=NULL)
|
|
DeleteListEnumerator (bcastItem->chngEnum);
|
|
if ((bcastItem->perdEnum!=NULL)
|
|
&& (bcastItem->perdEnum!=INVALID_HANDLE_VALUE))
|
|
DeleteListEnumerator (bcastItem->perdEnum);
|
|
ReleaseInterfaceReference (bcastItem->intf);
|
|
DeallocateWorker (bcastItem);
|
|
}
|
|
|
|
/*++
|
|
*******************************************************************
|
|
D o B r o a d c a s t
|
|
|
|
Routine Description:
|
|
Check for and broadcast changed servers
|
|
Check if it is time to do periodic broadcast and start it if so
|
|
Arguments:
|
|
bcastItem - pointer to broadcast work item
|
|
Return Value:
|
|
None
|
|
*******************************************************************
|
|
--*/
|
|
VOID
|
|
DoBroadcast (
|
|
PBCAST_ITEM bcastItem
|
|
) {
|
|
GR_FILTER_PARAMS params;
|
|
BOOLEAN periodic;
|
|
|
|
params.svrIdx = bcastItem->delayedSvrCount;
|
|
params.intf = bcastItem->intf;
|
|
params.packet = &bcastItem->packet;
|
|
|
|
if ( ((bcastItem->intf->stats.SapIfOperState==OPER_STATE_UP)
|
|
&& ((bcastItem->perdEnum!=NULL) // we are already in the middle of
|
|
// broadcast
|
|
|| IsLater(GetTickCount (),bcastItem->nextBcast))) // or it is
|
|
// time to start a new one
|
|
|| ((bcastItem->intf->stats.SapIfOperState==OPER_STATE_STOPPING)
|
|
// or interface is being stopped, so
|
|
// we need to broadcast the whole
|
|
// table as deleted
|
|
&& (bcastItem->perdEnum!=INVALID_HANDLE_VALUE))
|
|
// This value in the periodic
|
|
// enumeration handle field means
|
|
// that we are already done
|
|
// with this broadcast
|
|
) {
|
|
|
|
Trace (DEBUG_BCAST, "Checking for deleted servers on interface: %d.",
|
|
params.intf->index);
|
|
EnumerateServers (bcastItem->chngEnum, SplitHorizonDeletedFilter, ¶ms);
|
|
|
|
if (bcastItem->perdEnum==NULL) { // Need to start new boradcast
|
|
Trace (DEBUG_BCAST, "Starting broadcast enumeration on interface: %d (@ %ld).",
|
|
bcastItem->intf->index, bcastItem->nextBcast);
|
|
if (Routing) // Router installation: broadcast all servers
|
|
bcastItem->perdEnum = CreateListEnumerator (
|
|
SDB_HASH_TABLE_LINK,
|
|
0xFFFF,
|
|
NULL,
|
|
INVALID_INTERFACE_INDEX,
|
|
0xFFFFFFFF,
|
|
0);
|
|
else // Standalone SAP agent: only internal servers
|
|
bcastItem->perdEnum = CreateListEnumerator (
|
|
SDB_INTF_LIST_LINK,
|
|
0xFFFF,
|
|
NULL,
|
|
INTERNAL_INTERFACE_INDEX,
|
|
0xFFFFFFFF,
|
|
0);
|
|
|
|
|
|
// Set the time for next broadcast
|
|
bcastItem->nextBcast +=
|
|
bcastItem->intf->info.PeriodicUpdateInterval*1000;
|
|
}
|
|
|
|
if ((params.svrIdx<IPX_SAP_MAX_ENTRY)
|
|
&& (bcastItem->perdEnum!=NULL)
|
|
&& (bcastItem->perdEnum!=INVALID_HANDLE_VALUE)) {
|
|
Trace (DEBUG_BCAST, "Adding broadcast servers on interface: %d.",
|
|
params.intf->index);
|
|
params.localHopCount = IPX_MAX_HOP_COUNT-1;
|
|
params.localSvr = FALSE;
|
|
if (!EnumerateServers (bcastItem->perdEnum,
|
|
SplitHorizonHopCountFilter,
|
|
¶ms)) {
|
|
// All broadcast servers sent, dispose enumeration handle
|
|
DeleteListEnumerator (bcastItem->perdEnum);
|
|
Trace (DEBUG_BCAST, "Broadcast enumeration finished on interface:"
|
|
" %d (@ %ld, next @ %ld).",
|
|
bcastItem->intf->index,
|
|
GetTickCount (),
|
|
bcastItem->nextBcast);
|
|
if (bcastItem->intf->stats.SapIfOperState==OPER_STATE_UP)
|
|
bcastItem->perdEnum = NULL;
|
|
else // Nore that broadcast of the whole table is done
|
|
bcastItem->perdEnum = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
if (bcastItem->intf->stats.SapIfOperState==OPER_STATE_STOPPING) {
|
|
INT i;
|
|
for (i=0; i<params.svrIdx; i++) {
|
|
PUTUSHORT (IPX_MAX_HOP_COUNT, &bcastItem->packet.Entries[i].HopCount);
|
|
}
|
|
}
|
|
periodic = TRUE;
|
|
}
|
|
else
|
|
periodic = FALSE;
|
|
|
|
if ((params.svrIdx<IPX_SAP_MAX_ENTRY)
|
|
&& (bcastItem->intf->stats.SapIfOperState==OPER_STATE_UP)) {
|
|
if (bcastItem->delayedSvrCount==0)
|
|
bcastItem->delayedSendTime = GetTickCount ()+DelayChangeBroadcast*1000;
|
|
Trace (DEBUG_BCAST, "Checking for changed servers on interface: %d.",
|
|
params.intf->index);
|
|
params.localHopCount = IPX_MAX_HOP_COUNT+1;
|
|
EnumerateServers (bcastItem->chngEnum, SplitHorizonFilter, ¶ms);
|
|
}
|
|
|
|
if ((params.svrIdx>0)
|
|
&& (periodic
|
|
|| (params.svrIdx==IPX_SAP_MAX_ENTRY)
|
|
|| IsLater (GetTickCount (), bcastItem->delayedSendTime))) {
|
|
bcastItem->iow.io.cbBuffer = FIELD_OFFSET (SAP_BUFFER, Entries[params.svrIdx]);
|
|
PUTUSHORT (bcastItem->iow.io.cbBuffer, &bcastItem->packet.Length);
|
|
bcastItem->iow.io.adpt = bcastItem->intf->adapter.AdapterIndex;
|
|
bcastItem->delayedSvrCount = 0;
|
|
Trace (DEBUG_BCAST, "Broadcasting %d servers on interface: %d.",
|
|
params.svrIdx, params.intf->index);
|
|
EnqueueSendRequest (&bcastItem->iow.io);
|
|
}
|
|
else if (bcastItem->intf->stats.SapIfOperState==OPER_STATE_UP) {
|
|
// Nothing to send, go wait in the timer queue
|
|
bcastItem->delayedSvrCount = params.svrIdx;
|
|
if (bcastItem->delayedSvrCount>0) {
|
|
Trace (DEBUG_BCAST, "Delaying change broadcast on interface: %d (%d servers in the packet).",
|
|
params.intf->index, bcastItem->delayedSvrCount);
|
|
bcastItem->tmw.tm.dueTime = bcastItem->delayedSendTime;
|
|
}
|
|
else {
|
|
bcastItem->tmw.tm.dueTime = bcastItem->nextBcast;
|
|
Trace (DEBUG_BCAST, "Nothing to send, waiting for next broadcast time on interface: %d.",
|
|
params.intf->index);
|
|
}
|
|
AddLRTimerRequest (&bcastItem->tmw.tm);
|
|
}
|
|
else
|
|
// Interface is down or stopping and there are no more stuff to
|
|
// broadcast, -> go away
|
|
DeleteBcastItem (bcastItem);
|
|
|
|
}
|
|
|
|
|
|
BOOL
|
|
CheckBcastInterface (
|
|
PTM_PARAM_BLOCK tm,
|
|
PVOID context
|
|
) {
|
|
PBCAST_ITEM bcastItem = CONTAINING_RECORD (tm, BCAST_ITEM, tmw.tm);
|
|
if (bcastItem->intf->stats.SapIfOperState!=OPER_STATE_UP)
|
|
return TRUE;
|
|
else if (bcastItem->intf->index!=PtrToUlong(context))
|
|
return TRUE;
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
/*++
|
|
*******************************************************************
|
|
I n i t B c a s t I t e m
|
|
|
|
Routine Description:
|
|
Allocate and initialize broadcast item
|
|
Arguments:
|
|
intf - pointer to interface control block to send on
|
|
Return Value:
|
|
NO_ERROR - item was initialized and enqueued OK
|
|
other - operation failed (windows error code)
|
|
|
|
*******************************************************************
|
|
--*/
|
|
DWORD
|
|
InitBcastItem (
|
|
PINTERFACE_DATA intf
|
|
) {
|
|
PBCAST_ITEM bcastItem;
|
|
DWORD status;
|
|
|
|
if (!AllocateWorker (bcastItem, BCAST_ITEM)) {
|
|
Trace (DEBUG_FAILURES,
|
|
"File: %s, line %ld. Could not allocate broadcast item (gle:%ld).",
|
|
__FILE__, __LINE__, GetLastError ());
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
bcastItem->chngEnum = CreateListEnumerator (
|
|
SDB_CHANGE_QUEUE_LINK,
|
|
0xFFFF,
|
|
NULL,
|
|
Routing
|
|
? INVALID_INTERFACE_INDEX
|
|
: INTERNAL_INTERFACE_INDEX,
|
|
0xFFFFFFFF,
|
|
SDB_DISABLED_NODE_FLAG);
|
|
if (bcastItem->chngEnum==NULL) {
|
|
status = GetLastError ();
|
|
DeallocateWorker (bcastItem);
|
|
return status;
|
|
}
|
|
|
|
AcquireInterfaceReference (intf);
|
|
bcastItem->intf = intf;
|
|
bcastItem->iow.worker = ProcessBcastIOItem;
|
|
bcastItem->iow.io.buffer = (PUCHAR)&bcastItem->packet;
|
|
bcastItem->tmw.worker = ProcessBcastTMItem;
|
|
bcastItem->tmw.tm.ExpirationCheckProc = CheckBcastInterface;
|
|
bcastItem->perdEnum = NULL;
|
|
bcastItem->delayedSvrCount = 0;
|
|
SetupIpxSapPacket(&bcastItem->packet, SAP_GENERAL_RESP,
|
|
bcastItem->intf->adapter.Network,
|
|
IPX_BCAST_NODE,
|
|
IPX_SAP_SOCKET);
|
|
bcastItem->nextBcast = GetTickCount ();
|
|
|
|
Trace (DEBUG_BCAST, "Generated broadcast item %08lx for interface %d.",
|
|
bcastItem, bcastItem->intf->index);
|
|
DoBroadcast (bcastItem);
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/*++
|
|
*******************************************************************
|
|
P r o c e s s B c a s t I O I t e m
|
|
|
|
Routine Description:
|
|
Processes broadcast work item that just completed send
|
|
Arguments:
|
|
worker - pointer to work item to process
|
|
Return Value:
|
|
None
|
|
|
|
*******************************************************************
|
|
--*/
|
|
VOID APIENTRY
|
|
ProcessBcastIOItem (
|
|
PVOID worker
|
|
) {
|
|
PBCAST_ITEM bcastItem = CONTAINING_RECORD (worker, BCAST_ITEM, iow.worker);
|
|
ULONG curTime = GetTickCount ();
|
|
|
|
Trace (DEBUG_BCAST, "Processing broadcast io item for interface: %d.",
|
|
bcastItem->intf->index);
|
|
// Make sure interface is still up
|
|
if (bcastItem->iow.io.status==NO_ERROR) {
|
|
InterlockedIncrement (&bcastItem->intf->stats.SapIfOutputPackets);
|
|
// Make sure we do not send periodic broadcast packets to fast
|
|
if ((curTime-bcastItem->iow.io.compTime<IPX_SAP_INTERPACKET_GAP)
|
|
&& (bcastItem->perdEnum!=NULL)) {
|
|
bcastItem->tmw.tm.dueTime = bcastItem->iow.io.compTime
|
|
+ IPX_SAP_INTERPACKET_GAP;
|
|
AddHRTimerRequest (&bcastItem->tmw.tm);
|
|
}
|
|
else
|
|
DoBroadcast (bcastItem);
|
|
}
|
|
else if (bcastItem->intf->stats.SapIfOperState==OPER_STATE_UP) {
|
|
// Last sent io failed, we better wait before sending next one
|
|
bcastItem->tmw.tm.dueTime = curTime+SAP_ERROR_COOL_OFF_TIME;
|
|
AddLRTimerRequest (&bcastItem->tmw.tm);
|
|
}
|
|
else
|
|
// Interface is stopping or down on error, go away
|
|
DeleteBcastItem (bcastItem);
|
|
}
|
|
|
|
/*++
|
|
*******************************************************************
|
|
P r o c e s s B c a s t T M I t e m
|
|
|
|
Routine Description:
|
|
Processes broadcast work item that just completed wait in timer queue
|
|
Arguments:
|
|
worker - pointer to work item to process
|
|
Return Value:
|
|
None
|
|
|
|
*******************************************************************
|
|
--*/
|
|
VOID APIENTRY
|
|
ProcessBcastTMItem (
|
|
PVOID worker
|
|
) {
|
|
PBCAST_ITEM bcastItem = CONTAINING_RECORD (worker, BCAST_ITEM, tmw.worker);
|
|
|
|
Trace (DEBUG_BCAST, "Processing broadcast tm item for interface: %d.",
|
|
bcastItem->intf->index);
|
|
if ((bcastItem->intf->stats.SapIfOperState==OPER_STATE_UP)
|
|
|| (bcastItem->intf->stats.SapIfOperState==OPER_STATE_STOPPING))
|
|
DoBroadcast (bcastItem);
|
|
else // Interface is down, go away
|
|
DeleteBcastItem (bcastItem);
|
|
|
|
}
|
|
|
|
/*++
|
|
*******************************************************************
|
|
I n i t S r e q I t e m
|
|
|
|
Routine Description:
|
|
Allocate and initialize send request item (send SAP request on interface)
|
|
Arguments:
|
|
intf - pointer to interface control block to send on
|
|
Return Value:
|
|
NO_ERROR - item was initialized and enqueued OK
|
|
other - operation failed (windows error code)
|
|
|
|
*******************************************************************
|
|
--*/
|
|
DWORD
|
|
InitSreqItem (
|
|
PINTERFACE_DATA intf
|
|
) {
|
|
PSREQ_ITEM sreqItem;
|
|
|
|
if (!AllocateWorker (sreqItem, SREQ_ITEM)) {
|
|
Trace (DEBUG_FAILURES,
|
|
"File: %s, line %ld. Could not allocate send request item (gle:%ld.",
|
|
__FILE__, __LINE__, GetLastError ());
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
AcquireInterfaceReference (intf);
|
|
sreqItem->intf = intf;
|
|
sreqItem->iow.worker = ProcessSreqItem;
|
|
sreqItem->iow.io.buffer = (PUCHAR)&sreqItem->packet;
|
|
SetupIpxSapPacket(&sreqItem->packet, SAP_GENERAL_REQ,
|
|
sreqItem->intf->adapter.Network,
|
|
IPX_BCAST_NODE,
|
|
IPX_SAP_SOCKET);
|
|
sreqItem->packet.Entries[0].Type = 0xFFFF;
|
|
sreqItem->iow.io.cbBuffer = FIELD_OFFSET (SAP_BUFFER, Entries[0].Type)
|
|
+sizeof (sreqItem->packet.Entries[0].Type);
|
|
PUTUSHORT (sreqItem->iow.io.cbBuffer, &sreqItem->packet.Length);
|
|
sreqItem->iow.io.adpt = sreqItem->intf->adapter.AdapterIndex;
|
|
|
|
Trace (DEBUG_SREQ, "Generated general request item: %08lx on interface: %d.",
|
|
sreqItem, sreqItem->intf->index);
|
|
if ((sreqItem->intf->stats.SapIfOperState==OPER_STATE_UP)
|
|
&& (OperationalState==OPER_STATE_UP)) {
|
|
EnqueueSendRequest (&sreqItem->iow.io);
|
|
return NO_ERROR;
|
|
}
|
|
else {
|
|
// Interface got changed or deleted
|
|
Trace (DEBUG_SREQ,
|
|
"Freing general request item: %08lx for changed or deleted interface %ld.",
|
|
sreqItem, sreqItem->intf->index);
|
|
ReleaseInterfaceReference (sreqItem->intf);
|
|
DeallocateWorker (sreqItem);
|
|
return ERROR_INVALID_HANDLE;
|
|
}
|
|
|
|
}
|
|
|
|
/*++
|
|
*******************************************************************
|
|
P r o c e s s S r e q I t e m
|
|
|
|
Routine Description:
|
|
Processes send request work item that just completed io
|
|
Arguments:
|
|
worker - pointer to work item to process
|
|
Return Value:
|
|
None
|
|
|
|
*******************************************************************
|
|
--*/
|
|
VOID APIENTRY
|
|
ProcessSreqItem (
|
|
PVOID worker
|
|
) {
|
|
PSREQ_ITEM sreqItem = CONTAINING_RECORD (worker, SREQ_ITEM, iow.worker);
|
|
if (sreqItem->iow.io.status==NO_ERROR)
|
|
InterlockedIncrement (&sreqItem->intf->stats.SapIfOutputPackets);
|
|
Trace (DEBUG_SREQ, "Freeing general request item %08lx.", sreqItem);
|
|
// Just release all resources
|
|
ReleaseInterfaceReference (sreqItem->intf);
|
|
DeallocateWorker (sreqItem);
|
|
}
|
|
|
|
|
|
/*++
|
|
*******************************************************************
|
|
I n i t L P C I t e m
|
|
|
|
Routine Description:
|
|
Allocate and initialize LPC work item
|
|
Arguments:
|
|
None
|
|
Return Value:
|
|
NO_ERROR - item was initialized and enqueued OK
|
|
other - operation failed (windows error code)
|
|
|
|
*******************************************************************
|
|
--*/
|
|
DWORD
|
|
InitLPCItem (
|
|
void
|
|
) {
|
|
PLPC_ITEM lpcItem;
|
|
|
|
if (!AllocateWorker (lpcItem, LPC_ITEM)) {
|
|
Trace (DEBUG_FAILURES, "File: %s, line %ld. Could not allocate lpc item (gle:%ld.",
|
|
__FILE__, __LINE__, GetLastError ());
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
lpcItem->lpcw.lpc.request = &lpcItem->request;
|
|
lpcItem->lpcw.worker = ProcessLPCItem;
|
|
Trace (DEBUG_LPCREQ, "Generated lpc request item %08lx.", lpcItem);
|
|
// Posts request and awaits completion
|
|
return ProcessLPCRequests (&lpcItem->lpcw.lpc);
|
|
}
|
|
|
|
|
|
/*++
|
|
*******************************************************************
|
|
P r o c e s s L P C I t e m
|
|
|
|
Routine Description:
|
|
Processes LPC request and sends reply
|
|
Arguments:
|
|
worker - pointer to work item to process
|
|
Return Value:
|
|
None
|
|
|
|
*******************************************************************
|
|
--*/
|
|
VOID APIENTRY
|
|
ProcessLPCItem (
|
|
PVOID worker
|
|
) {
|
|
PLPC_ITEM lpcItem = CONTAINING_RECORD (worker, LPC_ITEM, lpcw.worker);
|
|
IPX_SERVER_ENTRY_P server;
|
|
NWSAP_REPLY_MESSAGE reply;
|
|
DWORD status;
|
|
BOOL newServer;
|
|
|
|
Trace (DEBUG_LPCREQ, "Processing lpc request for client: %08lx.",
|
|
lpcItem->lpcw.lpc.client);
|
|
if (lpcItem->lpcw.lpc.client==NULL) {
|
|
Trace (DEBUG_LPCREQ, "Freeing lpc item %08lx.", lpcItem);
|
|
DeallocateWorker (lpcItem);
|
|
return;
|
|
}
|
|
|
|
|
|
switch (lpcItem->request.MessageType) {
|
|
case NWSAP_LPCMSG_ADDADVERTISE:
|
|
server.Type = lpcItem->request.Message.AdvApi.ServerType;
|
|
IpxNameCpy (server.Name, lpcItem->request.Message.AdvApi.ServerName);
|
|
IpxAddrCpy (&server, (PIPX_ADDRESS_BLOCK)lpcItem->request.Message.AdvApi.ServerAddr);
|
|
// If net or node number are not set, use internal network
|
|
// parameters that we obtained from the adapter
|
|
if ((IpxNetCmp (server.Network, IPX_INVALID_NET)==0)
|
|
|| (IpxNodeCmp (server.Node, IPX_INVALID_NODE)==0)) {
|
|
IpxNetCpy (server.Network, INTERNAL_IF_NET);
|
|
IpxNodeCpy (server.Node, INTERNAL_IF_NODE);
|
|
}
|
|
|
|
server.HopCount = 0;
|
|
status = UpdateServer (&server,
|
|
INTERNAL_INTERFACE_INDEX,
|
|
IPX_PROTOCOL_LOCAL,
|
|
INFINITE,
|
|
IPX_BCAST_NODE,
|
|
lpcItem->request.Message.AdvApi.RespondNearest
|
|
? 0
|
|
: SDB_DONT_RESPOND_NODE_FLAG,
|
|
&newServer);
|
|
switch (status) {
|
|
case NO_ERROR:
|
|
if (newServer)
|
|
reply.Error = SAPRETURN_SUCCESS;
|
|
else
|
|
reply.Error = SAPRETURN_EXISTS;
|
|
IpxAddrCpy ((PIPX_ADDRESS_BLOCK)reply.Message.AdvApi.ServerAddr, &server);
|
|
Trace (DEBUG_LPCREQ, "\t%s server: type %04x, name %.48s.",
|
|
newServer ? "added" : "updated",
|
|
server.Type, server.Name);
|
|
break;
|
|
case ERROR_NOT_ENOUGH_MEMORY:
|
|
default:
|
|
reply.Error = SAPRETURN_NOMEMORY;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case NWSAP_LPCMSG_REMOVEADVERTISE:
|
|
server.Type = lpcItem->request.Message.AdvApi.ServerType;
|
|
IpxNameCpy (server.Name, lpcItem->request.Message.AdvApi.ServerName);
|
|
IpxAddrCpy (&server, (PIPX_ADDRESS_BLOCK)lpcItem->request.Message.AdvApi.ServerAddr);
|
|
// If net or node number are not set, use internal network
|
|
// parameters that we obtained from the adapter
|
|
if ((IpxNetCmp (server.Network, IPX_INVALID_NET)==0)
|
|
|| (IpxNodeCmp (server.Node, IPX_INVALID_NODE)==0)) {
|
|
IpxNetCpy (server.Network, INTERNAL_IF_NET);
|
|
IpxNodeCpy (server.Node, INTERNAL_IF_NODE);
|
|
}
|
|
server.HopCount = IPX_MAX_HOP_COUNT;
|
|
Trace (DEBUG_LPCREQ, "About to call UpdateServer because of NWSAP_LPCMSG_REMOVEADVERTISE");
|
|
status = UpdateServer (&server,
|
|
INTERNAL_INTERFACE_INDEX,
|
|
IPX_PROTOCOL_LOCAL,
|
|
INFINITE,
|
|
IPX_BCAST_NODE,
|
|
0,
|
|
&newServer);
|
|
switch (status) {
|
|
case NO_ERROR:
|
|
if (newServer)
|
|
reply.Error = SAPRETURN_NOTEXIST;
|
|
else
|
|
reply.Error = SAPRETURN_SUCCESS;
|
|
Trace (DEBUG_LPCREQ, "\t%s server: type %04x, name %.48s.",
|
|
newServer ? "already gone" : "deleted",
|
|
server.Type, server.Name);
|
|
break;
|
|
case ERROR_NOT_ENOUGH_MEMORY:
|
|
default:
|
|
reply.Error = SAPRETURN_NOMEMORY;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case NWSAP_LPCMSG_GETOBJECTID:
|
|
if (QueryServer(
|
|
lpcItem->request.Message.BindLibApi.ObjectType,
|
|
lpcItem->request.Message.BindLibApi.ObjectName,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&reply.Message.BindLibApi.ObjectID)) {
|
|
// Trace (DEBUG_ENTRIES, "\tgot id %0lx for server: type %04x, name %.48s.",
|
|
// reply.Message.BindLibApi.ObjectID,
|
|
// lpcItem->request.Message.BindLibApi.ObjectType,
|
|
// lpcItem->request.Message.BindLibApi.ObjectName);
|
|
reply.Message.BindLibApi.ObjectID |= BINDLIB_NCP_SAP;
|
|
reply.Error = SAPRETURN_SUCCESS;
|
|
}
|
|
else {
|
|
Trace (DEBUG_LPCREQ, "\tno server: type %04x, name %.48s.",
|
|
lpcItem->request.Message.BindLibApi.ObjectType,
|
|
lpcItem->request.Message.BindLibApi.ObjectName);
|
|
switch (GetLastError ()) {
|
|
case NO_ERROR:
|
|
reply.Error = SAPRETURN_NOTEXIST;
|
|
break;
|
|
case ERROR_NOT_ENOUGH_MEMORY:
|
|
default:
|
|
reply.Error = SAPRETURN_NOMEMORY;
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case NWSAP_LPCMSG_GETOBJECTNAME:
|
|
if (((lpcItem->request.Message.BindLibApi.ObjectID
|
|
& BINDLIB_NCP_SAP)==BINDLIB_NCP_SAP)
|
|
&& (lpcItem->request.Message.BindLibApi.ObjectID
|
|
<BINDLIB_NCP_MAX_SAP)) {
|
|
reply.Message.BindLibApi.ObjectID =
|
|
lpcItem->request.Message.BindLibApi.ObjectID
|
|
& SDB_OBJECT_ID_MASK;
|
|
if (GetServerFromID(
|
|
reply.Message.BindLibApi.ObjectID,
|
|
&server,
|
|
NULL,
|
|
NULL)) {
|
|
reply.Error = SAPRETURN_SUCCESS;
|
|
reply.Message.BindLibApi.ObjectID |= BINDLIB_NCP_SAP;
|
|
reply.Message.BindLibApi.ObjectType = server.Type;
|
|
IpxNameCpy (reply.Message.BindLibApi.ObjectName, server.Name);
|
|
IpxAddrCpy ((PIPX_ADDRESS_BLOCK)reply.Message.BindLibApi.ObjectAddr, &server);
|
|
// Trace (DEBUG_ENTRIES,
|
|
// "\tgot server: type %04x, name %.48s from id %0lx.",
|
|
// reply.Message.BindLibApi.ObjectType,
|
|
// reply.Message.BindLibApi.ObjectName,
|
|
// lpcItem->request.Message.BindLibApi.ObjectID);
|
|
}
|
|
else {
|
|
switch (GetLastError ()) {
|
|
case NO_ERROR:
|
|
Trace (DEBUG_LPCREQ, "\tno server for id %0lx.",
|
|
lpcItem->request.Message.BindLibApi.ObjectID);
|
|
reply.Error = SAPRETURN_NOTEXIST;
|
|
break;
|
|
case ERROR_NOT_ENOUGH_MEMORY:
|
|
default:
|
|
reply.Error = SAPRETURN_NOMEMORY;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
Trace (DEBUG_LPCREQ, "\tInvalid object id in get name request %0lx.",
|
|
lpcItem->request.Message.BindLibApi.ObjectID);
|
|
reply.Error = SAPRETURN_NOTEXIST;
|
|
}
|
|
break;
|
|
|
|
case NWSAP_LPCMSG_SEARCH:
|
|
if ((lpcItem->request.Message.BindLibApi.ObjectID
|
|
== SDB_INVALID_OBJECT_ID)
|
|
|| (((lpcItem->request.Message.BindLibApi.ObjectID
|
|
& BINDLIB_NCP_SAP)==BINDLIB_NCP_SAP)
|
|
&& (lpcItem->request.Message.BindLibApi.ObjectID
|
|
<BINDLIB_NCP_MAX_SAP))) {
|
|
if (lpcItem->request.Message.BindLibApi.ObjectID
|
|
== SDB_INVALID_OBJECT_ID)
|
|
reply.Message.BindLibApi.ObjectID = SDB_INVALID_OBJECT_ID;
|
|
else
|
|
reply.Message.BindLibApi.ObjectID =
|
|
lpcItem->request.Message.BindLibApi.ObjectID
|
|
& SDB_OBJECT_ID_MASK;
|
|
if (GetNextServerFromID (
|
|
&reply.Message.BindLibApi.ObjectID,
|
|
lpcItem->request.Message.BindLibApi.ScanType,
|
|
&server,
|
|
NULL,
|
|
NULL)) {
|
|
reply.Message.BindLibApi.ObjectID |= BINDLIB_NCP_SAP;
|
|
reply.Error = SAPRETURN_SUCCESS;
|
|
reply.Message.BindLibApi.ObjectType = server.Type;
|
|
IpxNameCpy (reply.Message.BindLibApi.ObjectName, server.Name);
|
|
IpxAddrCpy ((PIPX_ADDRESS_BLOCK)reply.Message.BindLibApi.ObjectAddr, &server);
|
|
// Trace (DEBUG_ENTRIES,
|
|
// "\tgot next server: type %04x, name %.48s, id %0lx from id %0lx.",
|
|
// reply.Message.BindLibApi.ObjectType,
|
|
// reply.Message.BindLibApi.ObjectName,
|
|
// reply.Message.BindLibApi.ObjectID,
|
|
// lpcItem->request.Message.BindLibApi.ObjectID);
|
|
}
|
|
else {
|
|
switch (GetLastError ()) {
|
|
case NO_ERROR:
|
|
Trace (DEBUG_LPCREQ, "\tno next server for id %0lx.",
|
|
lpcItem->request.Message.BindLibApi.ObjectID);
|
|
reply.Error = SAPRETURN_NOTEXIST;
|
|
break;
|
|
case ERROR_NOT_ENOUGH_MEMORY:
|
|
default:
|
|
reply.Error = SAPRETURN_NOMEMORY;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
Trace (DEBUG_LPCREQ, "\tInvalid object id in get next request %0lx.",
|
|
lpcItem->request.Message.BindLibApi.ObjectID);
|
|
reply.Error = SAPRETURN_NOTEXIST;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
Trace (DEBUG_FAILURES, "Got unknown LPC SAP msg: %d.",
|
|
lpcItem->request.MessageType );
|
|
reply.Error = 1;
|
|
break;
|
|
}
|
|
SendLPCReply (lpcItem->lpcw.lpc.client, &lpcItem->request, &reply);
|
|
Trace (DEBUG_LPCREQ, "Freeing lpc item %08lx.", lpcItem);
|
|
DeallocateWorker (lpcItem);
|
|
}
|
|
|
|
|
|
/*++
|
|
*******************************************************************
|
|
I n i t G n e a r I t e m
|
|
|
|
Routine Description:
|
|
Allocate and initialize GETNEAREST response work item
|
|
Arguments:
|
|
intf - pointer to interface control block to send on
|
|
svrType - type of servers to put in response packet
|
|
dst - where to send the response packet
|
|
Return Value:
|
|
NO_ERROR - item was initialized and enqueued OK
|
|
other - operation failed (windows error code)
|
|
|
|
*******************************************************************
|
|
--*/
|
|
DWORD
|
|
InitGnearItem (
|
|
PINTERFACE_DATA intf,
|
|
USHORT svrType,
|
|
PIPX_ADDRESS_BLOCK dst
|
|
) {
|
|
DWORD status;
|
|
GN_FILTER_PARAMS params;
|
|
HANDLE hEnum;
|
|
PGNEAR_ITEM gnearItem;
|
|
|
|
if (!AllocateWorker (gnearItem, GNEAR_ITEM)) {
|
|
Trace (DEBUG_FAILURES,
|
|
"File: %s, line %ld. Could not allocate get nearest response item (gle:%ld.",
|
|
__FILE__, __LINE__, GetLastError ());
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
AcquireInterfaceReference (intf);
|
|
gnearItem->intf = intf;
|
|
|
|
Trace (DEBUG_GET_NEAREST,
|
|
"Generated get nearest response item %08lx for server of type: %04x on interface: %ld.",
|
|
gnearItem, svrType, intf->index);
|
|
hEnum = CreateListEnumerator (
|
|
SDB_TYPE_LIST_LINK,
|
|
svrType,
|
|
NULL,
|
|
Routing
|
|
? INVALID_INTERFACE_INDEX
|
|
: INTERNAL_INTERFACE_INDEX,
|
|
0xFFFFFFFF,
|
|
SDB_MAIN_NODE_FLAG);
|
|
if (hEnum==NULL) {
|
|
status = GetLastError ();
|
|
ReleaseInterfaceReference (intf);
|
|
DeallocateWorker (gnearItem);
|
|
return status;
|
|
}
|
|
|
|
|
|
params.found = FALSE;
|
|
params.intf = gnearItem->intf;
|
|
params.packet = &gnearItem->packet;
|
|
params.localHopCount = IPX_MAX_HOP_COUNT-1;
|
|
EnumerateServers (hEnum, GetNearestFilter, (LPVOID)¶ms);
|
|
DeleteListEnumerator (hEnum);
|
|
|
|
|
|
if (params.found) {
|
|
gnearItem->iow.worker = ProcessGnearItem;
|
|
gnearItem->iow.io.buffer = (PUCHAR)&gnearItem->packet;
|
|
gnearItem->intf = intf;
|
|
|
|
SetupIpxSapPacket(&gnearItem->packet, SAP_GET_NEAREST_RESP,
|
|
dst->Network, dst->Node, dst->Socket);
|
|
gnearItem->iow.io.cbBuffer = FIELD_OFFSET (SAP_BUFFER, Entries[1]);
|
|
PUTUSHORT (gnearItem->iow.io.cbBuffer, &gnearItem->packet.Length);
|
|
|
|
gnearItem->iow.io.adpt = gnearItem->intf->adapter.AdapterIndex;
|
|
Trace (DEBUG_GET_NEAREST,
|
|
"Sending get nearest reply (type %04x, name:%.48s, hops:%d) on interface %ld.",
|
|
GETUSHORT (&gnearItem->packet.Entries[0].Type),
|
|
gnearItem->packet.Entries[0].Name,
|
|
GETUSHORT (&gnearItem->packet.Entries[0].HopCount),
|
|
intf->index);
|
|
if ((gnearItem->intf->stats.SapIfOperState==OPER_STATE_UP)
|
|
&& (OperationalState==OPER_STATE_UP)) {
|
|
EnqueueSendRequest (&gnearItem->iow.io);
|
|
return NO_ERROR;
|
|
}
|
|
}
|
|
|
|
Trace (DEBUG_GET_NEAREST,
|
|
"Freeing get nearest response item %08lx (nothing to reply) for interface %ld.",
|
|
gnearItem, gnearItem->intf->index);
|
|
ReleaseInterfaceReference (gnearItem->intf);
|
|
DeallocateWorker (gnearItem);
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
/*++
|
|
*******************************************************************
|
|
P r o c e s s G n e a r I t e m
|
|
|
|
Routine Description:
|
|
Processes completed GETNEAREST work item
|
|
Arguments:
|
|
worker - pointer to work item to process
|
|
Return Value:
|
|
None
|
|
|
|
*******************************************************************
|
|
--*/
|
|
VOID APIENTRY
|
|
ProcessGnearItem (
|
|
PVOID worker
|
|
) {
|
|
PGNEAR_ITEM gnearItem = CONTAINING_RECORD (worker, GNEAR_ITEM, iow.worker);
|
|
|
|
if (gnearItem->iow.io.status==NO_ERROR)
|
|
InterlockedIncrement (&gnearItem->intf->stats.SapIfOutputPackets);
|
|
Trace (DEBUG_GET_NEAREST, "Freeing get nearest response item %08lx for interface %ld.",
|
|
gnearItem, gnearItem->intf->index);
|
|
ReleaseInterfaceReference (gnearItem->intf);
|
|
DeallocateWorker (gnearItem);
|
|
}
|
|
|
|
BOOL
|
|
CheckInterfaceDown (
|
|
PTM_PARAM_BLOCK tm,
|
|
PVOID context
|
|
) {
|
|
PTREQ_ITEM treqItem = CONTAINING_RECORD (tm, TREQ_ITEM, tmw.tm);
|
|
return treqItem->intf->stats.SapIfOperState!=OPER_STATE_UP;
|
|
}
|
|
|
|
|
|
|
|
/*++
|
|
*******************************************************************
|
|
I n i t T r e q I t e m
|
|
|
|
Routine Description:
|
|
Allocate and initialize triggered request item (send SAP request on interface
|
|
and wait for responces to arrive)
|
|
Arguments:
|
|
intf - pointer to interface control block to send on
|
|
Return Value:
|
|
NO_ERROR - item was initialized and enqueued OK
|
|
other - operation failed (windows error code)
|
|
|
|
*******************************************************************
|
|
--*/
|
|
DWORD
|
|
InitTreqItem (
|
|
PINTERFACE_DATA intf
|
|
) {
|
|
PTREQ_ITEM treqItem;
|
|
HANDLE enumHdl;
|
|
|
|
|
|
enumHdl = CreateListEnumerator (
|
|
SDB_INTF_LIST_LINK,
|
|
0xFFFF,
|
|
NULL,
|
|
intf->index,
|
|
IPX_PROTOCOL_SAP,
|
|
SDB_DISABLED_NODE_FLAG);
|
|
if (enumHdl==NULL)
|
|
return GetLastError ();
|
|
|
|
EnumerateServers (enumHdl, DeleteAllServersCB, enumHdl);
|
|
DeleteListEnumerator (enumHdl);
|
|
|
|
if (!AllocateWorker (treqItem, TREQ_ITEM)) {
|
|
Trace (DEBUG_FAILURES,
|
|
"File: %s, line %ld. Could not allocate triggered request item (gle:%ld).",
|
|
__FILE__, __LINE__, GetLastError ());
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
AcquireInterfaceReference (intf);
|
|
treqItem->intf = intf;
|
|
treqItem->iow.worker = ProcessTreqIOItem;
|
|
treqItem->iow.io.buffer = (PUCHAR)&treqItem->packet;
|
|
treqItem->tmw.worker = ProcessTreqTMItem;
|
|
treqItem->tmw.tm.ExpirationCheckProc = CheckInterfaceDown;
|
|
|
|
SetupIpxSapPacket(&treqItem->packet, SAP_GENERAL_REQ,
|
|
treqItem->intf->adapter.Network,
|
|
IPX_BCAST_NODE,
|
|
IPX_SAP_SOCKET);
|
|
treqItem->packet.Entries[0].Type = 0xFFFF;
|
|
treqItem->iow.io.cbBuffer = FIELD_OFFSET (SAP_BUFFER, Entries[0].Type)
|
|
+sizeof (treqItem->packet.Entries[0].Type);
|
|
PUTUSHORT (treqItem->iow.io.cbBuffer, &treqItem->packet.Length);
|
|
treqItem->iow.io.adpt = treqItem->intf->adapter.AdapterIndex;
|
|
treqItem->listenSave = treqItem->intf->info.Listen;
|
|
treqItem->intf->info.Listen = ADMIN_STATE_ENABLED;
|
|
treqItem->intervalSave = treqItem->intf->info.PeriodicUpdateInterval;
|
|
treqItem->intf->info.PeriodicUpdateInterval = MAXULONG;
|
|
treqItem->resend = 0;
|
|
treqItem->pktCount = treqItem->intf->stats.SapIfInputPackets;
|
|
|
|
|
|
Trace (DEBUG_TREQ, "Generated triggered request item %08lx on interface %d.",
|
|
treqItem, treqItem->intf->index);
|
|
if ((treqItem->intf->stats.SapIfOperState==OPER_STATE_UP)
|
|
&& (OperationalState==OPER_STATE_UP)) {
|
|
EnqueueSendRequest (&treqItem->iow.io);
|
|
return NO_ERROR;
|
|
}
|
|
else {
|
|
// Interface got changed or deleted
|
|
Trace (DEBUG_TREQ,
|
|
"Freeing triggered request item %08lx for changed or deleted interface %ld.",
|
|
treqItem, treqItem->intf->index);
|
|
treqItem->intf->info.Listen = treqItem->listenSave;
|
|
treqItem->intf->info.PeriodicUpdateInterval = treqItem->intervalSave;
|
|
ReleaseInterfaceReference (treqItem->intf);
|
|
DeallocateWorker (treqItem);
|
|
return ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
}
|
|
|
|
/*++
|
|
*******************************************************************
|
|
R e t u r n U p d a t e R e s u l t
|
|
|
|
Routine Description:
|
|
Sets up parameter block and enquues results of update to
|
|
async result queue
|
|
Arguments:
|
|
treqItem - pointer to triggered request item that has completed the update
|
|
status - result of update performted by treqItem
|
|
Return Value:
|
|
NO_ERROR - item was initialized and enqueued OK
|
|
other - operation failed (windows error code)
|
|
|
|
*******************************************************************
|
|
--*/
|
|
VOID
|
|
ReturnUpdateResult (
|
|
PTREQ_ITEM treqItem,
|
|
DWORD status
|
|
) {
|
|
Trace (DEBUG_TREQ, "Reporting triggered request result (res:%d, count:%d)"
|
|
" for interface: %d.",
|
|
status,
|
|
treqItem->pktCount,
|
|
treqItem->intf->index);
|
|
treqItem->ar.event = UPDATE_COMPLETE;
|
|
treqItem->ar.message.UpdateCompleteMessage.InterfaceIndex
|
|
= treqItem->intf->index;
|
|
treqItem->ar.message.UpdateCompleteMessage.UpdateType = DEMAND_UPDATE_SERVICES;
|
|
treqItem->ar.message.UpdateCompleteMessage.UpdateStatus = status;
|
|
treqItem->ar.freeRsltCB = &FreeTreqItem;
|
|
|
|
treqItem->intf->info.Listen = treqItem->listenSave;
|
|
treqItem->intf->info.PeriodicUpdateInterval = treqItem->intervalSave;
|
|
ReleaseInterfaceReference (treqItem->intf);
|
|
|
|
EnqueueResult (&treqItem->ar);
|
|
}
|
|
|
|
/*++
|
|
*******************************************************************
|
|
P r o c e s s T r e q I O I t e m
|
|
|
|
Routine Description:
|
|
Processes triggered request work item that just completed io
|
|
Arguments:
|
|
worker - pointer to work item to process
|
|
Return Value:
|
|
None
|
|
|
|
*******************************************************************
|
|
--*/
|
|
VOID APIENTRY
|
|
ProcessTreqIOItem (
|
|
PVOID worker
|
|
) {
|
|
PTREQ_ITEM treqItem = CONTAINING_RECORD (worker, TREQ_ITEM, iow.worker);
|
|
HANDLE hEnum;
|
|
|
|
if (treqItem->iow.io.status==NO_ERROR)
|
|
InterlockedIncrement (&treqItem->intf->stats.SapIfOutputPackets);
|
|
|
|
Trace (DEBUG_TREQ, "Processing triggered request io item for interface: %d.",
|
|
treqItem->intf->index);
|
|
if ((treqItem->intf->stats.SapIfOperState==OPER_STATE_UP)
|
|
&& (OperationalState==OPER_STATE_UP)) {
|
|
treqItem->resend += 1;
|
|
treqItem->tmw.tm.dueTime = GetTickCount ()
|
|
+ TriggeredUpdateCheckInterval*1000;
|
|
AddLRTimerRequest (&treqItem->tmw.tm);
|
|
return;
|
|
}
|
|
|
|
ReturnUpdateResult (treqItem, ERROR_CAN_NOT_COMPLETE);
|
|
}
|
|
|
|
/*++
|
|
*******************************************************************
|
|
P r o c e s s T r e q T M I t e m
|
|
|
|
Routine Description:
|
|
Processes triggered request work item that just completed timer wait
|
|
Arguments:
|
|
worker - pointer to work item to process
|
|
Return Value:
|
|
None
|
|
|
|
*******************************************************************
|
|
--*/
|
|
VOID APIENTRY
|
|
ProcessTreqTMItem (
|
|
PVOID worker
|
|
) {
|
|
PTREQ_ITEM treqItem = CONTAINING_RECORD (worker, TREQ_ITEM, tmw.worker);
|
|
ULONG count = treqItem->intf->stats.SapIfInputPackets;
|
|
|
|
Trace (DEBUG_TREQ, "Processing triggered request tm item for interface: %d.",
|
|
treqItem->intf->index);
|
|
if ((treqItem->intf->stats.SapIfOperState==OPER_STATE_UP)
|
|
&& (OperationalState==OPER_STATE_UP)) {
|
|
if (treqItem->pktCount!=count) {
|
|
Trace (DEBUG_TREQ,
|
|
"\t%d more packets received during last check period.",
|
|
treqItem->intf->stats.SapIfInputPackets - treqItem->pktCount);
|
|
treqItem->pktCount = count;
|
|
treqItem->tmw.tm.dueTime = GetTickCount ()
|
|
+ TriggeredUpdateCheckInterval*1000;
|
|
AddLRTimerRequest (&treqItem->tmw.tm);
|
|
}
|
|
else if (treqItem->resend<MaxTriggeredUpdateRequests) {
|
|
Trace (DEBUG_TREQ,
|
|
"\tresending update request (%d request).",
|
|
treqItem->resend+1);
|
|
treqItem->iow.io.cbBuffer = FIELD_OFFSET (SAP_BUFFER, Entries[0].Type)
|
|
+sizeof (treqItem->packet.Entries[0].Type);
|
|
EnqueueSendRequest (&treqItem->iow.io);
|
|
}
|
|
else
|
|
ReturnUpdateResult (treqItem, NO_ERROR);
|
|
return;
|
|
}
|
|
|
|
ReturnUpdateResult (treqItem, ERROR_CAN_NOT_COMPLETE);
|
|
}
|
|
|
|
/*++
|
|
*******************************************************************
|
|
P r o c e s s T r e q A R I t e m
|
|
|
|
Routine Description:
|
|
Processes triggered request work item that was reported to client
|
|
in result queue
|
|
Arguments:
|
|
worker - pointer to work item to process
|
|
Return Value:
|
|
None
|
|
|
|
*******************************************************************
|
|
--*/
|
|
VOID
|
|
FreeTreqItem (
|
|
PAR_PARAM_BLOCK rslt
|
|
) {
|
|
PTREQ_ITEM treqItem = CONTAINING_RECORD (rslt, TREQ_ITEM, ar);
|
|
|
|
Trace (DEBUG_TREQ, "Freeing triggered request item %08lx.", treqItem);
|
|
DeallocateWorker (treqItem);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*++
|
|
*******************************************************************
|
|
S a p B u i l d I n t e r n a l U p d a t e L i s t F i l t e r
|
|
|
|
Routine Description:
|
|
Server enumeration callback proc createas a list of local servers
|
|
that need to have their internal network numbers updated.
|
|
|
|
Arguments:
|
|
CBParam - pointer to a list of SERVER_INTERNAL_UPDATE_NODE's
|
|
|
|
Return Value:
|
|
TRUE (to stop enumeration)
|
|
FALSE otherwise
|
|
*******************************************************************
|
|
--*/
|
|
BOOL SapBuildInternalUpdateListFilter (
|
|
IN LPVOID CBParam,
|
|
IN OUT PIPX_SERVER_ENTRY_P Server,
|
|
IN ULONG InterfaceIndex,
|
|
IN ULONG Protocol,
|
|
IN PUCHAR AdvertisingNode,
|
|
IN INT Flags)
|
|
{
|
|
IPX_SERVER_ENTRY_P TempServer;
|
|
SERVER_INTERNAL_UPDATE_NODE * pNew, **ppList;
|
|
|
|
// Get the list that we're dealing with
|
|
ppList = (SERVER_INTERNAL_UPDATE_NODE**)CBParam;
|
|
|
|
// If this is a local server with an out of date network number
|
|
// stored, then add it to the list of servers to update.
|
|
if (InterfaceIndex == INTERNAL_INTERFACE_INDEX) {
|
|
if (IpxNetCmp (Server->Network, INTERNAL_IF_NET) != 0) {
|
|
// Send some trace
|
|
Trace (DEBUG_SERVERDB, "Updating local server: %s %x%x%x%x:%x%x%x%x%x%x:%x%x",
|
|
Server->Name,
|
|
Server->Network[0], Server->Network[1], Server->Network[2], Server->Network[3],
|
|
Server->Node[0], Server->Node[1], Server->Node[2], Server->Node[3], Server->Node[4], Server->Node[5],
|
|
Server->Socket[0], Server->Socket[1]
|
|
);
|
|
|
|
// Create and initialize the new node
|
|
pNew = HeapAlloc (ServerTable.ST_Heap, 0, sizeof (SERVER_INTERNAL_UPDATE_NODE));
|
|
if (!pNew)
|
|
return TRUE;
|
|
CopyMemory (&(pNew->Server), Server, sizeof (IPX_SERVER_ENTRY_P));
|
|
pNew->InterfaceIndex = InterfaceIndex;
|
|
pNew->Protocol = Protocol;
|
|
pNew->AdvertisingNode = AdvertisingNode;
|
|
pNew->Flags = Flags;
|
|
|
|
// Insert the flag in the list
|
|
if (*ppList)
|
|
pNew->pNext = *ppList;
|
|
else
|
|
pNew->pNext = NULL;
|
|
*ppList = pNew;
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// When the internal network number changes, we need to update the
|
|
// control blocks of the internal servers.
|
|
//
|
|
DWORD SapUpdateLocalServers () {
|
|
SERVER_INTERNAL_UPDATE_NODE * pList = NULL, * pCur;
|
|
BOOL bNewServer = FALSE;
|
|
HANDLE hEnum;
|
|
|
|
Trace (DEBUG_SERVERDB, "SapUpdateLocalServers: entered.");
|
|
|
|
// Create a list enumerator that goes through all
|
|
// servers in the table.
|
|
hEnum = CreateListEnumerator (
|
|
SDB_HASH_TABLE_LINK,
|
|
0xFFFF,
|
|
NULL,
|
|
INVALID_INTERFACE_INDEX,
|
|
0xFFFFFFFF,
|
|
0);
|
|
if (hEnum == NULL)
|
|
return GetLastError ();
|
|
|
|
// Enumerate the servers sending them through a filter
|
|
// that updates their network number and node
|
|
EnumerateServers (hEnum, SapBuildInternalUpdateListFilter, (LPVOID)&pList);
|
|
DeleteListEnumerator (hEnum);
|
|
|
|
// pList will now point to a list of servers that need to have
|
|
// their information updated.
|
|
while (pList) {
|
|
pCur = pList;
|
|
|
|
// Send out a broadcast that the local server is now
|
|
// unreachable
|
|
pCur->Server.HopCount = IPX_MAX_HOP_COUNT;
|
|
UpdateServer ( &(pCur->Server),
|
|
pCur->InterfaceIndex,
|
|
pCur->Protocol,
|
|
INFINITE,
|
|
pCur->AdvertisingNode,
|
|
pCur->Flags,
|
|
&bNewServer );
|
|
Trace (DEBUG_SERVERDB, "%s has been marked with hop count 16", pCur->Server.Name);
|
|
|
|
// Update the network and node number and advertise that
|
|
// it is available
|
|
IpxNetCpy (pCur->Server.Network, INTERNAL_IF_NET);
|
|
IpxNodeCpy (pCur->Server.Node, INTERNAL_IF_NODE);
|
|
pCur->Server.HopCount = 0;
|
|
UpdateServer ( &(pCur->Server),
|
|
pCur->InterfaceIndex,
|
|
pCur->Protocol,
|
|
INFINITE,
|
|
pCur->AdvertisingNode,
|
|
pCur->Flags,
|
|
&bNewServer );
|
|
Trace (DEBUG_SERVERDB, "%s has been updated.", pCur->Server.Name);
|
|
|
|
// Cleanup
|
|
pList = pList->pNext;
|
|
HeapFree (ServerTable.ST_Heap, 0, pCur);
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
|
|
|