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

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);
}
}
}