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

864 lines
18 KiB
C

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
misc.c
Abstract:
Miscellaneous management functions
Author:
Stefan Solomon 03/13/1995
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
UCHAR bcastnode[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
VOID
SetAdapterBindingInfo(PIPX_ADAPTER_BINDING_INFO abip,
PACB acbp);
VOID
RMCreateLocalRoute(PICB icbp);
VOID
RMDeleteLocalRoute(PICB icbp);
VOID
ExternalBindInterfaceToAdapter(PICB icbp);
VOID
ExternalUnbindInterfaceFromAdapter(ULONG InterfaceIndex);
/*++
Function: GetTocEntry
Descr: Returns a pointer to the specified table of contents entry
in the interface info block.
--*/
PIPX_TOC_ENTRY
GetTocEntry(PIPX_INFO_BLOCK_HEADER InterfaceInfop,
ULONG InfoEntryType)
{
PIPX_TOC_ENTRY tocep;
UINT i;
for(i=0, tocep = InterfaceInfop->TocEntry;
i<InterfaceInfop->TocEntriesCount;
i++, tocep++) {
if(tocep->InfoType == InfoEntryType) {
return tocep;
}
}
return NULL;
}
/*++
Function: GetInfoEntry
Descr: Returns a pointer to the specified info entry in the interface
control block. If more then one entries, returns a pointer to
the first one.
--*/
LPVOID
GetInfoEntry(PIPX_INFO_BLOCK_HEADER InterfaceInfop,
ULONG InfoEntryType)
{
PIPX_TOC_ENTRY tocep;
if(tocep = GetTocEntry(InterfaceInfop, InfoEntryType)) {
return((LPVOID)((PUCHAR)InterfaceInfop + tocep->Offset));
}
else
{
return NULL;
}
}
/*++
Function: UpdateStaticIfEntries
Descr: Compares the entries in the interface info block with the
stored static entries. Deletes the entries not present
in the interface info blolck and adds the new entries
--*/
DWORD
UpdateStaticIfEntries(
PICB icbp,
HANDLE EnumHandle, // handle for the get next enumeration
ULONG StaticEntrySize,
ULONG NewStaticEntriesCount, // number of new static entries
LPVOID NewStaticEntry, // start of the new entries array
ULONG (*GetNextStaticEntry)(HANDLE EnumHandle, LPVOID entry),
ULONG (*DeleteStaticEntry)(ULONG IfIndex, LPVOID entry),
ULONG (*CreateStaticEntry)(PICB icbp, LPVOID entry))
{
PUCHAR EntryIsNew, nsep, OldStaticEntry;
BOOL found;
UINT i;
// delete non-present entries and add the new entries
// array of flags to mark the new entries
if((EntryIsNew = GlobalAlloc(GPTR, NewStaticEntriesCount)) == NULL) {
return 1;
}
memset(EntryIsNew, 1, NewStaticEntriesCount);
if((OldStaticEntry = GlobalAlloc(GPTR, StaticEntrySize)) == NULL) {
GlobalFree(EntryIsNew);
return 1;
}
if(EnumHandle) {
while(!GetNextStaticEntry(EnumHandle, OldStaticEntry))
{
// compare it with each new static static entry until we find a match
found = FALSE;
for(i = 0, nsep = NewStaticEntry;
i<NewStaticEntriesCount;
i++, nsep+= StaticEntrySize) {
if(!memcmp(OldStaticEntry, nsep, StaticEntrySize)) {
// match - set the flags to OLD
EntryIsNew[i] = 0;
found = TRUE;
break;
}
}
if(!found) {
// non present old entry -> delete it
DeleteStaticEntry(icbp->InterfaceIndex, OldStaticEntry);
}
}
}
// all compared and old non-present ones deleted
// now, add all the new ones
for(i=0, nsep = NewStaticEntry;
i<NewStaticEntriesCount;
i++, nsep+= StaticEntrySize) {
if(EntryIsNew[i]) {
CreateStaticEntry(icbp, nsep);
}
}
GlobalFree(EntryIsNew);
return 0;
}
/*++
Function: GetInterfaceAnsiName
Arguments:
AnsiInterfaceNameBuffer - buffer of IPX_INTERFACE_ANSI_NAME_LEN
UnicodeInterfaceNameBuffer -
Descr:
--*/
VOID
GetInterfaceAnsiName(PUCHAR AnsiInterfaceNameBuffer,
PWSTR UnicodeInterfaceNameBuffer)
{
UNICODE_STRING UnicodeInterfaceName;
ANSI_STRING AnsiInterfaceName;
NTSTATUS ntStatus;
// init a unicode string with the interface name string
RtlInitUnicodeString(&UnicodeInterfaceName, UnicodeInterfaceNameBuffer);
// make the interface name unicode string an ansi string
// in an rtl allocated buffer
ntStatus = RtlUnicodeStringToAnsiString(&AnsiInterfaceName,
&UnicodeInterfaceName,
TRUE // allocate the ansi buffer
);
if (ntStatus != STATUS_SUCCESS)
{
return;
}
// copy the interface name into the supplied buffer, up to the
// argument buffer max size
memcpy(AnsiInterfaceNameBuffer,
AnsiInterfaceName.Buffer,
min(AnsiInterfaceName.MaximumLength, IPX_INTERFACE_ANSI_NAME_LEN));
// free the rtl allocated buffer
RtlFreeAnsiString(&AnsiInterfaceName);
}
/*++
Function: BindInterfaceToAdapter
Descr: Binds the interface to the adapter in the router manager and in
all the other modules and creates a local route for the interface
in the RTM
--*/
VOID
BindInterfaceToAdapter(PICB icbp,
PACB acbp)
{
DWORD rc;
Trace(BIND_TRACE, "BindInterfaceToAdapter: Bind interface # %d to adapter # %d",
icbp->InterfaceIndex,
acbp->AdapterIndex);
if(icbp->acbp != NULL)
{
Trace(BIND_TRACE, "BindInterfaceToAdapter: interface # %d already bound !!!",
icbp->InterfaceIndex);
//SS_ASSERT(FALSE);
return;
}
// Make sure that the adapter is not currently claimed by any
// interface either.
//
if ((acbp->icbp) && (acbp->icbp->acbp == acbp))
{
Trace(
BIND_TRACE,
"BindInterfaceToAdapter: adapter # %d already bound to int # %d!!",
acbp->AdapterIndex,
acbp->icbp->InterfaceIndex);
return;
}
// internal bind the adapter control block and the interface control block
icbp->acbp = acbp;
acbp->icbp = icbp;
// if a connection was requested on this if, mark that it has been done
if(icbp->ConnectionRequestPending) {
icbp->ConnectionRequestPending = FALSE;
}
if(!icbp->InterfaceReachable) {
// we should never hit this code path in normal operation
// However, should anybody atempt and succeed a dial (manually?) on an
// interface marked unreachable, we should reset our state
// icbp->InterfaceReachable = TRUE;
if(icbp->AdminState == ADMIN_STATE_ENABLED) {
// enable all static routes for this interface
EnableStaticRoutes(icbp->InterfaceIndex);
// enable external interfaces. Implicitly, this will enable static services
// bound to this interface to be advertised
ExternalEnableInterface(icbp->InterfaceIndex);
}
}
if (icbp->AdminState==ADMIN_STATE_ENABLED) {
icbp->OperState = OPER_STATE_UP;
// create a local route entry in RTM for the connected interface
RMCreateLocalRoute(icbp);
}
ExternalBindInterfaceToAdapter(icbp);
// if the interface is a local client type (i.e. host doing manual dial from
// the local machine, try to update the internal routing table
if(icbp->MIBInterfaceType == IF_TYPE_ROUTER_WORKSTATION_DIALOUT) {
if((rc = RtProtRequestRoutesUpdate(icbp->InterfaceIndex)) == NO_ERROR) {
icbp->UpdateReq.RoutesReqStatus = UPDATE_PENDING;
}
else
{
Trace(UPDATE_TRACE, "BindInterfaceToAdapter: Routing Update is Disabled");
}
if((rc = RtProtRequestServicesUpdate(icbp->InterfaceIndex)) == NO_ERROR) {
icbp->UpdateReq.ServicesReqStatus = UPDATE_PENDING;
}
else
{
Trace(UPDATE_TRACE, "BindInterfaceToAdapter: Services Update is Disabled");
}
}
}
/*++
Function: UnbindInterfaceFromAdapter
Descr: Unbind the Rip, Sap and Forwarder interfaces with this index from
the respective adapter
--*/
VOID
UnbindInterfaceFromAdapter(PICB icbp)
{
PACB acbp;
ULONG new_if_oper_state;
acbp = icbp->acbp;
if (acbp==NULL) {
Trace(BIND_TRACE, "UnbindInterfaceFromAdapter:Interface # %d is not bound to any adapter",
icbp->InterfaceIndex);
return;
}
Trace(BIND_TRACE, "UnbindInterfaceFromAdapter: Unbind interface # %d from adapter # %d",
icbp->InterfaceIndex,
acbp->AdapterIndex);
switch(icbp->MIBInterfaceType) {
case IF_TYPE_PERSONAL_WAN_ROUTER:
case IF_TYPE_WAN_WORKSTATION:
case IF_TYPE_WAN_ROUTER:
case IF_TYPE_ROUTER_WORKSTATION_DIALOUT:
if (icbp->AdminState==ADMIN_STATE_ENABLED) {
icbp->OperState = OPER_STATE_SLEEPING;
break;
}
default:
icbp->OperState = OPER_STATE_DOWN;
break;
}
if (icbp->AdminState==ADMIN_STATE_ENABLED) {
// delete local route and ext unbind
RMDeleteLocalRoute(icbp);
}
ExternalUnbindInterfaceFromAdapter(icbp->InterfaceIndex);
// if there were updates going on they will get cancelled automatically
// by the respective routing protocols.
// We just have to reset the update state in the ICB
ResetUpdateRequest(icbp);
// Now we can unbind the adapter from interface
acbp->icbp = NULL;
icbp->acbp = NULL;
}
/*++
Function: GetNextInterfaceIndex
Descr: Returns the next available interface index. There are a number of
policies to consider here. The one we'll use is to keep the
interface index a small number and to return the first unused
interface index between 1 and MAX_INTERFACE_INDEX.
Note: Called with database locked
--*/
ULONG
GetNextInterfaceIndex(VOID)
{
PICB icbp;
PLIST_ENTRY lep;
ULONG i;
if((icbp = GetInterfaceByIndex(1)) == NULL) {
return 1;
}
lep = icbp->IndexListLinkage.Flink;
i = 2;
while(lep != &IndexIfList)
{
icbp = CONTAINING_RECORD(lep, ICB, IndexListLinkage);
if(i < icbp->InterfaceIndex) {
return i;
}
i = icbp->InterfaceIndex + 1;
if(i == MAX_INTERFACE_INDEX) {
// abort
SS_ASSERT(FALSE);
return i;
}
lep = icbp->IndexListLinkage.Flink;
}
SS_ASSERT(i < MAX_INTERFACE_INDEX);
return i;
}
VOID
SetAdapterBindingInfo(PIPX_ADAPTER_BINDING_INFO abip,
PACB acbp)
{
abip->AdapterIndex = acbp->AdapterIndex;
memcpy(abip->Network, acbp->AdapterInfo.Network, 4);
memcpy(abip->LocalNode, acbp->AdapterInfo.LocalNode, 6);
if(acbp->AdapterInfo.NdisMedium != NdisMediumWan) {
memcpy(abip->RemoteNode, bcastnode, 6);
}
else
{
memcpy(abip->RemoteNode, acbp->AdapterInfo.RemoteNode, 6);
}
abip->MaxPacketSize = acbp->AdapterInfo.MaxPacketSize;
abip->LinkSpeed = acbp->AdapterInfo.LinkSpeed;
}
VOID
ExternalBindInterfaceToAdapter(PICB icbp)
{
PACB acbp;
IPX_ADAPTER_BINDING_INFO abi;
acbp = icbp->acbp;
SetAdapterBindingInfo(&abi, acbp);
FwBindFwInterfaceToAdapter(icbp->InterfaceIndex, &abi);
BindRoutingProtocolsIfsToAdapter(icbp->InterfaceIndex, &abi);
}
VOID
ExternalUnbindInterfaceFromAdapter(ULONG InterfaceIndex)
{
UnbindRoutingProtocolsIfsFromAdapter(InterfaceIndex);
FwUnbindFwInterfaceFromAdapter(InterfaceIndex);
}
VOID
ExternalEnableInterface(ULONG InterfaceIndex)
{
RoutingProtocolsEnableIpxInterface(InterfaceIndex);
FwEnableFwInterface(InterfaceIndex);
}
VOID
ExternalDisableInterface(ULONG InterfaceIndex)
{
FwDisableFwInterface(InterfaceIndex);
RoutingProtocolsDisableIpxInterface(InterfaceIndex);
}
VOID
RMCreateLocalRoute(PICB icbp)
{
PADAPTER_INFO aip;
// check if a network number has been assigned to this interface
aip = &(icbp->acbp->AdapterInfo);
if(!memcmp(aip->Network, nullnet, 4)) {
// no net number
return;
}
// if the interface is a remote workstation and global wan net exists,
// we are done.
if((icbp->MIBInterfaceType == IF_TYPE_WAN_WORKSTATION) &&
EnableGlobalWanNet &&
!LanOnlyMode) {
SS_ASSERT(!memcmp(aip->Network, GlobalWanNet, 4));
return;
}
CreateLocalRoute(icbp);
}
VOID
RMDeleteLocalRoute(PICB icbp)
{
PADAPTER_INFO aip;
// check if a network number has been assigned to this interface
aip = &(icbp->acbp->AdapterInfo);
if(!memcmp(aip->Network, nullnet, 4)) {
// no net number
return;
}
// if the interface is a remote workstation and global wan net exists,
// we are done.
if((icbp->MIBInterfaceType == IF_TYPE_WAN_WORKSTATION) &&
EnableGlobalWanNet &&
!LanOnlyMode) {
SS_ASSERT(!memcmp(aip->Network, GlobalWanNet, 4));
return;
}
DeleteLocalRoute(icbp);
}
VOID
AdminEnable(PICB icbp)
{
PACB acbp;
IPX_ADAPTER_BINDING_INFO aii;
if(icbp->AdminState == ADMIN_STATE_ENABLED) {
return;
}
icbp->AdminState = ADMIN_STATE_ENABLED;
InterfaceEnabled (icbp->hDIMInterface, PID_IPX, TRUE);
if(icbp->acbp != NULL) {
// bound to adapter
icbp->OperState = OPER_STATE_UP;
RMCreateLocalRoute(icbp);
}
else {
switch(icbp->MIBInterfaceType) {
case IF_TYPE_PERSONAL_WAN_ROUTER:
case IF_TYPE_WAN_WORKSTATION:
case IF_TYPE_WAN_ROUTER:
case IF_TYPE_ROUTER_WORKSTATION_DIALOUT:
icbp->OperState = OPER_STATE_SLEEPING;
break;
default:
icbp->OperState = OPER_STATE_DOWN;
break;
}
}
// if REACHABLE, resume advertising routes and services
if(icbp->InterfaceReachable) {
// enable all static routes for this interface
EnableStaticRoutes(icbp->InterfaceIndex);
// enable external interfaces. Implicitly, this will enable static services
// bound to this interface to be advertised
ExternalEnableInterface(icbp->InterfaceIndex);
}
}
VOID
AdminDisable(PICB icbp)
{
if(icbp->AdminState == ADMIN_STATE_DISABLED) {
return;
}
icbp->AdminState = ADMIN_STATE_DISABLED;
InterfaceEnabled (icbp->hDIMInterface, PID_IPX, FALSE);
icbp->OperState = OPER_STATE_DOWN;
if(icbp->acbp != NULL)
RMDeleteLocalRoute(icbp);
// disable all static routes for this interface
DisableStaticRoutes(icbp->InterfaceIndex);
// disable external interfaces. Implicitly, static services bound to this
// interface will stop being advertised.
ExternalDisableInterface(icbp->InterfaceIndex);
}
NET_INTERFACE_TYPE
MapIpxToNetInterfaceType(PICB icbp)
{
NET_INTERFACE_TYPE NetInterfaceType;
switch(icbp->MIBInterfaceType) {
case IF_TYPE_WAN_ROUTER:
case IF_TYPE_PERSONAL_WAN_ROUTER:
NetInterfaceType = DEMAND_DIAL;
break;
case IF_TYPE_ROUTER_WORKSTATION_DIALOUT:
NetInterfaceType = LOCAL_WORKSTATION_DIAL;
break;
case IF_TYPE_WAN_WORKSTATION:
NetInterfaceType = REMOTE_WORKSTATION_DIAL;
break;
default:
NetInterfaceType = PERMANENT;
break;
}
return NetInterfaceType;
}
/*++
Function: I_SetFilters
Descr: Internal parses the traffic filter info block and sets the filter
driver info.
--*/
/*
DWORD
I_SetFilters(ULONG InterfaceIndex,
ULONG FilterMode, // inbound or outbound
LPVOID FilterInfop)
{
PIPX_TRAFFIC_FILTER_GLOBAL_INFO gip;
PIPX_TOC_ENTRY tocep;
LPVOID FilterDriverInfop;
ULONG FilterDriverInfoSize;
DWORD rc;
if(FilterInfop == NULL) {
// remove all filters
rc = SetFilters(InterfaceIndex,
FilterMode, // in or outbound,
0,
0,
NULL,
0);
return rc;
}
gip = GetInfoEntry((PIPX_INFO_BLOCK_HEADER)FilterInfop,
IPX_TRAFFIC_FILTER_GLOBAL_INFO_TYPE);
if(gip == NULL) {
return ERROR_CAN_NOT_COMPLETE;
}
FilterDriverInfop = GetInfoEntry((PIPX_INFO_BLOCK_HEADER)FilterInfop,
IPX_TRAFFIC_FILTER_INFO_TYPE);
if(FilterDriverInfop == NULL) {
rc = SetFilters(InterfaceIndex,
FilterMode, // in or outbound,
0, // pass or don't pass
0, // filter size
NULL,
0);
return rc;
}
tocep = GetTocEntry((PIPX_INFO_BLOCK_HEADER)FilterInfop,
IPX_TRAFFIC_FILTER_INFO_TYPE);
FilterDriverInfoSize = tocep->Count * tocep->InfoSize;
rc = SetFilters(InterfaceIndex,
FilterMode, // in or outbound,
gip->FilterAction, // pass or don't pass
tocep->InfoSize, // filter size
FilterDriverInfop,
FilterDriverInfoSize);
return rc;
}
*/
/*++
Function: I_GetFilters
Descr: Internal builds the traffic filters info block from the filter driver
information.
--*/
/*
typedef struct _FILTERS_INFO_HEADER {
IPX_INFO_BLOCK_HEADER Header;
IPX_TOC_ENTRY TocEntry;
IPX_TRAFFIC_FILTER_GLOBAL_INFO GlobalInfo;
} FILTERS_INFO_HEADER, *PFILTERS_INFO_HEADER;
DWORD
I_GetFilters(ULONG InterfaceIndex,
ULONG FilterMode,
LPVOID FilterInfop,
PULONG FilterInfoSize)
{
DWORD rc;
ULONG FilterAction;
ULONG FilterSize;
PFILTERS_INFO_HEADER fhp;
LPVOID FilterDriverInfop;
ULONG FilterDriverInfoSize = 0;
PIPX_TOC_ENTRY tocep;
if((FilterInfop == NULL) || (*FilterInfoSize == 0)) {
// we are asked for size
rc = GetFilters(InterfaceIndex,
FilterMode,
&FilterAction,
&FilterSize,
NULL,
&FilterDriverInfoSize);
if((rc != NO_ERROR) && (rc != ERROR_INSUFFICIENT_BUFFER)) {
return ERROR_CAN_NOT_COMPLETE;
}
if(FilterDriverInfoSize) {
// there are filters
*FilterInfoSize = sizeof(FILTERS_INFO_HEADER) + FilterDriverInfoSize;
return ERROR_INSUFFICIENT_BUFFER;
}
else
{
// NO filters exist
*FilterInfoSize = 0;
return NO_ERROR;
}
}
if(*FilterInfoSize <= sizeof(FILTERS_INFO_HEADER)) {
return ERROR_INSUFFICIENT_BUFFER;
}
FilterDriverInfoSize = *FilterInfoSize - sizeof(FILTERS_INFO_HEADER);
FilterDriverInfop = (LPVOID)((PUCHAR)FilterInfop + sizeof(FILTERS_INFO_HEADER));
rc = GetFilters(InterfaceIndex,
FilterMode,
&FilterAction,
&FilterSize,
FilterDriverInfop,
&FilterDriverInfoSize);
if(rc != NO_ERROR) {
if(rc == ERROR_MORE_DATA) {
*FilterInfoSize = sizeof(FILTERS_INFO_HEADER) + FilterDriverInfoSize;
return ERROR_INSUFFICIENT_BUFFER;
}
else
{
return ERROR_CAN_NOT_COMPLETE;
}
}
// got it
fhp = (PFILTERS_INFO_HEADER)FilterInfop;
fhp->Header.Version = IPX_ROUTER_VERSION_1;
fhp->Header.Size = *FilterInfoSize;
fhp->Header.TocEntriesCount = 2;
tocep = fhp->Header.TocEntry;
tocep->InfoType = IPX_TRAFFIC_FILTER_GLOBAL_INFO_TYPE;
tocep->InfoSize = sizeof(IPX_TRAFFIC_FILTER_GLOBAL_INFO);
tocep->Count = 1;
tocep->Offset = (ULONG)((PUCHAR)&(fhp->GlobalInfo) - (PUCHAR)FilterInfop);
tocep++;
tocep->InfoType = IPX_TRAFFIC_FILTER_INFO_TYPE;
tocep->InfoSize = FilterSize;
tocep->Count = FilterDriverInfoSize / FilterSize;
tocep->Offset = sizeof(FILTERS_INFO_HEADER);
fhp->GlobalInfo.FilterAction = FilterAction;
return NO_ERROR;
}
*/