windows-nt/Source/XPSP1/NT/net/qos/psched/sys/wansup.c
2020-09-26 16:20:57 +08:00

1531 lines
40 KiB
C

/*++
Copyright (c) 1996-1999 Microsoft Corporation
Module Name:
wansup.c
Abstract:
support for ndiswan
Author:
Yoram Bernet (yoramb) 29-Oct-1997
Rajesh Sundaram (rajeshsu) 01-Aug-1998
Environment:
Kernel Mode
Revision History:
--*/
#include "psched.h"
#pragma hdrstop
/* External */
/* Static */
//
// Should be defined in ndis.h. Put it here for now.
//
#define UNKNOWN_PROTOCOL_TYPE (USHORT) -1
NDIS_STATUS
CleanWanLink(PADAPTER Adapter,
PPS_WAN_LINK WanLink);
NDIS_STATUS
WanHandleISSLOW(
IN PGPC_CLIENT_VC Vc,
IN PCO_CALL_PARAMETERS CallParameters);
VOID
PsWanMungeAddress(PUSHORT id, USHORT Index)
{
*id = Index;
}
NDIS_STATUS
DeleteInterfaceForNdisWan(
IN PADAPTER Adapter,
IN PVOID StatusBuffer,
IN UINT StatusBufferSize
)
{
PNDIS_WAN_LINE_DOWN LineDownBuff;
PLIST_ENTRY NextWanLink;
PPS_WAN_LINK WanLink;
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
LineDownBuff = (PNDIS_WAN_LINE_DOWN)StatusBuffer;
PsDbgOut(DBG_TRACE, DBG_WAN,
("[DeleteInterfaceForNdisWan]: Linedown for remote address %02X:%02X:%02X:%02X:%02X:%02X \n",
LineDownBuff->RemoteAddress[0],
LineDownBuff->RemoteAddress[1],
LineDownBuff->RemoteAddress[2],
LineDownBuff->RemoteAddress[3],
LineDownBuff->RemoteAddress[4],
LineDownBuff->RemoteAddress[5]));
//
// Walk the List & remove the WanLink
//
PS_LOCK(&Adapter->Lock);
NextWanLink = Adapter->WanLinkList.Flink;
while(NextWanLink != &Adapter->WanLinkList) {
WanLink = CONTAINING_RECORD(NextWanLink, PS_WAN_LINK, Linkage);
//
// We cannot compare the LocalAddress, because NDISWAN initially
// passes us 0 for the LocalAddress in the LINE_UP
// The LocalAddress is for Wanarp to store its context which it
// sends down to NDISWAN. NDISWAN then sends this context back
// to us as LocalAddress in LINE_DOWN. So, we have to ignore
// the LocalAddress in the LINE_DOWN.
//
if(NdisEqualMemory(WanLink->OriginalRemoteMacAddress,
LineDownBuff->RemoteAddress,
sizeof(LineDownBuff->RemoteAddress)))
{
//
// Get rid of the wanlink from the list.
//
g_WanLinkTable[WanLink->UniqueIndex] = 0;
PS_UNLOCK(&Adapter->Lock);
//
// Munge the s-mac and r-mac so that wanarp can clean correctly.
//
PsWanMungeAddress((PUSHORT)&LineDownBuff->RemoteAddress[0],
WanLink->UniqueIndex);
PsWanMungeAddress((PUSHORT)&LineDownBuff->LocalAddress[0],
(USHORT)(*(PUSHORT)&WanLink->OriginalLocalMacAddress[0]));
Status = CleanWanLink(Adapter, WanLink);
NdisMIndicateStatus(Adapter->PsNdisHandle,
NDIS_STATUS_WAN_LINE_DOWN,
StatusBuffer,
StatusBufferSize);
return NDIS_STATUS_SUCCESS;
}
NextWanLink = NextWanLink->Flink;
}
PS_UNLOCK(&Adapter->Lock);
PsDbgOut(DBG_CRITICAL_ERROR, DBG_WAN,
("[DeleteInterfaceForNdisWan]: Could not find wanlink for Remote Mac: (%02X:%02X:%02X:%02X:%02X:%02X) \n",
LineDownBuff->RemoteAddress[0],
LineDownBuff->RemoteAddress[1],
LineDownBuff->RemoteAddress[2],
LineDownBuff->RemoteAddress[3],
LineDownBuff->RemoteAddress[4],
LineDownBuff->RemoteAddress[5]));
return Status;
}
NDIS_STATUS
PsWanGenerateUniqueIndex(
PPS_WAN_LINK WanLink
)
{
PADAPTER Adapter = WanLink->Adapter;
NDIS_STATUS Status = NDIS_STATUS_FAILURE;
USHORT size, Index, i, j;
PULONG_PTR NewTable;
PS_LOCK(&Adapter->Lock);
for(i=0, Index = g_NextWanIndex;
i < g_WanTableSize;
i++)
{
if(g_WanLinkTable[Index] == 0)
{
//
// We got a free slot.
//
g_WanLinkTable[Index] = (ULONG_PTR)WanLink;
WanLink->UniqueIndex = Index;
//
// Assume that the next one is free.
//
g_NextWanIndex ++;
g_NextWanIndex = g_NextWanIndex % g_WanTableSize;
PS_UNLOCK(&Adapter->Lock);
return NDIS_STATUS_SUCCESS;
}
Index ++;
Index = Index % g_WanTableSize;
}
//
// We could not find a slot to insert the wanlink. Grow the table
// and copy the existing table.
//
size = (g_WanTableSize + WAN_TABLE_INCREMENT) * sizeof(ULONG_PTR);
PsAllocatePool(NewTable, size, WanTableTag);
if(!NewTable)
{
PS_UNLOCK(&Adapter->Lock);
return NDIS_STATUS_FAILURE;
}
NdisZeroMemory(NewTable, size);
NdisMoveMemory(NewTable, g_WanLinkTable, g_WanTableSize * sizeof(ULONG_PTR));
PsFreePool(g_WanLinkTable);
g_WanLinkTable = NewTable;
//
//
//
g_WanLinkTable[g_WanTableSize] = (ULONG_PTR)WanLink;
WanLink->UniqueIndex = g_WanTableSize;
g_NextWanIndex = g_WanTableSize + 1;
g_WanTableSize += WAN_TABLE_INCREMENT;
PS_UNLOCK(&Adapter->Lock);
return NDIS_STATUS_SUCCESS;
}
VOID
DeleteWanLink(
PVOID Instance,
BOOLEAN AdapterLocked)
{
PPS_WAN_LINK WanLink = (PPS_WAN_LINK)Instance;
if(WanLink->pDiffServMapping)
{
PsFreePool(WanLink->pDiffServMapping);
}
if(WanLink->ShutdownMask & SHUTDOWN_DELETE_PIPE)
{
(*WanLink->PsComponent->DeletePipe)(WanLink->PsPipeContext);
}
if(WanLink->ShutdownMask & SHUTDOWN_FREE_PS_CONTEXT)
{
PsFreePool(WanLink->PsPipeContext);
}
if(WanLink->InstanceName.Buffer) {
PsFreePool(WanLink->InstanceName.Buffer);
}
if(WanLink->MpDeviceName.Buffer){
PsFreePool(WanLink->MpDeviceName.Buffer);
}
if(AdapterLocked)
{
RemoveEntryList(&WanLink->Linkage);
}
else
{
PS_LOCK(&WanLink->Adapter->Lock);
RemoveEntryList(&WanLink->Linkage);
PS_UNLOCK(&WanLink->Adapter->Lock);
}
NdisFreeSpinLock(&WanLink->Lock);
PsFreePool(WanLink);
}
NDIS_STATUS
CreateInterfaceForNdisWan(
IN PADAPTER Adapter,
IN PVOID StatusBuffer,
IN UINT StatusBufferSize
)
/*++
Routine Description:
Creates a TC interface to represent an underlying WAN link.
Arguments:
Adapter - the adapter on which the link is being created.
StatusBuffer - the buffer from NDISWAN.
StatusBufferSize - the length of the buffer.
Return Values:
None
--*/
{
PNDIS_WAN_LINE_UP LineUpBuff;
PPS_WAN_LINK WanLink;
PLIST_ENTRY NextWanLink;
NDIS_STATUS Status;
PIP_WAN_LINKUP_INFO RouterInfo;
NTSTATUS NtStatus;
LARGE_INTEGER Increment = {0, 1};
LARGE_INTEGER Index;
PGPC_CLIENT_VC Vc;
UCHAR ZeroAddress[] = {0, 0, 0, 0, 0, 0};
NDIS_HANDLE LineUpHandle;
int i,j;
LineUpBuff = (PNDIS_WAN_LINE_UP)StatusBuffer;
//
// Check for MultiLink:
//
// The first link up will have a ZeroLocal Address, in this case, we create a new QoS interface.
// All subsequent lineups will have a non-zero LocalAddress. If the link is being updated, we
// only need to update the linkspeed on the existing interface.
//
if(!(NdisEqualMemory(LineUpBuff->LocalAddress, ZeroAddress, 6)))
{
//
// Get the exisiting WanLink
//
PS_LOCK(&Adapter->Lock);
NextWanLink = Adapter->WanLinkList.Flink;
while(NextWanLink != &Adapter->WanLinkList) {
WanLink = CONTAINING_RECORD(NextWanLink, PS_WAN_LINK, Linkage);
if(NdisEqualMemory(WanLink->OriginalRemoteMacAddress,
LineUpBuff->RemoteAddress,
sizeof(LineUpBuff->RemoteAddress)))
{
REFADD(&Adapter->RefCount, 'WANU');
PS_UNLOCK(&Adapter->Lock);
PsDbgOut(DBG_TRACE, DBG_WAN,
("[CreateInterfaceForNdisWan]: Link speed of WanLink 0x%x has changed "
"from %d to %d \n", WanLink, WanLink->LinkSpeed, LineUpBuff->LinkSpeed));
WanLink->LinkSpeed = LineUpBuff->LinkSpeed;
UpdateWanLinkBandwidthParameters(WanLink);
TcIndicateInterfaceChange(Adapter, WanLink, NDIS_STATUS_INTERFACE_CHANGE);
//
// Munge s-mac and d-mac and send to wanarp.
//
PsWanMungeAddress((PUSHORT)&LineUpBuff->RemoteAddress[0],
WanLink->UniqueIndex);
PsWanMungeAddress((PUSHORT)&LineUpBuff->LocalAddress[0],
(USHORT)(*(PUSHORT)&WanLink->OriginalLocalMacAddress[0]));
NdisMIndicateStatus(Adapter->PsNdisHandle,
NDIS_STATUS_WAN_LINE_UP,
StatusBuffer,
StatusBufferSize);
REFDEL(&Adapter->RefCount, FALSE, 'WANU');
return NDIS_STATUS_SUCCESS;
}
NextWanLink = NextWanLink->Flink;
}
PS_UNLOCK(&Adapter->Lock);
PsDbgOut(DBG_FAILURE, DBG_WAN,
("[CreateInterfaceForNdisWan]: Got a change notification, but could not find wanlink "
"Remote Mac: (%02X:%02X:%02X:%02X:%02X:%02X) \n",
LineUpBuff->RemoteAddress[0],
LineUpBuff->RemoteAddress[1],
LineUpBuff->RemoteAddress[2],
LineUpBuff->RemoteAddress[3],
LineUpBuff->RemoteAddress[4],
LineUpBuff->RemoteAddress[5]));
return NDIS_STATUS_FAILURE;
}
//
// Create an internal representation of the link.
//
PsAllocatePool(WanLink,
sizeof(PS_WAN_LINK),
WanLinkTag);
if(WanLink == NULL)
{
PsDbgOut(DBG_FAILURE,
DBG_WAN,
("[CreateInterfaceForNdisWan]: Adapter %08X, couldn't create WanLink\n",
Adapter));
return NDIS_STATUS_RESOURCES;
}
//
// Initialize the wanlink.
//
NdisZeroMemory(WanLink, sizeof(PS_WAN_LINK));
WanLink->Adapter = Adapter;
REFINIT(&WanLink->RefCount, WanLink, DeleteWanLink);
REFADD(&WanLink->RefCount, 'WANU');
PS_INIT_SPIN_LOCK(&WanLink->Lock);
//
// Link the SausageLink on the link list.
//
NdisInterlockedIncrement(&Adapter->WanLinkCount);
NdisInterlockedInsertHeadList(&Adapter->WanLinkList,
&WanLink->Linkage,
&Adapter->Lock.Lock);
//
// Update the LinkSpeed and create a pipe off the wanlink.
//
WanLink->RawLinkSpeed = LineUpBuff->LinkSpeed;
WanLink->LinkSpeed = ( WanLink->RawLinkSpeed / 8 ) * 100;
Status = UpdateWanLinkBandwidthParameters(WanLink);
if(!NT_SUCCESS(Status))
{
PsDbgOut(DBG_FAILURE,
DBG_WAN,
("[CreateInterfaceForNdisWan]: Adapter %08X, UpdateWanLinkBandwidthParameters failed with %08X",
Adapter, Status));
REFDEL(&WanLink->RefCount, FALSE, 'WANU');
return Status;
}
//
// Extract the network addresses from the protocol part
// of the status buffer. Update the network layer address list
// which is held on the adapter.
//
switch(LineUpBuff->ProtocolType)
{
case PROTOCOL_IP:
RouterInfo = (PIP_WAN_LINKUP_INFO) LineUpBuff->ProtocolBuffer;
WanLink->DialUsage = RouterInfo->duUsage;
WanLink->ProtocolType = LineUpBuff->ProtocolType;
WanLink->LocalIpAddress = RouterInfo->dwLocalAddr;
WanLink->RemoteIpAddress = RouterInfo->dwRemoteAddr;
WanLink->LocalIpxAddress = 0;
WanLink->RemoteIpxAddress = 0;
break;
default:
//
// Unknown address type. We'll create a manageable
// entity, but - we don't know how to represent its
// addresses. Therefore, we also don't know how to
// format traffic control filters for it. So - it
// probably won't be particualrly useful. At least it
// lets the user see that there is an interface.
//
WanLink->ProtocolType = UNKNOWN_PROTOCOL_TYPE;
WanLink->LocalIpAddress = 0;
WanLink->RemoteIpAddress = 0;
WanLink->LocalIpxAddress = 0;
WanLink->RemoteIpxAddress = 0;
}
PsAllocatePool(WanLink->InstanceName.Buffer,
Adapter->WMIInstanceName.Length + WanPrefix.Length + INSTANCE_ID_SIZE,
PsMiscTag);
if(!WanLink->InstanceName.Buffer)
{
PsDbgOut(DBG_FAILURE,
DBG_WAN,
("[CreateInterfaceForNdisWan]: Adapter %08X, could not allocate memory for instance name \n",
Adapter));
REFDEL(&WanLink->RefCount, FALSE, 'WANU');
return NDIS_STATUS_RESOURCES;
}
if((Status = PsWanGenerateUniqueIndex(WanLink)) != NDIS_STATUS_SUCCESS)
{
PsDbgOut(DBG_FAILURE,
DBG_WAN,
("[CreateInterfaceForNdisWan]: Adapter %08X, PsWanGenerateUniqueIndex failed with Status %08X \n",
Adapter, Status));
REFDEL(&WanLink->RefCount, FALSE, 'WANU');
return Status;
}
Index.QuadPart = WanLink->UniqueIndex;
NtStatus = GenerateInstanceName(&WanPrefix,
Adapter,
&Index,
&WanLink->InstanceName);
//
// Copy the DeviceName
//
WanLink->MpDeviceName.MaximumLength = LineUpBuff->DeviceName.MaximumLength;
PsAllocatePool(WanLink->MpDeviceName.Buffer,
WanLink->MpDeviceName.MaximumLength,
PsMiscTag);
if(!WanLink->MpDeviceName.Buffer)
{
PsDbgOut(DBG_FAILURE,
DBG_WAN,
("[CreateInterfaceForNdisWan]: Adapter %08X, could not allocate memory for device name \n",
Adapter));
PS_LOCK(&Adapter->Lock);
g_WanLinkTable[WanLink->UniqueIndex] = 0;
REFDEL(&WanLink->RefCount, TRUE, 'WANU');
PS_UNLOCK(&Adapter->Lock);
return NDIS_STATUS_RESOURCES;
}
NdisZeroMemory(WanLink->MpDeviceName.Buffer, WanLink->MpDeviceName.MaximumLength);
Status = CreateBestEffortVc(Adapter,
&WanLink->BestEffortVc,
WanLink);
if(Status != NDIS_STATUS_SUCCESS)
{
PsDbgOut(DBG_FAILURE,
DBG_WAN,
("[CreateInterfaceForNdisWan]: Adapter %08X, could not create BestEffort Vc, status %08X",
Adapter, Status));
PS_LOCK(&Adapter->Lock);
g_WanLinkTable[WanLink->UniqueIndex] = 0;
REFDEL(&WanLink->RefCount, TRUE, 'WANU');
PS_UNLOCK(&Adapter->Lock);
return Status;
}
//
// Create 2 BEVCS and make the NextVc as the first one.
WanLink->NextVc = 0;
for( i = 0; i < BEVC_LIST_LEN; i++)
{
Status = CreateBestEffortVc(Adapter,
&WanLink->BeVcList[i],
WanLink);
if(Status != NDIS_STATUS_SUCCESS)
{
PsDbgOut(DBG_FAILURE,
DBG_WAN,
("[CreateInterfaceForNdisWan]: Adapter %08X, could not create BestEffort Vc, status %08X",
Adapter, Status));
PS_LOCK(&Adapter->Lock);
g_WanLinkTable[WanLink->UniqueIndex] = 0;
for( j = 0; j < i; j++ )
{
PS_LOCK_DPC(&WanLink->BeVcList[j].Lock);
InternalCloseCall(&WanLink->BeVcList[j]);
PS_LOCK(&Adapter->Lock);
}
PS_LOCK_DPC(&WanLink->BestEffortVc.Lock);
InternalCloseCall(&WanLink->BestEffortVc);
REFDEL(&WanLink->RefCount, TRUE, 'WANU');
return Status;
}
}
//
// Copy the original Remote Addresses and munge it.
//
NdisMoveMemory(&WanLink->OriginalRemoteMacAddress,
&LineUpBuff->RemoteAddress,
6);
PsWanMungeAddress((PUSHORT) &LineUpBuff->RemoteAddress[0], WanLink->UniqueIndex);
NdisMIndicateStatus(Adapter->PsNdisHandle,
NDIS_STATUS_WAN_LINE_UP,
StatusBuffer,
StatusBufferSize);
//
// Fail if wanarp has failed the line up
//
*((ULONG UNALIGNED *)(&LineUpHandle)) =
*((ULONG UNALIGNED *)(&LineUpBuff->LocalAddress[2]));
if (LineUpHandle == NULL)
{
PsDbgOut(DBG_FAILURE, DBG_WAN,
("[ClStatusIndication]: wanarp has failed the lineup. "
"Remote Address (%02X:%02X:%02X:%02X:%02X:%02X) \n",
LineUpBuff->RemoteAddress[0],
LineUpBuff->RemoteAddress[1],
LineUpBuff->RemoteAddress[2],
LineUpBuff->RemoteAddress[3],
LineUpBuff->RemoteAddress[4],
LineUpBuff->RemoteAddress[5]));
PS_LOCK(&Adapter->Lock);
g_WanLinkTable[WanLink->UniqueIndex] = 0;
for( j = 0; j < BEVC_LIST_LEN; j++ )
{
PS_LOCK_DPC(&WanLink->BeVcList[j].Lock);
InternalCloseCall(&WanLink->BeVcList[j]);
PS_LOCK(&Adapter->Lock);
}
PS_LOCK_DPC(&WanLink->BestEffortVc.Lock);
InternalCloseCall(&WanLink->BestEffortVc);
REFDEL(&WanLink->RefCount, FALSE, 'WANU');
return NDIS_STATUS_FAILURE;
}
else
{
//
// If wanarp has succeeded the lineup, we cannot get a zero local mac address.
//
PsAssert(!(NdisEqualMemory(LineUpBuff->LocalAddress, ZeroAddress, 6)));
}
//
// Copy the device name that wanarp has filled in.
//
WanLink->MpDeviceName.Length = LineUpBuff->DeviceName.Length;
NdisMoveMemory(WanLink->MpDeviceName.Buffer,
LineUpBuff->DeviceName.Buffer,
LineUpBuff->DeviceName.Length);
//
// Munge the smac address. Remember the original one that wanarp gave us.
//
NdisMoveMemory(&WanLink->OriginalLocalMacAddress,
&LineUpBuff->LocalAddress,
6);
PsWanMungeAddress((PUSHORT)&LineUpBuff->LocalAddress[0], WanLink->UniqueIndex);
//
// Create the headers that have to be slapped on the send/recv path.
//
NdisMoveMemory(&WanLink->SendHeader.DestAddr[0],
WanLink->OriginalRemoteMacAddress,
ARP_802_ADDR_LENGTH);
NdisMoveMemory(&WanLink->SendHeader.SrcAddr[0] ,
LineUpBuff->LocalAddress,
ARP_802_ADDR_LENGTH);
NdisMoveMemory(&WanLink->RecvHeader.DestAddr[0],
WanLink->OriginalLocalMacAddress,
ARP_802_ADDR_LENGTH);
NdisMoveMemory(&WanLink->RecvHeader.SrcAddr[0],
LineUpBuff->RemoteAddress,
ARP_802_ADDR_LENGTH);
//
// Unmunge the remote address in the lineup buff now.
//
PsWanMungeAddress((PUSHORT)&LineUpBuff->RemoteAddress[0],
(USHORT)(*(PUSHORT)WanLink->OriginalRemoteMacAddress));
//
// We are ready to recv and send packets.
//
PS_LOCK(&WanLink->Lock);
WanLink->State = WanStateOpen;
PS_UNLOCK(&WanLink->Lock);
PsScheduleInterfaceIdWorkItem(Adapter, WanLink);
//
// Indicate the new interface up to the TCI. We indicate both the
// addition of a new interface and the addresses available on it.
// The address descriptors indicated for WAN interfaces differ from
// those indicated for LAN interfaces. WAN interfaces include a
// destination network layer address, as well as a source address.
//
TcIndicateInterfaceChange(Adapter, WanLink, NDIS_STATUS_INTERFACE_UP);
PsDbgOut(DBG_TRACE, DBG_WAN,
("[CreateInterfaceForNdisWan]: Created WanLink 0x%x, Remote Address (%02X:%02X:%02X:%02X:%02X:%02X) \n",
WanLink,
LineUpBuff->RemoteAddress[0],
LineUpBuff->RemoteAddress[1],
LineUpBuff->RemoteAddress[2],
LineUpBuff->RemoteAddress[3],
LineUpBuff->RemoteAddress[4],
LineUpBuff->RemoteAddress[5]));
return(NDIS_STATUS_SUCCESS);
}
NDIS_STATUS
OpenWanAddressFamily(
IN PADAPTER Adapter,
IN PCO_ADDRESS_FAMILY WanAddressFamily
)
/*++
Routine Description:
Establish the binding between the PS miniport, NDISWAN and the
NDISWAN call manager.
Arguments:
Adapter - pointer to adapter
Return Value:
None
--*/
{
NDIS_CLIENT_CHARACTERISTICS WanClCharacteristics;
NDIS_STATUS Status;
WanClCharacteristics.MajorVersion = 5;
WanClCharacteristics.MinorVersion = 0;
WanClCharacteristics.Reserved = 0;
WanClCharacteristics.ClCreateVcHandler = WanCreateVc;
WanClCharacteristics.ClDeleteVcHandler = WanDeleteVc;
WanClCharacteristics.ClOpenAfCompleteHandler = WanOpenAddressFamilyComplete;
WanClCharacteristics.ClCloseAfCompleteHandler = WanCloseAddressFamilyComplete;
WanClCharacteristics.ClRegisterSapCompleteHandler = WanRegisterSapComplete;
WanClCharacteristics.ClDeregisterSapCompleteHandler = WanDeregisterSapComplete;
WanClCharacteristics.ClMakeCallCompleteHandler = WanMakeCallComplete;
WanClCharacteristics.ClModifyCallQoSCompleteHandler = WanModifyCallComplete;
WanClCharacteristics.ClCloseCallCompleteHandler = WanCloseCallComplete;
WanClCharacteristics.ClAddPartyCompleteHandler = WanAddPartyComplete;
WanClCharacteristics.ClDropPartyCompleteHandler = WanDropPartyComplete;
WanClCharacteristics.ClIncomingCallHandler = WanIncomingCall;
WanClCharacteristics.ClIncomingCallQoSChangeHandler = WanIncomingCallQoSChange;
WanClCharacteristics.ClIncomingCloseCallHandler = WanIncomingCloseCall;
WanClCharacteristics.ClIncomingDropPartyHandler = WanIncomingDropParty;
WanClCharacteristics.ClCallConnectedHandler = WanCallConnected;
WanClCharacteristics.ClRequestHandler = WanCoRequest;
WanClCharacteristics.ClRequestCompleteHandler = WanCoRequestComplete;
PsDbgOut(DBG_TRACE,
DBG_WAN | DBG_INIT,
("[OpenWanAddressFamily]: Adapter %08X \n", Adapter));
Status = NdisClOpenAddressFamily(Adapter->LowerMpHandle,
WanAddressFamily,
Adapter,
&WanClCharacteristics,
sizeof(WanClCharacteristics),
&Adapter->WanCmHandle);
if(Status != NDIS_STATUS_PENDING)
{
WanOpenAddressFamilyComplete(Status,
Adapter,
Adapter->WanCmHandle);
}
return Status;
} // OpenWanAddressFamily
VOID
WanOpenAddressFamilyComplete(
IN NDIS_STATUS Status,
IN NDIS_HANDLE ProtocolAfContext,
IN NDIS_HANDLE NdisAfHandle
)
/*++
Routine Description:
Complete a call to NdisClOpenAddressFamily.
Arguments:
see the DDK
Return Value:
None
--*/
{
PADAPTER Adapter = (PADAPTER)ProtocolAfContext;
if(Status != NDIS_STATUS_SUCCESS){
PsDbgOut(DBG_CRITICAL_ERROR,
DBG_WAN,
("[WanOpenAddressFamilyComplete]: Adapter %08X, open failed %08X\n",
Adapter, Status));
PsAdapterWriteEventLog(
EVENT_PS_REGISTER_ADDRESS_FAMILY_FAILED,
0,
&Adapter->MpDeviceName,
sizeof(Status),
&Status);
return;
}
else{
PS_LOCK(&Adapter->Lock);
Adapter->WanBindingState |= WAN_ADDR_FAMILY_OPEN;
Adapter->ShutdownMask |= SHUTDOWN_CLOSE_WAN_ADDR_FAMILY;
Adapter->WanCmHandle = NdisAfHandle;
Adapter->FinalStatus = Status;
PS_UNLOCK(&Adapter->Lock);
PsDbgOut(DBG_TRACE,
DBG_WAN | DBG_INIT,
("[WanOpenAddressFamilyComplete]: Adapter %08X, Status = %x\n",
Adapter,
Status));
}
} // WanOpenAddressFamilyComplete
VOID
WanMakeCallComplete(
IN NDIS_STATUS Status,
IN NDIS_HANDLE ProtocolVcContext,
IN NDIS_HANDLE NdisPartyHandle,
IN OUT PCO_CALL_PARAMETERS CallParameters
)
{
PGPC_CLIENT_VC Vc = (PGPC_CLIENT_VC) ProtocolVcContext;
PADAPTER Adapter = Vc->Adapter;
PsStructAssert(Adapter);
//
// Common code to complete both synchronous and asynchronous
// returns from WanMakeCall. Note that, unless there is a WAN
// adapter, CmMakeCall will always complete synchronously.
//
if(Status != NDIS_STATUS_SUCCESS){
//
// We probably at least succeeeded in creating a VC in NDISWAN.
// If we did, we should delete it here. We may have failed however,
// because we could not create the VC, in which case, we have
// nothing to delete.
//
if(Vc->NdisWanVcHandle){
NdisCoDeleteVc(Vc->NdisWanVcHandle);
Vc->NdisWanVcHandle = NULL;
}
}
CompleteMakeCall(Vc,
CallParameters,
Status);
}
VOID
WanModifyCallComplete(
IN NDIS_STATUS Status,
IN NDIS_HANDLE ProtocolVcContext,
IN OUT PCO_CALL_PARAMETERS CallParameters
)
{
PGPC_CLIENT_VC Vc = (PGPC_CLIENT_VC)ProtocolVcContext;
PADAPTER Adapter = Vc->Adapter;
PsStructAssert(Adapter);
//
// Common code to complete both synchronous and asynchronous
// returns from WanModifyCall.
//
if(Status != NDIS_STATUS_SUCCESS) {
//
// We changed some of the ISSLOW stuff - Time to revert back
//
WanHandleISSLOW(Vc, Vc->CallParameters);
}
ModifyCallComplete(Vc, CallParameters, Status);
}
VOID
WanCloseAddressFamilyComplete(
IN NDIS_STATUS Status,
IN NDIS_HANDLE ProtocolBindingContext
)
{
PADAPTER Adapter = (PADAPTER)ProtocolBindingContext;
PS_LOCK(&Adapter->Lock);
Adapter->WanBindingState &= ~WAN_ADDR_FAMILY_OPEN;
PS_UNLOCK(&Adapter->Lock);
}
NDIS_STATUS
WanCreateVc(
IN NDIS_HANDLE ProtocolAfContext,
IN NDIS_HANDLE NdisVcHandle,
OUT PNDIS_HANDLE ProtocolVcContext
)
{
DEBUGCHK;
return NDIS_STATUS_FAILURE;
}
NDIS_STATUS
WanDeleteVc(
IN NDIS_HANDLE ProtocolVcContext
)
{
DEBUGCHK;
return NDIS_STATUS_FAILURE;
}
VOID
WanRegisterSapComplete(
IN NDIS_STATUS Status,
IN NDIS_HANDLE ProtocolSapContext,
IN PCO_SAP Sap,
IN NDIS_HANDLE NdisSapHandle
)
{
DEBUGCHK;
}
VOID
WanDeregisterSapComplete(
IN NDIS_STATUS Status,
IN NDIS_HANDLE ProtocolSapContext
)
{
DEBUGCHK;
}
NDIS_STATUS
WanIncomingCall(
IN NDIS_HANDLE ProtocolSapContext,
IN NDIS_HANDLE ProtocolVcContext,
IN OUT PCO_CALL_PARAMETERS CallParameters
)
{
DEBUGCHK;
return NDIS_STATUS_FAILURE;
}
VOID
WanAddPartyComplete(
IN NDIS_STATUS Status,
IN NDIS_HANDLE ProtocolPartyContext,
IN NDIS_HANDLE NdisPartyHandle,
IN PCO_CALL_PARAMETERS CallParameters
)
{
DEBUGCHK;
}
VOID
WanDropPartyComplete(
IN NDIS_STATUS Status,
IN NDIS_HANDLE ProtocolPartyContext
)
{
DEBUGCHK;
}
NDIS_STATUS
WanHandleISSLOW(
IN PGPC_CLIENT_VC Vc,
IN PCO_CALL_PARAMETERS CallParameters
)
{
LONG ParamsLength;
LPQOS_OBJECT_HDR QoSObject;
PADAPTER Adapter = Vc->Adapter;
PCO_MEDIA_PARAMETERS CallMgrParams = CallParameters->MediaParameters;
ULONGLONG i,j,k;
//
// See if this is an ISSLOW flow.
//
ParamsLength = (LONG)CallMgrParams->MediaSpecific.Length;
QoSObject = (LPQOS_OBJECT_HDR)CallMgrParams->MediaSpecific.Parameters;
//
// By default, this is not an ISSLOW flow.
//
Vc->Flags &= ~GPC_ISSLOW_FLOW;
while(ParamsLength > 0){
if(QoSObject->ObjectType == QOS_OBJECT_WAN_MEDIA)
{
LPQOS_WAN_MEDIA WanMedia = (LPQOS_WAN_MEDIA)QoSObject;
WanMedia->ISSLOW = FALSE;
//
// See if the flow is an ISSLOW flow. If the TokenRate of the flow
// is under ISSLOW TokenRate and the PacketSize is under MaxPacketSize
// Then we qualify this as ISSLOW flows.
//
// If a wanlink's linkspeed is greater than a certain amount, we don't run issow over it.
//
if((Vc->WanLink->LinkSpeed <= Adapter->ISSLOWLinkSpeed) &&
(CallParameters->CallMgrParameters->Transmit.ServiceType != SERVICETYPE_BESTEFFORT))
{
i = (ULONG) Adapter->ISSLOWTokenRate * (ULONG) CallParameters->CallMgrParameters->Transmit.MaxSduSize;
j = (ULONG) Adapter->ISSLOWPacketSize * (ULONG) CallParameters->CallMgrParameters->Transmit.TokenRate;
k = (ULONG) Adapter->ISSLOWTokenRate * (ULONG)Adapter->ISSLOWPacketSize;
if((i+j)<k)
{
WanMedia->ISSLOW = TRUE;
PsDbgOut(DBG_TRACE, DBG_WAN,
("[WanHandleISSLOW]: Vc %08X is an ISSLOW VC (TokenRate = %d, PacketSize = %d \n",
Vc, CallParameters->CallMgrParameters->Transmit.TokenRate,
CallParameters->CallMgrParameters->Transmit.MaxSduSize));
//
// The MaxSDUSize is normally a measure of the latency requirements of -that- flow
// For audio codes, MaxSDUSize = f(Latency requirements, unit size);
//
// But, we don't want to chop these into very small fragments. Therefore, we have
// an upper bound and pick the maximum.
//
if(CallParameters->CallMgrParameters->Transmit.MaxSduSize > Adapter->ISSLOWFragmentSize)
{
Vc->ISSLOWFragmentSize = CallParameters->CallMgrParameters->Transmit.MaxSduSize;
}
else
{
Vc->ISSLOWFragmentSize = Adapter->ISSLOWFragmentSize;
}
Vc->Flags |= GPC_ISSLOW_FLOW;
PsDbgOut(DBG_TRACE, DBG_WAN,
("[WanHandleISSLOW]: Adapter %08X, ISSLOW Vc %08X, FragmentSize = %d bytes \n",
Adapter, Vc, Vc->ISSLOWFragmentSize));
}
else
{
PsDbgOut(DBG_TRACE, DBG_WAN,
("[WanHandleISSLOW]: Non ISSLOW Vc %08X. ISSLOW TokenRate %d, "
"ISSLOW Packet Size %d, VC TokenRate %d, VC Packet Size %d \n",
Vc, Adapter->ISSLOWTokenRate,
Adapter->ISSLOWPacketSize,
CallParameters->CallMgrParameters->Transmit.TokenRate,
CallParameters->CallMgrParameters->Transmit.MaxSduSize));
}
}
else
{
PsDbgOut(DBG_TRACE, DBG_WAN,
("[WanHandleISSLOW]: Non ISSLOW Vc %08X. (servicetype == B/E "
" or WAN LinkSpeed %d < ISSLOW LinkSpeed %d \n",
Vc, Vc->WanLink->LinkSpeed, Adapter->ISSLOWLinkSpeed));
}
return NDIS_STATUS_SUCCESS;
}
else {
if(
((LONG)QoSObject->ObjectLength <= 0) ||
((LONG)QoSObject->ObjectLength > ParamsLength)
){
return(QOS_STATUS_TC_OBJECT_LENGTH_INVALID);
}
ParamsLength -= QoSObject->ObjectLength;
QoSObject = (LPQOS_OBJECT_HDR)((UINT_PTR)QoSObject +
QoSObject->ObjectLength);
}
}
return NDIS_STATUS_FAILURE;
}
NDIS_STATUS
WanMakeCall(
IN PGPC_CLIENT_VC Vc,
IN OUT PCO_CALL_PARAMETERS CallParameters
)
{
NDIS_STATUS Status;
PADAPTER Adapter;
Adapter = Vc->Adapter;
PsStructAssert(Adapter);
//
// Handle ISSLOW
//
WanHandleISSLOW(Vc, CallParameters);
//
// Create a VC in the Wan adapter.
//
Vc->NdisWanVcHandle = NULL;
Status = NdisCoCreateVc(Adapter->LowerMpHandle,
Adapter->WanCmHandle,
Vc,
&Vc->NdisWanVcHandle);
PsAssert(Status != NDIS_STATUS_PENDING);
if(Status != NDIS_STATUS_SUCCESS)
{
Vc->NdisWanVcHandle = 0;
PsDbgOut(DBG_FAILURE, DBG_WAN,
("[WanMakeCall]: cannot create VC. Status = %d\n", Status));
WanMakeCallComplete(Status, Vc, NULL, CallParameters);
}
else
{
Status = NdisClMakeCall(Vc->NdisWanVcHandle, CallParameters, NULL, NULL);
if(Status != NDIS_STATUS_PENDING){
WanMakeCallComplete(Status, Vc, NULL, CallParameters);
}
}
return (NDIS_STATUS_PENDING);
}
VOID
WanCloseCall(
IN PGPC_CLIENT_VC Vc
)
{
NDIS_STATUS Status;
//
// Issue a CloseCall to the WAN call manager.
//
PsAssert(Vc->NdisWanVcHandle);
Status = NdisClCloseCall(Vc->NdisWanVcHandle,
NULL,
NULL,
0);
if(Status != NDIS_STATUS_PENDING)
{
WanCloseCallComplete(Status,
Vc,
Vc->CallParameters);
}
}
VOID
WanCloseCallComplete(
NDIS_STATUS Status,
NDIS_HANDLE ProtocolVcContext,
PCO_CALL_PARAMETERS CallParameters
)
{
PGPC_CLIENT_VC Vc = (PGPC_CLIENT_VC) ProtocolVcContext;
Status = NdisCoDeleteVc(Vc->NdisWanVcHandle);
PsAssert(Status != NDIS_STATUS_PENDING);
Vc->NdisWanVcHandle = 0;
CmDeleteVc(Vc);
}
NDIS_STATUS
WanModifyCall(
IN PGPC_CLIENT_VC Vc,
IN OUT PCO_CALL_PARAMETERS CallParameters
)
{
NDIS_STATUS Status;
WanHandleISSLOW(Vc, CallParameters);
PsAssert(Vc->NdisWanVcHandle);
Status = NdisClModifyCallQoS(Vc->NdisWanVcHandle, CallParameters);
if(Status != NDIS_STATUS_PENDING)
{
WanModifyCallComplete(Status, Vc, CallParameters);
}
return NDIS_STATUS_PENDING;
}
VOID
AskWanLinksToClose(PADAPTER Adapter)
{
PLIST_ENTRY NextWanLink;
PPS_WAN_LINK WanLink;
PsDbgOut(DBG_TRACE, DBG_WAN,
("[AskWanLinksToClose]: Adapter %08X - All wanlinks are closing \n", Adapter));
//
// Walk the List & remove the WanLink
//
PS_LOCK(&Adapter->Lock);
while(!IsListEmpty(&Adapter->WanLinkList)) {
NextWanLink = RemoveHeadList(&Adapter->WanLinkList);
WanLink = CONTAINING_RECORD(NextWanLink, PS_WAN_LINK, Linkage);
//
// Get rid of the wanlink from the list.
//
g_WanLinkTable[WanLink->UniqueIndex] = 0;
PS_UNLOCK(&Adapter->Lock);
CleanWanLink(Adapter, WanLink);
PS_LOCK(&Adapter->Lock);
}
PS_UNLOCK(&Adapter->Lock);
return;
}
NDIS_STATUS
CleanWanLink(PADAPTER Adapter,
PPS_WAN_LINK WanLink)
{
PLIST_ENTRY NextVc;
PGPC_CLIENT_VC Vc;
PUSHORT id;
int j;
PsDbgOut(DBG_TRACE, DBG_WAN, ("[CleanWanLink]: WanLink 0x%x is going down \n", WanLink));
TcIndicateInterfaceChange(Adapter, WanLink, NDIS_STATUS_INTERFACE_DOWN);
PS_LOCK(&WanLink->Lock);
WanLink->State = WanStateClosing;
PS_UNLOCK(&WanLink->Lock);
PS_LOCK(&Adapter->Lock);
//
// Make sure to delete Be Vc1 also..
for( j = 0; j < BEVC_LIST_LEN; j++ )
{
PS_LOCK_DPC(&WanLink->BeVcList[j].Lock);
InternalCloseCall(&WanLink->BeVcList[j]);
PS_LOCK(&Adapter->Lock);
}
PS_LOCK_DPC(&WanLink->BestEffortVc.Lock);
InternalCloseCall(&WanLink->BestEffortVc);
NdisInterlockedDecrement(&Adapter->WanLinkCount);
PS_LOCK(&Adapter->Lock);
//
// Clean up all the GPC VCs on the WanLink;
//
NextVc = Adapter->GpcClientVcList.Flink;
while(NextVc != &Adapter->GpcClientVcList)
{
Vc = CONTAINING_RECORD(NextVc, GPC_CLIENT_VC, Linkage);
NextVc = NextVc->Flink;
PsAssert(Vc);
if(Vc->WanLink == WanLink)
{
PS_LOCK_DPC(&Vc->Lock);
if(Vc->ClVcState == CL_INTERNAL_CLOSE_PENDING || Vc->Flags & INTERNAL_CLOSE_REQUESTED)
{
// We have already closed this Vc. Let's move on.
PS_UNLOCK_DPC(&Vc->Lock);
}
else
{
InternalCloseCall(Vc);
PS_LOCK(&Adapter->Lock);
//
// Sigh. We can't really get hold to the NextVc in a reliable manner. When we call
// InternalCloseCall on the Vc, it releases the Adapter Lock (since it might have to
// make calls into NDIS). Now, in this window, the next Vc could go away, and we
// could point to a stale Vc. So, we start at the head of the list.
// Note that this can never lead to a infinite loop, since we don't process the
// internal close'd VCs repeatedly.
//
NextVc = Adapter->GpcClientVcList.Flink;
}
}
}
PS_UNLOCK(&Adapter->Lock);
REFDEL(&WanLink->RefCount, FALSE, 'WANU');
return NDIS_STATUS_SUCCESS;
}
VOID
WanIncomingCallQoSChange(
IN NDIS_HANDLE ProtocolVcContext,
IN PCO_CALL_PARAMETERS CallParameters
)
{
DEBUGCHK;
}
VOID
WanIncomingCloseCall(
IN NDIS_STATUS CloseStatus,
IN NDIS_HANDLE ProtocolVcContext,
IN PVOID CloseData OPTIONAL,
IN UINT Size OPTIONAL
)
{
PGPC_CLIENT_VC Vc = (PGPC_CLIENT_VC) ProtocolVcContext;
PsAssert(Vc);
CheckLLTag(Vc, GpcClientVc);
PS_LOCK(&Vc->Adapter->Lock);
PS_LOCK_DPC(&Vc->Lock);
InternalCloseCall(Vc);
return;
}
VOID
WanIncomingDropParty(
IN NDIS_STATUS DropStatus,
IN NDIS_HANDLE ProtocolPartyContext,
IN PVOID CloseData OPTIONAL,
IN UINT Size OPTIONAL
)
{
DEBUGCHK;
}
VOID
WanCallConnected(
IN NDIS_HANDLE ProtocolPartyContext
)
{
DEBUGCHK;
}
NDIS_STATUS
WanCoRequest(
IN NDIS_HANDLE ProtocolAfContext,
IN NDIS_HANDLE ProtocolVcContext OPTIONAL,
IN NDIS_HANDLE ProtocolPartyContext OPTIONAL,
IN OUT PNDIS_REQUEST NdisRequest
)
{
DEBUGCHK;
return NDIS_STATUS_INVALID_OID;
}
VOID
WanCoRequestComplete(
IN NDIS_STATUS Status,
IN NDIS_HANDLE ProtocolAfContext,
IN NDIS_HANDLE ProtocolVcContext OPTIONAL,
IN NDIS_HANDLE ProtocolPartyContext OPTIONAL,
IN PNDIS_REQUEST NdisRequest
)
{
ClRequestComplete(ProtocolAfContext,
NdisRequest,
Status);
}
NDIS_STATUS
UpdateWanLinkBandwidthParameters(PPS_WAN_LINK WanLink)
{
//
// Called any time the link speed is updated. This
// function generates the adapter link speed and the
// and non-best-effort rate limits, both in bytes per second.
//
PsUpdateLinkSpeed(WanLink->Adapter,
WanLink->RawLinkSpeed,
&WanLink->RemainingBandWidth,
&WanLink->LinkSpeed,
&WanLink->NonBestEffortLimit,
&WanLink->Lock);
return UpdateWanSchedulingPipe(WanLink);
}