587 lines
16 KiB
C
587 lines
16 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1995 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
adptmgr.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module contains the adapter management functions
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Stefan Solomon 03/07/1995
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "precomp.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
//
|
||
|
// Adapter Manager Globals
|
||
|
//
|
||
|
|
||
|
|
||
|
HANDLE AdapterConfigPortHandle;
|
||
|
HANDLE AdapterNotificationThreadHandle;
|
||
|
|
||
|
// Counter of created adapters
|
||
|
ULONG AdaptersCount = 0;
|
||
|
|
||
|
PICB
|
||
|
GetInterfaceByAdptNameAndPktType(LPWSTR AdapterName, DWORD dwType);
|
||
|
|
||
|
DWORD
|
||
|
PnpAdapterConfigHandler(ADAPTER_INFO * pAdapterInfo,
|
||
|
ULONG AdapterIndex,
|
||
|
ULONG AdapterConfigurationStatus);
|
||
|
|
||
|
DWORD
|
||
|
ReConfigureAdapter(IN DWORD dwAdapterIndex,
|
||
|
IN PWSTR pszAdapterName,
|
||
|
IN PADAPTER_INFO pAdapter);
|
||
|
|
||
|
VOID
|
||
|
CreateAdapter(ULONG AdapterIndex,
|
||
|
PWSTR AdapterNamep,
|
||
|
PADAPTER_INFO adptip);
|
||
|
|
||
|
VOID
|
||
|
DeleteAdapter(ULONG AdapterIndex);
|
||
|
|
||
|
VOID
|
||
|
AdapterUp(ULONG AdapterIndex);
|
||
|
|
||
|
VOID
|
||
|
AdapterDown(ULONG AdapterIndex);
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Function: StartAdapterManager
|
||
|
|
||
|
Descr: opens the IPX stack notification port
|
||
|
|
||
|
--*/
|
||
|
|
||
|
DWORD
|
||
|
StartAdapterManager(VOID)
|
||
|
{
|
||
|
ADAPTERS_GLOBAL_PARAMETERS AdptGlobalParameters;
|
||
|
DWORD threadid;
|
||
|
|
||
|
Trace(ADAPTER_TRACE, "StartAdapterManager: Entered\n");
|
||
|
|
||
|
// create adapter config port
|
||
|
if((AdapterConfigPortHandle = IpxCreateAdapterConfigurationPort(
|
||
|
g_hEvents[ADAPTER_NOTIFICATION_EVENT],
|
||
|
&AdptGlobalParameters)) == INVALID_HANDLE_VALUE) {
|
||
|
|
||
|
// can't create config port
|
||
|
return (1);
|
||
|
}
|
||
|
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Function: StopAdapterManager
|
||
|
|
||
|
Descr: Closes the IPX notification port
|
||
|
|
||
|
--*/
|
||
|
|
||
|
VOID
|
||
|
StopAdapterManager(VOID)
|
||
|
{
|
||
|
DWORD rc;
|
||
|
ULONG AdapterIndex;
|
||
|
|
||
|
Trace(ADAPTER_TRACE, "StopAdapterManager: Entered\n");
|
||
|
|
||
|
// Close the IPX stack notification port
|
||
|
IpxDeleteAdapterConfigurationPort(AdapterConfigPortHandle);
|
||
|
}
|
||
|
// Debugging functions
|
||
|
char * DbgTypeToString(DWORD dwType) {
|
||
|
switch (dwType) {
|
||
|
case MISN_FRAME_TYPE_ETHERNET_II:
|
||
|
return "EthII";
|
||
|
case MISN_FRAME_TYPE_802_3:
|
||
|
return "802.3";
|
||
|
case MISN_FRAME_TYPE_802_2:
|
||
|
return "802.2";
|
||
|
case MISN_FRAME_TYPE_SNAP:
|
||
|
return "SNAP";
|
||
|
case MISN_FRAME_TYPE_ARCNET:
|
||
|
return "Arcnet";
|
||
|
case ISN_FRAME_TYPE_AUTO:
|
||
|
return "Autodetect";
|
||
|
}
|
||
|
|
||
|
return "Unknown";
|
||
|
}
|
||
|
|
||
|
// Helper debug function traces out information about a given interface
|
||
|
VOID DbgTraceAdapterInfo(IN PADAPTER_INFO pAdapter, DWORD dwIndex, LPSTR pszTitle) {
|
||
|
Trace(ADAPTER_TRACE, "%s: Ind=%d IfInd=%d Net=%x Lcl=%x Rmt=%x Spd=%d Type=%d",
|
||
|
pszTitle,
|
||
|
dwIndex,
|
||
|
pAdapter->InterfaceIndex,
|
||
|
*((LONG*)(pAdapter->Network)),
|
||
|
*((LONG*)(pAdapter->LocalNode)),
|
||
|
*((LONG*)(pAdapter->RemoteNode)),
|
||
|
pAdapter->LinkSpeed,
|
||
|
pAdapter->NdisMedium);
|
||
|
}
|
||
|
|
||
|
// Outputs the current status of an adapter to the trace window
|
||
|
VOID DbgTraceAdapter(PACB acbp) {
|
||
|
Trace(ADAPTER_TRACE, "[%d] Interface: %d, Network: %x, Type: %s",
|
||
|
acbp->AdapterIndex,
|
||
|
(acbp->icbp) ? acbp->icbp->InterfaceIndex : -1,
|
||
|
*((LONG*)(acbp->AdapterInfo.Network)),
|
||
|
DbgTypeToString(acbp->AdapterInfo.PacketType));
|
||
|
}
|
||
|
|
||
|
|
||
|
// Outputs the current list of adapters to the trace window
|
||
|
VOID DbgTraceAdapterList() {
|
||
|
PLIST_ENTRY lep;
|
||
|
DWORD i;
|
||
|
PACB acbp;
|
||
|
|
||
|
ACQUIRE_DATABASE_LOCK;
|
||
|
|
||
|
Trace(ADAPTER_TRACE, "List of current adapters:");
|
||
|
Trace(ADAPTER_TRACE, "=========================");
|
||
|
// Loop through the adapter hash table, printing as we go
|
||
|
for (i = 0; i < ADAPTER_HASH_TABLE_SIZE; i++) {
|
||
|
lep = IndexAdptHt[i].Flink;
|
||
|
while(lep != &IndexAdptHt[i]) {
|
||
|
acbp = CONTAINING_RECORD(lep, ACB, IndexHtLinkage);
|
||
|
DbgTraceAdapter(acbp);
|
||
|
lep = acbp->IndexHtLinkage.Flink;
|
||
|
}
|
||
|
}
|
||
|
Trace(ADAPTER_TRACE, "\n");
|
||
|
|
||
|
RELEASE_DATABASE_LOCK;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Function: AdapterNotification
|
||
|
|
||
|
Descr: Processes adapter notification events
|
||
|
|
||
|
--*/
|
||
|
|
||
|
VOID
|
||
|
AdapterNotification(VOID)
|
||
|
{
|
||
|
ADAPTER_INFO AdapterInfo;
|
||
|
ULONG AdapterIndex;
|
||
|
ULONG AdapterConfigurationStatus;
|
||
|
DWORD rc;
|
||
|
|
||
|
Trace(ADAPTER_TRACE, "AdapterNotification: Entered");
|
||
|
|
||
|
// Adaptif manages the adapter information. Get the next piece of
|
||
|
// information that adptif has queued for us.
|
||
|
while((rc = IpxGetQueuedAdapterConfigurationStatus(
|
||
|
AdapterConfigPortHandle,
|
||
|
&AdapterIndex,
|
||
|
&AdapterConfigurationStatus,
|
||
|
&AdapterInfo)) == NO_ERROR)
|
||
|
{
|
||
|
switch(AdapterConfigurationStatus) {
|
||
|
// An adapter is being created. This is happening either
|
||
|
// because we are receiving the list of current adapters
|
||
|
// at initialization time or as a result of a PnP event.
|
||
|
// Either way, the smarts to deal with the situation are built
|
||
|
// into our PnP handler.
|
||
|
//
|
||
|
// This message is also sent when an existing adapter is
|
||
|
// being configured.
|
||
|
case ADAPTER_CREATED:
|
||
|
PnpAdapterConfigHandler(&AdapterInfo,
|
||
|
AdapterIndex,
|
||
|
AdapterConfigurationStatus);
|
||
|
break;
|
||
|
// Handle an adapter being deleted -- this can happen as a result of
|
||
|
// pcmcia removing the adapter or as a result of a binding change
|
||
|
// or a wan link removal.
|
||
|
case ADAPTER_DELETED:
|
||
|
DeleteAdapter(AdapterIndex);
|
||
|
break;
|
||
|
// A wan line came up.
|
||
|
case ADAPTER_UP:
|
||
|
AdapterUp(AdapterIndex);
|
||
|
break;
|
||
|
// A wan line went down
|
||
|
case ADAPTER_DOWN:
|
||
|
AdapterDown(AdapterIndex);
|
||
|
break;
|
||
|
|
||
|
// Some internal error has occured.
|
||
|
default:
|
||
|
SS_ASSERT(FALSE);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
DbgTraceAdapterList();
|
||
|
}
|
||
|
|
||
|
// Handles adapter creation and configuration notifications.
|
||
|
DWORD PnpAdapterConfigHandler(ADAPTER_INFO * pAdapterInfo,
|
||
|
ULONG AdapterIndex,
|
||
|
ULONG AdapterConfigurationStatus)
|
||
|
{
|
||
|
ULONG AdapterNameSize;
|
||
|
LPWSTR AdapterNameBuffer;
|
||
|
DWORD dwErr;
|
||
|
|
||
|
Trace(ADAPTER_TRACE, "PnpAdapterConfigHandler: Entered for adpt #%d", AdapterIndex);
|
||
|
|
||
|
// If this is the internal adapter, we don't need an adapter name
|
||
|
if (AdapterIndex == 0)
|
||
|
AdapterNameBuffer = L"";
|
||
|
|
||
|
// Otherwise, get the adapter name from the stack
|
||
|
else {
|
||
|
AdapterNameSize = wcslen(pAdapterInfo->pszAdpName) * sizeof (WCHAR) + sizeof(WCHAR);
|
||
|
|
||
|
//Allocate the memory to hold the name of the adapter
|
||
|
if((AdapterNameBuffer = GlobalAlloc(GPTR, AdapterNameSize)) == NULL)
|
||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||
|
|
||
|
wcscpy(AdapterNameBuffer, pAdapterInfo->pszAdpName);
|
||
|
}
|
||
|
|
||
|
// Either create or configure the adapter depending on whether
|
||
|
// it has already exists in the adapter database.
|
||
|
ACQUIRE_DATABASE_LOCK;
|
||
|
|
||
|
if(GetAdapterByIndex(AdapterIndex))
|
||
|
ReConfigureAdapter(AdapterIndex, AdapterNameBuffer, pAdapterInfo);
|
||
|
else
|
||
|
CreateAdapter(AdapterIndex, AdapterNameBuffer, pAdapterInfo);
|
||
|
|
||
|
RELEASE_DATABASE_LOCK;
|
||
|
|
||
|
// Cleanup
|
||
|
if (AdapterIndex != 0)
|
||
|
GlobalFree(AdapterNameBuffer);
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
// Attempt to bind an unbound adapter
|
||
|
DWORD AttemptAdapterBinding (PACB acbp) {
|
||
|
PICB icbp;
|
||
|
|
||
|
// Make sure we aren't already bound
|
||
|
if (acbp->icbp)
|
||
|
return NO_ERROR;
|
||
|
|
||
|
if(acbp->AdapterInfo.NdisMedium != NdisMediumWan) {
|
||
|
// this is a DEDICATED (e.g LAN) adapter. If an interface already exists for it,
|
||
|
// bind it to its interface and notify the other modules
|
||
|
if(acbp->AdapterIndex != 0) {
|
||
|
icbp = GetInterfaceByAdptNameAndPktType(acbp->AdapterNamep,
|
||
|
acbp->AdapterInfo.PacketType);
|
||
|
if (icbp)
|
||
|
BindInterfaceToAdapter(icbp, acbp);
|
||
|
}
|
||
|
else {
|
||
|
// This is the internal adapter
|
||
|
InternalAdapterp = acbp;
|
||
|
|
||
|
// If the internal network number was set to zero (nullnet), then
|
||
|
// we have a configuration problem -- don't barf on this, just log
|
||
|
// the fact.
|
||
|
if(!memcmp(acbp->AdapterInfo.Network, nullnet, 4)) {
|
||
|
IF_LOG (EVENTLOG_ERROR_TYPE) {
|
||
|
RouterLogErrorDataA (RMEventLogHdl,
|
||
|
ROUTERLOG_IPX_NO_VIRTUAL_NET_NUMBER,
|
||
|
0, NULL, 0, NULL);
|
||
|
}
|
||
|
Trace(ADAPTER_TRACE, "CreateAdapter: Internal net number is not configured !");
|
||
|
// [pmay] now when we get a bad internal net number, we re-configure.
|
||
|
// SS_ASSERT(FALSE);
|
||
|
PnpAutoSelectInternalNetNumber(ADAPTER_TRACE);
|
||
|
}
|
||
|
|
||
|
// if the internal interface already exists, bind to it
|
||
|
if(icbp = InternalInterfacep) {
|
||
|
BindInterfaceToAdapter(icbp, acbp);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
// this is a connected WAN adapter
|
||
|
SS_ASSERT(acbp->icbp == NULL);
|
||
|
|
||
|
// bind to corresponding interface
|
||
|
if(icbp = GetInterfaceByIndex(acbp->AdapterInfo.InterfaceIndex)) {
|
||
|
// bind all interfaces to this adapter
|
||
|
BindInterfaceToAdapter(icbp, acbp);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
// Resets the configuration of the given adapter. This function assumes that
|
||
|
// the database is locked and that the given adapter index references an
|
||
|
// adapter in the database. Furthermore this function assumes that it does
|
||
|
// not need to release its lock on the database.
|
||
|
DWORD ReConfigureAdapter(IN DWORD dwAdapterIndex,
|
||
|
IN PWSTR pszAdapterName,
|
||
|
IN PADAPTER_INFO pAdapter)
|
||
|
{
|
||
|
PACB acbp;
|
||
|
PICB icbp;
|
||
|
|
||
|
Trace(
|
||
|
ADAPTER_TRACE,
|
||
|
"ReConfigureAdapter: Entered for %d: %S: %x, %d",
|
||
|
dwAdapterIndex,
|
||
|
pszAdapterName,
|
||
|
*((DWORD*)(pAdapter->Network)),
|
||
|
pAdapter->InterfaceIndex
|
||
|
);
|
||
|
|
||
|
// If the adapter being configured is the internal adapter and if it is to be
|
||
|
// re-configured to a zero net number, that is to be a signal to automatically
|
||
|
// assign a new network number.
|
||
|
if ((dwAdapterIndex == 0) && (*((DWORD*)pAdapter->Network) == 0)) {
|
||
|
DWORD dwErr;
|
||
|
|
||
|
Trace(ADAPTER_TRACE, "ReConfigureAdapter: Internal Net = 0, selecting new number");
|
||
|
if ((dwErr = PnpAutoSelectInternalNetNumber(ADAPTER_TRACE)) != NO_ERROR)
|
||
|
Trace(ADAPTER_TRACE, "ReConfigureAdapter: Auto-select of new net number FAILED!");
|
||
|
return dwErr;
|
||
|
}
|
||
|
|
||
|
// Get a reference to the adapter and the interface
|
||
|
if (dwAdapterIndex == 0)
|
||
|
acbp = InternalAdapterp;
|
||
|
else
|
||
|
acbp = GetAdapterByIndex(dwAdapterIndex);
|
||
|
|
||
|
if (!acbp) {
|
||
|
Trace(ADAPTER_TRACE, "ReConfigureAdapter: Invalid adapter %d!", dwAdapterIndex);
|
||
|
return ERROR_CAN_NOT_COMPLETE;
|
||
|
}
|
||
|
icbp = acbp->icbp;
|
||
|
|
||
|
// If this adapter isn't bound yet, update it and then
|
||
|
// try to bind it.
|
||
|
if (!icbp) {
|
||
|
acbp->AdapterInfo = *pAdapter;
|
||
|
AttemptAdapterBinding (acbp);
|
||
|
}
|
||
|
|
||
|
// Otherwise, unbind and then re-bind the adapter
|
||
|
else {
|
||
|
// Unbind the interface from the adapter
|
||
|
UnbindInterfaceFromAdapter(icbp);
|
||
|
|
||
|
// Update the information
|
||
|
acbp->AdapterInfo = *pAdapter;
|
||
|
|
||
|
// Rebind the interface to the adapter
|
||
|
AttemptAdapterBinding(acbp);
|
||
|
}
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Function: CreateAdapter
|
||
|
|
||
|
Descr: creates the adapter control block
|
||
|
|
||
|
Modification:
|
||
|
[pmay] Assume the database lock is aquired before this function enters
|
||
|
and that the given adapter index has not already been added
|
||
|
to the adapter database.
|
||
|
--*/
|
||
|
VOID
|
||
|
CreateAdapter(ULONG AdapterIndex,
|
||
|
PWSTR AdapterNamep,
|
||
|
PADAPTER_INFO adptip)
|
||
|
{
|
||
|
PACB acbp;
|
||
|
PICB icbp;
|
||
|
ULONG namelen;
|
||
|
PUCHAR ln = adptip->LocalNode;
|
||
|
|
||
|
Trace(
|
||
|
ADAPTER_TRACE,
|
||
|
"CreateAdapter: Entered for %d (%x%x%x%x%x%x)(%S), %d",
|
||
|
AdapterIndex,
|
||
|
ln[0], ln[1], ln[2], ln[3], ln[4], ln[5],
|
||
|
AdapterNamep,
|
||
|
adptip->InterfaceIndex);
|
||
|
|
||
|
// adapter name len including the unicode null
|
||
|
namelen = (wcslen(AdapterNamep) + 1) * sizeof(WCHAR);
|
||
|
|
||
|
// new adapter, try to get an ACB
|
||
|
if((acbp = GlobalAlloc(GPTR, sizeof(ACB) + namelen)) == NULL) {
|
||
|
Trace(ADAPTER_TRACE, "CreateAdapter: RETURNING BECAUSE INSUFFICIENT MEMORY TO ALLOCATE ADAPTER");
|
||
|
// [pmay] PnP handler takes care of aquiring and releasing the database lock.
|
||
|
// RELEASE_DATABASE_LOCK;
|
||
|
SS_ASSERT(FALSE);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// make the ACB
|
||
|
acbp->AdapterIndex = AdapterIndex;
|
||
|
AddToAdapterHt(acbp);
|
||
|
memcpy(acbp->Signature, AdapterSignature, 4);
|
||
|
|
||
|
// We haven't bound to any interface at this point
|
||
|
acbp->icbp = NULL;
|
||
|
|
||
|
// Store the adapter information pertinent to this adapter
|
||
|
acbp->AdapterInfo = *adptip;
|
||
|
|
||
|
// Copy of the adapter name
|
||
|
acbp->AdapterNamep = (LPWSTR)((PUCHAR)acbp + sizeof(ACB));
|
||
|
wcscpy(acbp->AdapterNamep, AdapterNamep);
|
||
|
acbp->AdapterNameLen = namelen - 1; // without the unicode null
|
||
|
|
||
|
// Attempt to bind the adapter
|
||
|
AttemptAdapterBinding (acbp);
|
||
|
|
||
|
AdaptersCount++;
|
||
|
|
||
|
if(acbp->AdapterInfo.NdisMedium != NdisMediumWan) {
|
||
|
if(acbp->AdapterIndex == 0) {
|
||
|
Trace(ADAPTER_TRACE, "CreateAdapter: Created INTERNAL adapter index 0");
|
||
|
}
|
||
|
else {
|
||
|
Trace(ADAPTER_TRACE, "CreateAdapter: Created LAN adapter # %d name %S",
|
||
|
acbp->AdapterIndex,
|
||
|
acbp->AdapterNamep);
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
Trace(ADAPTER_TRACE, "CreateAdapter: created WAN adapter # %d", acbp->AdapterIndex);
|
||
|
}
|
||
|
|
||
|
// [pmay] PnP handler takes care of aquiring and releasing the database lock.
|
||
|
// RELEASE_DATABASE_LOCK;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Function: DeleteAdapter
|
||
|
Descr:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
VOID
|
||
|
DeleteAdapter(ULONG AdapterIndex)
|
||
|
{
|
||
|
PACB acbp, acbp2;
|
||
|
PICB icbp;
|
||
|
WCHAR pszAdapterName[MAX_ADAPTER_NAME_LEN];
|
||
|
|
||
|
Trace(ADAPTER_TRACE, "DeleteAdapter: Entered for adapter # %d", AdapterIndex);
|
||
|
|
||
|
ACQUIRE_DATABASE_LOCK;
|
||
|
|
||
|
// Get the adapter
|
||
|
if((acbp = GetAdapterByIndex(AdapterIndex)) == NULL) {
|
||
|
RELEASE_DATABASE_LOCK;
|
||
|
Trace(ADAPTER_TRACE, "DeleteAdapter: Ignored. There is no adapter # %d to be deleted !\n", AdapterIndex);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// 1. if the adapter is bound to an interface -> unbind it. Also, save the adapter name.
|
||
|
if((icbp = acbp->icbp) != NULL) {
|
||
|
wcscpy(pszAdapterName, acbp->AdapterNamep);
|
||
|
UnbindInterfaceFromAdapter(acbp->icbp);
|
||
|
}
|
||
|
|
||
|
// Remove the adapter from the database
|
||
|
RemoveFromAdapterHt(acbp);
|
||
|
AdaptersCount--;
|
||
|
|
||
|
// [pmay]
|
||
|
// Since pnp can cause adapters to be added and removed from the database
|
||
|
// in unpredictable orders, see if there is already another adapter in the
|
||
|
// database with which the bound interface can immediately re-bind.
|
||
|
if (icbp) {
|
||
|
if((acbp2 = GetAdapterByNameAndPktType (pszAdapterName, icbp->PacketType)) != NULL)
|
||
|
BindInterfaceToAdapter(icbp, acbp2);
|
||
|
}
|
||
|
|
||
|
RELEASE_DATABASE_LOCK;
|
||
|
|
||
|
Trace(ADAPTER_TRACE, "DeleteAdapter: deleted adapter # %d", acbp->AdapterIndex);
|
||
|
GlobalFree(acbp);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Function: AdapterDown
|
||
|
|
||
|
Descr: Called if the LAN adapter isn't functional.
|
||
|
It calls back into the SNMP Agent with a trap - AdapterDown
|
||
|
|
||
|
--*/
|
||
|
|
||
|
VOID
|
||
|
AdapterDown(ULONG AdapterIndex)
|
||
|
{
|
||
|
// Call AdapterDownTrap
|
||
|
}
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Function: AdapterUp
|
||
|
|
||
|
Descr: Called if the LAN adapter isn't functional.
|
||
|
It calls back into the SNMP Agent with a trap - AdapterUP
|
||
|
|
||
|
--*/
|
||
|
|
||
|
VOID
|
||
|
AdapterUp(ULONG AdapterIndex)
|
||
|
{
|
||
|
// Call AdapterUpTrap
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
DestroyAllAdapters(VOID)
|
||
|
{
|
||
|
PLIST_ENTRY IfHtBucketp, lep;
|
||
|
PACB acbp;
|
||
|
ULONG AdapterIndex;
|
||
|
int i;
|
||
|
|
||
|
for(i=0, IfHtBucketp = IndexAdptHt; i<ADAPTER_HASH_TABLE_SIZE; i++, IfHtBucketp++) {
|
||
|
if (!IsListEmpty(IfHtBucketp)) {
|
||
|
acbp = CONTAINING_RECORD(IfHtBucketp->Flink, ACB, IndexHtLinkage);
|
||
|
RemoveFromAdapterHt(acbp);
|
||
|
AdaptersCount--;
|
||
|
Trace(ADAPTER_TRACE, "DestroyAllAdapters: destroyed adapter # %d\n", acbp->AdapterIndex);
|
||
|
GlobalFree(acbp);
|
||
|
}
|
||
|
}
|
||
|
}
|