IF.C

/*++ 

Copyright 1997 - 1998 Microsoft Corporation

Module Name:

sample\ip\if.c

Abstract:
Interface related functions exported by the Sample Routing Protocol DLL and
other code dealing with interfaces

Revision History:


--*/

#include "sampinc.h"



BOOL
ValidateInterfaceInfo(
PSAMPLE_PROTOCOL_INTERFACE_INFO pInfo
);
DWORD
ActivateBinding(
PINTRNL_IF pBind
);
DWORD
DeactivateBinding(
PINTRNL_IF pBind
);
PNT_IF
GetIfBlockGivenIndex(
DWORD dwIndex
);
PINTRNL_IF
GetBindingGivenAddress(
PNT_IF pIf,
DWORD dwAddress
);
DWORD
CreateSocket(
IN DWORD dwAddress,
OUT SOCKET *psSocket
);


DWORD
APIENTRY
AddInterface(
IN PWCHAR pwszInterfaceName,
IN DWORD dwIndex,
IN NET_INTERFACE_TYPE dwIfType,
IN PVOID pvConfig
)
/*++
Routine Description
Called by the IP Router Manager to add an interface when
it finds our information block (header) within the interface's
configuration.
We verify the information and create the structure for the
interface. Then we see all the configured addresses for
the interface and create a binding structure for each address
The interface comes up as UNBOUND-DISABLED

Arguments
pwszInterfaceName The name of the interface. We store it for logging
dwIndex The positive integer this interface will be referred to by
dwIfType The type of the interface (WAN/LAN etc)
pvConfig Our config for this interface

Return Value
ERROR_INVALID_PARAMETER
ERROR_INVALID_DATA
NO_ERROR

--*/
{
ULONG ulNameLen,i;
DWORD dwResult;
PWCHAR pwszName;
PINTRNL_IF pBind;
PNT_IF pIf,pPrev;
PLIST_ENTRY pleNode;


PSAMPLE_PROTOCOL_INTERFACE_INFO pIfInfo;


EnterProtocolApi();

TraceEnter("AddInterface");

Trace3(INTF, "AddInterface called for: %S %d %d ",
pwszInterfaceName,
dwIndex,
dwIfType);

ulNameLen = wcslen(pwszInterfaceName);

if((pwszInterfaceName == NULL) ||
(pvConfig == NULL) ||
(ulNameLen == 0))
{
Trace0(ERR,
"AddInterface: Router Manager called us with NULL info");

TraceLeave("AddInterface");

ExitProtocolApi();

return ERROR_INVALID_PARAMETER;
}

pIfInfo = (PSAMPLE_PROTOCOL_INTERFACE_INFO)pvConfig;

if(!ValidateInterfaceInfo(pIfInfo))
{
TraceLeave("AddInterface");

ExitProtocolApi();

return ERROR_INVALID_DATA;
}

EnterCriticalSection(&g_csIfListLock);

//
// Create the interface block and the blocks for the binding
//

dwResult = NO_ERROR;

__try
{
pIf = HeapAlloc(g_hPrivateHeap,
HEAP_ZERO_MEMORY,
sizeof(NT_IF));

if(pIf == NULL)
{
dwResult = GetLastError();

Trace1(ERR,
"AddInterface: Error %d allocating memory for i/f",
dwResult);

__leave;
}

InitializeListHead(&pIf->leInternalIfHead);

pwszName = HeapAlloc(g_hPrivateHeap,
HEAP_ZERO_MEMORY,
(ulNameLen + 1)*sizeof(WCHAR));

if(pwszName == NULL)
{
dwResult = GetLastError();

Trace1(ERR,
"AddInterface: Error %d allocating memory for name",
dwResult);

__leave;
}

wcscpy(pwszName,
pwszInterfaceName);

pIf->pwszIfName = pwszName;

ClearNtState(pIf);

pIf->dwType = dwIfType;

pIf->ulNumBindings = pIfInfo->ulNumBindings;

for(i = 0; i < pIfInfo->ulNumBindings; i++)
{
pBind = HeapAlloc(g_hPrivateHeap,
HEAP_ZERO_MEMORY,
sizeof(INTRNL_IF));

if(pBind == NULL)
{
dwResult = GetLastError();

Trace1(ERR,
"AddInterface: Error %d allocating memory for internal i/f",
dwResult);

__leave;
}

InsertHeadList(&(pIf->leInternalIfHead),
&(pBind->leInternalIfLink));

//
// Copy out binding info
//

pBind->dwAddress = pIfInfo->rgbiInfo[i].dwAddress;
pBind->dwMask = pIfInfo->rgbiInfo[i].dwMask;
pBind->bEnabled = pIfInfo->rgbiInfo[i].bEnabled;
pBind->dwState = BINDING_DOWN;
pBind->sSocket = INVALID_SOCKET;

if(pIfInfo->ulNumBindings == 1)
{
//
// If we have only one address, we set that to 0.0.0.0
// for now even if our config has screwed up
//

pBind->dwAddress = 0x00000000;
pBind->dwMask = 0x00000000;
}
}
}
__finally
{
if(dwResult != NO_ERROR)
{
//
// Clean up all resources
//

if(pIf)
{
if(pIf->pwszIfName)
{
HeapFree(g_hPrivateHeap,
0,
pIf->pwszIfName);
}

pleNode = pIf->leInternalIfHead.Flink;

while(pleNode != &pIf->leInternalIfHead)
{
pBind = CONTAINING_RECORD(pleNode,
INTRNL_IF,
leInternalIfLink);

pleNode = pleNode->Flink;

HeapFree(g_hPrivateHeap,
0,
pBind);
}
}
}
else
{
//
// Insert the interface into our link
//

for(pleNode = g_leIfListHead.Flink;
pleNode != &g_leIfListHead;
pleNode = pleNode->Flink)
{
pPrev = CONTAINING_RECORD(pleNode,
NT_IF,
leNtIfLink);

if(pPrev->dwNtIndex > dwIndex)
{
break;
}
}

//
// pPrev now points to the interface with a higher index
// pPrev->Blink < dwIndex so put our interface after
// pPrev->Blink. This way we get an ordered list
//

InsertHeadList(pPrev->leNtIfLink.Blink,
&(pIf->leNtIfLink));

}
}


LeaveCriticalSection(&g_csIfListLock);

TraceLeave("AddInterface");

ExitProtocolApi();

return dwResult;
}


DWORD
APIENTRY
DeleteInterface(
IN DWORD dwIndex
)
/*++
Routine Description
Called by the IP Router Manager to delete an interface. If the interface is
running we shut it down and free all the resources used by it

Arguments
dwIndex The index of the interface to be deleted

Return Value
ERROR_INVALID_PARAMETER If an interface with the given index was not found
NO_ERROR

--*/
{
PNT_IF pIf;
PLIST_ENTRY pleNode;
PINTRNL_IF pBind;


EnterProtocolApi();

TraceEnter("DeleteInterface");

Trace1(ERR,
"DeleteInterface: Called for interface %d",
dwIndex);

EnterCriticalSection(&g_csIfListLock);

pIf = GetIfBlockGivenIndex(dwIndex);

if(pIf == NULL)
{
//
// Did not have an interface corresponding to
// this index
//

LeaveCriticalSection(&g_csIfListLock);

Trace1(ERR,
"DeleteInterface: Interface %d does not exist",
dwIndex);

TraceLeave("DeleteInterface");

ExitProtocolApi();

return ERROR_INVALID_PARAMETER;
}

//
// Remove it from the list of NT Interfaces
//

RemoveEntryList(&(pIf->leNtIfLink));

ASSERT(pIf->dwNtIndex == dwIndex);
ASSERT(pIf->pwszIfName);

//
// Shut down each binding on the interface. We may have already
// gotten Unbind() calls so they may have already been shut down
//

pleNode = pIf->leInternalIfHead.Flink;

while(pleNode != &(pIf->leInternalIfHead))
{
pBind = CONTAINING_RECORD(pleNode, INTRNL_IF, leInternalIfLink);

pleNode = pleNode->Flink;

if(pBind->dwState == BINDING_UP)
{
//
// So we did not get an unbind or disable for this
//

ASSERT(pBind->sSocket != INVALID_SOCKET);

if(closesocket(pBind->sSocket) != NO_ERROR)
{
Trace3(ERR,
"DeleteInterface: Error %d closing socket %d on interface %S",
WSAGetLastError(),
pBind->sSocket,
pIf->pwszIfName);
}
}

HeapFree(g_hPrivateHeap,
0,
pBind);
}

//
// Free other resources
//

HeapFree(g_hPrivateHeap,
0,
pIf->pwszIfName);


//
// Lastly free the interface itself
//

HeapFree(g_hPrivateHeap,
0,
pIf);


LeaveCriticalSection(&g_csIfListLock);

TraceLeave("AddInterface");

ExitProtocolApi();

return NO_ERROR;
}


DWORD
APIENTRY
GetInterfaceConfigInfo(
IN DWORD dwIndex,
IN OUT PVOID pvConfig,
IN OUT PDWORD pdwSize
)
/*++
Routine Description
Called by the IP Router Manager to retrieve an interface's configuration.
Usually this is because an admin utility is displaying this information.
The Router Manager calls us with a NULL config and ZERO size. We return
the required size to it. It then allocates the needed memory and calls
us a second time with a valid buffer. We validate parameters each time
and copy out our config if we can

Arguments
dwIndex Index of the interface being queried
pvConfig Pointer to buffer to store the config
pdwSize Size of the buffer

Return Value
ERROR_INSUFFICIENT_BUFFER If the size of the buffer is too small
ERROR_INVALID_PARAMETER
ERROR_INVALID_DATA
NO_ERROR

--*/
{
PNT_IF pIf;
PLIST_ENTRY pleNode;
PINTRNL_IF pBind;
ULONG i;

PSAMPLE_PROTOCOL_INTERFACE_INFO pIfInfo;


EnterProtocolApi();

TraceEnter("GetInterfaceConfigInfo");

if(pdwSize == NULL)
{
Trace0(ERR,
"GetInterfaceConfigInfo: Router Manager called us with NULL size");

TraceLeave("GetInterfaceConfigInfo");

ExitProtocolApi();

return ERROR_INVALID_PARAMETER;
}

EnterCriticalSection(&g_csIfListLock);

pIf = GetIfBlockGivenIndex(dwIndex);

if(pIf == NULL)
{
LeaveCriticalSection(&g_csIfListLock);

Trace1(ERR,
"GetInterfaceConfigInfo: Interface %d does not exist",
dwIndex);

TraceLeave("GetInterfaceConfigInfo");

ExitProtocolApi();

return ERROR_INVALID_PARAMETER;
}

if(*pdwSize < SIZEOF_PROTO_IF_INFO(pIf->ulNumBindings))
{
*pdwSize = SIZEOF_PROTO_IF_INFO(pIf->ulNumBindings);

LeaveCriticalSection(&g_csIfListLock);

TraceLeave("GetInterfaceConfigInfo");

ExitProtocolApi();

return ERROR_INSUFFICIENT_BUFFER;
}

*pdwSize = SIZEOF_PROTO_IF_INFO(pIf->ulNumBindings);

if(pvConfig == NULL)
{
LeaveCriticalSection(&g_csIfListLock);

Trace0(ERR,
"GetInterfaceConfigInfo: Router Manager called us with NULL config buffer");

TraceLeave("GetInterfaceConfigInfo");

ExitProtocolApi();

return ERROR_INVALID_PARAMETER;
}

//
// So we have a good buffer of the right size
// Copy out the info
//


pIfInfo = (PSAMPLE_PROTOCOL_INTERFACE_INFO)pvConfig;

pIfInfo->ulNumBindings = pIf->ulNumBindings;

for(pleNode = pIf->leInternalIfHead.Flink, i = 0;
pleNode != &pIf->leInternalIfHead;
pleNode = pleNode->Flink, i++)
{
pBind = CONTAINING_RECORD(pleNode, INTRNL_IF, leInternalIfLink);

pIfInfo->rgbiInfo[i].dwAddress = pBind->dwAddress;
pIfInfo->rgbiInfo[i].dwMask = pBind->dwMask;
pIfInfo->rgbiInfo[i].bEnabled = pBind->bEnabled;
}

ASSERT(i == pIf->ulNumBindings);

//
// If we had only one address we will return 0.0.0.0 as the address
// even if we know what the current address is
//

if(pIf->ulNumBindings == 1)
{
pIfInfo->rgbiInfo[0].dwAddress = 0x00000000;
pIfInfo->rgbiInfo[0].dwMask = 0x00000000;
}

LeaveCriticalSection(&g_csIfListLock);

TraceLeave("GetInterfaceConfigInfo");

ExitProtocolApi();

return NO_ERROR;
}

DWORD
APIENTRY
SetInterfaceConfigInfo(
IN DWORD dwIndex,
IN PVOID pvConfig
)
/*++
Routine Description


Arguments


Return Value
NO_ERROR

--*/
{
PNT_IF pIf;

PSAMPLE_PROTOCOL_INTERFACE_INFO pIfInfo;


EnterProtocolApi();

TraceEnter("SetInterfaceConfigInfo");

if(pvConfig == NULL)
{
//
// A NULL config means no change
//

TraceLeave("SetInterfaceConfigInfo");

ExitProtocolApi();

return NO_ERROR;
}

pIfInfo = (PSAMPLE_PROTOCOL_INTERFACE_INFO)pvConfig;

if(!ValidateInterfaceInfo(pIfInfo))
{
TraceLeave("SetInterfaceConfigInfo");

ExitProtocolApi();

return ERROR_INVALID_DATA;
}

EnterCriticalSection(&g_csIfListLock);

pIf = GetIfBlockGivenIndex(dwIndex);

if(pIf == NULL)
{
Trace1(ERR,
"SetInterfaceConfigInfo: Interface %d does not exist",
dwIndex);

TraceLeave("SetInterfaceConfigInfo");

ExitProtocolApi();

return ERROR_INVALID_PARAMETER;
}

//
// Do what needs to be done with the info
//


return NO_ERROR;
}


DWORD
APIENTRY
BindInterface(
IN DWORD dwIndex,
IN PVOID pBinding
)
/*++
Routine Description
Called by the IP Router Manager once it learns the address(es) on an
interface. This may happen as soon as the router starts (after the
interface is added, ofcourse) when the interface has a static address
or may happen when an interface acquires a DHCP address or may happen
when IPCP acquire the address for a dial up link
The binding may consist of one or more addresses. We walk the addresses
given and find the corresponding block in our config. We then update
any information and if the interface has been enabled, we activate the
binding, i.e. begin running on it.

Arguments
dwIndex Index of the interface in question
pBinding Pointer to IP_ADAPTER_BINDING_INFO containing info about
the addresses on the interface

Return Value
ERROR_INVALID_PARAMETER
NO_ERROR

--*/
{
PNT_IF pIf;
PLIST_ENTRY pleNode;
PINTRNL_IF pBind;
ULONG i;
DWORD dwResult;

PIP_ADAPTER_BINDING_INFO pBindingInfo;

EnterProtocolApi();

TraceEnter("BindInterface");

if(pBinding == NULL)
{
Trace0(ERR,
"BindInterface: Router Manager called us with NULL binding");

TraceLeave("BindInterface");

ExitProtocolApi();

return ERROR_INVALID_PARAMETER;
}

pBindingInfo = (PIP_ADAPTER_BINDING_INFO)pBinding;

if(pBindingInfo->NumAddresses < 1)
{
Trace0(ERR,
"BindInterface: Router Manager called us with NO binding");

TraceLeave("BindInterface");

ExitProtocolApi();

return ERROR_INVALID_PARAMETER;
}


EnterCriticalSection(&g_csIfListLock);

pIf = GetIfBlockGivenIndex(dwIndex);

if(pIf == NULL)
{
LeaveCriticalSection(&g_csIfListLock);

Trace1(ERR,
"BindInterface: Interface %d does not exist",
dwIndex);

TraceLeave("BindInterface");

ExitProtocolApi();

return ERROR_INVALID_PARAMETER;
}

if(IsNtBound(pIf))
{
//
// Can not receive two bind notifications without an
// Unbind in the middle
//

Trace1(ERR,
"BindInterface: Interface %S is already bound",
pIf->pwszIfName);

LeaveCriticalSection(&g_csIfListLock);


TraceLeave("BindInterface");

ExitProtocolApi();

return ERROR_INVALID_PARAMETER;
}

SetNtBound(pIf);

for(i = 0; i < pBindingInfo->NumAddresses; i++)
{
pBind = GetBindingGivenAddress(pIf,
pBindingInfo->Address[i].IPAddress);

if(pBind == NULL)
{
//
// Our config is bad, we will try and go through all the blocks
// and see if we can atleast bind on the others.
//

Trace3(ERR,
"BindInterface: Couldnt find config block for %d.%d.%d.%d/%d.%d.%d.%d over %S",
PRINT_ADDRESS(pBindingInfo->Address[i].IPAddress),
PRINT_ADDRESS(pBindingInfo->Address[i].Mask),
pIf->pwszIfName);

continue;
}

if(pBindingInfo->NumAddresses == 1)
{
//
// If we have only one address, then the addresses
// may not match, so update them
//

pBind->dwAddress = pBindingInfo->Address[i].IPAddress;
pBind->dwMask = pBindingInfo->Address[i].Mask;
}
}

#if DBG

//
// Check to make sure we got bindings for all the configured addresses
//

if(pIf->ulNumBindings > 1)
{
for(pleNode = pIf->leInternalIfHead.Flink;
pleNode != &pIf->leInternalIfHead;
pleNode = pleNode->Flink)
{
bFound = FALSE;

pBind = CONTAINING_RECORD(pleNode, INTRNL_IF, leInternalIfLink);

for(i = 0; i < pBindingInfo->NumAddresses; i++)
{
if(pBind->dwAddress == pBindingInfo->Address[i].IPAddress)
{
ASSERT(pBind->dwMask == pBindingInfo->Address[i].Mask);

bFound = TRUE;
break;
}
}

if(!bFound)
{
Trace3(ERR,
"BindInterface: Binding not indicated for %d.%d.%d.%d/%d.%d.%d.%d over %S",
PRINT_ADDRESS(pBind->dwAddress),
PRINT_ADDRESS(pBind->dwMask),
pIf->pwszIfName);
}
}
}

#endif // DBG


//
// OK now we have the bindings all set up
//

if(IsNtEnabled(pIf))
{
//
// So the interface is bound and enabled => we are all set
// to go
//

for(pleNode = pIf->leInternalIfHead.Flink;
pleNode != &pIf->leInternalIfHead;
pleNode = pleNode->Flink)
{
pBind = CONTAINING_RECORD(pleNode, INTRNL_IF, leInternalIfLink);

if(pBind->bEnabled)
{
//
// Our config tells us that we are enabled for this address
//

ASSERT(pBind->dwState != BINDING_UP);

//
// This will set the state to BINDING_UP
//

dwResult = ActivateBinding(pBind);

if(dwResult != NO_ERROR)
{
Trace2(ERR,
"BindInterface: Unable to activate %d.%d.%d.%d over %S",
PRINT_ADDRESS(pBind->dwAddress),
pIf->pwszIfName);
}
}
}
}

LeaveCriticalSection(&g_csIfListLock);

TraceLeave("BindInterface");

ExitProtocolApi();

return NO_ERROR;
}

DWORD
APIENTRY
UnBindInterface(
IN DWORD dwIndex
)
/*++
Routine Description
Called when the interface loses its IP Address(es). This may
happen when the interface is shutting down. It may be because an
admin Disabled the interface with IP (as opposed to just disabling
or protocol on the interface). It can happen when the admin releases
a DHCP acquired interface or when a dial up link disconnects
We see if we were running on the binding and if so, we shut it down.
We dont release any memory associated with the binding because
we can get bound again

Arguments
dwIndex The index of the interface being unbound

Return Value
ERROR_INVALID_PARAMETER
NO_ERROR

--*/
{
PNT_IF pIf;
PLIST_ENTRY pleNode;
PINTRNL_IF pBind;
DWORD dwResult;


EnterProtocolApi();

TraceEnter("UnbindInterface");

EnterCriticalSection(&g_csIfListLock);

pIf = GetIfBlockGivenIndex(dwIndex);

if(pIf == NULL)
{
LeaveCriticalSection(&g_csIfListLock);

Trace1(ERR,
"UnbindInterface: Interface %d does not exist",
dwIndex);

TraceLeave("UnbindInterface");

ExitProtocolApi();

return ERROR_INVALID_PARAMETER;
}

if(!IsNtBound(pIf))
{
//
// Nothing new happening
//

Trace1(INTF,
"UnbindInterface: Unbind received for %S which was never bound",
pIf->pwszIfName);

LeaveCriticalSection(&g_csIfListLock);

TraceLeave("UnbindInterface");

ExitProtocolApi();

return NO_ERROR;
}

ClearNtBound(pIf);

if(IsNtEnabled(pIf))
{
//
// Since it is enabled and was bound, deactivate the
// bindings
//

for(pleNode = pIf->leInternalIfHead.Flink;
pleNode != &pIf->leInternalIfHead;
pleNode = pleNode->Flink)
{
pBind = CONTAINING_RECORD(pleNode, INTRNL_IF, leInternalIfLink);

if(pBind->dwState == BINDING_UP)
{
//
// This binding had been successfully activated
//

dwResult = DeactivateBinding(pBind);

if(dwResult != NO_ERROR)
{
Trace2(ERR,
"UnbindInterface: Unable to deactivate %d.%d.%d.%d over %S",
PRINT_ADDRESS(pBind->dwAddress),
pIf->pwszIfName);
}
}
}

if(pIf->ulNumBindings == 1)
{
//
// Clear out the old address
//

pBind = CONTAINING_RECORD(pIf->leInternalIfHead.Flink,
INTRNL_IF,
leInternalIfLink);

pBind->dwAddress = 0x00000000;
pBind->dwMask = 0x00000000;
}
}

LeaveCriticalSection(&g_csIfListLock);

TraceLeave("UnbindInterface");

ExitProtocolApi();

return NO_ERROR;

}


DWORD
APIENTRY
EnableInterface(
IN DWORD dwIndex
)
/*++
Routine Description
An interface comes up in a DISABLED state. This function is
called by the router manager to enable the interface. It can also
be called when the interface is being reenabled after being disabled
by the admin
The bindings on an interface are kept across and Enable-Disable, so
we heck to see if we were already bound, and if so we activate the
protocol over the bindings.

Arguments
dwIndex Interface to be enabled

Return Value
NO_ERROR

--*/
{
PNT_IF pIf;
PLIST_ENTRY pleNode;
PINTRNL_IF pBind;
DWORD dwResult;


EnterProtocolApi();

TraceEnter("EnableInterface");

EnterCriticalSection(&g_csIfListLock);

pIf = GetIfBlockGivenIndex(dwIndex);

if(pIf == NULL)
{
LeaveCriticalSection(&g_csIfListLock);

Trace1(ERR,
"EnableInterface: Interface %d does not exist",
dwIndex);

TraceLeave("EnableInterface");

ExitProtocolApi();

return ERROR_INVALID_PARAMETER;
}

if(IsNtEnabled(pIf))
{
//
// Nothing new happening
//

Trace1(INTF,
"EnableInterface: Enable received for %S which is already enabled",
pIf->pwszIfName);

LeaveCriticalSection(&g_csIfListLock);

TraceLeave("EnableInterface");

ExitProtocolApi();

return NO_ERROR;
}

SetNtEnabled(pIf);

if(IsNtBound(pIf))
{
//
// Since it is enabled and bound, activate the bindings
//

for(pleNode = pIf->leInternalIfHead.Flink;
pleNode != &pIf->leInternalIfHead;
pleNode = pleNode->Flink)
{
pBind = CONTAINING_RECORD(pleNode, INTRNL_IF, leInternalIfLink);

ASSERT(pBind->dwState == BINDING_DOWN);

if(pBind->bEnabled)
{
dwResult = ActivateBinding(pBind);

if(dwResult != NO_ERROR)
{
Trace2(ERR,
"EnableInterface: Unable to activate %d.%d.%d.%d over %S",
PRINT_ADDRESS(pBind->dwAddress),
pIf->pwszIfName);
}
}
}
}

LeaveCriticalSection(&g_csIfListLock);

TraceLeave("EnableInterface");

ExitProtocolApi();

return NO_ERROR;
}


DWORD
APIENTRY
DisableInterface(
IN DWORD dwIndex
)
/*++
Routine Description
Called by the IP Router Manger to disable an interface. This is
usually in response to an admin setting the AdminStatus in IP to DOWN.
This is different from an admin just disabling the bEnabled flag in our
config because that is opaque to IP. That is a routing protocol specific
disable and is conveyed to us via SetInterfaceConfig() calls. THIS IS
AN IMPORTANT DISTINCTION. A ROUTING PROTOCOL NEEDS TO MANTAIN TWO STATES -
AN NT STATE AND A PROTOCOL SPECIFIC STATE.


Arguments
dwIndex The index of the interface to disable

Return Value
ERROR_INVALID_PARAMETER
NO_ERROR

--*/
{
PNT_IF pIf;
PLIST_ENTRY pleNode;

PINTRNL_IF  pBind; 
DWORD dwResult;


EnterProtocolApi();

TraceEnter("DisableInterface");

EnterCriticalSection(&g_csIfListLock);

pIf = GetIfBlockGivenIndex(dwIndex);

if(pIf == NULL)
{
LeaveCriticalSection(&g_csIfListLock);

Trace1(ERR,
"DisableInterface: Interface %d does not exist",
dwIndex);

TraceLeave("DisableInterface");

ExitProtocolApi();

return ERROR_INVALID_PARAMETER;
}

if(!IsNtEnabled(pIf))
{
//
// Nothing new happening
//

Trace1(INTF,
"DisableInterface: Disable received for %S which was never enabled",
pIf->pwszIfName);

LeaveCriticalSection(&g_csIfListLock);

TraceLeave("DisableInterface");

ExitProtocolApi();

return NO_ERROR;
}

ClearNtEnabled(pIf);

if(IsNtBound(pIf))
{
//
// Since it was enabled and is bound, it must have been
// activated, so deactivate the bindings now
//

for(pleNode = pIf->leInternalIfHead.Flink;
pleNode != &pIf->leInternalIfHead;
pleNode = pleNode->Flink)
{
pBind = CONTAINING_RECORD(pleNode, INTRNL_IF, leInternalIfLink);

if(pBind->dwState == BINDING_UP)
{
//
// This binding had been successfully activated
//

dwResult = DeactivateBinding(pBind);

if(dwResult != NO_ERROR)
{
Trace2(ERR,
"DisableInterface: Unable to deactivate %d.%d.%d.%d over %S",
PRINT_ADDRESS(pBind->dwAddress),
pIf->pwszIfName);
}
}
}
}

LeaveCriticalSection(&g_csIfListLock);

TraceLeave("DisableInterface");

ExitProtocolApi();

return NO_ERROR;

}


BOOL
ValidateInterfaceInfo(
PSAMPLE_PROTOCOL_INTERFACE_INFO pInfo
)
/*++
Routine Description


Locks


Arguments


Return Value
NO_ERROR

--*/
{
return TRUE;
}

PNT_IF
GetIfBlockGivenIndex(
DWORD dwIndex
)
/*++
Routine Description


Locks
Assumes the IF List lock is held

Arguments


Return Value
NO_ERROR

--*/
{
PLIST_ENTRY pleNode;
PNT_IF pIf;


for(pleNode = g_leIfListHead.Flink;
pleNode != &g_leIfListHead;
pleNode = pleNode->Flink)
{
pIf = CONTAINING_RECORD(pleNode,
NT_IF,
leNtIfLink);

if(pIf->dwNtIndex == dwIndex)
{
return pIf;
}

if(pIf->dwNtIndex > dwIndex)
{
//
// Since the list is ordered, we wont find this further on
//

return NULL;
}
}

return NULL;
}

PINTRNL_IF
GetBindingGivenAddress(
PNT_IF pIf,
DWORD dwAddress
)
/*++
Routine Description


Locks
Assumes the IF List lock is held

Arguments


Return Value
NO_ERROR

--*/
{

return NULL;
}

DWORD
ActivateBinding(
PINTRNL_IF pBind
)
/*++
Routine Description
Called when the interface needs to be brought up on this Address
We create a socket and fire it off

Locks
Assumes the IF List lock is held

Arguments


Return Value
NO_ERROR

--*/
{
DWORD dwResult;

ASSERT(pBind->dwState == BINDING_DOWN);
ASSERT(pBind->sSocket == INVALID_SOCKET);

ASSERT(pBind->dwAddress != 0x00000000);
ASSERT(pBind->dwMask != 0x00000000);

dwResult = CreateSocket(pBind->dwAddress,
&pBind->sSocket);

if(dwResult == NO_ERROR)
{
pBind->dwState = BINDING_UP;
}

return dwResult;
}

DWORD
DeactivateBinding(
PINTRNL_IF pBind
)
/*++
Routine Description


Locks
Assumes the IF List lock is held

Arguments


Return Value
NO_ERROR

--*/
{
ASSERT(pBind->dwState == BINDING_UP);
ASSERT(pBind->sSocket != INVALID_SOCKET);

ASSERT(pBind->dwAddress != 0x00000000);
ASSERT(pBind->dwMask != 0x00000000);

if(WSAEventSelect(pBind->sSocket,
(WSAEVENT)NULL,
0) == SOCKET_ERROR)
{
Trace2(ERR,
"DeactivateBinding: Error %d clearing socket (%d.%d.%d.%d) association with event",
WSAGetLastError(),
PRINT_ADDRESS(pBind->dwAddress));

}

closesocket(pBind->sSocket);

pBind->sSocket = INVALID_SOCKET;

return NO_ERROR;
}


DWORD
CreateSocket(
IN DWORD dwAddress,
OUT SOCKET *psSocket
)
/*++
Routine Description
Activates router discovery messages on an interface. The interface must already
be bound

Locks
ICB_LIST lock must be held as WRITER

Arguments
picb The ICB of the interface to activate

Return Value
NO_ERROR or some error code
--*/
{
DWORD dwResult, dwBytesReturned;
LINGER lLinger;
BOOL bOption, bLoopback;
SOCKADDR_IN sinSockAddr;
INT iScope;

TraceEnter("CreateSocket");

//
// Create the sockets for the interface
//

*psSocket = INVALID_SOCKET;

do
{
*psSocket = WSASocket(AF_INET,
SOCK_RAW,
SAMPLE_PROTOCOL_IP_ID,
NULL,
0,
WSA_FLAG_MULTIPOINT_C_LEAF|WSA_FLAG_MULTIPOINT_D_LEAF);

if(*psSocket == INVALID_SOCKET)
{
dwResult = WSAGetLastError();

Trace2(ERR,
"CreateSocket Couldnt create socket on %d.%d.%d.%d . Error %d",
PRINT_ADDRESS(dwAddress),
dwResult);

break;
}

//
// Set SO_LINGER to off
//

lLinger.l_onoff = 0;
lLinger.l_linger = 0;

if(setsockopt(*psSocket,
SOL_SOCKET,
SO_LINGER,
(const char *)&lLinger,
sizeof(LINGER)) == SOCKET_ERROR)
{
Trace2(ERR,
"CreateSocket: Couldnt set linger option on %d.%d.%d.%d - continuing. Error %d",
PRINT_ADDRESS(dwAddress),
WSAGetLastError());
}


//
// Set to SO_REUSEADDR
//

bOption = TRUE;

if(setsockopt(*psSocket,
SOL_SOCKET,
SO_REUSEADDR,
(const char FAR*)&bOption,
sizeof(BOOL)) == SOCKET_ERROR)
{
Trace2(ERR,
"CreateSocket: Couldnt set reuse option on %d.%d.%d.%d - continuing. Error %d",
PRINT_ADDRESS(dwAddress),
WSAGetLastError());
}

if(WSAEventSelect(*psSocket,
(WSAEVENT)g_hSocketEvent,
FD_READ) == SOCKET_ERROR)
{
dwResult = WSAGetLastError();

Trace2(ERR,
"CreateSocket: WSAEventSelect() failed for socket on %d.%d.%d.%d.Error %d",
PRINT_ADDRESS(dwAddress),
dwResult);

closesocket(*psSocket);

*psSocket = INVALID_SOCKET;

break;
}

//
// Bind to the addresses on the interface
//

sinSockAddr.sin_family = AF_INET;
sinSockAddr.sin_addr.s_addr = dwAddress;
sinSockAddr.sin_port = 0;

if(bind(*psSocket,
(const struct sockaddr FAR*)&sinSockAddr,
sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
{
dwResult = WSAGetLastError();

Trace2(ERR,
"CreateSocket: Couldnt bind to %d.%d.%d.%d. Error %d",
PRINT_ADDRESS(dwAddress),
dwResult);

closesocket(*psSocket);

*psSocket = INVALID_SOCKET;

break;
}

//
// Set scope/TTL to 1 since we always multicast the responses
// Also set Loopback to ignore self generated packets. Loopback
// d==card doesnt work currently on NT, so we still have code to
// filter our own multicasts in the receive path
//

bLoopback = FALSE;

dwResult = WSAIoctl(*psSocket,
SIO_MULTIPOINT_LOOPBACK,
(PVOID)&bLoopback,
sizeof(BOOL),
NULL,
0,
&dwBytesReturned,
NULL,
NULL);

if(dwResult == SOCKET_ERROR)
{
Trace2(ERR,
"CreateSocket: Error %d setting loopback to FALSE on %d.%d.%d.%d",
WSAGetLastError(),
PRINT_ADDRESS(dwAddress));
}

iScope = 1;

dwResult = WSAIoctl(*psSocket,
SIO_MULTICAST_SCOPE,
(PVOID)&iScope,
sizeof(INT),
NULL,
0,
&dwBytesReturned,
NULL,
NULL);

if(dwResult == SOCKET_ERROR)
{
Trace2(ERR,
"CreateSocket: Error %d setting multicast scope to 1 on %d.%d.%d.%d",
WSAGetLastError(),
PRINT_ADDRESS(dwAddress));
}


//
// Join the multicast session on SAMPLE_PROTOCOL_MULTICAST_GROUP1
//

sinSockAddr.sin_family = AF_INET;
sinSockAddr.sin_addr.s_addr = SAMPLE_PROTOCOL_MULTICAST_GROUP1;
sinSockAddr.sin_port = 0;

if(WSAJoinLeaf(*psSocket,
(const struct sockaddr FAR*)&sinSockAddr,
sizeof(SOCKADDR_IN),
NULL,
NULL,
NULL,
NULL,
JL_BOTH) == INVALID_SOCKET)
{
dwResult = WSAGetLastError();

Trace2(ERR,
"CreateSocket: Couldnt join multicast group1 on socket for %d.%d.%d.%d. Error %d",
PRINT_ADDRESS(dwAddress),
dwResult);

closesocket(*psSocket);

*psSocket = INVALID_SOCKET;

break;
}

//
// Join the multicast session on SAMPLE_PROTOCOL_MULTICAST_GROUP2
//

sinSockAddr.sin_family = AF_INET;
sinSockAddr.sin_addr.s_addr = SAMPLE_PROTOCOL_MULTICAST_GROUP2;
sinSockAddr.sin_port = 0;

if(WSAJoinLeaf(*psSocket,
(const struct sockaddr FAR*)&sinSockAddr,
sizeof(SOCKADDR_IN),
NULL,
NULL,
NULL,
NULL,
JL_BOTH) == INVALID_SOCKET)
{
dwResult = WSAGetLastError();

Trace2(ERR,
"CreateSocket: Couldnt join multicast group2 on socket on %d.%d.%d.%d. Error %d",
PRINT_ADDRESS(dwAddress),
dwResult);

closesocket(*psSocket);

*psSocket = INVALID_SOCKET;

break;
}

}while(FALSE);

TraceLeave("CreateSocket");

return dwResult;
}