/*++ 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)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); }