Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

640 lines
14 KiB

/*******************************************************************/
/* Copyright(c) 1993 Microsoft Corporation */
/*******************************************************************/
//***
//
// Filename: nicman.c
//
// Description: NicCb management routines
//
// Author: Stefan Solomon (stefans) October 7, 1993.
//
// Revision History:
//
//***
#include "rtdefs.h"
// counters
USHORT MaximumNicCount; // total number of Nics possble
// array of pointers to NicCb indexed by the NicId
PNICCB *NicCbPtrTab;
PNICCB NicCbArray;
VOID
ConfigureNicCb(PNICCB niccbp,
PIPX_NIC_DATA nicdatp);
USHORT VirtualNicId;
UCHAR VirtualNetwork[4];
VOID
StartNicCloseTimer(PNICCB niccbp);
VOID
NicCloseTimeout(PKDPC Dpc,
PVOID DefferedContext,
PVOID SystemArgument1,
PVOID SystemArgument2);
//***
//
// Function: CreateNicCbs
//
// Descr: creates the NicCbs structures and queues them in their respective
// lists
//
// Params: none
//
// Returns: 0 - success, 1 - failure
//
//***
UINT
CreateNicCbs(PIPX_INTERNAL_BIND_RIP_OUTPUT IpxBindBuffp)
{
ULONG tablen, arraylen;
PNICCB niccbp;
PIPX_NIC_DATA nicdatp;
UINT LanNicsCount = 0;
UINT WanNicsCount = 0;
USHORT ConfiguredNicCount;
USHORT i;
RtPrint(DBG_INIT, ("IpxRouter: CreateNicCbs: Entered\n"));
MaximumNicCount = IpxBindBuffp->MaximumNicCount;
ConfiguredNicCount = IpxBindBuffp->NicInfoBuffer.NicCount;
RtPrint(DBG_INIT, ("IpxRouter: Max Nics Count = %d, Configured Nics Count = %d\n",
MaximumNicCount, ConfiguredNicCount));
ASSERT(ConfiguredNicCount <= MaximumNicCount);
// allocate the NicCbs Ptrs and NicCbs structures tables
tablen = sizeof(PNICCB) * MaximumNicCount;
if((NicCbPtrTab = (PNICCB *)CTEAllocMem(tablen)) == NULL) {
// memory allocation failure, abort all
return 1;
}
// zero the tables
RtlZeroMemory(NicCbPtrTab, tablen);
arraylen = sizeof(NICCB) * MaximumNicCount;
if((NicCbArray = (PNICCB)CTEAllocMem(arraylen)) == NULL) {
// memory allocation failure, abort all
CTEFreeMem(NicCbPtrTab);
return 1;
}
// zero the tables
RtlZeroMemory(NicCbArray, arraylen);
// initialize the NicCb pointers table and
// initialize ALL NicCbs to the NIC_CLOSED status
niccbp = NicCbArray; // NicCb table start
for(i=0; i<MaximumNicCount; i++, niccbp++) {
// pointers table
NicCbPtrTab[i] = niccbp;
// NicCb
niccbp->NicId = i;
InitializeListHead(&niccbp->SendQueue);
InitializeListHead(&niccbp->ReceiveQueue);
KeInitializeDpc(&niccbp->NicCloseDpc, NicCloseTimeout, niccbp);
KeInitializeTimer(&niccbp->NicCloseTimer);
KeInitializeEvent(&niccbp->NicClosedEvent, NotificationEvent, FALSE);
// initialize the WanGenRequests sender
KeInitializeDpc(&niccbp->WanGenRequestDpc, WanGenRequestTimeout, niccbp);
KeInitializeTimer(&niccbp->WanGenRequestTimer);
niccbp->WanGenRequestCount = 0;
INITIALIZE_SPIN_LOCK(&niccbp->NicLock);
InitRipSndAtNic(niccbp);
// default -> always enabled
niccbp->WanRoutingDisabled = FALSE;
niccbp->NicState = NIC_CLOSED;
// set device type to an invalid type
niccbp->DeviceType = IPX_ROUTER_INVALID_DEVICE_TYPE;
}
// configure the NicCbs that we got in the config data buffer
nicdatp = IpxBindBuffp->NicInfoBuffer.NicData; // config data start
for(i=0; i<ConfiguredNicCount; i++, nicdatp++) {
ASSERT(nicdatp->NicId < MaximumNicCount);
niccbp = NicCbPtrTab[nicdatp->NicId];
ConfigureNicCb(niccbp, nicdatp);
// If this is not a Wan device, open it
if(niccbp->DeviceType != NdisMediumWan) {
niccbp->NicState = NIC_PENDING_OPEN;
}
#if DBG
if(niccbp->DeviceType == NdisMediumWan) {
WanNicsCount++;
}
else
{
LanNicsCount++;
}
#endif
}
RtPrint(DBG_INIT, ("IpxRouter: CreateNicCbs created %d Lan Nics\n", LanNicsCount));
RtPrint(DBG_INIT, ("IpxRouter: CreateNicCbs created %d Wan Nics\n", WanNicsCount));
// get the virtual numbers, if any
VirtualNicId = IpxBindBuffp->NicInfoBuffer.VirtualNicId;
memcpy(VirtualNetwork, IpxBindBuffp->NicInfoBuffer.VirtualNetwork, IPX_NET_LEN);
// All Done
return 0;
}
//***
//
// Function: DestroyNicCbs
//
// Descr: frees the memory allocated for NicCbs
//
// Params: none
//
// Returns: none
//
//***
VOID
DestroyNicCbs(VOID)
{
UINT i;
for(i=0; i<MaximumNicCount; i++) {
DEINITIALIZE_SPIN_LOCK(&NicCbPtrTab[i]->NicLock);
}
CTEFreeMem(NicCbPtrTab);
CTEFreeMem(NicCbArray);
}
//***
//
// Function: ConfigureNicCb
//
// Descr: Initializes the NicCb data struct
//
// Params: NicCb ptr, Nic data buffer ptr
//
// Returns: none
//
//***
VOID
ConfigureNicCb(PNICCB niccbp,
PIPX_NIC_DATA nicdatp)
{
#if DBG
char *devtypestr;
#endif
niccbp->NicId = nicdatp->NicId;
memcpy(niccbp->Network, nicdatp->Network, 4);
memcpy(niccbp->Node, nicdatp->Node, 6);
niccbp->LinkSpeed = nicdatp->LineInfo.LinkSpeed;
niccbp->TickCount = tickcount(niccbp->LinkSpeed);
niccbp->MaximumPacketSize = nicdatp->LineInfo.MaximumPacketSize;
niccbp->MacOptions = nicdatp->LineInfo.MacOptions;
niccbp->DeviceType = nicdatp->DeviceType;
niccbp->SendPktsQueuedCount = 0;
ZeroNicStatistics(niccbp);
#if DBG
if(niccbp->DeviceType == NdisMediumWan) {
devtypestr = "WAN";
}
else
{
devtypestr = "LAN";
}
#endif
// update the WanRoutingDisabled flag from the IPX_NIC_DATA
if(nicdatp->EnableWanRouter) {
RtPrint(DBG_INIT, ("IpxRouter: Wan Router Enabled for NicId %d\n", niccbp->NicId));
niccbp->WanRoutingDisabled = FALSE;
}
else
{
RtPrint(DBG_INIT, ("IpxRouter: Wan Router Disabled for NicId %d\n", niccbp->NicId));
niccbp->WanRoutingDisabled = TRUE;
}
RtPrint(DBG_INIT, ("IpxRouter: Configured Nic %d with DeviceType %s\n", niccbp->NicId, devtypestr));
}
USHORT
tickcount(UINT linkspeed)
{
USHORT tc;
ASSERT(linkspeed != 0);
if(linkspeed >= 10000) {
// link speed >= 1M bps
return 1;
}
else
{
// compute the necessary time to send a 576 bytes packet over this
// line and express it as nr of ticks.
// One tick = 55ms
tc = 57600 / linkspeed;
tc = tc / 55 + 1;
return tc;
}
}
//***
//
// Function: NicClose
//
// Descr: Starts the nic closing operation, as follows:
// 1. Sets the nic state to NIC_CLOSING, which disables further
// receives/sends on this nic. Doing this will complete immediately
// any receives, receive complete and sends.
// 2. Dequeues and completes all snd requests waiting in this nic
// rip snd req queue.
// 3. Checks if all closing conditions are met.
// 4. If the resources are freed, nic is closed. Else the nic closing
// timer is started which will do a periodic check of closing
// conditions.
//
//***
NIC_CLOSE_STATUS
NicClose(PNICCB niccbp,
USHORT CloseCompletionOption)
{
PLIST_ENTRY lep;
PRIP_SNDREQ sndreqp;
LIST_ENTRY RemovedRipSndReqList;
NIC_CLOSE_STATUS rc;
ACQUIRE_SPIN_LOCK(&niccbp->NicLock);
switch(niccbp->NicState) {
case NIC_CLOSED:
RELEASE_SPIN_LOCK(&niccbp->NicLock);
return NIC_CLOSE_SUCCESS;
case NIC_CLOSING:
niccbp->CloseCompletionOptions |= CloseCompletionOption;
RELEASE_SPIN_LOCK(&niccbp->NicLock);
return NIC_CLOSE_PENDING;
case NIC_ACTIVE:
niccbp->CloseCompletionOptions |= CloseCompletionOption;
break;
default:
ASSERT(FALSE);
break;
}
// cancel the Wan Gen Requests timer
if(niccbp->DeviceType == NdisMediumWan) {
// check if the timer has been scheduled to fire
// (this is equivalent with checking if there are wan gen req to send)
if(niccbp->WanGenRequestCount) {
// the wan requests timer is in the system's timer queue because
// there still are requests to send. Try to cancel it now
if(KeCancelTimer(&niccbp->WanGenRequestTimer)) {
RtPrint(DBG_NIC, ("IpxRouter: NicClose: Cancel WanReqTimer for NicId %d was successful\n", niccbp->NicId));
// cancel was successful, reset the request count
niccbp->WanGenRequestCount = 0;
}
else
{
RtPrint(DBG_NIC, ("IpxRouter: NicClose: Could not cancel WanReqTimer for NicId %d\n", niccbp->NicId));
}
}
}
InitializeListHead(&RemovedRipSndReqList);
// remove all pending rip snd requests
while(!IsListEmpty(&niccbp->RipSendQueue)) {
lep = RemoveHeadList(&niccbp->RipSendQueue);
sndreqp = CONTAINING_RECORD(lep, RIP_SNDREQ, NicLinkage);
InsertTailList(&RemovedRipSndReqList, &sndreqp->NicLinkage);
}
// check if all resources for this nic have been de-allocated
if(IsListEmpty(&niccbp->SendQueue) &&
IsListEmpty(&niccbp->ReceiveQueue) &&
(niccbp->RipSndReqp == NULL) &&
(niccbp->WanGenRequestCount == 0)) {
niccbp->NicState = NIC_CLOSED;
niccbp->CloseCompletionOptions = 0;
rc = NIC_CLOSE_SUCCESS;
}
else
{
niccbp->NicState = NIC_CLOSING;
KeResetEvent(&niccbp->NicClosedEvent);
StartNicCloseTimer(niccbp);
rc = NIC_CLOSE_PENDING;
}
RELEASE_SPIN_LOCK(&niccbp->NicLock);
// invoke completion routine for all the removed snd requests
while(!IsListEmpty(&RemovedRipSndReqList)) {
lep = RemoveHeadList(&RemovedRipSndReqList);
sndreqp = CONTAINING_RECORD(lep, RIP_SNDREQ, NicLinkage);
RipSendAtNicCompleted(sndreqp);
}
#if DBG
if(rc == NIC_CLOSE_SUCCESS) {
RtPrint(DBG_NIC, ("IpxRouter: NicClose: Closed OK for NicId: %d\n", niccbp->NicId));
}
else
{
RtPrint(DBG_NIC, ("IpxRouter: NicClose: Close pending for NicId: %d\n", niccbp->NicId));
}
#endif
return rc;
}
VOID
NicCloseTimeout(PKDPC Dpc,
PVOID DefferedContext,
PVOID SystemArgument1,
PVOID SystemArgument2)
{
PNICCB niccbp;
BOOLEAN SignalCompletionEvent = FALSE;
BOOLEAN CallCompletionRoutine = FALSE;
niccbp = (PNICCB)DefferedContext;
ACQUIRE_SPIN_LOCK(&niccbp->NicLock);
switch(niccbp->NicState) {
case NIC_CLOSING:
// check closing conditions
if((IsListEmpty(&niccbp->SendQueue)) &&
(IsListEmpty(&niccbp->ReceiveQueue)) &&
(niccbp->RipSndReqp == NULL) &&
(niccbp->WanGenRequestCount == 0)) {
niccbp->NicState = NIC_CLOSED;
if(niccbp->CloseCompletionOptions & SIGNAL_CLOSE_COMPLETION_EVENT) {
SignalCompletionEvent = TRUE;
}
if(niccbp->CloseCompletionOptions & CALL_CLOSE_COMPLETION_ROUTINE) {
CallCompletionRoutine = TRUE;
}
niccbp->CloseCompletionOptions = 0;
RELEASE_SPIN_LOCK(&niccbp->NicLock);
if(CallCompletionRoutine) {
NicCloseComplete(niccbp);
}
if(SignalCompletionEvent) {
// signal the router driver that this nic is closed
KeSetEvent(&niccbp->NicClosedEvent, 0L, FALSE);
}
RtPrint(DBG_NIC, ("IpxRouter: NicCloseTimeout: Closed OK for NicId: %d\n", niccbp->NicId));
}
else
{
RELEASE_SPIN_LOCK(&niccbp->NicLock);
// restart the timer and check next time
StartNicCloseTimer(niccbp);
RtPrint(DBG_NIC, ("IpxRouter: NicCloseTimeout: Close pending for NicId: %d\n", niccbp->NicId));
}
break;
case NIC_CLOSED:
// we can be called with nic closed only to check that nic
// rcv pkts have all been released
if(IsRcvPktResourceFree) {
// signal the router driver that this nic is closed
RELEASE_SPIN_LOCK(&niccbp->NicLock);
KeSetEvent(&niccbp->NicClosedEvent, 0L, FALSE);
RtPrint(DBG_NIC, ("IpxRouter: NicCloseTimeout: Free Resources OK for NicId: %d\n", niccbp->NicId));
}
else
{
RELEASE_SPIN_LOCK(&niccbp->NicLock);
// restart the timer and check next time
StartNicCloseTimer(niccbp);
RtPrint(DBG_NIC, ("IpxRouter: NicCloseTimeout: Free Resources pending for NicId: %d\n", niccbp->NicId));
}
break;
default:
RELEASE_SPIN_LOCK(&niccbp->NicLock);
ASSERT(FALSE);
break;
}
}
NIC_RESOURCES_STATUS
NicFreeResources(PNICCB niccbp)
{
NIC_RESOURCES_STATUS rc;
ASSERT(niccbp->NicState == NIC_CLOSED);
if(IsRcvPktResourceFree(niccbp)) {
rc = NIC_RESOURCES_FREED;
}
else
{
// we reuse the closing timer for freeing the resources
KeResetEvent(&niccbp->NicClosedEvent);
StartNicCloseTimer(niccbp);
rc = NIC_RESOURCES_PENDING;
}
#if DBG
if(rc == NIC_RESOURCES_FREED) {
RtPrint(DBG_NIC, ("IpxRouter: NicFreeResources: Resources freed OK for NicId: %d\n", niccbp->NicId));
}
else
{
RtPrint(DBG_NIC, ("IpxRouter: NicFreeResources: Free resources pending for NicId: %d\n", niccbp->NicId));
}
#endif
return rc;
}
//***
//
// Function: NicOpen
//
// Descr: Sets the nic state to active so that further receives/snd can
// execute.
//
//***
NIC_OPEN_STATUS
NicOpen(PNICCB niccbp)
{
RtPrint(DBG_NIC, ("IpxRouter: NicOpen: Entered for NicId: %d\n", niccbp->NicId));
ACQUIRE_SPIN_LOCK(&niccbp->NicLock);
if(RouterUnloading) {
RELEASE_SPIN_LOCK(&niccbp->NicLock);
return NIC_OPEN_FAILURE;
}
// check that we are CLOSED
switch(niccbp->NicState) {
case NIC_CLOSED:
case NIC_PENDING_OPEN:
// reset the close completion options
niccbp->CloseCompletionOptions = 0;
break;
default:
RELEASE_SPIN_LOCK(&niccbp->NicLock);
return NIC_OPEN_FAILURE;
}
niccbp->NicState = NIC_ACTIVE;
RELEASE_SPIN_LOCK(&niccbp->NicLock);
return NIC_OPEN_SUCCESS;
}
//***
//
// Function: StartNicCloseTimer
//
// Descr: Starts the timer for 200 ms at this Nic Cb
//
// Params: pointer to Nic Cb
//
// Returns: none
//
//***
VOID
StartNicCloseTimer(PNICCB niccbp)
{
LARGE_INTEGER timeout;
timeout.LowPart = (ULONG)(-200 * 10000L); // 200 ms
timeout.HighPart = -1;
KeSetTimer(&niccbp->NicCloseTimer, timeout, &niccbp->NicCloseDpc);
}
VOID
ZeroNicStatistics(PNICCB niccbp)
{
niccbp->StatBadReceived = 0;
niccbp->StatRipReceived = 0;
niccbp->StatRipSent = 0;
niccbp->StatRoutedReceived = 0;
niccbp->StatRoutedSent = 0;
niccbp->StatType20Received = 0;
niccbp->StatType20Sent = 0;
}