/* §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ (C) Copyright 1999 All rights reserved. §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ Portions of this software are: (C) Copyright 1995 TriplePoint, Inc. -- http://www.TriplePoint.com License to use this software is granted under the same terms outlined in the Microsoft Windows Device Driver Development Kit. (C) Copyright 1992 Microsoft Corp. -- http://www.Microsoft.com License to use this software is granted under the terms outlined in the Microsoft Windows Device Driver Development Kit. §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @doc INTERNAL CallMgr CallMgr_c @module CallMgr.c | This module defines the interface to the . Supports the interface between NDISPROXY and the Miniport. All the Address Family, SAP, VC, and call related events pass through these interface on their way to and from NDPROXY. @comm This module will require some changes depending on how your hardware works. But in general, you should try to isolate your changes down in and . @head3 Contents | @index class,mfunc,func,msg,mdata,struct,enum | CallMgr_c @end §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ */ /* @doc EXTERNAL INTERNAL §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @topic 3.1 Call Manager Interface | The NDPROXY driver is a provider for the Windows Telephony service. Applications make TAPI requests and the Windows Telephony service routes these requests to NDPROXY. NDPROXY implements the Telephony Service Provider Interface (TSPI) for the Windows Telephony service. NDPROXY then communicates through NDIS with the NDISWAN driver and CoNDIS WAN miniport drivers. These CoNDIS WAN miniport drivers must provide TAPI capability. The NDPROXY driver passes TAPI requests by encapsulating TAPI parameters in NDIS structures. NDPROXY presents a client interface to CoNDIS WAN miniport drivers and a call manager interface to NDISWAN. NDISWAN presents a client interface to NDPROXY. CoNDIS WAN miniport drivers present a call manager interface to NDPROXY and a CoNDIS miniport interface to NDISWAN. A TAPI-capable CoNDIS WAN miniport driver registers and initializes itself as a user of both WAN and TAPI services. After registration and initialization are complete, a user-level application can make telephonic requests to the Windows Telephony service module, which converts TAPI requests to TSPI requests. The Windows Telephony service module passes these requests to the NDPROXY driver. NDPROXY encapsulates parameters for TAPI requests in NDIS structures and routes the requests to the appropriate CoNDIS WAN miniport driver. These requests are routed in order to set up, monitor, and tear down lines, and calls. A TAPI-capable CoNDIS WAN miniport driver can also communicate changes in the states of lines and calls, for instance the arrival of an incoming call or a remote disconnection. @ex Registering and opening the TAPI address family between NDPROXY and MCM | NDPROXY NDIS MCM |----------------------------------|----------------------------------| | | NdisMCmRegisterAddressFamily | | ProtocolCoAfRegisterNotify |«---------------------------------| |«---------------------------------| | | NdisClOpenAddressFamily | | |---------------------------------»| ProtocolCmOpenAf | | |---------------------------------»| | | CompleteCmOpenAf | | | NdisCmOpenAddressFamilyComplete | | ProtocolOpenAfComplete |«---------------------------------| |«---------------------------------| | |----------------------------------|----------------------------------| @ex Closing the TAPI address family between NDPROXY and MCM | NDPROXY NDIS MCM |----------------------------------|----------------------------------| | NdisClCloseAddressFamily | | |---------------------------------»| ProtocolCmCloseAf | | |---------------------------------»| | | CompleteCmCloseAf | | | NdisMCmCloseAddressFamilyComplete| | ProtocolClCloseAfComplete |«---------------------------------| |«---------------------------------| | |----------------------------------|----------------------------------| @ex Registering a SAP between NDPROXY and MCM | NDPROXY NDIS MCM |----------------------------------|----------------------------------| | NdisClRegisterSap | | |---------------------------------»| ProtocolCmRegisterSap | | |---------------------------------»| | | CompleteCmRegisterSap | | | NdisMCmRegisterSapComplete | | ProtocolClRegisterSapComplete |«---------------------------------| |«---------------------------------| | |----------------------------------|----------------------------------| @ex Deregistering a SAP between NDPROXY and MCM | NDPROXY NDIS MCM |----------------------------------|----------------------------------| | NdisClDeregisterSap | | |---------------------------------»| ProtocolCmDeregisterSap | | |---------------------------------»| | | CompleteCmDeregisterSap | | | NdisMCmDeregisterSapComplete | | ProtocolClDeregisterSapComplete |«---------------------------------| |«---------------------------------| | |----------------------------------|----------------------------------| @ex Seting up an outgoing call from NDPROXY to MCM | NDPROXY NDIS MCM |----------------------------------|----------------------------------| | NdisCoCreateVc | ProtocolCoCreateVC | |---------------------------------»|«--------------------------------»| | NdisClMakeCall | ProtocolCmMakeCall | |---------------------------------»|---------------------------------»| | . | . | | . | . | | . | . | | | NdisMCmActivateVC | | |«---------------------------------| | | ProtocolCmActivateVcComplete | | |---------------------------------»| | ProtocolClMakeCallComplete | NdisMCmMakeCallComplete | |«--------------------------------»|«---------------------------------| | . | . | | . "Tranmit & receive packets" . | | . | . | | "Client/MCM initiated call termination" | | NdisCoDeleteVc | ProtocolCoDeleteVc | |---------------------------------»|«--------------------------------»| |----------------------------------|----------------------------------| @ex Setting up an incoming call from MCM to NDPROXY | NDPROXY NDIS MCM |----------------------------------|----------------------------------| | NdisCoCreateVc | NdisMCmCreateVC | |«--------------------------------»|«---------------------------------| | | NdisMCmActivateVC | | |«---------------------------------| | | ProtocolCmActivateVcComplete | | |---------------------------------»| | ProtocolClIncomingCall | NdisMCmDispatchIncomingCall | |«---------------------------------|«---------------------------------| | | | | NdisClIncomingCallComplete | ProtocolCmIncomingCallComplete | |---------------------------------»|«--------------------------------»| | ProtocolClCallConnected | NdisMCmDispatchCallConnected | |«--------------------------------»|«---------------------------------| | . | . | | . "Tranmit & receive packets" . | | . | . | | "Client/MCM initiated call termination" | | ProtocolCoDeleteVc | NdisMCmDeleteVc | |«--------------------------------»|«---------------------------------| |----------------------------------|----------------------------------| @ex NDPROXY initiated call termination | NDPROXY NDIS MCM |----------------------------------|----------------------------------| | NdisClCloseCall | ProtocolCmCloseCall | |---------------------------------»|---------------------------------»| | | NdisMCmDeactivateVc | | |«---------------------------------| | | ProtocolCmDeactivateVcComplete | | |---------------------------------»| | ProtocolClCloseCallComplete | NdisCmCloseCallComplete | |«--------------------------------»|«---------------------------------| |----------------------------------|----------------------------------| @ex MCM initiated call termination | NDPROXY NDIS MCM |----------------------------------|----------------------------------| | ProtocolClIncomingCloseCall | NdisMCmDispatchIncomingCloseCall | |«---------------------------------|«---------------------------------| | NdisClCloseCall | ProtocolCmCloseCall | |---------------------------------»|---------------------------------»| | | NdisMCmDeactivateVc | | |«---------------------------------| | | ProtocolCmDeactivateVcComplete | | |---------------------------------»| | ProtocolClCloseCallComplete | NdisCmCloseCallComplete | |«--------------------------------»|«---------------------------------| |----------------------------------|----------------------------------| @end */ #define __FILEID__ CALL_MANAGER_OBJECT_TYPE // Unique file ID for error logging #include "Miniport.h" // Defines all the miniport objects #if defined(NDIS_LCODE) # pragma NDIS_LCODE // Windows 9x wants this code locked down! # pragma NDIS_LDATA #endif /* @doc INTERNAL CallMgr CallMgr_c CompleteCmOpenAf §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func is called when the miniport is done processing the request. @comm If you return NDIS_STATUS_PENDING from , you must call so that can be called to complete the request. */ VOID CompleteCmOpenAf( IN PMINIPORT_ADAPTER_OBJECT pAdapter, // @parm // A pointer to the instance return by // . IN NDIS_STATUS Status // @parm // The NDIS status code to be passed to NdisMCmOpenAddressFamilyComplete. ) { DBG_FUNC("CompleteCmOpenAf") DBG_ENTER(pAdapter); /* // Try to connect to the DChannel. */ DChannelOpen(pAdapter->pDChannel); NdisMCmOpenAddressFamilyComplete(Status, pAdapter->NdisAfHandle, pAdapter); DBG_LEAVE(pAdapter); } /* @doc EXTERNAL INTERNAL CallMgr CallMgr_c ProtocolCmOpenAf §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func is a required function that allocates per-open resources for a call manager to interact with a connection-oriented NDIS client that is opening the address family. @comm ProtocolCmOpenAf performs any required allocations of dynamic resources and structures that the call manager writer deems necessary to perform operations on behalf of the client that is opening an instance of this address family. Such resources include, but are not limited to, memory buffers, data structures, events, and other such similar resources. A call manager should also initialize any relevant per-open data before returning control to NDIS. When a call manager has allocated its per-open state area, the address of the state area should be set in the CallMgrAfContext handle before returning control to NDIS. To do this, dereference CallMgrAfContext and store a pointer to the data area as the value of the handle. For example: *CallMgrAfContext = SomeBuffer; // We use . If ProtocolCmOpenAf cannot allocate the per-open resources it needs to carry out subsequent requests on behalf of the client opening this address family, it should free all resources that it allocated for the open and return control to the NDIS with NDIS_STATUS_RESOURCES. If ProtocolCmOpenAf has completed its required operations and the CM is ready to accept requests from the client, ProtocolCmOpenAf should return control as quickly as possible with a status of NDIS_STATUS_SUCCESS. ProtocolCmOpenAf must be written so that it can run at IRQL DISPATCH_LEVEL. @rdesc ProtocolCmOpenAf returns the status of its operation(s) as one of the following: @rvalue NDIS_STATUS_SUCCESS | Indicates that the call manager has successfully allocated and initialized any resources necessary to accept requests from the client to this address family. @rvalue NDIS_STATUS_PENDING | Indicates that the requested operation is being handled asynchronously. The call manager must call NdisCmOpenAddressFamilyComplete when it has completed all its open-AF operations to indicate to NDIS (and the client) that the operation(s) has been completed. @rvalue NDIS_STATUS_RESOURCES | Indicates that the call manager could not complete its necessary operation(s) because of a lack of available system resources, such as memory. @rvalue NDIS_STATUS_XXX | Indicates that the call manager could not set itself into a state where it can accept requests from the client to operate on this address family. This could be an error status propagated from another NDIS library function or any error status determined appropriate by the driver writer. @xref NdisClOpenAddressFamily, NdisCmOpenAddressFamilyComplete, NdisCmRegisterAddressFamily, NdisOpenAdapter, */ NDIS_STATUS ProtocolCmOpenAf( IN PMINIPORT_ADAPTER_OBJECT pAdapter, // @parm // A pointer to the instance return by // . AKA CallMgrBindingContext. // Specifies the handle to a call manager-allocated context area in which // the call managers maintains its per-binding state information. The call // manager supplied this handle when it called NdisOpenAdapter. IN PCO_ADDRESS_FAMILY AddressFamily, // @parm // Specifies the address family that a client is opening. This address // family was registered by the call manager when it called // NdisCmRegisterAddressFamily. IN NDIS_HANDLE NdisAfHandle, // @parm // Specifies a handle, supplied by NDIS, that uniquely identifies this // address family instance. This handle is opaque to the call manager and // reserved for system use. OUT PNDIS_HANDLE CallMgrAfContext // @parm // Specifies the handle to a call manager-supplied context area in which // the call manager maintains state about this open of an address family it // provides. ) { DBG_FUNC("ProtocolCmOpenAf") NDIS_STATUS Status; ASSERT(pAdapter && pAdapter->ObjectType == MINIPORT_ADAPTER_OBJECT_TYPE); DBG_ENTER(pAdapter); if (pAdapter->NdisAfHandle != NULL) { // Our AF has already been opened and it doesn't make any sense to // accept another since there is no way to distinguish which should // receive incoming calls. DBG_ERROR(pAdapter, ("Attempting to open AF again!\n")); Status = NDIS_STATUS_FAILURE; } else { pAdapter->NdisAfHandle = NdisAfHandle; DBG_FILTER(pAdapter, DBG_TAPICALL_ON, ("TAPI AF=0x%X AddressFamily=0x%X MajorVersion=0x%X MinorVersion=0x%X\n", NdisAfHandle, AddressFamily->AddressFamily, AddressFamily->MajorVersion, AddressFamily->MinorVersion )); // Since we return NDIS_STATUS_PENDING here, we must call // NdisMCmOpenAddressFamilyComplete to complete this request. // If necessary, you can do the completion asynchronously. *CallMgrAfContext = pAdapter; CompleteCmOpenAf(pAdapter, NDIS_STATUS_SUCCESS); Status = NDIS_STATUS_PENDING; } DBG_RETURN(pAdapter, Status); return (Status); } /* @doc INTERNAL CallMgr CallMgr_c CompleteCmCloseAf §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func is called when the miniport is done processing the request. @comm If you return NDIS_STATUS_PENDING from , you must call so that can be called to complete the request. */ VOID CompleteCmCloseAf( IN PMINIPORT_ADAPTER_OBJECT pAdapter, // @parm // A pointer to the instance return by // . IN NDIS_STATUS Status // @parm // The NDIS status code to be passed to NdisMCmCloseAddressFamilyComplete. ) { DBG_FUNC("CompleteCmCloseAf") NDIS_HANDLE NdisAfHandle; DBG_ENTER(pAdapter); NdisAfHandle = pAdapter->NdisAfHandle; pAdapter->NdisAfHandle = NULL; DBG_FILTER(pAdapter, DBG_TAPICALL_ON, ("TAPI AF=0x%X\n", NdisAfHandle)); NdisMCmCloseAddressFamilyComplete(Status, NdisAfHandle); DBG_LEAVE(pAdapter); } /* @doc EXTERNAL INTERNAL CallMgr CallMgr_c ProtocolCmCloseAf §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func is a required function that releases per-open resources for an address family that a call manager supports. @comm ProtocolCmCloseAf releases and/or deactivates any resources that were allocated by the call manager in its ProtocolCmOpenAf function. The call manager also should undo any other actions it took on behalf of the connection-oriented client when the address family was opened by that client. If there are any outstanding requests or connections still open on an address family stored in the CallMgrAfContext, a call manager can respond to a client's request to close the address family in either of the following ways: The call manager can fail the request with NDIS_STATUS_NOT_ACCEPTED. The call manager can return NDIS_STATUS_PENDING. After the client has closed all calls and deregistered all SAPs, the call manager can then close the address family and call Ndis(M)CmCloseAddressFamilyComplete to notify the client. This is the preferred response. ProtocolCmCloseAf must be written so that it can run at IRQL DISPATCH_LEVEL. @rdesc ProtocolCmCloseAf returns the status of its operation(s) as one of the following: @rvalue NDIS_STATUS_SUCCESS | Indicates that the call manager has successfully released or deactivated any resources that is allocated on behalf of the connection-oriented client that opened this instance of the address family. @rvalue NDIS_STATUS_PENDING | Indicates that the request to close the open instance of the address family will be completed asynchronously. The call manager must call NdisCmCloseAddressFamilyComplete when all such operations have been completed. @xref NdisCmCloseAddressFamilyComplete, */ NDIS_STATUS ProtocolCmCloseAf( IN PMINIPORT_ADAPTER_OBJECT pAdapter // @parm // A pointer to the instance return by // . AKA CallMgrAfContext. // Specifies the handle to the call manager's per-AF context area, // originally supplied to NDIS by the call manager's ProtocolCmOpenAf // function. ) { DBG_FUNC("ProtocolCmCloseAf") NDIS_STATUS Result = NDIS_STATUS_SUCCESS; // Holds the result code returned by this function. ASSERT(pAdapter && pAdapter->ObjectType == MINIPORT_ADAPTER_OBJECT_TYPE); DBG_ENTER(pAdapter); // Since we return NDIS_STATUS_PENDING here, we must call // NdisMCmCloseAddressFamilyComplete to complete this request. // TODO: If necessary, you can do the completion asynchronously. DChannelClose(pAdapter->pDChannel); CompleteCmCloseAf(pAdapter, NDIS_STATUS_SUCCESS); Result = NDIS_STATUS_PENDING; DBG_RETURN(pAdapter, Result); return (Result); } VOID CompleteCmRegisterSap( IN PBCHANNEL_OBJECT pBChannel, // @parm // A pointer to the returned by . IN NDIS_STATUS Status // @parm // The NDIS status code to be passed to NdisMCmRegisterSapComplete. ) { DBG_FUNC("CompleteCmRegisterSap") PMINIPORT_ADAPTER_OBJECT pAdapter; // A pointer to the . ASSERT(pBChannel && pBChannel->ObjectType == BCHANNEL_OBJECT_TYPE); pAdapter = pBChannel->pAdapter; ASSERT(pAdapter && pAdapter->ObjectType == MINIPORT_ADAPTER_OBJECT_TYPE); DBG_ENTER(pAdapter); /* // TODO: What statistics do you want to collect and report? */ pAdapter->TotalRxBytes = 0; pAdapter->TotalTxBytes = 0; pAdapter->TotalRxPackets = 0; pAdapter->TotalTxPackets = 0; // If you return NDIS_STATUS_PENDING from ProtocolCmRegisterSap, you // must call NdisMCmRegisterSapComplete to complete the request. NdisMCmRegisterSapComplete(Status, pBChannel->NdisSapHandle, pBChannel); DBG_LEAVE(pAdapter); } /* @doc EXTERNAL INTERNAL CallMgr CallMgr_c ProtocolCmRegisterSap §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func is a required function that is called by NDIS to request that a call manager register a SAP (service access point) on behalf of a connection-oriented client. @comm ProtocolCmRegisterSap communicates with network control devices or other media-specific agents, as necessary, to register the SAP, as specified at Sap, on the network for a connection-oriented client. Such actions could include, but are not limited to communicating with switching hardware, communicating with a network control station, or other actions that are appropriate to the network medium. If a call manager is required to communicate with networking control agents (e.g. a network switch) it should use a virtual connection to the network control agent that it established in its ProtocolBindAdapter function. Standalone call managers communicate through the underlying NIC miniport by calling NdisCoSendPackets. NIC miniports with integrated call-management support never call NdisCoSendPackets. Instead, they transmit the data directly across the network. In addition, ProtocolCmRegisterSap should perform any necessary allocations of dynamic resources and structures that the call manager needs to maintain state information about the SAP on behalf of the connection-oriented client. Such resources include, but are not limited to, memory buffers, data structures, events, and other such similar resources. A call manager must also initialize any resources it allocates before returning control to NDIS. Call managers must store the NDIS-supplied handle identifying the SAP, provided at NdisSapHandle, in their context area for future use. If ProtocolCmRegisterSap will return NDIS_STATUS_SUCCESS, it should, after allocating the per-SAP state area, set the address of this state area in CallMgrSapContext before returning control to NDIS. To do this, dereference CallMgrSapContext and store a pointer to the data area as the value of the handle. For example: *CallMgrSapContext = SomeBuffer; // We use . If the given SAP that is already registered by another connection-oriented client, the call manager must fail the request and return NDIS_STATUS_INVALID_DATA. After a call manager has registered a SAP on behalf of a connection-oriented client, it notifies that client of an incoming call offer directed to that SAP by calling NdisCmDispatchIncomingCall. ProtocolCmRegisterSap must be written so that it can run at IRQL DISPATCH_LEVEL. @rdesc ProtocolCmRegisterSap returns the status of its operation(s) as one of the following: @rvalue NDIS_STATUS_SUCCESS | Indicates that the call manager successfully allocated and/or initialized any necessary resources to register and maintain the SAP. In addition, it also indicates that the SAP was registered successfully as required by the network media that the call manager supports. @rvalue NDIS_STATUS_PENDING | Indicates that the call manager will complete the processing of this request asynchronously. Call managers must call NdisCmRegisterSapComplete when all processing has been completed to signal NDIS that the registration is finished. @rvalue NDIS_STATUS_RESOURCES | Indicates that the call manager was unable to allocated and/or initialize its resources required to register the SAP on behalf of the connection-oriented client. @rvalue NDIS_STATUS_INVALID_DATA | Indicates that the specification provided at Sap is invalid or cannot be supported. @rvalue NDIS_STATUS_XXX | Indicates that the call manager encountered an error in attempting to register the SAP for the connection-oriented client. The return code is appropriate to the error and could be a return code propagated from another NDIS library function. @xref NdisCmDispatchIncomingCall, NdisCmRegisterSapComplete, NdisCoSendPackets, , */ NDIS_STATUS ProtocolCmRegisterSap( IN PMINIPORT_ADAPTER_OBJECT pAdapter, // @parm // A pointer to the instance return by // . AKA CallMgrAfContext. // Specifies the handle to a call-manager allocated context area in which // the call manager maintains its per-open AF state. The call manager // supplied this handle to NDIS from its ProtocolCmOpenAf function. IN PCO_SAP Sap, // @parm // Points to a media-specific CO_SAP structure that contains the specific // SAP that a connection-oriented client is registering. IN NDIS_HANDLE NdisSapHandle, // @parm // Specifies a handle, supplied by NDIS, that uniquely identifies this SAP. // This handle is opaque to the call manager and reserved for NDIS library // use. OUT PNDIS_HANDLE CallMgrSapContext // @parm // On return, specifies the handle to a call manager-supplied context area // in which the call manager maintains state about this SAP. We will // return a pointer to the instance identified by this // SAP's lineID. ) { DBG_FUNC("ProtocolCmRegisterSap") PCO_AF_TAPI_SAP pTapiSap = (PCO_AF_TAPI_SAP) Sap->Sap; PBCHANNEL_OBJECT pBChannel; // A pointer to the returned by . NDIS_STATUS Result = NDIS_STATUS_SUCCESS; // Holds the result code returned by this function. ASSERT(pAdapter && pAdapter->ObjectType == MINIPORT_ADAPTER_OBJECT_TYPE); DBG_ENTER(pAdapter); if (pTapiSap->ulLineID < pAdapter->NumBChannels) { pBChannel = GET_BCHANNEL_FROM_INDEX(pAdapter, pTapiSap->ulLineID); if (pBChannel->NdisSapHandle != NULL) { // A SAP has already been registered and it doesn't make any sense to // accept another since there are no SAP parameters to distinguish // them. DBG_ERROR(pAdapter, ("#%d Attempting to register SAP again!\n", pBChannel->ObjectID)); Result = NDIS_STATUS_SAP_IN_USE; } else { pBChannel->NdisSapHandle = NdisSapHandle; ASSERT(Sap->SapType == AF_TAPI_SAP_TYPE); ASSERT(Sap->SapLength == sizeof(CO_AF_TAPI_SAP)); pBChannel->NdisTapiSap = *pTapiSap; DBG_FILTER(pAdapter, DBG_TAPICALL_ON, ("#%d SAP=0x%X ulLineID=0x%X ulAddressID=0x%X ulMediaModes=0x%X\n", pBChannel->ObjectID, NdisSapHandle, pBChannel->NdisTapiSap.ulLineID, pBChannel->NdisTapiSap.ulAddressID, pBChannel->NdisTapiSap.ulMediaModes )); // If this BChannel is currently on the available list, move it // to the end of the list, so listening BChannels can be easily // allocated to incoming calls from the end of the list. NdisAcquireSpinLock(&pAdapter->EventLock); if (!IsListEmpty(&pBChannel->LinkList)) { RemoveEntryList(&pBChannel->LinkList); InsertTailList(&pAdapter->BChannelAvailableList, &pBChannel->LinkList); } NdisReleaseSpinLock(&pAdapter->EventLock); // Since we return NDIS_STATUS_PENDING here, we must call // NdisMCmRegisterSapComplete to complete this request. // TODO: If necessary, you can do the completion asynchronously. *CallMgrSapContext = pBChannel; CompleteCmRegisterSap(pBChannel, NDIS_STATUS_SUCCESS); Result = NDIS_STATUS_PENDING; } } else { DBG_ERROR(pAdapter, ("Attempting to register invalid SAP=%d\n", pTapiSap->ulLineID)); Result = NDIS_STATUS_INVALID_DATA; } DBG_RETURN(pAdapter, Result); return (Result); } /* @doc INTERNAL CallMgr CallMgr_c CompleteCmDeregisterSap §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func is called when the miniport is done processing the request. @comm If you return NDIS_STATUS_PENDING from , you must call so that can be called to complete the request. */ VOID CompleteCmDeregisterSap( IN PBCHANNEL_OBJECT pBChannel, // @parm // A pointer to the returned by . IN NDIS_STATUS Status // @parm // The NDIS status code to be passed to NdisMCmRegisterSapComplete. ) { DBG_FUNC("CompleteCmDeregisterSap") NDIS_HANDLE NdisSapHandle; PMINIPORT_ADAPTER_OBJECT pAdapter; // A pointer to the . ASSERT(pBChannel && pBChannel->ObjectType == BCHANNEL_OBJECT_TYPE); pAdapter = pBChannel->pAdapter; ASSERT(pAdapter && pAdapter->ObjectType == MINIPORT_ADAPTER_OBJECT_TYPE); DBG_ENTER(pAdapter); NdisSapHandle = pBChannel->NdisSapHandle; pBChannel->NdisSapHandle = NULL; DBG_FILTER(pAdapter, DBG_TAPICALL_ON, ("#%d SAP=0x%X\n", pBChannel->ObjectID, NdisSapHandle )); NdisMCmDeregisterSapComplete(Status, NdisSapHandle); DBG_LEAVE(pAdapter); } /* @doc EXTERNAL INTERNAL CallMgr CallMgr_c ProtocolCmDeregisterSap §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func is a required function that is called by NDIS to request that a call manager deregister a SAP on behalf of a connection-oriented client. @comm ProtocolCmDeregisterSap communicates with network control devices or other media-specific agents, as necessary, to deregister the SAP on the network. Such actions could include, but are not limited to: Communicating with a switching hardware Communicating with a network control station Communicating with other media-specific network agents If a call manager is required to communicate with networking control agents, such as a network switch, it should use a virtual connection to the network control agent that it established in its ProtocolBindAdapter function. Standalone call managers communicate through the underlying NIC miniport by calling NdisCoSendPackets. NIC miniports that provide integrated call-management support never call NdisCoSendPackets. Instead, they transmit the data directly across the network. In addition, ProtocolCmDeregisterSap must free any dynamically-allocated resources in its per-SAP area, provided at CallMgrSapContext, as well as freeing the state area itself before returning control to NDIS. ProtocolCmDeregisterSap must be written such that it can be run at IRQL DISPATCH_LEVEL. @rdesc ProtocolCmDeregisterSap returns the status of its operation(s) as one of the following: @rvalue NDIS_STATUS_SUCCESS | Indicates that the call manager successfully removed the SAP registration and freed any resources allocated to maintain per-SAP information. @rvalue NDIS_STATUS_PENDING | Indicates that the call manager will complete the request to deregister the SAP asynchronously. The call manager must call NdisCmDeregisterSapComplete to signal NDIS when the operation is complete. @xref NdisCmDeregisterSapComplete, NdisCoSendPackets, ProtocolBindAdapter, */ NDIS_STATUS ProtocolCmDeregisterSap( IN PBCHANNEL_OBJECT pBChannel // @parm // A pointer to the instance returned by // . AKA CallMgrSapContext. // Specifies the handle to a call-manager allocated context area in which // the call manager maintains its per-SAP state information. The call // manager supplied this handle to NDIS from its ProtocolCmRegisterSap // function. ) { DBG_FUNC("ProtocolCmDeregisterSap") NDIS_STATUS Result = NDIS_STATUS_SUCCESS; // Holds the result code returned by this function. PMINIPORT_ADAPTER_OBJECT pAdapter; // A pointer to the . ASSERT(pBChannel && pBChannel->ObjectType == BCHANNEL_OBJECT_TYPE); pAdapter = pBChannel->pAdapter; ASSERT(pAdapter && pAdapter->ObjectType == MINIPORT_ADAPTER_OBJECT_TYPE); DBG_ENTER(pAdapter); // Since we return NDIS_STATUS_PENDING here, we must call // NdisMCmDeregisterSapComplete to complete this request. // TODO: If necessary, you can do the completion asynchronously. CompleteCmDeregisterSap(pBChannel, NDIS_STATUS_SUCCESS); Result = NDIS_STATUS_PENDING; // If you return NDIS_STATUS_PENDING here, you must call // NdisMCmDeregisterSapComplete to complete this request. DBG_RETURN(pAdapter, Result); return (Result); } /* @doc EXTERNAL INTERNAL BChannel BChannel_c ProtocolCoCreateVc §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func is a required function for connection-oriented miniports. is called by NDIS to indicate to the miniport that a new VC is being created. @comm ProtocolCoCreateVc must be written as a synchronous function and cannot, under any circumstances, return NDIS_STATUS_PENDING without causing a system-wide failure. ProtocolCoCreateVc allocates any necessary resources that the miniport requires to maintain state information about the VC. The resources could include, but are not limited to memory buffers, events, data structures, and other such similar resources. After allocating all required resources the miniport should initialize the resources into a usable state and return a pointer to the state area in MiniportVcContext. The handle is set by dereferencing the handle and storing a pointer to the state buffer as the value of the handle. For example: *MiniportVcContext = SomeBuffer; // We use . Miniport drivers must store the handle to the VC, NdisVcHandle, in their state area as it is a required parameter to other NDIS library routines that are subsequently called by the miniport. ProtocolCoCreateVc must be written such that it can be run at IRQL DISPATCH_LEVEL. @rdesc Call managers or clients cannot return NDIS_STATUS_PENDING from their ProtocolCoCreateVc functions. Returning pending will render this virtual connection unusable and the NDIS library will call the client or call manager to delete it. ProtocolCoCreateVc returns the status of its operation(s) as one of the following values: @rvalue NDIS_STATUS_SUCCESS | Indicates that the call manager or client successfully allocated and/or initialized any necessary resources that were needed to establish and maintain a virtual connection. @rvalue NDIS_STATUS_RESOURCES | Indicates that the call manager or client was unable to allocate and/or initialize its resources for establishing and maintaining a virtual connection. @rvalue NDIS_STATUS_XXX | Indicates that the call manager or client could not set itself into a state where it could establish a virtual connection. This can could be an error return value propagated from another NDIS library routine. @xref , NdisMSetAttributes, NdisMSetAttributesEx, , , */ NDIS_STATUS ProtocolCoCreateVc( IN PMINIPORT_ADAPTER_OBJECT pAdapter, // @parm // A pointer to the instance return by // . AKA ProtocolAfContext. IN NDIS_HANDLE NdisVcHandle, // @parm // Specifies a handle, supplied by NDIS, that uniquely identifies // the VC being created. This handle is opaque to the miniport // and reserved for NDIS library use. OUT PBCHANNEL_OBJECT * ppBChannel // @parm // Specifies, on output, a handle to a miniport-supplied context // area in which the miniport maintains state about the VC. // A pointer to the returned by . ) { DBG_FUNC("ProtocolCoCreateVc") NDIS_STATUS Result = NDIS_STATUS_VC_NOT_AVAILABLE; // Holds the result code returned by this function. PBCHANNEL_OBJECT pBChannel = NULL; // A pointer to the returned by . ASSERT(pAdapter && pAdapter->ObjectType == MINIPORT_ADAPTER_OBJECT_TYPE); ASSERT(ppBChannel); DBG_ENTER(pAdapter); // Allocate BChannel for VC based on whether it's incoming or outgoing. #if defined(SAMPLE_DRIVER) if (NdisVcHandle == NULL) { // The calling side has already removed the BChannel from the available // list, so we just need to use it. ASSERT(ppBChannel && *ppBChannel && (*ppBChannel)->ObjectType == BCHANNEL_OBJECT_TYPE); pBChannel = *ppBChannel; } else { #endif // SAMPLE_DRIVER NdisAcquireSpinLock(&pAdapter->EventLock); if (!IsListEmpty(&pAdapter->BChannelAvailableList)) { if (NdisVcHandle) { // Pull from the head of the available list, so we can avoid // using the BChannels that are setup with listening SAPs at // the end of the list. pBChannel = (PBCHANNEL_OBJECT) RemoveHeadList( &pAdapter->BChannelAvailableList); // Reset the link info so we can tell that it's not on the list. InitializeListHead(&pBChannel->LinkList); } else { // Pull from the tail of the available list, to see if there // are any listening SAPs that can accept this call. pBChannel = (PBCHANNEL_OBJECT) RemoveTailList( &pAdapter->BChannelAvailableList); // Reset the link info so we can tell that it's not on the list. InitializeListHead(&pBChannel->LinkList); if (pBChannel->NdisSapHandle) { // TODO: You should look to make sure the incoming call matches // the SAP of the listener. The sample driver just assumes it. } else { // Sorry, no one up there wants to hear about it. InsertTailList(&pAdapter->BChannelAvailableList, &pBChannel->LinkList); pBChannel = NULL; } } } NdisReleaseSpinLock(&pAdapter->EventLock); #if defined(SAMPLE_DRIVER) } #endif // SAMPLE_DRIVER if (pBChannel == NULL) { DBG_ERROR(pAdapter, ("BChannelAvailableList is empty\n")); } else if (BChannelOpen(pBChannel, NdisVcHandle) == NDIS_STATUS_SUCCESS) { Result = NDIS_STATUS_SUCCESS; DBG_FILTER(pAdapter, DBG_TAPICALL_ON, ("#%d VC=0x%X CallState=0x%X Status=0x%X\n", pBChannel->ObjectID, pBChannel->NdisVcHandle, pBChannel->CallState, Result )); } else { // BChannel was already open - this should never happen... DBG_ERROR(pAdapter,("BChannelOpen failed, but it should be availble\n")); NdisAcquireSpinLock(&pAdapter->EventLock); if (NdisVcHandle) { // Put it back on the head of the available list. InsertHeadList(&pAdapter->BChannelAvailableList, &pBChannel->LinkList); } else { // Put it back on the tail of the available list. InsertTailList(&pAdapter->BChannelAvailableList, &pBChannel->LinkList); } NdisReleaseSpinLock(&pAdapter->EventLock); pBChannel = NULL; } *ppBChannel = pBChannel; DBG_RETURN(pAdapter, Result); return (Result); } /* @doc EXTERNAL INTERNAL BChannel BChannel_c ProtocolCoDeleteVc §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func is a required function for connection-oriented miniports. indicates that a VC is being torn down and deleted by NDIS. @comm ProtocolCoDeleteVc must be written as a synchronous function and cannot, under any circumstances, return NDIS_STATUS_PENDING without causing a system-wide failure. ProtocolCoDeleteVc frees any resources allocated on a per-VC basis and stored in the context area MiniportVcContext. The miniport must also free the MiniportVcContext that is allocated in its ProtocolCoCreateVc function. must be written such that it can be run from IRQL DISPATCH_LEVEL. @rdesc ProtocolCoDeleteVc can return one of the following: @rvalue NDIS_STATUS_SUCCESS | The protocol has released or prepared for reuse all the resources that it originally allocated for the VC. @rvalue NDIS_STATUS_NOT_ACCEPTED | The VC is still active and the protocol has outstanding operations pending on the VC so it could not be destroyed. @rvalue NDIS_STATUS_XXX | The protocol failed the VC deletion for a driver-determined reason. @xref NdisClCloseCall, NdisCmDispatchIncomingCloseCall, NdisCoCreateVc, NdisCoDeleteVc, , , */ NDIS_STATUS ProtocolCoDeleteVc( IN PBCHANNEL_OBJECT pBChannel // @parm // A pointer to the instance returned by // . AKA ProtocolVcContext. // Specifies the handle to the client's or call manager's per-VC context // area. The protocol originally supplied this handle from its // function. ) { DBG_FUNC("ProtocolCoDeleteVc") NDIS_STATUS Result = NDIS_STATUS_SUCCESS; // Holds the result code returned by this function. PMINIPORT_ADAPTER_OBJECT pAdapter; // A pointer to the . ASSERT(pBChannel && pBChannel->ObjectType == BCHANNEL_OBJECT_TYPE); pAdapter = GET_ADAPTER_FROM_BCHANNEL(pBChannel); DBG_ENTER(pAdapter); DBG_FILTER(pAdapter, DBG_TAPICALL_ON, ("#%d VC=0x%X CallState=0x%X Status=0x%X\n", pBChannel->ObjectID, pBChannel->NdisVcHandle, pBChannel->CallState, Result )); BChannelClose(pBChannel); NdisAcquireSpinLock(&pAdapter->EventLock); if (pBChannel->NdisSapHandle) { // Listening BChannels are kept at the end of the list. InsertTailList(&pAdapter->BChannelAvailableList, &pBChannel->LinkList); } else { // Non-listening BChannels are kept at the end of the list. InsertHeadList(&pAdapter->BChannelAvailableList, &pBChannel->LinkList); } NdisReleaseSpinLock(&pAdapter->EventLock); DBG_RETURN(pAdapter, Result); return (Result); } /* @doc EXTERNAL INTERNAL Link Link_c MiniportCoActivateVc §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func is a required function for connection-oriented miniports. is called by NDIS to indicate to the miniport that a virtual connection is being activated. @comm The miniport driver must validate the call parameters for this VC, as specified in CallParameters, to verify that the adapter can support the requested call. If the requested call parameters cannot be satisfied, the miniport should fail the request with NDIS_STATUS_INVALID_DATA. MiniportCoActivateVc can be called many times for a single VC in order to change the call parameters for an already active call. At every call, the miniport should validate the parameters and perform any processing as required by its adapter in order to satisfy the request. However, if it cannot set the given call parameters, MiniportCoActivateVc must leave the VC in a usable state, because the connection-oriented client or a call manager can continue to send or receive data using the older call parameters. If the ROUND_UP_FLOW or ROUND_DOWN_FLOW flags are set in the call parameters structure at CallParameters-\>MediaParameters-\>Flags, the miniport has been requested to return the actual flow rate of the VC after the flow rate has been rounded according to the appropriate flag that has been set. If the miniport does change any of the call parameters because these flags have been set, it must return the actual call parameters in use for the VC at CallParameters. If the call parameters are acceptable, MiniportCoActivateVc communicates with its adapter as necessary to prepare the adapter to receive or transmit data across the virtual connection (e.g. programming receive buffers). MiniportCoActivateVc must be written so that it can be run from IRQL DISPATCH_LEVEL. @rdesc MiniportCoActivateVc can return one of the following: @rvalue NDIS_STATUS_SUCCESS | Indicates that the VC was activated successfully. @rvalue NDIS_STATUS_PENDING | Indicates that the miniport will complete the request to activate a VC asynchronously. When the miniport has finished with its operations, it must call NdisMCoActivateVcComplete. @rvalue NDIS_STATUS_INVALID_DATA | Indicates that the call parameters specified at CallParameters are invalid or illegal for the media type that this miniport supports. @rvalue NDIS_STATUS_RESOURCES | Indicates that the miniport could not activate the VC because it could not allocate all of the required resources that the miniport needs to maintain state information about the active VC. @xref , , NdisMCoActivateVcComplete */ NDIS_STATUS MiniportCoActivateVc( IN PBCHANNEL_OBJECT pBChannel, // @parm // A pointer to the instance returned by // . AKA MiniportVcContext. // Specifies the handle to a miniport-allocated context area in which the // miniport maintains its per-VC state. The miniport supplied this handle // to NDIS from its function. IN OUT PCO_CALL_PARAMETERS pCallParameters // @parm // A pointer to the // Specifies the call parameters, as specified by the call manager, to be // established for this VC. On output, the miniport returns altered call // parameters if certain flags are set in the CO_CALL_PARAMETERS structure. ) { DBG_FUNC("MiniportCoActivateVc") NDIS_STATUS Result = NDIS_STATUS_SUCCESS; // Holds the result code returned by this function. PMINIPORT_ADAPTER_OBJECT pAdapter; // A pointer to the . ASSERT(pBChannel && pBChannel->ObjectType == BCHANNEL_OBJECT_TYPE); pAdapter = GET_ADAPTER_FROM_BCHANNEL(pBChannel); DBG_ENTER(pAdapter); // TODO: Add code here if needed DBG_RETURN(pAdapter, Result); return (Result); } /* @doc EXTERNAL INTERNAL Link Link_c MiniportCoDeactivateVc §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func is a required function for connection-oriented miniports. is called by NDIS to indicate that a VC is being marked as unusable. @comm MiniportCoDeactivateVc communicates with its network adapter to terminate all communication across this VC (e.g. deprogramming receive or send buffers on the adapter). The miniport should also mark the VC, it its context area, as being inactive to prevent any further communication across the VC. There is not a one-to-one relationship between calls to MiniportCoActivateVc and MiniportCoDeactivateVc. While NDIS may call MiniportCoActivateVc multiple times on a single VC, only one call to MiniportCoDeactivateVc is made to shut down a virtual connection. For example, a VC can be reused for different calls possibly causing multiple calls to MiniportCoActivateVc. @rdesc MiniportCoDeactivateVc can return one of the following: @rvalue NDIS_STATUS_SUCCESS | Indicates that the miniport successfully halted any communication across the VC and marked it as unusable. @rvalue NDIS_STATUS_PENDING | Indicates that the miniport will complete the request to halt the VC asynchronously. When the miniport has completed halting the VC, it must then call NdisMCoDeactivateVcComplete to signal NDIS that this operation has been completed. @xref , NdisMCoDeactivateVcComplete */ NDIS_STATUS MiniportCoDeactivateVc( IN PBCHANNEL_OBJECT pBChannel // @parm // A pointer to the instance returned by // . AKA MiniportVcContext. // Specified the handle to a miniport-allocated context area in which the // miniport maintains state information per-VC. The miniport supplied this // handle to NDIS from its function. ) { DBG_FUNC("MiniportCoDeactivateVc") NDIS_STATUS Result = NDIS_STATUS_SUCCESS; // Holds the result code returned by this function. PMINIPORT_ADAPTER_OBJECT pAdapter; // A pointer to the . ASSERT(pBChannel && pBChannel->ObjectType == BCHANNEL_OBJECT_TYPE); pAdapter = GET_ADAPTER_FROM_BCHANNEL(pBChannel); DBG_ENTER(pAdapter); // TODO: Add code here if needed DBG_RETURN(pAdapter, Result); return (Result); } /* @doc INTERNAL CallMgr CallMgr_c CompleteCmMakeCall §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func is called when the miniport is done processing the request. @comm If you return NDIS_STATUS_PENDING from , you must call so that can be called to complete the request. This routine also activates the VC and marks the call state as connected. */ VOID CompleteCmMakeCall( IN PBCHANNEL_OBJECT pBChannel, // @parm // A pointer to the returned by . IN NDIS_STATUS Status // @parm // Status to return to . If status does not // equal NDIS_STATUS_SUCCESS, the call is closed and the BChannel is // released. ) { DBG_FUNC("CompleteCmMakeCall") PMINIPORT_ADAPTER_OBJECT pAdapter; // A pointer to the . ASSERT(pBChannel && pBChannel->ObjectType == BCHANNEL_OBJECT_TYPE); pAdapter = pBChannel->pAdapter; ASSERT(pAdapter && pAdapter->ObjectType == MINIPORT_ADAPTER_OBJECT_TYPE); DBG_ENTER(pAdapter); DBG_FILTER(pAdapter, DBG_TAPICALL_ON, ("#%d VC=0x%X CallState=0x%X Status=0x%X\n", pBChannel->ObjectID, pBChannel->NdisVcHandle, pBChannel->CallState, Status )); if (Status == NDIS_STATUS_SUCCESS) { pBChannel->pOutCallParms->CallMgrParameters->Receive.PeakBandwidth = pBChannel->pOutCallParms->CallMgrParameters->Transmit.PeakBandwidth = pBChannel->LinkSpeed/8; Status = NdisMCmActivateVc(pBChannel->NdisVcHandle, pBChannel->pOutCallParms); if (Status == NDIS_STATUS_SUCCESS) { pBChannel->Flags |= VCF_VC_ACTIVE; pBChannel->CallState = LINECALLSTATE_CONNECTED; } else { DBG_ERROR(pAdapter,("NdisMCmActivateVc Error=0x%X\n",Status)); } } NdisMCmMakeCallComplete(Status, pBChannel->NdisVcHandle, NULL, NULL, pBChannel->pOutCallParms); if (Status != NDIS_STATUS_SUCCESS) { // The call failed, so cleanup and bail out. pBChannel->Flags &= ~VCF_OUTGOING_CALL; } DBG_LEAVE(pAdapter); } /* @doc EXTERNAL INTERNAL CallMgr CallMgr_c ProtocolCmMakeCall §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func is a required function that sets up media specific parameters for a virtual connection (VC) and activates the virtual connection. @comm If ProtocolCmMakeCall is given an explicit NdisPartyHandle, this VC was created by the client for a multipoint call. The call manager must allocate and initialize any necessary resources required to maintain state information and control a multipoint call. Such resources include, but are not limited to, memory buffers, data structures, events, and other similar resources. If the call manager cannot allocate or initialize the needed resources for its state area(s), it should return control to NDIS with NDIS_STATUS_RESOURCES. ProtocolCmMakeCall communicates with network control devices or other media-specific actors, as necessary, to make a connection between the local node and a remote node based on the call parameters specified at CallParameters. Such actions could include, but are not limited to, communication with switching hardware, communications with a network control station, or other actions as appropriate to the network medium. If a call manager is required to communication with networking hardware (e.g. a networking switch) it should use a virtual connection to the network control device that it established in its ProtocolBindAdapter function. Call managers communicate with their network hardware through the miniport driver by calling NdisCoSendPackets. NIC miniports with integrated call-management support will not call NdisCoSendPackets, but rather will transmit the data themselves. After a call manager has done all necessary communication with its networking hardware as required by its medium, call managers must call NdisCmActivateVc. If this call was a multipoint call, after the call manager has communicated with the networking hardware, verified call parameters, and allocated and initialized its per-party state data, the address of its state block should be set in the handle CallMgrPartyContext before returning control to NDIS. The handle is set by dereferencing the handle and storing a pointer to the state block as the value of the handle. For example: *CallMgrPartyContext = SomeBuffer; // We use NULL If ProtocolCmMakeCall has completed the required operations for its network and the VC has been successfully activated through NdisCmActivateVc, ProtocolCmMakeCall should return control as quickly as possible with a status of NDIS_STATUS_SUCCESS. After ProtocolCmMakeCall returns control to NDIS, the call manager should expect to take no further actions on this call to set it up. ProtocolCmMakeCall is responsible for establishing the connection so that the client can make data transfers over the network on this VC. However, the call manager can be called subsequently to modify the call's quality of service, to add or drop parties if this is a multipoint VC, and eventually to terminate this call. ProtocolCmMakeCall must be written so that it can run at IRQL DISPATCH_LEVEL. @rdesc returns the status of its operation(s) as one of the following values: @rvalue NDIS_STATUS_SUCCESS | Indicates that the call manager successfully allocated the necessary resources to make the call and was able to activate the virtual connection with the miniport driver. @rvalue NDIS_STATUS_PENDING | Indicates that the call manager will complete the request to make a call asynchronously. When the call manager has completed all operations for making a call, it must call NdisCmMakeCallComplete to signal NDIS that this call has been completed. @rvalue NDIS_STATUS_RESOURCES | Indicates that the call manager was unable to allocate and/or initialize its resources for activating the virtual connection as requested by the client. @rvalue NDIS_STATUS_NOT_SUPPORTED | Indicates that the call manager was unable to activate a virtual connection because the caller requested invalid or unavailable features in the call parameters specified at CallParameters. @xref NdisClMakeCall, NdisCmActivateVc, NdisCmMakeCallComplete, */ NDIS_STATUS ProtocolCmMakeCall( IN PBCHANNEL_OBJECT pBChannel, // @parm // A pointer to the instance returned by // . AKA CallMgrVcContext. // Specifies the handle to a call manager-allocated context area in which // the call managers maintains its per-VC state. The call manager supplied // this handle to NDIS from its ProtocolCoCreateVc function. IN OUT PCO_CALL_PARAMETERS pCallParameters, // @parm // Points to a CO_CALL_PARAMETERS structure that contains the parameters, // specified by a connection-oriented client, for this outgoing call. IN NDIS_HANDLE NdisPartyHandle, // @parm // Specifies a handle, supplied by NDIS, that uniquely identifies the // initial party on the multipoint virtual connection. This handle is // opaque to the call manager and reserved for NDIS library use. This // handle is NULL if the client is not setting up an outgoing multipoint // call. OUT PNDIS_HANDLE CallMgrPartyContext // @parm // On return, specifies a handle to a call manager-supplied context area in // which the call manager maintains state about the initial party on the // multipoint call. If NdisPartyHandle is NULL, this handle must be set to // NULL. ) { DBG_FUNC("ProtocolCmMakeCall") PCO_AF_TAPI_MAKE_CALL_PARAMETERS pTapiCallParameters; // Points to the TAPI call parameters contained in pCallParameters. PLINE_CALL_PARAMS pLineCallParams; // Points to the LINE call parameters contained in pTapiCallParameters. USHORT DialStringLength; // Length of the dial string in bytes. PUSHORT pDialString; // Points to the dial string contained in pTapiCallParameters. UCHAR DialString[CARD_MAX_DIAL_DIGITS+1]; // Temporary copy of dial string. One extra for NULL terminator. NDIS_STATUS Result = NDIS_STATUS_SUCCESS; // Holds the result code returned by this function. PMINIPORT_ADAPTER_OBJECT pAdapter; // A pointer to the . ASSERT(pBChannel && pBChannel->ObjectType == BCHANNEL_OBJECT_TYPE); pAdapter = pBChannel->pAdapter; ASSERT(pAdapter && pAdapter->ObjectType == MINIPORT_ADAPTER_OBJECT_TYPE); DBG_ENTER(pAdapter); // Check a few preconditions ;) Maybe the NDPROXY will change the rules // someday, and we'll have to change our assumptions... ASSERT(NdisPartyHandle == NULL); ASSERT(pCallParameters->Flags == 0); ASSERT(pCallParameters->CallMgrParameters); ASSERT(pCallParameters->CallMgrParameters->Transmit.TokenRate == pBChannel->LinkSpeed/8); ASSERT(pCallParameters->CallMgrParameters->Receive.TokenRate == pBChannel->LinkSpeed/8); ASSERT(pCallParameters->CallMgrParameters->CallMgrSpecific.ParamType == 0); ASSERT(pCallParameters->CallMgrParameters->CallMgrSpecific.Length == 0); ASSERT(pCallParameters->MediaParameters); ASSERT(pCallParameters->MediaParameters->Flags & TRANSMIT_VC); ASSERT(pCallParameters->MediaParameters->Flags & RECEIVE_VC); ASSERT(pCallParameters->MediaParameters->ReceiveSizeHint >= pAdapter->pCard->BufferSize); ASSERT(pCallParameters->MediaParameters->MediaSpecific.ParamType == 0); ASSERT(pCallParameters->MediaParameters->MediaSpecific.Length >= sizeof(CO_AF_TAPI_MAKE_CALL_PARAMETERS)); pTapiCallParameters = (PCO_AF_TAPI_MAKE_CALL_PARAMETERS) pCallParameters->MediaParameters->MediaSpecific.Parameters; ASSERT(pTapiCallParameters->ulLineID < pAdapter->NumBChannels); ASSERT(pTapiCallParameters->ulAddressID == TSPI_ADDRESS_ID); ASSERT(pTapiCallParameters->ulFlags & CO_TAPI_FLAG_OUTGOING_CALL); ASSERT(pTapiCallParameters->DestAddress.Length > sizeof(USHORT)); ASSERT(pTapiCallParameters->DestAddress.MaximumLength >= pTapiCallParameters->DestAddress.Length); ASSERT(pTapiCallParameters->DestAddress.Offset >= sizeof(NDIS_VAR_DATA_DESC)); DialStringLength = pTapiCallParameters->DestAddress.Length; pDialString = (PUSHORT) ((PUCHAR)&pTapiCallParameters->DestAddress + pTapiCallParameters->DestAddress.Offset); ASSERT(pTapiCallParameters->LineCallParams.Length >= sizeof(LINE_CALL_PARAMS)); ASSERT(pTapiCallParameters->LineCallParams.MaximumLength >= pTapiCallParameters->LineCallParams.Length); ASSERT(pTapiCallParameters->LineCallParams.Offset >= sizeof(NDIS_VAR_DATA_DESC)); pLineCallParams = (PLINE_CALL_PARAMS) ((PUCHAR)&pTapiCallParameters->LineCallParams + pTapiCallParameters->LineCallParams.Offset); // This was useful for debugging the nested call parameter structures. DBG_NOTICE(pAdapter,( "\t\tsizeof(CO_CALL_PARAMETERS) =%03d\n" "\t\tsizeof(CO_CALL_MANAGER_PARAMETERS) =%03d\n" "\t\tsizeof(CO_MEDIA_PARAMETERS) =%03d\n" "\t\tsizeof(CO_AF_TAPI_MAKE_CALL_PARAMETERS) =%03d\n" "\t\tsizeof(LINE_CALL_PARAMS) =%03d\n", "\t\tMaximumLength =%03d\n", sizeof(CO_CALL_PARAMETERS), sizeof(CO_CALL_MANAGER_PARAMETERS), sizeof(CO_MEDIA_PARAMETERS), sizeof(CO_AF_TAPI_MAKE_CALL_PARAMETERS), sizeof(LINE_CALL_PARAMS), pTapiCallParameters->LineCallParams.MaximumLength )); /* // TODO: The sample driver doesn't support multi-party calls. */ *CallMgrPartyContext = NULL; /* // Make sure the call parameters are valid for us. */ if (pLineCallParams->ulBearerMode & ~pBChannel->BearerModesCaps) { DBG_WARNING(pAdapter, ("TAPI_INVALBEARERMODE=0x%X\n", pLineCallParams->ulBearerMode)); Result = NDIS_STATUS_NOT_SUPPORTED; } else if (pLineCallParams->ulMediaMode & ~pBChannel->MediaModesCaps) { DBG_WARNING(pAdapter, ("TAPI_INVALMEDIAMODE=0x%X\n", pLineCallParams->ulMediaMode)); Result = NDIS_STATUS_NOT_SUPPORTED; } else if (pLineCallParams->ulMinRate > _64KBPS || pLineCallParams->ulMinRate > pLineCallParams->ulMaxRate) { DBG_WARNING(pAdapter, ("TAPI_INVALRATE=%d:%d\n", pLineCallParams->ulMinRate,pLineCallParams->ulMaxRate)); Result = NDIS_STATUS_NOT_SUPPORTED; } else if (pLineCallParams->ulMaxRate && pLineCallParams->ulMaxRate < _56KBPS) { DBG_WARNING(pAdapter, ("TAPI_INVALRATE=%d:%d\n", pLineCallParams->ulMinRate,pLineCallParams->ulMaxRate)); Result = NDIS_STATUS_NOT_SUPPORTED; } else if (DialStringLength == 0) { DBG_WARNING(pAdapter, ("TAPI_INVALPARAM=No dial string\n")); Result = NDIS_STATUS_NOT_SUPPORTED; } else { /* // Dial the number, but don't include the null terminator. */ DialStringLength = CardCleanPhoneNumber(DialString, pDialString, DialStringLength); if (DialStringLength > 0) { /* // Save the call parameters. */ pBChannel->MediaMode = pLineCallParams->ulMediaMode; pBChannel->BearerMode = pLineCallParams->ulBearerMode; pBChannel->LinkSpeed = pLineCallParams->ulMaxRate == 0 ? _64KBPS : pLineCallParams->ulMaxRate; pBChannel->pOutCallParms = pCallParameters; DBG_FILTER(pAdapter, DBG_TAPICALL_ON, ("#%d VC=0x%X CallState=0x%X DIALING: '%s'\n" "\tLineID=%d - AddressID=%d - " "Rate=%d-%d - MediaMode=0x%X - BearerMode=0x%X\n", pBChannel->ObjectID, pBChannel->NdisVcHandle, pBChannel->CallState, DialString, pTapiCallParameters->ulLineID, pTapiCallParameters->ulAddressID, pLineCallParams->ulMinRate, pLineCallParams->ulMaxRate, pLineCallParams->ulMediaMode, pLineCallParams->ulBearerMode )); // Now we're ready to tell the network about the call. Result = DChannelMakeCall(pAdapter->pDChannel, pBChannel, DialString, DialStringLength, pLineCallParams); if (Result != NDIS_STATUS_PENDING) { CompleteCmMakeCall(pBChannel, Result); Result = NDIS_STATUS_PENDING; } } else { DBG_WARNING(pAdapter, ("TAPI_INVALPARAM=Invalid dial string=%s\n", pDialString)); Result = NDIS_STATUS_NOT_SUPPORTED; } } DBG_RETURN(pAdapter, Result); return (Result); } /* @doc INTERNAL CallMgr CallMgr_c CompleteCmCloseCall §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func is called when the miniport is done processing the request. @comm If you return NDIS_STATUS_PENDING from , you must call so that can be called to complete the request. Upon return from this routine, you can no longer access the BChannel/VC as it has been deactivated and returned to the available pool. */ VOID CompleteCmCloseCall( IN PBCHANNEL_OBJECT pBChannel, // @parm // A pointer to the instance returned by // . IN NDIS_STATUS Status // @parm // Status to return to . Regardless of the // status, the VC is deactivated and deleted. ) { DBG_FUNC("CompleteCmCloseCall") PMINIPORT_ADAPTER_OBJECT pAdapter; // A pointer to the . ASSERT(pBChannel && pBChannel->ObjectType == BCHANNEL_OBJECT_TYPE); pAdapter = pBChannel->pAdapter; ASSERT(pAdapter && pAdapter->ObjectType == MINIPORT_ADAPTER_OBJECT_TYPE); DBG_ENTER(pAdapter); DBG_FILTER(pAdapter, DBG_TAPICALL_ON, ("#%d VC=0x%X CallState=0x%X Status=0x%X\n", pBChannel->ObjectID, pBChannel->NdisVcHandle, pBChannel->CallState, Status )); // Deactivate the VC if needed. if (pBChannel->Flags & VCF_VC_ACTIVE) { pBChannel->Flags &= ~VCF_VC_ACTIVE; NdisMCmDeactivateVc(pBChannel->NdisVcHandle); } // Tell NDPROXY we're done. NdisMCmCloseCallComplete(Status, pBChannel->NdisVcHandle, NULL); // If it was an incoming call, it's up to us to delete the VC. if (pBChannel->Flags & VCF_INCOMING_CALL) { pBChannel->Flags &= ~VCF_INCOMING_CALL; if (pBChannel->NdisVcHandle) { NdisMCmDeleteVc(pBChannel->NdisVcHandle); pBChannel->NdisVcHandle = NULL; ProtocolCoDeleteVc((NDIS_HANDLE) pBChannel); } } else if (pBChannel->Flags & VCF_OUTGOING_CALL) { pBChannel->Flags &= ~VCF_OUTGOING_CALL; } DBG_LEAVE(pAdapter); } /* @doc EXTERNAL INTERNAL CallMgr CallMgr_c ProtocolCmCloseCall §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func is a required function that terminates an existing call and releases any resources that the call manager allocated for the call. @comm ProtocolCmCloseCall communicated with network control devices or other media-specific actors, as necessitated by its media, to terminate a connection between the local node and a remote node. If the call manager is required to communicate with network control devices (e.g. a networking switch) it should use a virtual connection to the network control device that it established in its ProtocolBindAdapter function. Standalone call managers communicate to such network devices by calling NdisCoSendPackets. NIC miniports with integrated call-management support never call NdisCoSendPackets. Instead, they transmit the data directly across the network. If CloseData is nonNULL and sending data at connection termination is supported by the media that this call manager handles, the call manager should transmit the data specified at CloseData to the remote node before completing the call termination. If sending data concurrent with a connection being terminated is not supported, call managers should return NDIS_STATUS_INVALID_DATA. If ProtocolCmCloseCall is passed an explicit CallMgrPartyContext, then the call being terminated is a multipoint VC, and the call manager must perform any necessary network communication with its networking hardware, as appropriate to its media type, to terminate the call as a multipoint call. The call manager must also free the memory that it allocated earlier, in ProtocolCmMakeCall, for its per-party state that is pointed to by CallMgrPartyContext. Failure to properly release, de-allocate, or otherwise deactivate those resources causes a memory leak. After the call has been terminated with the network, any close data has been sent, and any resources at CallMgrPartyContext have been freed, the call manager must call NdisCmDeactivateVc. This notifies NDIS and the underlying NIC miniport, if any, to expect no further transfers on the given VC. ProtocolCmCloseCall must be written so that it can run at IRQL DISPATCH_LEVEL. @rdesc ProtocolCmCloseCall returns the status of its operation(s) as one of the following: @rvalue NDIS_STATUS_SUCCESS | Indicates that the call manager successfully terminated the call. @rvalue NDIS_STATUS_PENDING | Indicates that the call manager will complete the request to terminate the call asynchronously. When the call manager has completed all operations required to terminate the connection, it must then call NdisCmCloseCallComplete to signal NDIS that the call has been closed. @rvalue NDIS_STATUS_INVALID_DATA | Indicates that CloseData was specified, but the underlying network medium does not support sending data concurrent with terminating a call. @rvalue NDIS_STATUS_XXX | Indicates that the call manager could not terminate the call. The actual error returned can be a status propagated from another NDIS library routine. @xref NdisClMakeCall, NdisCmDeactivateVc, NdisCoSendPackets, */ NDIS_STATUS ProtocolCmCloseCall( IN PBCHANNEL_OBJECT pBChannel, // @parm // A pointer to the instance returned by // . AKA CallMgrVcContext. // Specifies the handle to a call manager-allocated context area in which // the call manager maintains its per-VC state. This handle was provided to // NDIS from the call managers function. IN NDIS_HANDLE CallMgrPartyContext, // @parm // Specifies the handle, if any, to a call manager-allocated context area // in which the call manager maintain information about a party on a // multipoint VC. This handle is NULL if the call being closed is not a // multipoint call. IN PVOID CloseData, // @parm // Points to a buffer containing connection-oriented client-specified data // that should be sent across the connection before the call is terminated. // This parameter is NULL if the underlying network medium does not support // transfers of data when closing a connection. IN UINT Size // @parm // Specifies the length, in bytes, of the buffer at CloseData, zero if // CloseData is NULL. ) { DBG_FUNC("ProtocolCmCloseCall") NDIS_STATUS Result = NDIS_STATUS_SUCCESS; // Holds the result code returned by this function. PMINIPORT_ADAPTER_OBJECT pAdapter; // A pointer to the . ASSERT(pBChannel && pBChannel->ObjectType == BCHANNEL_OBJECT_TYPE); pAdapter = pBChannel->pAdapter; ASSERT(pAdapter && pAdapter->ObjectType == MINIPORT_ADAPTER_OBJECT_TYPE); DBG_ENTER(pAdapter); DBG_FILTER(pAdapter, DBG_TAPICALL_ON, ("#%d VC=0x%X CallState=0x%X\n", pBChannel->ObjectID, pBChannel->NdisVcHandle, pBChannel->CallState )); Result = DChannelCloseCall(pAdapter->pDChannel, pBChannel); if (Result != NDIS_STATUS_PENDING) { CompleteCmCloseCall(pBChannel, Result); Result = NDIS_STATUS_PENDING; } DBG_RETURN(pAdapter, Result); return (Result); } /* @doc EXTERNAL INTERNAL CallMgr CallMgr_c ProtocolCmIncomingCallComplete §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func is a required function that, when called by NDIS, indicates to the call manager that the connection-oriented client has finished processing of an incoming call offer that the call manager previously dispatched through NdisCmDispatchIncomingCall. @comm When the connection-oriented client has completed processing of an incoming connection offer that the call manager dispatched to it, this routine will be called if NdisCmDispatchIncomingCall returned NDIS_STATUS_PENDING. The final status of the incoming call is found in Status. Possible values for Status include, but are not limited to: @flag NDIS_STATUS_SUCCESS | Indicates that the call manager has accepted the incoming call. @flag NDIS_STATUS_FAILURE | Indicates that either the address family or the SAP that the call dispatched for is currently in the process of closing. @flag NDIS_STATUS_RESOURCES | Indicates that the incoming call was not accepted because the connection-oriented client was unable to dynamically allocate resources required for it to process the call. @flag NDIS_STATUS_INVALID_DATA | Indicates that the connection-oriented client rejected the call because the call parameters specified were invalid. @normal If the client accepts the incoming call, the call manager should send signaling message(s) to indicate to the calling entity that the call has been accepted. If the client does not accept the call, the call manager should send signaling message(s) to indicate that the call has been rejected. ProtocolCmIncomingCallComplete must be written so that is can be run at IRQL DISPATCH_LEVEL. @xref NdisCmDispatchIncomingCall, ProtocolClIncomingCall, */ VOID ProtocolCmIncomingCallComplete( IN NDIS_STATUS Status, // @parm // Indicates the final status of the operation to dispatch an incoming call // to a connection-oriented client. IN PBCHANNEL_OBJECT pBChannel, // @parm // A pointer to the instance returned by // . AKA CallMgrVcContext. // Specifies the handle to a call manager-allocated context area in which // the call manager maintains its per-VC state. The call manager supplied // this handle from its function. IN PCO_CALL_PARAMETERS pCallParameters // @parm // Points to the call parameters as specified by the call manager in the // call to NdisCmDispatchIncomingCall. The signaling protocol determines // which call parameters, if any, the call manager can change. ) { DBG_FUNC("ProtocolCmIncomingCallComplete") PMINIPORT_ADAPTER_OBJECT pAdapter; // A pointer to the . ASSERT(pBChannel && pBChannel->ObjectType == BCHANNEL_OBJECT_TYPE); pAdapter = pBChannel->pAdapter; ASSERT(pAdapter && pAdapter->ObjectType == MINIPORT_ADAPTER_OBJECT_TYPE); DBG_ENTER(pAdapter); DBG_FILTER(pAdapter, DBG_TAPICALL_ON, ("#%d VC=0x%X CallState=0x%X Status=0x%X\n", pBChannel->ObjectID, pBChannel->NdisVcHandle, pBChannel->CallState, Status )); if (Status != NDIS_STATUS_SUCCESS) { // We're not going to answer this call. DChannelRejectCall(pAdapter->pDChannel, pBChannel); if (pBChannel->Flags & VCF_VC_ACTIVE) { pBChannel->Flags &= ~VCF_VC_ACTIVE; NdisMCmDeactivateVc(pBChannel->NdisVcHandle); } if (pBChannel->NdisVcHandle) { NdisMCmDeleteVc(pBChannel->NdisVcHandle); pBChannel->NdisVcHandle = NULL; ProtocolCoDeleteVc((NDIS_HANDLE) pBChannel); } } else { Status = DChannelAnswerCall(pAdapter->pDChannel, pBChannel); if (Status == NDIS_STATUS_SUCCESS) { pBChannel->CallState = LINECALLSTATE_CONNECTED; NdisMCmDispatchCallConnected(pBChannel->NdisVcHandle); } else if (Status != NDIS_STATUS_PENDING) { InitiateCallTeardown(pAdapter, pBChannel); } } DBG_LEAVE(pAdapter); } /* @doc EXTERNAL INTERNAL CallMgr CallMgr_c ProtocolCmActivateVcComplete §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func is a required function that indicates to the call manager that a previous call to NdisCoActivateVc has been completed by the miniport. @comm When other network components have completed their operations for activating a virtual connection, initiated when the call manager called NdisCmActivateVc, NDIS notifies the call manager that the VC has been activated by calling its ProtocolCmActivateVcComplete function. The status of the activation is found in Status. Possible values for Status include, but are not limited to: @flag NDIS_STATUS_SUCCESS | Indicates that the VC completed successfully and the call manager can continue operations on this VC as required by its media. @flag NDIS_STATUS_RESOURCES | Indicates that another component in the activation has failed to activate the virtual connection because of a lack of memory or an inability allocate another type of resource. @flag NDIS_STATUS_NOT_ACCEPTED | Indicates that an activation is currently pending on the virtual connection. Only one activation can be processed at a time for a virtual connection. The request to activate the VC should be tried again at a later time. @flag NDIS_STATUS_CLOSING | Indicates that a deactivation is pending on the VC and the VC is no longer available for network communication until the deactivation has been completed and a successful activation has taken place. @flag NDIS_STATUS_INVALID_DATA | Indicates that the miniport has rejected the call parameters at CallParamters as invalid for the adapter. @normal ProtocolCmActivateVcComplete must check the status returned in Status to ensure that the virtual connection has been activated successfully. The call manager must not attempt to communicate over the virtual connection if Status is not NDIS_STATUS_SUCCESS. Call managers must complete any processing required by their network media to ensure that the virtual connection is ready for data transmission before returning control to NDIS. If the call manager specified either ROUND_UP_FLOW or ROUND_DOWN_FLOW in the CallParameters->MediaParamters->Flags, the call parameters returned in CallParamters can have been changed by the miniport. Call managers should examine the call parameters that were returned to ensure proper operation. If the new call parameters are unsatisfactory, the call manager should either call NdisCmActivateVc again with new call parameters or deactivate the VC with NdisCmDeactivateVc. ProtocolCmActivateVcComplete must be written so that it can run at IRQL DISPATCH_LEVEL. @xref NdisCmActivateVc, NdisCmDeactivateVc, */ VOID ProtocolCmActivateVcComplete( IN NDIS_STATUS Status, // @parm // Specifies the final status, as indicated by the miniport, of the request // by the call manager to activate a VC. IN PBCHANNEL_OBJECT pBChannel, // @parm // A pointer to the instance returned by // . AKA CallMgrVcContext. // Specifies the handle to a call manager-allocated context area in which // the call manager maintains its per-VC state. The call manager supplied // this handle from its function. IN PCO_CALL_PARAMETERS pCallParameters // @parm // Points the call parameters as specified by the call manager in a call to // NdisCmActivateVc. ) { DBG_FUNC("ProtocolCmActivateVcComplete") PMINIPORT_ADAPTER_OBJECT pAdapter; // A pointer to the . ASSERT(pBChannel && pBChannel->ObjectType == BCHANNEL_OBJECT_TYPE); pAdapter = pBChannel->pAdapter; ASSERT(pAdapter && pAdapter->ObjectType == MINIPORT_ADAPTER_OBJECT_TYPE); DBG_ENTER(pAdapter); DBG_FILTER(pAdapter, DBG_TAPICALL_ON, ("#%d VC=0x%X CallState=0x%X Status=0x%X\n", pBChannel->ObjectID, pBChannel->NdisVcHandle, pBChannel->CallState, Status )); DBG_LEAVE(pAdapter); } /* @doc EXTERNAL INTERNAL CallMgr CallMgr_c ProtocolCmDeactivateVcComplete §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func is a required function that completes the processing of a call-manager initiated request that the underlying miniport (and NDIS) deactivate a VC for which NdisCmDeactivateVc previously returned NDIS_STATUS_PENDING. @comm NDIS usually calls ProtocolCmDeactivateVcComplete in the context of the call manager's closing down a call on behalf of a connection-oriented client. The call manager typically calls NdisCmDeactivateVc from its ProtocolCmCloseCall function. Whenever NdisCmDeactivateVc returns NDIS_STATUS_PENDING, NDIS subsequently calls its ProtocolCmDeactivateVcComplete function. That is, when the underlying connection-oriented miniport has deactivated the VC, NDIS calls ProtocolCmDeactivateVcComplete. The final status of the deactivation is found in Status. Possible values for the final status include, but are not limited to: @flag NDIS_STATUS_SUCCESS | Indicates that the VC was deactivated successfully. @flag NDIS_STATUS_NOT_ACCEPTED | Indicates that an activation is pending on this VC. The call manager should attempt to deactivate the VC at a later time. @flag NDIS_STATUS_CLOSING | Indicates that a deactivation is currently pending on this VC. The call manager need not call NdisCmDeactivateVc again as only one call to NdisCmDeactivateVc is required to deactivate a VC. @normal ProtocolCmDeactivateVcComplete performs whatever postprocessing is necessary to complete the deactivation of a virtual connection, such as setting flags in its state area to indicate that the connection is inactive or releasing dynamically allocated resources used while the VC is active. Completion of the deactivation means that all call parameters for the VC used on activation are no longer valid. Any further use of the VC is prohibited except to reactivate it with a new set of call parameters. Call managers should release any resources that were allocated for the VC activation and return control as quickly as possible. If the call manager previously returned NDIS_STATUS_PENDING from its ProtocolCmCloseCall function and all operations to close the call have been completed, ProtocolCmDeactivateVcComplete should now call NdisCmCloseCallComplete. ProtocolCmDeactivateVcComplete must be written so that it can run at IRQL DISPATCH_LEVEL. @xref , NdisCmCloseCallComplete, NdisCmDeactivateVc, */ VOID ProtocolCmDeactivateVcComplete( IN NDIS_STATUS Status, // @parm // Specifies the final status of the deactivation. IN PBCHANNEL_OBJECT pBChannel // @parm // A pointer to the instance returned by // . AKA CallMgrVcContext. // Specifies the handle to a call manager-allocated context area in which // the call manager maintains its per-VC state. The call manager supplied // this handle from its function. ) { DBG_FUNC("ProtocolCmDeactivateVcComplete") PMINIPORT_ADAPTER_OBJECT pAdapter; // A pointer to the . ASSERT(pBChannel && pBChannel->ObjectType == BCHANNEL_OBJECT_TYPE); pAdapter = pBChannel->pAdapter; ASSERT(pAdapter && pAdapter->ObjectType == MINIPORT_ADAPTER_OBJECT_TYPE); DBG_ENTER(pAdapter); DBG_FILTER(pAdapter, DBG_TAPICALL_ON, ("#%d VC=0x%X CallState=0x%X Status=0x%X\n", pBChannel->ObjectID, pBChannel->NdisVcHandle, pBChannel->CallState, Status )); DBG_LEAVE(pAdapter); } /* @doc EXTERNAL INTERNAL CallMgr CallMgr_c ProtocolCmModifyCallQoS §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func is a required function that is called by NDIS when a connection-oriented client requests that the call parameters be changed for an existing virtual connection (VC). If the underlying network medium does not support QoS, ProtocolCmModifyQoS should simply return NDIS_STATUS_NOT_SUPPORTED. @comm ProtocolCmModifyQoS communicates with network control devices or other media-specific agents, as necessitated by its media, to modify the media-specific call parameters for an established virtual connection. If the call manager is required to communicate with network control agents (e.g. a networking switch) it should use a virtual connection to the network control agents that it established in its ProtocolBindAdapter function. Standalone call managers communicated to the network agents by calling NdisCoSendPackets. NIC miniports with integrated call-management support never call NdisCoSendPackets. Instead, such a driver simply transfers the data over the network to the target network agent. After communicating with the network and if the changes were successful, the call manager must then call NdisCmActivateVc with the new call parameters. This notifies NDIS and/or the connection-oriented miniport that the call parameters have changed and provides the miniport with an opportunity to validate those parameters. If either the network cannot accept the new call parameters or the underlying miniport cannot accept the parameters, the call manager must restore the virtual connection to the state that existed before any modifications were attempted, and return NDIS_STATUS_FAILURE. ProtocolCmModifyQoSComplete must be written so that it can run at IRQL DISPATCH_LEVEL. @rdesc ProtocolCmModifyQoS returns the status of its operation(s) as one of the following values: @rvalue NDIS_STATUS_SUCCESS | Indicates that the call manager successfully changed the parameters of the call with the network to the call parameters specified at CallParameters. @rvalue NDIS_STATUS_PENDING | Indicates that the call manager will complete the request to modify the call parameters asynchronously. When the call manager has completed all operations necessary to modify the call parameters, it must call NdisCmModifyCallQoSComplete. @rvalue NDIS_STATUS_RESOURCES | Indicates that the call manager could not change the call parameters of the VC because dynamically allocated resources were not available. @rvalue NDIS_STATUS_INVALID_DATA | Indicates that the call manager was unable to change the call parameters of the VC because the call parameters provided at CallParameters were illegal or invalid. @rvalue NDIS_STATUS_FAILURE | Indicates that the call parameters could not be set to the call parameters provided because of a failure in the network or in another connection-oriented network component. @xref NdisCmActivateVc, NdisCmModifyCallQoSComplete, NdisCoSendPackets, */ NDIS_STATUS ProtocolCmModifyCallQoS( IN PBCHANNEL_OBJECT pBChannel, // @parm // A pointer to the instance returned by // . AKA CallMgrVcContext. // Specifies the handle to a call manager-allocated context area in which // the call manager maintains its per-VC state. The call manager supplied // this handle from its function. IN PCO_CALL_PARAMETERS pCallParameters // @parm // Points to a CO_CALL_PARAMETERS structure that contains the new call // parameters, as specified by a connection-oriented client, for the VC. ) { DBG_FUNC("ProtocolCmModifyCallQoS") NDIS_STATUS Result = NDIS_STATUS_SUCCESS; // Holds the result code returned by this function. PMINIPORT_ADAPTER_OBJECT pAdapter; // A pointer to the . ASSERT(pBChannel && pBChannel->ObjectType == BCHANNEL_OBJECT_TYPE); pAdapter = pBChannel->pAdapter; ASSERT(pAdapter && pAdapter->ObjectType == MINIPORT_ADAPTER_OBJECT_TYPE); DBG_ENTER(pAdapter); DBG_FILTER(pAdapter, DBG_TAPICALL_ON, ("#%d VC=0x%X CallState=0x%X\n", pBChannel->ObjectID, pBChannel->NdisVcHandle, pBChannel->CallState )); // What do you want to do with this request? DBG_ERROR(pAdapter, ("pCallParameters=0x%X\n", pCallParameters)); DBG_RETURN(pAdapter, Result); return (Result); } /* @doc EXTERNAL INTERNAL CallMgr CallMgr_c ProtocolCoRequest §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func is a required function that handles OID_CO_XXX requests initiated by calls to NdisCoRequest from the corresponding client(s) or stand-alone call manager or initiated by an MCM driver's calls to NdisMCmRequest. @comm Connection-oriented clients and stand-alone call managers communicate information to each other by specifying an explicit NdisAfHandle when they call NdisCoRequest. Similarly, a connection-oriented miniport with integrated call-management support calls NdisMCmRequest with explicit NdisAfHandles to communicate information to its individual clients. Such a call to NdisCoRequest or NdisMCmRequest with an explicit NdisAfHandle causes NDIS to call the ProtocolCoRequest function of the client, stand-alone call manager, or MCM driver that shares the given NdisAfHandle. If the input NdisVcHandle and NdisPartyHandle are NULL, ProtocolCoRequest can consider the request global in nature. For example, ProtocolCoRequest satisfies any OID_GEN_CO_XXX query for which it is passed only an explicit NdisAfHandle by returning information about all currently active VCs, including any active multipoint VCs, on the given address family. An explicit NdisVcHandle or NdisPartyHandle indicates that ProtocolCoRequest should satisfy the given request on a per-VC or per-party basis, respectively. ProtocolCoRequest can assume that the buffer at NdisRequest was allocated from nonpaged pool and is, therefore, accessible at raised IRQL. The caller of NdisCoRequest (or NdisMCmRequest) is responsible for releasing this buffer and the internal buffer at InformationBuffer that it allocated when its request has been completed. If ProtocolCoRequest returns NDIS_STATUS_PENDING, the driver must make a subsequent call to NdisCoRequestComplete or, for an MCM driver, to NdisMCmRequestComplete when the driver completes its operations to satisfy the given request. For more information about the sets of OIDs defined for use with NdisCoRequest, NdisMCmRequest, and NdisRequest, see Part 2 of this manual. ProtocolCoRequest must be written so that it can run at IRQL DISPATCH_LEVEL. @rdesc ProtocolCoRequest can return one of the following: @rvalue NDIS_STATUS_SUCCESS | The client or call manager carried out the requested operation. @rvalue NDIS_STATUS_PENDING | The client or call manager is handling this request asynchronously, and it will call NdisCoRequestComplete (or, from a NIC miniport with integrated call-management support, NdisMCmRequestComplete) when the requested operation is done. @rvalue NDIS_STATUS_INVALID_LENGTH or NDIS_STATUS_BUFFER_TOO_SHORT | The driver is failing this request because the caller of NdisCoRequest or NdisMCmRequest did not supply an adequate InformationBuffer for the given request. The driver set the BytesNeeded member in the buffer at NdisRequest to the Oid-specific value of the InformationBufferLength required to carry out the requested operation. @rvalue NDIS_STATUS_XXX | The client or call manager failed the request for some driver-determined reason, such as invalid input data specified for a set. @rvalue NDIS_STATUS_NOT_SUPPORTED | The client or call manager failed this request because it did not recognize the OID_GEN_CO_XXX code in the Oid member in the buffer at NdisRequest. @xref NdisClOpenAddressFamily, NdisCoRequest, NdisCoRequestComplete, NdisMCmRequest, NdisMCmRequestComplete, NdisRequest, NDIS_REQUEST, ProtocolCmOpenAf, ProtocolCoRequestComplete */ NDIS_STATUS ProtocolCoRequest( IN PMINIPORT_ADAPTER_OBJECT pAdapter, // @parm // A pointer to the instance return by // . AKA ProtocolAfContext. // Specifies the handle to the driver's per-AF context area. The client // supplied this handle when it called NdisClOpenAddressFamily to connect // itself to the call manager. The call manager supplied this handle from // its function, so this handle effectively identifies // the particular client that issued this request. IN PBCHANNEL_OBJECT pBChannel OPTIONAL, // @parm // A pointer to the instance returned by // . AKA ProtocolVcContext. // Specifies the handle identifying the active VC for which the client or // call manager is requesting or setting information if the request is // VC-specific. Otherwise, this parameter is NULL. IN NDIS_HANDLE ProtocolPartyContext OPTIONAL, // @parm // Specifies the handle identifying the party on a multipoint VC for which // the client or call manager is requesting or setting information if the // request is party-specific. Otherwise, this parameter is NULL. IN OUT PNDIS_REQUEST NdisRequest // Points to a buffer, formatted as an NDIS_REQUEST structure specifying // the operation to be carried out by ProtocolCoRequest. The Oid member of // the NDIS_REQUEST structure contains the system-defined OID_GEN_CO_XXX // code specifying the requested query or set operation, together with a // buffer in which the protocol returns the requested information for a // query or from which it transfers the given information for a set. ) { DBG_FUNC("ProtocolCmRequest") NDIS_STATUS Result = NDIS_STATUS_SUCCESS; // Holds the result code returned by this function. // ASSERT(pBChannel && pBChannel->ObjectType == BCHANNEL_OBJECT_TYPE); ASSERT(pAdapter && pAdapter->ObjectType == MINIPORT_ADAPTER_OBJECT_TYPE); DBG_ENTER(pAdapter); Result = MiniportCoRequest(pAdapter, pBChannel, NdisRequest); DBG_RETURN(pAdapter, Result); return (Result); } /* @doc EXTERNAL INTERNAL CallMgr CallMgr_c ProtocolCoRequestComplete §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func is a required function that postprocesses the results of a connection-oriented client's or stand-alone call manager's call to NdisCoRequest or of an MCM driver's call to NdisMCmRequest. @comm ProtocolCoRequestComplete can use the input Status as follows: If this argument is NDIS_STATUS_SUCCESS, the BytesRead or BytesWritten member of the NDIS_REQUEST structure has been set to specify how much data was transferred into or from the buffer at InformationBuffer. If the given OID_GEN_CO_XXX was a query, ProtocolCoRequestComplete can use the data returned at InformationBuffer in any driver-determined way, depending on the value of the Oid member. ProtocolCoRequestComplete is responsible for releasing the driver-allocated buffers at NdisRequest and InformationBuffer when the driver completes its postprocessing of this request. If this argument is NDIS_STATUS_INVALID_LENGTH or NDIS_STATUS_BUFFER_TOO_SHORT, the BytesNeeded member specifies the Oid-specific value of the InformationBufferLength required to carry out the requested operation. In these circumstances, ProtocolCoRequestComplete can allocate sufficient buffer space for the request, set up another NDIS_REQUEST structure with the required InformationBufferLength and the same Oid value, and retry the driver's call to NdisCoRequest or NdisMCmRequest. If this argument is an NDIS_STATUS_XXX that indicates an unrecoverable error, ProtocolCoRequestComplete should release the buffer at NdisRequest and carry out any driver-determined operations that are necessary. For example, ProtocolCoRequestComplete might tear down the driver-created VC if a returned error status indicates that the driver cannot continue to make transfers on the virtual connection. Even if a driver's call to NdisCoRequest or NdisMCmRequest returns something other than NDIS_STATUS_PENDING, that driver should use its ProtocolCoRequestComplete function to postprocess completed requests. Making an internal call to the driver's own ProtocolCoRequestComplete function on return from NdisCoRequest or NdisMCmRequest has almost no adverse effect on the driver's performance, makes the driver's image smaller, and makes the driver easier to maintain from one OS release to the next since such a driver has no duplicate code doing status-return checking on driver-initiated requests. For more information about the sets of OIDs defined for use with NdisCoRequest and NdisMCmRequest, see Part 2 of this manual. ProtocolCoRequestComplete must be written so that it can run at IRQL DISPATCH_LEVEL. @xref NdisCoRequest, NdisCoRequestComplete, NdisMCmRequest, NdisMCmRequestComplete, NDIS_REQUEST, */ VOID ProtocolCoRequestComplete( IN NDIS_STATUS Status, // @parm // Specifies the final status of the driver-initiated request, either // NDIS_STATUS_SUCCESS or a failure NDIS_STATUS_XXX that was set by the // corresponding client or call manager that handled this request. This // parameter is never NDIS_STATUS_PENDING. IN PMINIPORT_ADAPTER_OBJECT pAdapter, // @parm // A pointer to the instance return by // . AKA ProtocolAfContext. // Specifies the handle to the driver's per-AF context area. The client // supplied this handle when it called NdisClOpenAddressFamily to connect // itself to the call manager. The call manager supplied this handle from // its ProtocolCmOpenAf function, so this handle effectively identifies the // particular client to which this request was directed. IN PBCHANNEL_OBJECT pBChannel OPTIONAL, // @parm // A pointer to the instance returned by // . AKA ProtocolVcContext. // Specifies the handle identifying the active VC for which the client or // call manager was requesting or setting information if the request was // VC-specific. Otherwise, this parameter is NULL. IN NDIS_HANDLE ProtocolPartyContext OPTIONAL, // @parm // Specifies the handle identifying the party on a multipoint VC for which // the client or call manager was requesting or setting information if the // request is party-specific. Otherwise, this parameter is NULL. IN PNDIS_REQUEST NdisRequest // @parm // Points to the driver-allocated buffer, formatted as an NDIS_REQUEST // structure that the driver passed in a preceding call to NdisCoRequest or // NdisMCmRequest. The Oid member of the NDIS_REQUEST structure contains // the system-defined OID_GEN_CO_XXX code specifying the requested query or // set operation, together with a buffer in which the corresponding client // or call manager returned the requested information for a query or from // which it transferred the given information for a set if Status is // NDIS_STATUS_SUCCESS. ) { DBG_FUNC("ProtocolCmRequestComplete") // ASSERT(pBChannel && pBChannel->ObjectType == BCHANNEL_OBJECT_TYPE); ASSERT(pAdapter && pAdapter->ObjectType == MINIPORT_ADAPTER_OBJECT_TYPE); DBG_ENTER(pAdapter); DBG_FILTER(pAdapter, DBG_TAPICALL_ON, ("#%d VC=0x%X CallState=0x%X Status=0x%X\n", pBChannel->ObjectID, pBChannel->NdisVcHandle, pBChannel->CallState, Status )); // MCM's don't typically need this, since there's nothing below... DBG_LEAVE(pAdapter); } /* @doc INTERNAL CallMgr CallMgr_c AllocateIncomingCallParameters §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func is called by when getting ready to indicate an incoming call up to NDPROXY. @comm AllocateIncomingCallParameters allocates memory for the incoming call parameters . The memory is only allocated the first time a call comes in on a particular BChannel. After that, the same structure is reused for each incoming call on that BChannel. The structure is defined by NDPROXY, CONDIS, and TAPI so it includes all the necessary media specific parameters. The data structures are allocated and laid out end to end in the following format: sizeof(CO_CALL_PARAMETERS) sizeof(CO_CALL_MANAGER_PARAMETERS) sizeof(CO_MEDIA_PARAMETERS) sizeof(CO_AF_TAPI_INCOMING_CALL_PARAMETERS) sizeof(LINE_CALL_INFO) The call parameters for the sample driver are hard coded, but you should fill in the correct information from incoming call request. */ PCO_CALL_PARAMETERS AllocateIncomingCallParameters( IN PBCHANNEL_OBJECT pBChannel // @parm // A pointer to the instance returned by // . ) { DBG_FUNC("AllocateIncomingCallParameters") PCO_CALL_PARAMETERS pCp; PCO_CALL_MANAGER_PARAMETERS pCmp; PCO_MEDIA_PARAMETERS pMp; PCO_AF_TAPI_INCOMING_CALL_PARAMETERS pTcp; PLINE_CALL_INFO pLci; NDIS_STATUS Result = NDIS_STATUS_SUCCESS; // Holds the result code returned by this function. PMINIPORT_ADAPTER_OBJECT pAdapter; // A pointer to the . ASSERT(pBChannel && pBChannel->ObjectType == BCHANNEL_OBJECT_TYPE); pAdapter = GET_ADAPTER_FROM_BCHANNEL(pBChannel); DBG_ENTER(pAdapter); ASSERT(pBChannel->NdisTapiSap.ulMediaModes & LINEMEDIAMODE_DIGITALDATA); pBChannel->MediaMode = LINEMEDIAMODE_DIGITALDATA; pBChannel->BearerMode = LINEBEARERMODE_DATA; pBChannel->LinkSpeed = _64KBPS; if (pBChannel->pInCallParms != NULL) { // Already allocated call parameters for this channel. return (pBChannel->pInCallParms); } pBChannel->CallParmsSize = sizeof(CO_CALL_PARAMETERS) + sizeof(CO_CALL_MANAGER_PARAMETERS) + sizeof(CO_MEDIA_PARAMETERS) + sizeof(CO_AF_TAPI_INCOMING_CALL_PARAMETERS) + sizeof(LINE_CALL_INFO); ALLOCATE_MEMORY(pBChannel->pInCallParms, pBChannel->CallParmsSize, pAdapter->MiniportAdapterHandle); if (pBChannel->pInCallParms == NULL) { return (pBChannel->pInCallParms); } NdisZeroMemory(pBChannel->pInCallParms, pBChannel->CallParmsSize); DBG_NOTICE(pAdapter,( "\n" "\t\tsizeof(CO_CALL_PARAMETERS) =%03d\n" "\t\tsizeof(CO_CALL_MANAGER_PARAMETERS) =%03d\n" "\t\tsizeof(CO_MEDIA_PARAMETERS) =%03d\n" "\t\tsizeof(CO_AF_TAPI_INCOMING_CALL_PARAMETERS)=%03d\n" "\t\tsizeof(LINE_CALL_INFO) =%03d\n" "\t\tTotal =%03d\n", sizeof(CO_CALL_PARAMETERS), sizeof(CO_CALL_MANAGER_PARAMETERS), sizeof(CO_MEDIA_PARAMETERS), sizeof(CO_AF_TAPI_INCOMING_CALL_PARAMETERS), sizeof(LINE_CALL_INFO), pBChannel->CallParmsSize )); pCp = (PCO_CALL_PARAMETERS) pBChannel->pInCallParms; pCmp = (PCO_CALL_MANAGER_PARAMETERS)(pCp + 1); pMp = (PCO_MEDIA_PARAMETERS) (pCmp + 1); pTcp = (PCO_AF_TAPI_INCOMING_CALL_PARAMETERS) pMp->MediaSpecific.Parameters; pLci = (PLINE_CALL_INFO) (pTcp + 1); // TODO: Fill in the call parameters as needed. pCp->Flags = PERMANENT_VC; pCp->CallMgrParameters = pCmp; pCp->MediaParameters = pMp; pCmp->Transmit.TokenRate = pBChannel->LinkSpeed / 8; pCmp->Transmit.TokenBucketSize = pAdapter->pCard->BufferSize; pCmp->Transmit.PeakBandwidth = pBChannel->LinkSpeed / 8; pCmp->Transmit.Latency = 0; pCmp->Transmit.DelayVariation = 0; pCmp->Transmit.ServiceType = SERVICETYPE_BESTEFFORT; pCmp->Transmit.MaxSduSize = pAdapter->pCard->BufferSize; pCmp->Transmit.MinimumPolicedSize = 0; pCmp->Receive = pCmp->Transmit; pCmp->CallMgrSpecific.ParamType = 0; pCmp->CallMgrSpecific.Length = 0; pMp->Flags = TRANSMIT_VC | RECEIVE_VC; pMp->ReceiveSizeHint = pAdapter->pCard->BufferSize; pMp->MediaSpecific.ParamType = 0; pMp->MediaSpecific.Length = sizeof(*pTcp) + sizeof(*pLci); pTcp->ulLineID = pBChannel->NdisTapiSap.ulLineID; pTcp->ulAddressID = TSPI_ADDRESS_ID; pTcp->ulFlags = CO_TAPI_FLAG_INCOMING_CALL; pTcp->LineCallInfo.Length = sizeof(*pLci); pTcp->LineCallInfo.MaximumLength = sizeof(*pLci); pTcp->LineCallInfo.Offset = sizeof(NDIS_VAR_DATA_DESC); pLci->ulTotalSize = pLci->ulNeededSize = pLci->ulUsedSize = sizeof(*pLci); /* // The link has all the call information we need to return. */ pLci->hLine = (ULONG) (ULONG_PTR) pBChannel; pLci->ulLineDeviceID = pTcp->ulLineID; pLci->ulAddressID = pTcp->ulAddressID; pLci->ulBearerMode = pBChannel->BearerMode; pLci->ulRate = pBChannel->LinkSpeed; pLci->ulMediaMode = pBChannel->MediaMode; pLci->ulCallParamFlags = LINECALLPARAMFLAGS_IDLE; pLci->ulCallStates = pBChannel->CallStatesCaps; /* // We don't support any of the callerid functions. */ pLci->ulCallerIDFlags = pLci->ulCalledIDFlags = pLci->ulConnectedIDFlags = pLci->ulRedirectionIDFlags = pLci->ulRedirectingIDFlags = LINECALLPARTYID_UNAVAIL; DBG_RETURN(pAdapter, pBChannel->pInCallParms); return (pBChannel->pInCallParms); } /* @doc INTERNAL CallMgr CallMgr_c SetupIncomingCall §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func is called by the card level DPC routine when it detects an incoming call from the network. @comm Before calling this routine, the caller should save information about the call so it can be used by to setup the incoming call parameters for NDPROXY. @rdesc returns zero if it is successful. Otherwise, a non-zero return value indicates an error condition. */ NDIS_STATUS SetupIncomingCall( IN PMINIPORT_ADAPTER_OBJECT pAdapter, // @parm // A pointer to the instance return by // . OUT PBCHANNEL_OBJECT * ppBChannel // @parm // Specifies, on output, a pointer to the instance // returned by that is to be associated with this // incoming call. ) { DBG_FUNC("SetupIncomingCall") NDIS_STATUS Result; // Holds the result code returned by this function. PCO_CALL_PARAMETERS pCallParams; // Pointer to the incoming call parameters. PBCHANNEL_OBJECT pBChannel; ASSERT(pAdapter && pAdapter->ObjectType == MINIPORT_ADAPTER_OBJECT_TYPE); DBG_ENTER(pAdapter); // See if there's a VC availble for this call. Result = ProtocolCoCreateVc(pAdapter, NULL, ppBChannel); if (Result != NDIS_STATUS_SUCCESS) { goto exit; } // Save the VC info and allocate the call parameters. pBChannel = *ppBChannel; pBChannel->Flags |= VCF_INCOMING_CALL; pCallParams = AllocateIncomingCallParameters(pBChannel); // Make sure we have the parameters if (pCallParams == NULL) { Result = NDIS_STATUS_RESOURCES; goto error2; } // Tell NDPROXY to create a VC for this call. Result = NdisMCmCreateVc(pAdapter->MiniportAdapterHandle, pAdapter->NdisAfHandle, pBChannel, &pBChannel->NdisVcHandle); if (Result != NDIS_STATUS_SUCCESS) { DBG_ERROR(pAdapter, ("NdisMCmCreateVc Status=0x%X\n", Result)); goto error2; } // Tell NDPROXY to activate the VC. Result = NdisMCmActivateVc(pBChannel->NdisVcHandle, pCallParams); if (Result != NDIS_STATUS_SUCCESS) { DBG_ERROR(pAdapter, ("NdisMCmActivateVc Status=0x%X\n", Result)); goto error3; } // Mark the VC as active and update the call state. pBChannel->Flags |= VCF_VC_ACTIVE; pBChannel->CallState = LINECALLSTATE_OFFERING; DBG_FILTER(pAdapter,DBG_TAPICALL_ON, ("#%d VC=0x%X AF=0x%X SAP=0x%X\n", pBChannel->ObjectID, pBChannel->NdisVcHandle, pAdapter->NdisAfHandle, pBChannel->NdisSapHandle )); // Tell NDPROXY to dispatch the call to the TAPI clients. Result = NdisMCmDispatchIncomingCall(pBChannel->NdisSapHandle, pBChannel->NdisVcHandle, pCallParams); switch (Result) { case NDIS_STATUS_SUCCESS: DBG_NOTICE(pAdapter,("NdisMCmDispatchIncomingCall completed synchronously\n")); ProtocolCmIncomingCallComplete(Result, pBChannel, NULL); goto exit; case NDIS_STATUS_PENDING: DBG_NOTICE(pAdapter,("NdisMCmDispatchIncomingCall returned pending\n")); // Let ProtocolCmIncomingCallComplete deal with it now. goto exit; } // BUMMER - There must be a problem with NDPRROXY... DBG_ERROR(pAdapter, ("NdisMCmDispatchIncomingCall Status=0x%X\n", Result)); pBChannel->CallState = LINECALLSTATE_IDLE; if (pBChannel->Flags & VCF_VC_ACTIVE) { pBChannel->Flags &= ~VCF_VC_ACTIVE; NdisMCmDeactivateVc(pBChannel->NdisVcHandle); } error3: if (pBChannel->NdisVcHandle) { NdisMCmDeleteVc(pBChannel->NdisVcHandle); pBChannel->NdisVcHandle = NULL; } error2: ProtocolCoDeleteVc((NDIS_HANDLE) pBChannel); exit: DBG_RETURN(pAdapter, Result); return (Result); } /* @doc INTERNAL CallMgr CallMgr_c InitiateCallTeardown §§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§§ @func is called by the card level DPC routine when it detects a call disconnect from the network. @comm The disconnect here is coming from the telephone network rather than from NDIS. This can be called on either an incoming call or an outgoing call when the miniport has determined that the link has been lost to the remote endpoint. */ VOID InitiateCallTeardown( IN PMINIPORT_ADAPTER_OBJECT pAdapter, // @parm // A pointer to the instance return by // . IN PBCHANNEL_OBJECT pBChannel // @parm // A pointer to the instance returned by // . ) { DBG_FUNC("InitiateCallTeardown") NDIS_STATUS Status; ASSERT(pAdapter && pAdapter->ObjectType == MINIPORT_ADAPTER_OBJECT_TYPE); ASSERT(pBChannel && pBChannel->ObjectType == BCHANNEL_OBJECT_TYPE); DBG_ENTER(pAdapter); if (pBChannel->Flags & VCF_VC_ACTIVE) { // Normal teardown. Status = NDIS_STATUS_SUCCESS; } else { // Call never fully established. Status = NDIS_STATUS_FAILURE; } DBG_FILTER(pAdapter, DBG_TAPICALL_ON, ("#%d VC=0x%X CallState=0x%X Status=0x%X\n", pBChannel->ObjectID, pBChannel->NdisVcHandle, pBChannel->CallState, Status )); pBChannel->CallState = LINECALLSTATE_DISCONNECTED; // Make sure there are no packets left on this channel before it closes. FlushSendPackets(pAdapter, pBChannel); // Notify NDPROXY that the call's connection has been lost. NdisMCmDispatchIncomingCloseCall(Status, pBChannel->NdisVcHandle, NULL, 0); DBG_LEAVE(pAdapter); }