/*++ Copyright (c) 1990-1995 Microsoft Corporation Module Name: Protocol.c Abstract: This file contains the procedures that makeup most of the NDIS 4.0/5.0 Protocol interface. This interface is what NdisWan exposes to the WAN Miniports below. NdisWan is not really a protocol and does not do TDI, but is a shim that sits between the protocols and the WAN Miniport drivers. Author: Tony Bell (TonyBe) June 06, 1995 Environment: Kernel Mode Revision History: TonyBe 06/06/95 Created --*/ #include "wan.h" #define __FILE_SIG__ PROTOCOL_FILESIG #ifdef DBG_SENDARRAY extern UCHAR SendArray[]; extern ULONG __si; #endif EXPORT VOID NdisTapiRegisterProvider( IN NDIS_HANDLE, IN PNDISTAPI_CHARACTERISTICS ); EXPORT VOID NdisTapiDeregisterProvider( IN NDIS_HANDLE ); EXPORT VOID NdisTapiIndicateStatus( IN NDIS_HANDLE BindingContext, IN PVOID StatusBuffer, IN UINT StatusBufferLength ); // // Local functions... // VOID CompleteSendDesc( PSEND_DESC SendDesc, NDIS_STATUS Status ); VOID CloseWanAdapterWorker( PNDIS_WORK_ITEM WorkItem, POPENCB pOpenCB ); #if 0 ULONG CalcPPPHeaderLength( ULONG FramingBits, ULONG Flags ); #endif // // Common functions used by both 4.0 and 5.0 miniports // NDIS_STATUS ProtoOpenWanAdapter( IN POPENCB pOpenCB ) /*++ Routine Name: Routine Description: Arguments: Return Values: --*/ { NDIS_STATUS Status, OpenErrorStatus; ULONG SelectedMediumIndex; NDIS_MEDIUM MediumArray[] = {NdisMediumWan, NdisMediumAtm, NdisMediumCoWan}; NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoOpenAdapter: Enter - AdapterName %ls", pOpenCB->MiniportName.Buffer)); // // This is the only initialization of this event // NdisWanInitializeNotificationEvent(&pOpenCB->NotificationEvent); NdisOpenAdapter(&Status, &OpenErrorStatus, &(pOpenCB->BindingHandle), &SelectedMediumIndex, MediumArray, sizeof(MediumArray) / sizeof(NDIS_MEDIUM), NdisWanCB.ProtocolHandle, (NDIS_HANDLE)pOpenCB, &(pOpenCB->MiniportName), 0, NULL); if (Status == NDIS_STATUS_PENDING) { NdisWanWaitForNotificationEvent(&pOpenCB->NotificationEvent); Status = pOpenCB->NotificationStatus; NdisWanClearNotificationEvent(&pOpenCB->NotificationEvent); } if (Status == NDIS_STATUS_SUCCESS) { pOpenCB->MediumType = MediumArray[SelectedMediumIndex]; } NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoOpenAdapter: Exit")); return (Status); } // // Enter with the opencb->lock held, exit with the lock released! // NDIS_STATUS ProtoCloseWanAdapter( IN POPENCB pOpenCB ) { NDIS_STATUS Status; NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoCloseWanAdapter: Enter %p", pOpenCB)); pOpenCB->Flags |= OPEN_CLOSING; NdisReleaseSpinLock(&pOpenCB->Lock); // // NdisCloseAdapter must be called at IRQL PASSIVE_LEVEL! // if (KeGetCurrentIrql() > PASSIVE_LEVEL) { NdisAcquireSpinLock(&pOpenCB->Lock); ASSERT(!(pOpenCB->Flags & CLOSE_SCHEDULED)); NdisInitializeWorkItem(&pOpenCB->WorkItem, CloseWanAdapterWorker, pOpenCB); NdisScheduleWorkItem(&pOpenCB->WorkItem); pOpenCB->Flags |= CLOSE_SCHEDULED; NdisReleaseSpinLock(&pOpenCB->Lock); return (NDIS_STATUS_PENDING); } NdisCloseAdapter(&Status, pOpenCB->BindingHandle); if (Status != NDIS_STATUS_PENDING) { ProtoCloseAdapterComplete(pOpenCB, Status); } NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoCloseWanAdapter: Exit")); return(Status); } VOID CloseWanAdapterWorker( PNDIS_WORK_ITEM WorkItem, POPENCB pOpenCB ) { NDIS_STATUS Status; NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("CloseWanAdapterWorker: Enter %p", pOpenCB)); NdisCloseAdapter(&Status, pOpenCB->BindingHandle); if (Status != NDIS_STATUS_PENDING) { ProtoCloseAdapterComplete(pOpenCB, Status); } NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("CloseWanAdapterWorker: Exit")); } VOID ProtoOpenAdapterComplete( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS Status, IN NDIS_STATUS OpenErrorStatus ) /*++ Routine Name: ProtoOpenAdapterComplete Routine Description: This function is called upon completion of an open of a miniport. The status of the openadapter call is stored and the notification event is signalled. Arguments: Return Values: --*/ { POPENCB pOpenCB = (POPENCB)ProtocolBindingContext; NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoOpenAdapterComplete: Enter - OpenCB 0x%p", pOpenCB)); pOpenCB->NotificationStatus = Status; NdisWanSetNotificationEvent(&pOpenCB->NotificationEvent); NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoOpenAdapterComplete: Exit")); } VOID ProtoCloseAdapterComplete( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS Status ) /*++ Routine Name: ProtoCloseAdapterComplete Routine Description: This function is called upon completion of a close of a miniport. The status of the closeadapter call is stored and the notification event is signalled. Arguments: Return Values: --*/ { POPENCB pOpenCB = (POPENCB)ProtocolBindingContext; NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoCloseAdapterComplete: Enter - OpenCB %p", pOpenCB)); if (pOpenCB->UnbindContext != NULL) { NdisCompleteUnbindAdapter(pOpenCB->UnbindContext, Status); } if (pOpenCB->Flags & OPEN_IN_BIND) { // // We are attempting to close the adapter from // within our bind handler. Per AliD we must wait // for the close to finish before we can return // from the bind handler thus we have to special case // this code and not free the OpenCB here. // NdisWanSetNotificationEvent(&pOpenCB->NotificationEvent); } else { NdisWanFreeOpenCB(pOpenCB); } NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoCloseAdapterComplete: Exit")); } VOID ProtoResetComplete( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS Status ) { POPENCB pOpenCB = (POPENCB)ProtocolBindingContext; NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoResetComplete: Enter - OpenCB %p", pOpenCB)); pOpenCB->NotificationStatus = Status; NdisWanSetNotificationEvent(&pOpenCB->NotificationEvent); NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoResetComplete: Exit")); } VOID ProtoReceiveComplete( IN NDIS_HANDLE ProtocolBindingContext ) { POPENCB pOpenCB = (POPENCB)ProtocolBindingContext; NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ProtoIndicateStatus: Enter - OpenCB %8.x8\n", pOpenCB)); NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ProtoIndicateStatus: Exit")); } VOID ProtoIndicateStatus( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS GeneralStatus, IN PVOID StatusBuffer, IN UINT StatusBufferSize ) { POPENCB pOpenCB = (POPENCB)ProtocolBindingContext; switch (GeneralStatus) { case NDIS_STATUS_WAN_LINE_UP: NdisWanLineUpIndication(pOpenCB, StatusBuffer, StatusBufferSize); break; case NDIS_STATUS_WAN_LINE_DOWN: NdisWanLineDownIndication(pOpenCB, StatusBuffer, StatusBufferSize); break; case NDIS_STATUS_WAN_FRAGMENT: NdisWanFragmentIndication(pOpenCB, StatusBuffer, StatusBufferSize); break; case NDIS_STATUS_TAPI_INDICATION: NdisWanTapiIndication(pOpenCB, StatusBuffer, StatusBufferSize); break; default: NdisWanDbgOut(DBG_INFO, DBG_PROTOCOL, ("Unknown Status Indication: 0x%x", GeneralStatus)); break; } } VOID ProtoIndicateStatusComplete( IN NDIS_HANDLE ProtocolBindingContext ) { POPENCB pOpenCB = (POPENCB)ProtocolBindingContext; } VOID ProtoWanSendComplete( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_WAN_PACKET WanPacket, IN NDIS_STATUS Status ) { PSEND_DESC SendDesc; PLINKCB LinkCB, RefLinkCB; NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("ProtoWanSendComplete: Enter - WanPacket %p", WanPacket)); // // Get info from the WanPacket // SendDesc = (PSEND_DESC)WanPacket->ProtocolReserved1; LinkCB = SendDesc->LinkCB; if (!IsLinkValid(LinkCB->hLinkHandle, FALSE, &RefLinkCB)) { NdisWanDbgOut(DBG_FAILURE, DBG_CL, ("NDISWAN: SendComplete after link has gone down NdisContext %p\n", LinkCB)); return; } REMOVE_DBG_SEND(PacketTypeWan, LinkCB->OpenCB, WanPacket); ASSERT(RefLinkCB == LinkCB); NdisAcquireSpinLock(&LinkCB->Lock); CompleteSendDesc(SendDesc, Status); // // Deref for the ref applied in IsLinkValid // DEREF_LINKCB(LinkCB); NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("ProtoWanSendComplete: Exit")); } NDIS_STATUS ProtoWanReceiveIndication( IN NDIS_HANDLE NdisLinkHandle, IN PUCHAR Packet, IN ULONG PacketSize ) { NDIS_STATUS Status = NDIS_STATUS_SUCCESS; PLINKCB LinkCB = NULL; PBUNDLECB BundleCB = NULL; PUCHAR DataBuffer; ULONG DataBufferSize; ULONG BytesCopied; PNDIS_PACKET NdisPacket; PNDIS_BUFFER NdisBuffer; PRECV_DESC RecvDesc; NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ProtoWanReceiveIndication: Enter - Context %x", NdisLinkHandle)); do { if (!AreLinkAndBundleValid(NdisLinkHandle, TRUE, &LinkCB, &BundleCB)) { #if DBG DbgPrint("NDISWAN: Recv after link has gone down LinkContext %x\n", NdisLinkHandle); #endif break; } AcquireBundleLock(BundleCB); // // Make sure we don't try to process a receive indication // that is larger then our max data buffer size // winse 26544 // if (PacketSize > glMRU) { break; } // // Build a receive descriptor for this receive. We have // to allocate with a large size because this packet might // be compressed. // RecvDesc = NdisWanAllocateRecvDesc(glLargeDataBufferSize); if (RecvDesc == NULL) { break; } // // Update the bandwidth on demand sample array with the latest send. // If we need to notify someone of a bandwidth event do it. // if (BundleCB->Flags & BOND_ENABLED) { UpdateBandwidthOnDemand(BundleCB->RUpperBonDInfo, PacketSize); CheckUpperThreshold(BundleCB); UpdateBandwidthOnDemand(BundleCB->RLowerBonDInfo, PacketSize); CheckLowerThreshold(BundleCB); } RecvDesc->CopyRequired = TRUE; RecvDesc->CurrentBuffer = Packet; RecvDesc->CurrentLength = PacketSize; RecvDesc->LinkCB = LinkCB; RecvDesc->BundleCB = BundleCB; // // Indicate to netmon if we are sniffing at // the link level // if (gbSniffLink && (NdisWanCB.PromiscuousAdapter != NULL)) { // // Indicate a packet to netmon // IndicatePromiscuousRecv(BundleCB, RecvDesc, RECV_LINK); } // // Add up the statistics // LinkCB->Stats.BytesReceived += RecvDesc->CurrentLength; LinkCB->Stats.FramesReceived++; BundleCB->Stats.BytesReceived += RecvDesc->CurrentLength; LinkCB->Flags |= LINK_IN_RECV; BundleCB->Flags |= BUNDLE_IN_RECV; Status = (*LinkCB->RecvHandler)(LinkCB, RecvDesc); BundleCB->Flags &= ~BUNDLE_IN_RECV; LinkCB->Flags &= ~LINK_IN_RECV; if (Status != NDIS_STATUS_PENDING) { NdisWanFreeRecvDesc(RecvDesc); } } while ( 0 ); NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ProtoWanReceiveIndication: Exit")); // // Deref's for the ref's applied in AreLinkAndBundleValid // DEREF_BUNDLECB_LOCKED(BundleCB); DEREF_LINKCB(LinkCB); return (NDIS_STATUS_SUCCESS); } VOID ProtoRequestComplete( IN NDIS_HANDLE ProtocolBindingContext, IN PNDIS_REQUEST NdisRequest, IN NDIS_STATUS Status ) { POPENCB pOpenCB = (POPENCB)ProtocolBindingContext; PWAN_REQUEST pWanRequest; pWanRequest = CONTAINING_RECORD(NdisRequest, WAN_REQUEST, NdisRequest); NdisWanDbgOut(DBG_VERBOSE, DBG_REQUEST, ("ProtoRequestComplete: Enter - pWanRequest: 0x%p", pWanRequest)); pWanRequest->NotificationStatus = Status; switch (pWanRequest->Origin) { case NDISWAN: NdisWanSetNotificationEvent(&pWanRequest->NotificationEvent); break; default: ASSERT(pWanRequest->Origin == NDISTAPI); NdisWanTapiRequestComplete(pOpenCB, pWanRequest); break; } NdisWanDbgOut(DBG_VERBOSE, DBG_REQUEST, ("ProtoRequestComplete: Exit")); } VOID ProtoBindAdapter( OUT PNDIS_STATUS Status, IN NDIS_HANDLE BindContext, IN PNDIS_STRING DeviceName, IN PVOID SystemSpecific1, IN PVOID SystemSpecific2 ) /*++ Routine Name: ProtoBindAdapter Routine Description: This function is called by the NDIS wrapper to tell NdisWan to bind to an underlying miniport. NdisWan will open the miniport and query information on the device. Arguments: Status - Return status BindContext - Used in NdisBindAdapterComplete DeviceName - Name of device we are opening SS1 - Used in NdisOpenProtocolConfig SS2 - Reserved Return Values: --*/ { POPENCB pOpenCB; NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoBindAdapter - Enter %ls", DeviceName->Buffer)); pOpenCB = NdisWanAllocateOpenCB(DeviceName); if (pOpenCB == NULL) { *Status = NDIS_STATUS_RESOURCES; return; } pOpenCB->Flags |= OPEN_IN_BIND; NdisWanInitializeNotificationEvent(&pOpenCB->InitEvent); *Status = ProtoOpenWanAdapter(pOpenCB); if (*Status != NDIS_STATUS_SUCCESS) { RemoveEntryGlobalList(OpenCBList, &pOpenCB->Linkage); NdisWanDbgOut(DBG_CRITICAL_ERROR, DBG_INIT, ("Failed to bind to %ls! Error 0x%x - %s", pOpenCB->MiniportName.Buffer, *Status, NdisWanGetNdisStatus(*Status))); NdisWanFreeOpenCB(pOpenCB); return; } // // Figure out if this is a legacy wan miniport. // if (pOpenCB->MediumType == NdisMediumWan) { pOpenCB->Flags |= OPEN_LEGACY; } NdisWanDbgOut(DBG_TRACE, DBG_INIT, ("Successful Binding to %s miniport %ls!", (pOpenCB->Flags & OPEN_LEGACY) ? "Legacy" : "NDIS 5.0", pOpenCB->MiniportName.Buffer)); // // Get the wan medium subtype // { WAN_REQUEST WanRequest; NdisZeroMemory(&WanRequest, sizeof(WanRequest)); WanRequest.Type = SYNC; WanRequest.Origin = NDISWAN; WanRequest.OpenCB = pOpenCB; NdisWanInitializeNotificationEvent(&WanRequest.NotificationEvent); WanRequest.NdisRequest.RequestType = NdisRequestQueryInformation; WanRequest.NdisRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_MEDIUM_SUBTYPE; WanRequest.NdisRequest.DATA.QUERY_INFORMATION.InformationBuffer = &pOpenCB->MediumSubType; WanRequest.NdisRequest.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(pOpenCB->MediumSubType); *Status = NdisWanSubmitNdisRequest(pOpenCB, &WanRequest); if (*Status != NDIS_STATUS_SUCCESS) { NdisWanDbgOut(DBG_FAILURE, DBG_INIT, ("Error returned from OID_WAN_MEDIUM_SUBTYPE! Error 0x%x - %s", *Status, NdisWanGetNdisStatus(*Status))); pOpenCB->MediumSubType = NdisWanMediumHub; *Status = NDIS_STATUS_SUCCESS; } } if (pOpenCB->Flags & OPEN_LEGACY) { NDIS_WAN_INFO WanInfo; WAN_REQUEST WanRequest; // // This is a legacy wan miniport // NdisZeroMemory(&WanRequest, sizeof(WanRequest)); WanRequest.Type = SYNC; WanRequest.Origin = NDISWAN; WanRequest.OpenCB = pOpenCB; NdisWanInitializeNotificationEvent(&WanRequest.NotificationEvent); // // Get more info... // NdisZeroMemory(&WanInfo, sizeof(WanInfo)); WanRequest.NdisRequest.RequestType = NdisRequestQueryInformation; WanRequest.NdisRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_GET_INFO; WanRequest.NdisRequest.DATA.QUERY_INFORMATION.InformationBuffer = &WanInfo; WanRequest.NdisRequest.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(WanInfo); *Status = NdisWanSubmitNdisRequest(pOpenCB, &WanRequest); if (*Status != NDIS_STATUS_SUCCESS) { NDIS_STATUS CloseStatus; NdisWanDbgOut(DBG_FAILURE, DBG_INIT, ("Error returned from OID_WAN_GET_INFO! Error 0x%x - %s", *Status, NdisWanGetNdisStatus(*Status))); NdisAcquireSpinLock(&pOpenCB->Lock); pOpenCB->Flags |= OPEN_CLOSING; NdisWanInitializeNotificationEvent(&pOpenCB->NotificationEvent); NdisReleaseSpinLock(&pOpenCB->Lock); NdisCloseAdapter(&CloseStatus, pOpenCB->BindingHandle); if (CloseStatus == NDIS_STATUS_PENDING) { NdisWanWaitForNotificationEvent(&pOpenCB->NotificationEvent); } NdisWanFreeOpenCB(pOpenCB); return; } NdisMoveMemory(&pOpenCB->WanInfo, &WanInfo, sizeof(NDIS_WAN_INFO)); if (pOpenCB->WanInfo.MaxTransmit == 0) { pOpenCB->WanInfo.MaxTransmit = 1; } if (pOpenCB->WanInfo.Endpoints == 0) { pOpenCB->WanInfo.Endpoints = 1000; } *Status = NdisWanAllocateSendResources(pOpenCB); if (*Status != NDIS_STATUS_SUCCESS) { NDIS_STATUS CloseStatus; NdisWanDbgOut(DBG_FAILURE, DBG_INIT, ("Error returned from AllocateSendResources! Error 0x%x - %s", *Status, NdisWanGetNdisStatus(*Status))); NdisAcquireSpinLock(&pOpenCB->Lock); pOpenCB->Flags |= OPEN_CLOSING; NdisWanInitializeNotificationEvent(&pOpenCB->NotificationEvent); NdisReleaseSpinLock(&pOpenCB->Lock); NdisCloseAdapter(&CloseStatus, pOpenCB->BindingHandle); if (CloseStatus == NDIS_STATUS_PENDING) { NdisWanWaitForNotificationEvent(&pOpenCB->NotificationEvent); } NdisWanFreeOpenCB(pOpenCB); return; } // // Tell tapi about this device // if (pOpenCB->WanInfo.FramingBits & TAPI_PROVIDER) { NDISTAPI_CHARACTERISTICS Chars; ULONG NdisTapiKey; NdisMoveMemory(&Chars.Guid, &pOpenCB->Guid, sizeof(Chars.Guid)); Chars.MediaType = pOpenCB->MediumSubType; Chars.RequestProc = NdisWanTapiRequestProc; // // Note that since there are typically very few // (< 10) wan miniports, just having an incrementing // counter will do. There is a pathological case where // one of the miniports can be added and removed a billion // times so that the counter wraps around and clashes with // an existing miniport - this is not even a stress scenario. // NdisTapiKey = NdisWanInterlockedInc( &glNdisTapiKey); pOpenCB->NdisTapiKey = UlongToHandle(NdisTapiKey); NdisTapiRegisterProvider(pOpenCB->NdisTapiKey, &Chars); } } else { // // This is a 5.0 miniport! We will do init work // when a call manager registers for this! // } pOpenCB->Flags &= ~OPEN_IN_BIND; NdisWanSetNotificationEvent(&pOpenCB->InitEvent); NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoBindAdapter - Exit")); } VOID ProtoUnbindAdapter( OUT PNDIS_STATUS Status, IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE UnbindContext ) { POPENCB pOpenCB = (POPENCB)ProtocolBindingContext; NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoUnbindAdapter: Enter - OpenCB %p", pOpenCB)); NdisAcquireSpinLock(&pOpenCB->Lock); while (pOpenCB->AfRegisteringCount != 0) { NdisReleaseSpinLock(&pOpenCB->Lock); NdisWanWaitForNotificationEvent(&pOpenCB->AfRegisteringEvent); NdisAcquireSpinLock(&pOpenCB->Lock); } if (!(pOpenCB->Flags & OPEN_LEGACY)) { while (!IsListEmpty(&pOpenCB->AfSapCBList)) { PCL_AFSAPCB AfSapCB; NDIS_STATUS RetStatus; AfSapCB = (PCL_AFSAPCB)RemoveHeadList(&pOpenCB->AfSapCBList); InsertTailList(&pOpenCB->AfSapCBClosing, &AfSapCB->Linkage); NdisReleaseSpinLock(&pOpenCB->Lock); NdisAcquireSpinLock(&AfSapCB->Lock); AfSapCB->Flags |= AFSAP_REMOVED_UNBIND; DEREF_CLAFSAPCB_LOCKED(AfSapCB); NdisAcquireSpinLock(&pOpenCB->Lock); } } pOpenCB->UnbindContext = UnbindContext; NdisReleaseSpinLock(&pOpenCB->Lock); if (pOpenCB->WanInfo.FramingBits & TAPI_PROVIDER) { NdisTapiDeregisterProvider(pOpenCB->NdisTapiKey); } DEREF_OPENCB(pOpenCB); NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoUnbindAdapter: Exit")); *Status = NDIS_STATUS_PENDING; } VOID ProtoUnload( VOID ) { NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoUnload: Enter")); NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoUnload: Exit")); } NDIS_STATUS ProtoPnPEvent( IN NDIS_HANDLE ProtocolBindingContext, IN PNET_PNP_EVENT NetPnPEvent ) { NDIS_STATUS Status = NDIS_STATUS_SUCCESS; POPENCB pOpenCB = (POPENCB)ProtocolBindingContext; if (pOpenCB == NULL) { return (NDIS_STATUS_SUCCESS); } switch (NetPnPEvent->NetEvent) { case NetEventSetPower: { NET_DEVICE_POWER_STATE PowerState; PowerState = *((NET_DEVICE_POWER_STATE*)NetPnPEvent->Buffer); NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoPnPEvent: OpenCB %p %s State %d", pOpenCB, "SetPower", PowerState)); switch (PowerState) { case NetDeviceStateD0: break; case NetDeviceStateD1: case NetDeviceStateD2: case NetDeviceStateD3: // // If this is the open on asyncmac I do not want it to be closed. // I will succeed the set power which should keep ndis from // unbinding me. If this is an open on any other miniport // I will return not supported so that I will get unbound from // the miniport. This is required for correct tapi behavior. // if (pOpenCB->MediumType == NdisMediumWan && pOpenCB->MediumSubType == NdisWanMediumSerial && !(pOpenCB->WanInfo.FramingBits & TAPI_PROVIDER)) { Status = NDIS_STATUS_SUCCESS; } else { Status = NDIS_STATUS_NOT_SUPPORTED; } // // In the case of a Critical Power event we will not // receive a Query so we must tear the connection down // directly from the Set. // // If we have any active connections signal rasman to // tear them down. // if (InterlockedCompareExchange(&pOpenCB->ActiveLinkCount, 0, 0)) { PIRP Irp; NdisAcquireSpinLock(&NdisWanCB.Lock); Irp = NdisWanCB.HibernateEventIrp; if ((Irp != NULL) && IoSetCancelRoutine(Irp, NULL)){ NdisWanCB.HibernateEventIrp = NULL; NdisReleaseSpinLock(&NdisWanCB.Lock); // // The irp is not being canceled so // lets do it! // Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); NdisAcquireSpinLock(&NdisWanCB.Lock); } NdisReleaseSpinLock(&NdisWanCB.Lock); } break; default: break; } } break; case NetEventQueryPower: { NET_DEVICE_POWER_STATE PowerState; PowerState = *((NET_DEVICE_POWER_STATE*)NetPnPEvent->Buffer); NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoPnPEvent: OpenCB %p %s State %d", pOpenCB, "QueryPower", PowerState)); // // If there is an active connection // on this binding refuse to go away // switch (PowerState) { case NetDeviceStateD0: break; case NetDeviceStateD1: case NetDeviceStateD2: case NetDeviceStateD3: // // If we have any active connections signal rasman to // tear them down. // if (InterlockedCompareExchange(&pOpenCB->ActiveLinkCount, 0, 0)) { PIRP Irp; NdisAcquireSpinLock(&NdisWanCB.Lock); Irp = NdisWanCB.HibernateEventIrp; if ((Irp != NULL) && IoSetCancelRoutine(Irp, NULL)) { NdisWanCB.HibernateEventIrp = NULL; NdisReleaseSpinLock(&NdisWanCB.Lock); Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NETWORK_INCREMENT); NdisAcquireSpinLock(&NdisWanCB.Lock); } NdisReleaseSpinLock(&NdisWanCB.Lock); } break; default: break; } } break; case NetEventQueryRemoveDevice: case NetEventCancelRemoveDevice: case NetEventReconfigure: case NetEventBindList: default: break; } NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoPnPEvent: Exit")); return (Status); } VOID ProtoCoSendComplete( IN NDIS_STATUS Status, IN NDIS_HANDLE ProtocolVcContext, IN PNDIS_PACKET Packet ) { PLINKCB LinkCB; PBUNDLECB BundleCB; PSEND_DESC SendDesc; NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("ProtoCoSendComplete: Enter - VC %p Packet: %p", ProtocolVcContext, Packet)); if (!IsLinkValid(ProtocolVcContext, FALSE, &LinkCB)) { NdisWanDbgOut(DBG_FAILURE, DBG_CL, ("NDISWAN: SendComplete after link has gone down ProtocolVcContext %p\n", LinkCB)); return; } REMOVE_DBG_SEND(PacketTypeNdis, LinkCB->OpenCB, Packet); // // Get Info from the NdisPacket // SendDesc = PPROTOCOL_RESERVED_FROM_NDIS(Packet)->SendDesc; NdisAcquireSpinLock(&LinkCB->Lock); ASSERT(SendDesc->LinkCB == LinkCB); CompleteSendDesc(SendDesc, Status); NdisAcquireSpinLock(&LinkCB->Lock); // // Remove ref that keeps the vc around // DerefVc(LinkCB); // // Deref for the ref applied in IsLinkValid // DEREF_LINKCB_LOCKED(LinkCB); NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("ProtoCoSendComplete: Exit")); } VOID ProtoCoIndicateStatus( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE ProtocolVcContext OPTIONAL, IN NDIS_STATUS GeneralStatus, IN PVOID StatusBuffer, IN UINT StatusBufferSize ) { POPENCB pOpenCB = (POPENCB)ProtocolBindingContext; PLINKCB LinkCB; PBUNDLECB BundleCB; if (!AreLinkAndBundleValid(ProtocolVcContext, TRUE, &LinkCB, &BundleCB)) { return; } switch (GeneralStatus) { case NDIS_STATUS_WAN_CO_FRAGMENT: NdisCoWanFragmentIndication(LinkCB, BundleCB, StatusBuffer, StatusBufferSize); break; case NDIS_STATUS_WAN_CO_LINKPARAMS: NdisCoWanLinkParamChange(LinkCB, BundleCB, StatusBuffer, StatusBufferSize); default: NdisWanDbgOut(DBG_INFO, DBG_PROTOCOL, ("Unknown Status Indication: 0x%x", GeneralStatus)); break; } // // Deref's for ref's applied in AreLinkAndBundleValid // DEREF_LINKCB(LinkCB); DEREF_BUNDLECB(BundleCB); } UINT ProtoCoReceivePacket( IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_HANDLE ProtocolVcContext, IN PNDIS_PACKET Packet ) { POPENCB pOpenCB = (POPENCB)ProtocolBindingContext; PLINKCB LinkCB = NULL; PBUNDLECB BundleCB = NULL; NDIS_STATUS Status; ULONG BufferCount; LONG PacketSize; PNDIS_BUFFER FirstBuffer; PRECV_DESC RecvDesc; UINT RefCount = 0; NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ProtoCoReceivePacket: Enter - OpenCB %p", pOpenCB)); do { if (!AreLinkAndBundleValid(ProtocolVcContext, TRUE, &LinkCB, &BundleCB)) { break; } #if DBG NdisAcquireSpinLock(&LinkCB->Lock); if (LinkCB->ClCallState != CL_CALL_CONNECTED) { DbgPrint("NDISWAN: Vc not fully active but indicating data!\n"); } NdisReleaseSpinLock(&LinkCB->Lock); #endif AcquireBundleLock(BundleCB); NdisQueryPacket(Packet, NULL, &BufferCount, &FirstBuffer, &PacketSize); if (PacketSize > (LONG)glMRU) { break; } PRECV_RESERVED_FROM_NDIS(Packet)->MagicNumber = MAGIC_EXTERNAL_RECV; RecvDesc = NdisWanAllocateRecvDesc(glLargeDataBufferSize); if (RecvDesc == NULL) { break; } RecvDesc->LinkCB = LinkCB; RecvDesc->BundleCB = BundleCB; // // If the packet has only one buffer we are happy, if not // we have to allocate our own ndis packet and buffers // and copy the data from the miniports packet into our packet // if (BufferCount > 1 || NDIS_GET_PACKET_STATUS(Packet) == NDIS_STATUS_RESOURCES) { RecvDesc->CurrentBuffer = RecvDesc->StartBuffer + MAC_HEADER_LENGTH + PROTOCOL_HEADER_LENGTH; // // Copy from the miniports packet to my packet // NdisWanCopyFromPacketToBuffer(Packet, 0, PacketSize, RecvDesc->CurrentBuffer, &RecvDesc->CurrentLength); ASSERT(PacketSize == RecvDesc->CurrentLength); } else { NdisQueryBuffer(FirstBuffer, &RecvDesc->CurrentBuffer, &RecvDesc->CurrentLength); ASSERT(PacketSize == RecvDesc->CurrentLength); RecvDesc->CopyRequired = TRUE; RecvDesc->OriginalPacket = Packet; RefCount = 1; } // // Indicate to netmon if we are sniffing at // the link level // if (gbSniffLink && (NdisWanCB.PromiscuousAdapter != NULL)) { // // Indicate a packet to netmon // IndicatePromiscuousRecv(BundleCB, RecvDesc, RECV_LINK); } // // Update the bandwidth on demand sample array with the latest send. // If we need to notify someone of a bandwidth event do it. // if (BundleCB->Flags & BOND_ENABLED) { UpdateBandwidthOnDemand(BundleCB->RUpperBonDInfo, PacketSize); CheckUpperThreshold(BundleCB); UpdateBandwidthOnDemand(BundleCB->RLowerBonDInfo, PacketSize); CheckLowerThreshold(BundleCB); } // // Add up the statistics // LinkCB->Stats.BytesReceived += RecvDesc->CurrentLength; LinkCB->Stats.FramesReceived++; BundleCB->Stats.BytesReceived += RecvDesc->CurrentLength; Status = (*LinkCB->RecvHandler)(LinkCB, RecvDesc); if (Status != NDIS_STATUS_PENDING) { RecvDesc->OriginalPacket = NULL; NdisWanFreeRecvDesc(RecvDesc); RefCount = 0; } NdisWanDbgOut(DBG_TRACE, DBG_RECEIVE, ("ProtoCoReceivePacket: Exit")); } while (0); // // Deref's for ref's applied by AreLinkAndBundleValid // DEREF_BUNDLECB_LOCKED(BundleCB); DEREF_LINKCB(LinkCB); return (RefCount); } NDIS_STATUS ProtoCoRequest( IN NDIS_HANDLE ProtocolAfContext, IN NDIS_HANDLE ProtocolVcContext OPTIONAL, IN NDIS_HANDLE ProtocolPartyContext OPTIONAL, IN OUT PNDIS_REQUEST NdisRequest ) { PCL_AFSAPCB AfSapCB = (PCL_AFSAPCB)ProtocolAfContext; NDIS_OID Oid; NdisWanDbgOut(DBG_TRACE, DBG_REQUEST, ("ProtoCoRequest: Enter - AfContext %p", ProtocolAfContext)); if (NdisRequest->RequestType == NdisRequestQueryInformation) { Oid = NdisRequest->DATA.QUERY_INFORMATION.Oid; } else { Oid = NdisRequest->DATA.SET_INFORMATION.Oid; } NdisWanDbgOut(DBG_TRACE, DBG_REQUEST, ("Oid - %x", Oid)); ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); switch (Oid) { case OID_CO_AF_CLOSE: { POPENCB OpenCB; PCL_AFSAPCB tAfSapCB; OpenCB = AfSapCB->OpenCB; NdisAcquireSpinLock(&OpenCB->Lock); while (OpenCB->AfRegisteringCount != 0) { NdisReleaseSpinLock(&OpenCB->Lock); NdisWanWaitForNotificationEvent(&OpenCB->AfRegisteringEvent); NdisAcquireSpinLock(&OpenCB->Lock); } for (tAfSapCB = (PCL_AFSAPCB)OpenCB->AfSapCBList.Flink; (PVOID)tAfSapCB != (PVOID)&OpenCB->AfSapCBList; tAfSapCB = (PCL_AFSAPCB)AfSapCB->Linkage.Flink) { if (tAfSapCB == AfSapCB) { break; } } if ((PVOID)tAfSapCB == (PVOID)&OpenCB->AfSapCBList) { NdisWanDbgOut(DBG_FAILURE, DBG_REQUEST, \ ("ProtoCoRequest: Af %p not on OpenCB %p list!", \ AfSapCB, OpenCB)); NdisReleaseSpinLock(&OpenCB->Lock); break; } RemoveEntryList(&AfSapCB->Linkage); InsertTailList(&OpenCB->AfSapCBClosing, &AfSapCB->Linkage); NdisReleaseSpinLock(&OpenCB->Lock); NdisAcquireSpinLock(&AfSapCB->Lock); ASSERT(!(AfSapCB->Flags & AFSAP_REMOVED_FLAGS)); ASSERT(AfSapCB->Flags & SAP_REGISTERED); AfSapCB->Flags |= AFSAP_REMOVED_REQUEST; DEREF_CLAFSAPCB_LOCKED(AfSapCB); } break; default: break; } NdisWanDbgOut(DBG_TRACE, DBG_REQUEST, ("ProtoCoRequest: Exit")); ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL); return (NDIS_STATUS_SUCCESS); } VOID ProtoCoRequestComplete( IN NDIS_STATUS Status, IN NDIS_HANDLE ProtocolAfContext, IN NDIS_HANDLE ProtocolVcContext OPTIONAL, IN NDIS_HANDLE ProtocolPartyContext OPTIONAL, IN PNDIS_REQUEST NdisRequest ) { PCL_AFSAPCB AfSapCB = (PCL_AFSAPCB)ProtocolAfContext; PWAN_REQUEST pWanRequest; POPENCB pOpenCB; pWanRequest = CONTAINING_RECORD(NdisRequest, WAN_REQUEST, NdisRequest); pOpenCB = pWanRequest->OpenCB; NdisWanDbgOut(DBG_TRACE, DBG_REQUEST, ("ProtoCoRequestComplete: Enter - WanRequest 0x%p", pWanRequest)); pWanRequest->NotificationStatus = Status; switch (pWanRequest->Origin) { case NDISWAN: NdisWanSetNotificationEvent(&pWanRequest->NotificationEvent); break; default: ASSERT(pWanRequest->Origin == NDISTAPI); NdisWanTapiRequestComplete(pOpenCB, pWanRequest); break; } NdisWanDbgOut(DBG_TRACE, DBG_REQUEST, ("ProtoCoRequestComplete: Exit")); } VOID ProtoCoAfRegisterNotify( IN NDIS_HANDLE ProtocolBindingContext, IN PCO_ADDRESS_FAMILY AddressFamily ) { POPENCB OpenCB = (POPENCB)ProtocolBindingContext; NDIS_CLIENT_CHARACTERISTICS ClCharacteristics; PCL_AFSAPCB AfSapCB; NDIS_STATUS Status; ULONG GenericUlong; NDIS_HANDLE AfHandle; WAN_REQUEST WanRequest; NDIS_WAN_CO_INFO WanInfo; NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoCoAfRegisterNotify: Enter - OpenCB %p AfType: %x", OpenCB, AddressFamily->AddressFamily)); // // If this is a proxied address family we are interested, // so open the address family, register a sap and return success. // if (AddressFamily->AddressFamily != CO_ADDRESS_FAMILY_TAPI) { NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoCoAfRegisterNotify: Af not tapi do not open!")); return; } NdisAcquireSpinLock(&OpenCB->Lock); for (AfSapCB = (PCL_AFSAPCB)OpenCB->AfSapCBList.Flink; (PVOID)AfSapCB != (PVOID)&OpenCB->AfSapCBList; AfSapCB = (PCL_AFSAPCB)AfSapCB->Linkage.Flink) { if (AfSapCB->Af.AddressFamily == AddressFamily->AddressFamily) { // // we already have this addressfamily on this open block. // NdisReleaseSpinLock(&OpenCB->Lock); return; } } AfSapCB = NdisWanAllocateClAfSapCB(OpenCB, AddressFamily); if (AfSapCB == NULL) { NdisReleaseSpinLock(&OpenCB->Lock); return; } // // Use this crude mechanism to keep us from unbinding while in the // middle of af notification. The count is cleaned up either in // openafcomplete (if open failed) or in registersapcomplete. // if (OpenCB->AfRegisteringCount == 0) { NdisWanInitializeNotificationEvent(&OpenCB->AfRegisteringEvent); } OpenCB->AfRegisteringCount++; NdisReleaseSpinLock(&OpenCB->Lock); // // Open the address family // NdisZeroMemory(&ClCharacteristics, sizeof(NDIS_CLIENT_CHARACTERISTICS)); ClCharacteristics.MajorVersion = NDISWAN_MAJOR_VERSION; ClCharacteristics.MinorVersion = NDISWAN_MINOR_VERSION; ClCharacteristics.ClCreateVcHandler = ClCreateVc; ClCharacteristics.ClDeleteVcHandler = ClDeleteVc; ClCharacteristics.ClRequestHandler = ProtoCoRequest; ClCharacteristics.ClRequestCompleteHandler = ProtoCoRequestComplete; ClCharacteristics.ClOpenAfCompleteHandler = ClOpenAfComplete; ClCharacteristics.ClCloseAfCompleteHandler = ClCloseAfComplete; ClCharacteristics.ClRegisterSapCompleteHandler = ClRegisterSapComplete; ClCharacteristics.ClDeregisterSapCompleteHandler = ClDeregisterSapComplete; ClCharacteristics.ClMakeCallCompleteHandler = ClMakeCallComplete; ClCharacteristics.ClModifyCallQoSCompleteHandler = ClModifyQoSComplete; ClCharacteristics.ClCloseCallCompleteHandler = ClCloseCallComplete; ClCharacteristics.ClAddPartyCompleteHandler = NULL; ClCharacteristics.ClDropPartyCompleteHandler = NULL; ClCharacteristics.ClIncomingCallHandler = ClIncomingCall; ClCharacteristics.ClIncomingCallQoSChangeHandler = ClIncomingCallQoSChange; ClCharacteristics.ClIncomingCloseCallHandler = ClIncomingCloseCall; ClCharacteristics.ClIncomingDropPartyHandler = NULL; ClCharacteristics.ClCallConnectedHandler = ClCallConnected; Status = NdisClOpenAddressFamily(OpenCB->BindingHandle, AddressFamily, AfSapCB, &ClCharacteristics, sizeof(NDIS_CLIENT_CHARACTERISTICS), &AfHandle); if (Status != NDIS_STATUS_PENDING) { ClOpenAfComplete(Status, AfSapCB, AfHandle); } NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ClOpenAddressFamily AfHandle 0x%x status: 0x%x", AfSapCB->AfHandle, Status)); // // Do some OID's to the miniport. This is a // CoNDIS miniport and are destined for the // miniport so AfHandle and VcHandle = NULL! // NdisZeroMemory(&WanRequest, sizeof(WanRequest)); WanRequest.Type = SYNC; WanRequest.Origin = NDISWAN; WanRequest.OpenCB = OpenCB; WanRequest.AfHandle = NULL; WanRequest.VcHandle = NULL; NdisWanInitializeNotificationEvent(&WanRequest.NotificationEvent); // // Get more info... // WanRequest.NdisRequest.RequestType = NdisRequestQueryInformation; WanRequest.NdisRequest.DATA.QUERY_INFORMATION.Oid = OID_WAN_CO_GET_INFO; WanRequest.NdisRequest.DATA.QUERY_INFORMATION.InformationBuffer = &WanInfo; WanRequest.NdisRequest.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(WanInfo); Status = NdisWanSubmitNdisRequest(OpenCB, &WanRequest); if (Status == NDIS_STATUS_SUCCESS) { OpenCB->WanInfo.MaxFrameSize = WanInfo.MaxFrameSize; OpenCB->WanInfo.MaxTransmit = WanInfo.MaxSendWindow; OpenCB->WanInfo.FramingBits = WanInfo.FramingBits; OpenCB->WanInfo.DesiredACCM = WanInfo.DesiredACCM; NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("CO_GET_INFO: FrameSize %d SendWindow %d", WanInfo.MaxFrameSize, WanInfo.MaxSendWindow)); } else { // // This guy will get default framing behaviour // OpenCB->WanInfo.FramingBits = PPP_FRAMING; OpenCB->WanInfo.DesiredACCM = 0; // // Find the send window // WanRequest.NdisRequest.RequestType = NdisRequestQueryInformation; WanRequest.NdisRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_SEND_PACKETS; WanRequest.NdisRequest.DATA.QUERY_INFORMATION.InformationBuffer = &GenericUlong; WanRequest.NdisRequest.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(ULONG); Status = NdisWanSubmitNdisRequest(OpenCB, &WanRequest); OpenCB->WanInfo.MaxTransmit = (Status == NDIS_STATUS_SUCCESS && GenericUlong > 0) ? GenericUlong : 10; // // Find the max transmit size // WanRequest.NdisRequest.RequestType = NdisRequestQueryInformation; WanRequest.NdisRequest.DATA.QUERY_INFORMATION.Oid = OID_GEN_MAXIMUM_TOTAL_SIZE; WanRequest.NdisRequest.DATA.QUERY_INFORMATION.InformationBuffer = &GenericUlong; WanRequest.NdisRequest.DATA.QUERY_INFORMATION.InformationBufferLength = sizeof(ULONG); Status = NdisWanSubmitNdisRequest(OpenCB, &WanRequest); OpenCB->WanInfo.MaxFrameSize = (Status == NDIS_STATUS_SUCCESS) ? GenericUlong : 1500; } OpenCB->WanInfo.Endpoints = 1000; NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("ProtoCoAfRegisterNotify: Exit")); } NDIS_STATUS DoNewLineUpToProtocol( PPROTOCOLCB ProtocolCB ) /*++ Routine Name: Routine Description: Arguments: Return Values: --*/ { PMINIPORTCB MiniportCB; NDIS_STATUS Status; PBUNDLECB BundleCB = ProtocolCB->BundleCB; NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("DoNewLineupToProtocol: Enter")); do { NdisAcquireSpinLock(&MiniportCBList.Lock); // // Find the adapter that this lineup is for. Look for the adapter // that has the appropriate protocoltype. If it is NBF we need // to look for a specific adapter. // for (MiniportCB = (PMINIPORTCB)MiniportCBList.List.Flink; (PVOID)MiniportCB != (PVOID)&MiniportCBList.List; MiniportCB = (PMINIPORTCB)MiniportCB->Linkage.Flink) { if (MiniportCB->ProtocolType == ProtocolCB->ProtocolType) { if (ProtocolCB->ProtocolType != PROTOCOL_NBF) { break; } // // Must be NBF so verify the AdapterName!!! // if (NdisEqualUnicodeString(&MiniportCB->AdapterName,&ProtocolCB->BindingName, FALSE)) { break; } } } if ((PVOID)MiniportCB == (PVOID)&MiniportCBList.List) { // // The adapter was not found... // NdisWanDbgOut(DBG_FAILURE, DBG_PROTOCOL, ("Adapter not found!")); NdisReleaseSpinLock(&MiniportCBList.Lock); Status = NDISWAN_ERROR_NO_ROUTE; break; } ASSERT(MiniportCB->ProtocolType == ProtocolCB->ProtocolType); ETH_COPY_NETWORK_ADDRESS(ProtocolCB->NdisWanAddress, MiniportCB->NetworkAddress); FillNdisWanIndices(ProtocolCB->NdisWanAddress, BundleCB->hBundleHandle, ProtocolCB->ProtocolHandle); NdisZeroMemory(ProtocolCB->TransportAddress, 6); NdisAcquireSpinLock(&MiniportCB->Lock); InsertTailList(&MiniportCB->ProtocolCBList, &ProtocolCB->MiniportLinkage); ProtocolCB->MiniportCB = MiniportCB; REF_MINIPORTCB(MiniportCB); NdisReleaseSpinLock(&MiniportCB->Lock); NdisReleaseSpinLock(&MiniportCBList.Lock); Status = DoLineUpToProtocol(ProtocolCB); if (Status != NDIS_STATUS_SUCCESS) { NdisAcquireSpinLock(&MiniportCBList.Lock); NdisAcquireSpinLock(&MiniportCB->Lock); RemoveEntryList(&ProtocolCB->MiniportLinkage); if (MiniportCB->Flags & HALT_IN_PROGRESS) { NdisWanSetSyncEvent(&MiniportCB->HaltEvent); } NdisReleaseSpinLock(&MiniportCB->Lock); NdisReleaseSpinLock(&MiniportCBList.Lock); DEREF_MINIPORTCB(MiniportCB); } } while (FALSE); NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("DoNewLineupToProtocols: Exit")); return (Status); } NDIS_STATUS DoLineUpToProtocol( IN PPROTOCOLCB ProtocolCB ) /*++ Routine Name: Routine Description: Arguments: Return Values: --*/ { ULONG AllocationSize; NDIS_STATUS Status = NDIS_STATUS_SUCCESS; PNDIS_WAN_LINE_UP LineUpInfo; PMINIPORTCB MiniportCB = ProtocolCB->MiniportCB; PBUNDLECB BundleCB = ProtocolCB->BundleCB; KIRQL OldIrql; NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("DoLineupToProtocol: Enter")); ASSERT(MiniportCB != NULL); AllocationSize = sizeof(NDIS_WAN_LINE_UP) + ProtocolCB->ulLineUpInfoLength + (sizeof(WCHAR) * (MAX_NAME_LENGTH + 1) + (2 * sizeof(PVOID))); NdisWanAllocateMemory(&LineUpInfo, AllocationSize, LINEUPINFO_TAG); if (LineUpInfo != NULL) { ULONG LineUpHandle = ProtocolCB->ulTransportHandle; // // Needs to be in 1/100bps, we store in Bps // LineUpInfo->LinkSpeed = BundleCB->SFlowSpec.PeakBandwidth * 8 / 100; // // Set the MTU for this protocol // { POPENCB OpenCB = BundleCB->NextLinkToXmit->OpenCB; // // If this connection is running over a VPN we will downsize // the MTU // if ((OpenCB->MediumSubType == NdisWanMediumPPTP || OpenCB->MediumSubType == NdisWanMediumL2TP)) { LineUpInfo->MaximumTotalSize = ProtocolCB->TunnelMTU; } else { LineUpInfo->MaximumTotalSize = ProtocolCB->MTU; } if (LineUpInfo->MaximumTotalSize > BundleCB->SFlowSpec.MaxSduSize) { LineUpInfo->MaximumTotalSize = BundleCB->SFlowSpec.MaxSduSize; } #if 0 // // Figure out the size of the ppp header... // BundleCB->FramingInfo.PPPHeaderLength = CalcPPPHeaderLength(BundleCB->FramingInfo.SendFramingBits, BundleCB->SendFlags); if (LineUpInfo->MaximumTotalSize > BundleCB->FramingInfo.PPPHeaderLength) { LineUpInfo->MaximumTotalSize -= BundleCB->FramingInfo.PPPHeaderLength; } else { LineUpInfo->MaximumTotalSize = 0; } #endif } LineUpInfo->Quality = NdisWanReliable; LineUpInfo->SendWindow = (USHORT)BundleCB->SendWindow; LineUpInfo->ProtocolType = ProtocolCB->ProtocolType; LineUpInfo->DeviceName.Length = ProtocolCB->InDeviceName.Length; LineUpInfo->DeviceName.MaximumLength = MAX_NAME_LENGTH + 1; LineUpInfo->DeviceName.Buffer = (PWCHAR)((PUCHAR)LineUpInfo + sizeof(NDIS_WAN_LINE_UP) + sizeof(PVOID)); (ULONG_PTR)LineUpInfo->DeviceName.Buffer &= ~((ULONG_PTR)sizeof(PVOID) - 1); if (ProtocolCB->InDeviceName.Length != 0) { NdisMoveMemory(LineUpInfo->DeviceName.Buffer, ProtocolCB->InDeviceName.Buffer, ProtocolCB->InDeviceName.Length); } LineUpInfo->ProtocolBuffer = (PUCHAR)LineUpInfo + sizeof(NDIS_WAN_LINE_UP) + (sizeof(WCHAR) * (MAX_NAME_LENGTH + 1) + sizeof(PVOID)); (ULONG_PTR)LineUpInfo->ProtocolBuffer &= ~((ULONG_PTR)sizeof(PVOID) - 1); // // // The Remote address (DEST address in a send) is what we use to // mutilplex sends across our single adapter/binding context. // The address has the following format: // // XX XX XX YY YY ZZ // // XX = Randomly generated OUI // YY = Index into the active bundle connection table to get bundlecb // ZZ = Index into the protocol table of a bundle to get protocolcb // ETH_COPY_NETWORK_ADDRESS(LineUpInfo->RemoteAddress,ProtocolCB->NdisWanAddress); ETH_COPY_NETWORK_ADDRESS(LineUpInfo->LocalAddress,ProtocolCB->TransportAddress); // // Fill in the protocol specific information // LineUpInfo->ProtocolBufferLength = ProtocolCB->ulLineUpInfoLength; if (ProtocolCB->ulLineUpInfoLength > 0) { NdisMoveMemory(LineUpInfo->ProtocolBuffer, ProtocolCB->LineUpInfo, ProtocolCB->ulLineUpInfoLength); } // KeRaiseIrql(DISPATCH_LEVEL, &OldIrql); // DbgPrint("LineUp: %x, MTU %d\n", // LineUpInfo->ProtocolType, LineUpInfo->MaximumTotalSize); // // Do the line up indication // NdisMIndicateStatus(MiniportCB->MiniportHandle, NDIS_STATUS_WAN_LINE_UP, LineUpInfo, AllocationSize); // KeLowerIrql(OldIrql); // // Update protocol queue depth // { PROTOCOL_INFO ProtocolInfo = {0}; ULONG ByteDepth; ULONG i; AcquireBundleLock(BundleCB); ProtocolInfo.ProtocolType = ProtocolCB->ProtocolType; GetProtocolInfo(&ProtocolInfo); // // Set the send queue byte depth. // ByteDepth = ProtocolInfo.PacketQueueDepth; // // If the byte depth is less then 4 // full packets, then set it to 4 full // packets. // if (ByteDepth < (ProtocolInfo.MTU * 4)) { ByteDepth = ProtocolInfo.MTU * 4; } for (i = 0; i <= MAX_MCML; i++) { ProtocolCB->PacketQueue[i].MaxByteDepth = ByteDepth; } ReleaseBundleLock(BundleCB); } // // If this was the first line up for this protocolcb and // this lineup was answered we need to collect some info // if (ProtocolCB->ulTransportHandle == 0) { *((ULONG UNALIGNED *)(&LineUpHandle)) = *((ULONG UNALIGNED *)(&LineUpInfo->LocalAddress[2])); if (LineUpHandle != 0) { AcquireBundleLock(BundleCB); ETH_COPY_NETWORK_ADDRESS(ProtocolCB->TransportAddress, LineUpInfo->LocalAddress); ProtocolCB->ulTransportHandle = LineUpHandle; if (LineUpInfo->DeviceName.Length != 0) { NdisWanStringToNdisString(&ProtocolCB->OutDeviceName, LineUpInfo->DeviceName.Buffer); } ReleaseBundleLock(BundleCB); // // If this is an nbf adapter // if (ProtocolCB->ProtocolType == (USHORT)PROTOCOL_NBF) { ASSERT(MiniportCB->ProtocolType == (USHORT)PROTOCOL_NBF); MiniportCB->NbfProtocolCB = ProtocolCB; } } else { Status = NDISWAN_ERROR_NO_ROUTE; } } NdisWanFreeMemory(LineUpInfo); } else { Status = NDIS_STATUS_RESOURCES; } NdisWanDbgOut(DBG_TRACE, DBG_PROTOCOL, ("DoLineupToProtocol: Exit")); return (Status); } NDIS_STATUS DoLineDownToProtocol( PPROTOCOLCB ProtocolCB ) { NDIS_WAN_LINE_DOWN WanLineDown; PNDIS_WAN_LINE_DOWN LineDownInfo = &WanLineDown; PMINIPORTCB MiniportCB = ProtocolCB->MiniportCB; PBUNDLECB BundleCB = ProtocolCB->BundleCB; KIRQL OldIrql; // // The Remote address (DEST address) is what we use to mutilplex // sends across our single adapter/binding context. The address // has the following format: // // XX XX YY YY YY YY // // XX = Randomly generated OUI // YY = ProtocolCB // ETH_COPY_NETWORK_ADDRESS(LineDownInfo->RemoteAddress, ProtocolCB->NdisWanAddress); ETH_COPY_NETWORK_ADDRESS(LineDownInfo->LocalAddress, ProtocolCB->TransportAddress); // // If this is an nbf adapter // if (ProtocolCB->ProtocolType == PROTOCOL_NBF) { MiniportCB->NbfProtocolCB = NULL; } ProtocolCB->ulTransportHandle = 0; ProtocolCB->State = PROTOCOL_UNROUTED; ReleaseBundleLock(BundleCB); NdisMIndicateStatus(MiniportCB->MiniportHandle, NDIS_STATUS_WAN_LINE_DOWN, LineDownInfo, sizeof(NDIS_WAN_LINE_DOWN)); NdisAcquireSpinLock(&MiniportCB->Lock); RemoveEntryList(&ProtocolCB->MiniportLinkage); if (MiniportCB->Flags & HALT_IN_PROGRESS) { NdisWanSetSyncEvent(&MiniportCB->HaltEvent); } NdisReleaseSpinLock(&MiniportCB->Lock); DEREF_MINIPORTCB(MiniportCB); AcquireBundleLock(BundleCB); return (NDIS_STATUS_SUCCESS); } VOID CompleteSendDesc( PSEND_DESC SendDesc, NDIS_STATUS Status ) { PLINKCB LinkCB; PBUNDLECB BundleCB; PPROTOCOLCB ProtocolCB; PNDIS_PACKET OriginalPacket; BOOLEAN FreeLink = FALSE, FreeBundle = FALSE; BOOLEAN LegacyLink; PULONG pulRefCount; PCM_VCCB CmVcCB; INT Class; ULONG DescFlags; LinkCB = SendDesc->LinkCB; ProtocolCB = SendDesc->ProtocolCB; OriginalPacket = SendDesc->OriginalPacket; Class = SendDesc->Class; DescFlags = SendDesc->Flags; NdisWanDbgOut(DBG_TRACE, DBG_SEND, ("SendDesc: 0x%p, OriginalPacket: 0x%p, Status: %x", SendDesc, OriginalPacket, Status)); NdisWanFreeSendDesc(SendDesc); // // Bundle that this link is on // BundleCB = LinkCB->BundleCB; // // Deref for the ref applied when a senddesc // was retrieved for this link. We don't need to do // the full deref here because we are keeping the // link from going away with the ref applied when // we got the sendcomplete. // --LinkCB->RefCount; #ifdef DBG_SENDARRAY { SendArray[__si] = 'c'; if (++__si == MAX_BYTE_DEPTH) { __si = 0; } } #endif NdisReleaseSpinLock(&LinkCB->Lock); AcquireBundleLock(BundleCB); LegacyLink = (LinkCB->OpenCB->Flags & OPEN_LEGACY) ? 1 : 0; // // If the sendwindow is currently full, this completion // opens the sendwindow. // if (LinkCB->OutstandingFrames == LinkCB->SendWindow) { LinkCB->SendWindowOpen = TRUE; if (LinkCB->LinkActive) { BundleCB->SendingLinks++; } } LinkCB->OutstandingFrames--; if (DescFlags & SEND_DESC_FRAG) { InterlockedDecrement(&ProtocolCB->PacketQueue[Class].OutstandingFrags); } pulRefCount = &(PMINIPORT_RESERVED_FROM_NDIS(OriginalPacket)->RefCount); ASSERT(*pulRefCount > 0); // // See if the reference count is zero, if it is not // we just return. // if (InterlockedDecrement(pulRefCount) != 0) { SendPacketOnBundle(BundleCB); return; } ReleaseBundleLock(BundleCB); // // Complete this NdisPacket back to the transport // NDIS_SET_PACKET_STATUS(OriginalPacket, Status); CompleteNdisPacket(ProtocolCB->MiniportCB, ProtocolCB, OriginalPacket); AcquireBundleLock(BundleCB); BundleCB->OutstandingFrames--; if ((BundleCB->Flags & FRAMES_PENDING_EVENT) && (BundleCB->OutstandingFrames == 0)) { NdisWanSetSyncEvent(&BundleCB->OutstandingFramesEvent); } // // Called with bundle lock help but returns with lock released // SendPacketOnBundle(BundleCB); // // Deref for ref applied when sent a packet to be framed. // DEREF_BUNDLECB(BundleCB); } #if 0 ULONG CalcPPPHeaderLength( ULONG FramingBits, ULONG Flags ) { ULONG HeaderLength = 0; if (FramingBits & PPP_FRAMING) { if (!(FramingBits & PPP_COMPRESS_ADDRESS_CONTROL)) { // // If there is no address/control compression // we need a pointer and a length // if (FramingBits & LLC_ENCAPSULATION) { HeaderLength += 4; } else { HeaderLength += 2; } } // // If this is not from our private I/O interface we will // build the rest of the header. // if (FramingBits & PPP_MULTILINK_FRAMING) { if (!(FramingBits & PPP_COMPRESS_PROTOCOL_FIELD)) { // // No protocol compression // HeaderLength += 1; } HeaderLength += 1; if (!(FramingBits & PPP_SHORT_SEQUENCE_HDR_FORMAT)) { // // We are using long sequence number // HeaderLength += 2; } HeaderLength += 2; } if (Flags & (DO_COMPRESSION | DO_ENCRYPTION)) { // // We are doing compression/encryption so we need // a length // // // It appears that legacy ras (< NT 4.0) requires that // the PPP protocol field in a compressed packet not // be compressed, ie has to have the leading 0x00 // if (!(FramingBits & PPP_COMPRESS_PROTOCOL_FIELD)) { // // No protocol compression // HeaderLength += 1; } // // Add protocol and coherency bytes // HeaderLength += 3; } if (!(FramingBits & PPP_COMPRESS_PROTOCOL_FIELD) || (Flags & (DO_COMPRESSION | DO_ENCRYPTION))) { HeaderLength += 1; } HeaderLength += 1; } else if (FramingBits & RAS_FRAMING) { // // If this is old ras framing: // // Alter the framing so that 0xFF 0x03 is not added // and that the first byte is 0xFD not 0x00 0xFD // // So basically, a RAS compression looks like // <0xFD> <2 BYTE COHERENCY> // // Whereas uncompressed looks like // which always starts with 0xF0 // // If this is ppp framing: // // A compressed frame will look like (before address/control // - multilink is added) // <0x00> <0xFD> <2 Byte Coherency> // if (Flags & (DO_COMPRESSION | DO_ENCRYPTION)) { // // Coherency bytes // HeaderLength += 3; } } // DbgPrint("PPPHeaderLength %d\n", HeaderLength); return (HeaderLength); } #endif