You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2528 lines
55 KiB
2528 lines
55 KiB
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
D:\nt\private\ntos\tdi\rawwan\core\ndisconn.c
|
|
|
|
Abstract:
|
|
|
|
NDIS Entry points and support routines for Connection setup and
|
|
release.
|
|
|
|
Revision History:
|
|
|
|
Who When What
|
|
-------- -------- ----------------------------------------------
|
|
arvindm 05-06-97 Created
|
|
|
|
Notes:
|
|
|
|
Code under ifndef NO_POST_DISCON: Nov 17, 98
|
|
Added code to send a TDI DisconInd to AFD before completing
|
|
a TDI Disconnect Request that AFD had sent to us. Without this,
|
|
if an app calls shutdown(SD_SEND) -> TDI Disconnect Request,
|
|
a subsequent call by the app to recv() blocks forever, because
|
|
AFD expects the TDI transport to send up a TDI DisconInd!
|
|
|
|
--*/
|
|
|
|
#include <precomp.h>
|
|
|
|
#define _FILENUMBER 'NCDN'
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
RWanNdisCreateVc(
|
|
IN NDIS_HANDLE ProtocolAfContext,
|
|
IN NDIS_HANDLE NdisVcHandle,
|
|
OUT PNDIS_HANDLE pProtocolVcContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the NDIS entry point for creating a new endpoint (VC).
|
|
We allocate a new NDIS_VC structure and return a pointer to it
|
|
as our context for the VC.
|
|
|
|
Arguments:
|
|
|
|
ProtocolAfContext - Pointer to our NDIS AF block
|
|
NdisVcHandle - Handle for the newly created VC
|
|
pProtocolVcContext - Place where we return our context for the VC
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS if we could allocate a VC,
|
|
NDIS_STATUS_RESOURCES otherwise.
|
|
|
|
--*/
|
|
{
|
|
PRWAN_NDIS_AF pAf;
|
|
PRWAN_NDIS_VC pVc;
|
|
NDIS_STATUS Status;
|
|
|
|
pAf = (PRWAN_NDIS_AF)ProtocolAfContext;
|
|
|
|
RWAN_STRUCT_ASSERT(pAf, naf);
|
|
|
|
do
|
|
{
|
|
pVc = RWanAllocateVc(pAf, FALSE);
|
|
|
|
if (pVc == NULL_PRWAN_NDIS_VC)
|
|
{
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
pVc->NdisVcHandle = NdisVcHandle;
|
|
|
|
RWANDEBUGP(DL_EXTRA_LOUD, DC_CONNECT,
|
|
("CreateVc: pVc x%x, pAf x%x\n", pVc, pAf));
|
|
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
while (FALSE);
|
|
|
|
*pProtocolVcContext = (NDIS_HANDLE)pVc;
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
RWanNdisDeleteVc(
|
|
IN NDIS_HANDLE ProtocolVcContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This entry point is called by NDIS to delete a VC context
|
|
used for an incoming call. At this time, there should be
|
|
no call on the VC. All we need to do is unlink the VC from
|
|
the list it belongs to, and free it.
|
|
|
|
Arguments:
|
|
|
|
ProtocolVcContext - Points to our VC context.
|
|
|
|
Return Value:
|
|
|
|
NDIS_STATUS_SUCCESS always.
|
|
|
|
--*/
|
|
{
|
|
PRWAN_NDIS_VC pVc;
|
|
|
|
pVc = (PRWAN_NDIS_VC)ProtocolVcContext;
|
|
RWAN_STRUCT_ASSERT(pVc, nvc);
|
|
|
|
RWAN_ASSERT(pVc->pConnObject == NULL_PRWAN_TDI_CONNECTION);
|
|
|
|
RWANDEBUGP(DL_EXTRA_LOUD, DC_DISCON,
|
|
("DeleteVc: pVc x%x, pAf x%x\n", pVc, pVc->pNdisAf));
|
|
|
|
//
|
|
// Unlink the VC from the list of VCs on the AF block
|
|
//
|
|
RWanUnlinkVcFromAf(pVc);
|
|
|
|
RWanFreeVc(pVc);
|
|
|
|
return (NDIS_STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
RWanNdisMakeCallComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolVcContext,
|
|
IN NDIS_HANDLE NdisPartyHandle OPTIONAL,
|
|
IN PCO_CALL_PARAMETERS pCallParameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the NDIS entry point that is called when a previous
|
|
call we made to NdisClMakeCall has completed.
|
|
|
|
We locate the TDI Connection Object for this call. If the
|
|
user hasn't aborted the Connect/JoinLeaf, we complete the
|
|
pended request. Otherwise, we initiate a CloseCall.
|
|
|
|
This primitive can happen only when the endpoint is in
|
|
the "Out call initiated" state.
|
|
|
|
Arguments:
|
|
|
|
Status - Final status of the MakeCall
|
|
ProtocolVcContext - Actually a pointer to our NDIS VC structure
|
|
NdisPartyHandle - If this is a PMP call, this is the handle to the
|
|
first party
|
|
pCallParameters - Final call parameters.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PRWAN_TDI_CONNECTION pRootConnObject;
|
|
PRWAN_TDI_CONNECTION pConnObject;
|
|
PRWAN_TDI_ADDRESS pAddrObject;
|
|
NDIS_HANDLE NdisVcHandle;
|
|
TDI_STATUS TdiStatus;
|
|
PRWAN_CONN_REQUEST pConnReq; // Saved context about the TdiConnect
|
|
BOOLEAN bIsConnClosing; // Have we seen a TdiCloseConnection?
|
|
PRWAN_NDIS_AF pAf;
|
|
PRWAN_NDIS_VC pVc;
|
|
PRWAN_NDIS_PARTY pParty;
|
|
PCO_CALL_PARAMETERS pOriginalParams;// What we used in the MakeCall
|
|
RWAN_HANDLE AfSpConnContext;
|
|
#if DBG
|
|
RWAN_IRQL EntryIrq, ExitIrq;
|
|
#endif // DBG
|
|
|
|
RWAN_GET_ENTRY_IRQL(EntryIrq);
|
|
|
|
pVc = (PRWAN_NDIS_VC)ProtocolVcContext;
|
|
|
|
RWAN_STRUCT_ASSERT(pVc, nvc);
|
|
|
|
//
|
|
// Check if this is a point-to-multipoint call.
|
|
//
|
|
if (!RWAN_IS_BIT_SET(pVc->Flags, RWANF_VC_PMP))
|
|
{
|
|
//
|
|
// Point-to-point call.
|
|
//
|
|
pConnObject = pVc->pConnObject;
|
|
pRootConnObject = pConnObject; // for consistency.
|
|
pParty = NULL;
|
|
pOriginalParams = pVc->pCallParameters;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// PMP Call. Get at the Party structure.
|
|
//
|
|
pParty = pVc->pPartyMakeCall;
|
|
RWAN_STRUCT_ASSERT(pParty, npy);
|
|
|
|
pConnObject = pParty->pConnObject;
|
|
pRootConnObject = pVc->pConnObject;
|
|
pOriginalParams = pParty->pCallParameters;
|
|
}
|
|
|
|
RWAN_ASSERT(pOriginalParams != NULL);
|
|
|
|
pAf = pVc->pNdisAf;
|
|
|
|
RWANDEBUGP(DL_LOUD, DC_CONNECT,
|
|
("MakeCallComplete: pConn x%x, State/Flags/Ref x%x/x%x/%d, pAddr %x, pVc x%x, Status x%x\n",
|
|
pConnObject, pConnObject->State, pConnObject->Flags, pConnObject->RefCount, pConnObject->pAddrObject, pVc, Status));
|
|
|
|
RWAN_ACQUIRE_CONN_LOCK(pConnObject);
|
|
|
|
RWAN_ASSERT(pConnObject->State == RWANS_CO_OUT_CALL_INITIATED ||
|
|
pConnObject->State == RWANS_CO_DISCON_REQUESTED);
|
|
|
|
//
|
|
// Has the user initiated a TdiCloseConnection() or a TdiDisconnect()
|
|
// while this outgoing call was in progress?
|
|
//
|
|
bIsConnClosing = RWAN_IS_BIT_SET(pConnObject->Flags, RWANF_CO_CLOSING) ||
|
|
(pConnObject->State == RWANS_CO_DISCON_REQUESTED);
|
|
|
|
//
|
|
// We would have saved context about the TdiConnect(). Get it.
|
|
//
|
|
pConnReq = pConnObject->pConnReq;
|
|
pConnObject->pConnReq = NULL;
|
|
|
|
|
|
if (pParty)
|
|
{
|
|
pVc->AddingPartyCount --;
|
|
pParty->pCallParameters = NULL;
|
|
pParty->NdisPartyHandle = NdisPartyHandle;
|
|
}
|
|
else
|
|
{
|
|
pVc->pCallParameters = NULL;
|
|
}
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
RWAN_SET_VC_EVENT(pVc, RWANF_VC_EVT_MAKECALL_OK);
|
|
|
|
if (!bIsConnClosing)
|
|
{
|
|
//
|
|
// Outgoing connection successfully set up.
|
|
//
|
|
|
|
pConnObject->State = RWANS_CO_CONNECTED;
|
|
|
|
//
|
|
// Update PMP information.
|
|
//
|
|
if (pParty)
|
|
{
|
|
pVc->ActivePartyCount ++; // MakeCall PMP complete
|
|
pRootConnObject->State = RWANS_CO_CONNECTED;
|
|
}
|
|
|
|
AfSpConnContext = pConnObject->AfSpConnContext;
|
|
|
|
RWAN_RELEASE_CONN_LOCK(pConnObject);
|
|
|
|
RWanCompleteConnReq( // MakeCall OK
|
|
pAf,
|
|
pConnReq,
|
|
TRUE,
|
|
pCallParameters,
|
|
AfSpConnContext,
|
|
TDI_SUCCESS
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Abort this call.
|
|
//
|
|
pConnObject->State = RWANS_CO_ABORTING;
|
|
|
|
RWanStartCloseCall(pConnObject, pVc);
|
|
}
|
|
RWAN_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// MakeCall failed.
|
|
//
|
|
|
|
INT rc;
|
|
|
|
//
|
|
// XXX TBD : how about trying this call on another NDIS AF?
|
|
//
|
|
|
|
RWAN_SET_VC_EVENT(pVc, RWANF_VC_EVT_MAKECALL_FAIL);
|
|
|
|
if (pParty == NULL)
|
|
{
|
|
//
|
|
// Point-to-Point call.
|
|
//
|
|
|
|
//
|
|
// Unlink the NDIS VC from this Conn Object.
|
|
//
|
|
RWAN_UNLINK_CONNECTION_AND_VC(pConnObject, pVc); // MakeCall fail
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// PMP Call. The VC would be attached to the Root
|
|
// Connection Object. Unlink the VC and the Root Connection.
|
|
//
|
|
RWAN_ACQUIRE_CONN_LOCK(pRootConnObject);
|
|
|
|
RWAN_UNLINK_CONNECTION_AND_VC(pRootConnObject, pVc); // MakeCallPMP fail
|
|
|
|
rc = RWanDereferenceConnObject(pRootConnObject); // VC deref: MakeCallPMP fail
|
|
|
|
if (rc > 0)
|
|
{
|
|
RWAN_RELEASE_CONN_LOCK(pRootConnObject);
|
|
}
|
|
|
|
//
|
|
// Unlink the Party from the Connection and VC.
|
|
//
|
|
RWAN_DELETE_FROM_LIST(&(pParty->PartyLink));
|
|
pParty->pVc = NULL;
|
|
|
|
pParty->pConnObject = NULL;
|
|
pConnObject->NdisConnection.pNdisParty = NULL;
|
|
}
|
|
|
|
rc = RWanDereferenceConnObject(pConnObject); // VC/Pty deref: MakeCall fail
|
|
|
|
//
|
|
// Continue with the Connection Object for this MakeCall,
|
|
// if it is still alive.
|
|
//
|
|
if (rc > 0)
|
|
{
|
|
if (pConnObject->pAddrObject != NULL)
|
|
{
|
|
//
|
|
// Move the Connection Object to the Idle list.
|
|
//
|
|
|
|
pAddrObject = pConnObject->pAddrObject;
|
|
|
|
//
|
|
// Reacquire some locks in the right order.
|
|
//
|
|
RWAN_RELEASE_CONN_LOCK(pConnObject);
|
|
|
|
RWAN_ACQUIRE_ADDRESS_LOCK(pAddrObject);
|
|
RWAN_ACQUIRE_CONN_LOCK_DPC(pConnObject);
|
|
|
|
//
|
|
// Move this Connection to the Idle list.
|
|
//
|
|
RWAN_DELETE_FROM_LIST(&(pConnObject->ConnLink));
|
|
RWAN_INSERT_TAIL_LIST(&(pAddrObject->IdleConnList),
|
|
&(pConnObject->ConnLink));
|
|
|
|
//
|
|
// Send this back to the state it was in before the TdiConnect.
|
|
//
|
|
pConnObject->State = RWANS_CO_ASSOCIATED;
|
|
|
|
AfSpConnContext = pConnObject->AfSpConnContext;
|
|
|
|
RWAN_RELEASE_CONN_LOCK_DPC(pConnObject);
|
|
|
|
RWAN_RELEASE_ADDRESS_LOCK(pAddrObject);
|
|
|
|
//
|
|
// Complete the TdiConnect() with a failure status.
|
|
//
|
|
TdiStatus = RWanNdisToTdiStatus(Status);
|
|
|
|
if (TdiStatus == TDI_NOT_ACCEPTED)
|
|
{
|
|
TdiStatus = TDI_CONN_REFUSED;
|
|
}
|
|
|
|
RWanCompleteConnReq( // MakeCall Fail
|
|
pAf,
|
|
pConnReq,
|
|
TRUE,
|
|
NULL,
|
|
AfSpConnContext,
|
|
TdiStatus
|
|
);
|
|
}
|
|
else
|
|
{
|
|
RWAN_RELEASE_CONN_LOCK(pConnObject);
|
|
}
|
|
}
|
|
//
|
|
// else the Conn Object is gone. A TdiCloseConnection might be
|
|
// (must be?) in progress.
|
|
//
|
|
#if 1
|
|
// XXX: Remove this after debugging.
|
|
pVc = (PRWAN_NDIS_VC)ProtocolVcContext;
|
|
|
|
RWAN_STRUCT_ASSERT(pVc, nvc);
|
|
#endif // 1
|
|
|
|
NdisVcHandle = pVc->NdisVcHandle;
|
|
|
|
//
|
|
// Unlink the VC from the AF it is attached to.
|
|
//
|
|
RWanUnlinkVcFromAf(pVc);
|
|
|
|
//
|
|
// Get rid of the VC.
|
|
//
|
|
Status = NdisCoDeleteVc(NdisVcHandle);
|
|
RWAN_ASSERT(Status == NDIS_STATUS_SUCCESS);
|
|
|
|
RWanFreeVc(pVc); // MakeCall complete fail
|
|
|
|
if (pParty != NULL)
|
|
{
|
|
RWAN_FREE_MEM(pParty); // MakeCall complete fail
|
|
}
|
|
|
|
RWAN_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
|
|
}
|
|
|
|
//
|
|
// Return the Call Parameters structure to the AF-specific module.
|
|
//
|
|
(*pAf->pAfInfo->AfChars.pAfSpReturnNdisOptions)(
|
|
pAf->AfSpAFContext,
|
|
pOriginalParams
|
|
);
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
RWanNdisAddPartyComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolPartyContext,
|
|
IN NDIS_HANDLE NdisPartyHandle,
|
|
IN PCO_CALL_PARAMETERS pCallParameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the NDIS entry indicating completion of a call to NdisClAddParty
|
|
that had pended.
|
|
|
|
Arguments:
|
|
|
|
Status - Final status of the AddParty
|
|
ProtocolPartyContext- Actually a pointer to our NDIS PARTY structure
|
|
NdisPartyHandle - If the AddParty was successful, an NDIS handle for it
|
|
pCallParameters - Final parameters after the AddParty
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PRWAN_NDIS_PARTY pParty;
|
|
PRWAN_TDI_CONNECTION pConnObject;
|
|
PRWAN_TDI_ADDRESS pAddrObject;
|
|
PRWAN_CONN_REQUEST pConnReq;
|
|
PRWAN_NDIS_AF pAf;
|
|
PRWAN_NDIS_VC pVc;
|
|
PCO_CALL_PARAMETERS pOriginalParams; // what was used in the AddParty
|
|
TDI_STATUS TdiStatus;
|
|
BOOLEAN bIsConnClosing;
|
|
RWAN_HANDLE AfSpConnContext;
|
|
#if DBG
|
|
RWAN_IRQL EntryIrq, ExitIrq;
|
|
#endif // DBG
|
|
|
|
RWAN_GET_ENTRY_IRQL(EntryIrq);
|
|
|
|
pParty = (PRWAN_NDIS_PARTY)ProtocolPartyContext;
|
|
RWAN_STRUCT_ASSERT(pParty, npy);
|
|
|
|
pVc = pParty->pVc;
|
|
RWAN_STRUCT_ASSERT(pVc, nvc);
|
|
|
|
pAf = pVc->pNdisAf;
|
|
pConnObject = pParty->pConnObject;
|
|
|
|
RWAN_ACQUIRE_CONN_LOCK(pConnObject);
|
|
|
|
pOriginalParams = pParty->pCallParameters;
|
|
RWAN_ASSERT(pOriginalParams != NULL);
|
|
|
|
pParty->pCallParameters = NULL;
|
|
|
|
RWAN_ASSERT(pConnObject->State == RWANS_CO_OUT_CALL_INITIATED ||
|
|
pConnObject->State == RWANS_CO_DISCON_REQUESTED);
|
|
|
|
//
|
|
// Has the user initiated a TdiCloseConnection() or a TdiDisconnect()
|
|
// while this outgoing call was in progress?
|
|
//
|
|
bIsConnClosing = RWAN_IS_BIT_SET(pConnObject->Flags, RWANF_CO_CLOSING) ||
|
|
(pConnObject->State == RWANS_CO_DISCON_REQUESTED);
|
|
|
|
RWANDEBUGP(DL_LOUD, DC_CONNECT,
|
|
("AddPartyComplete: pConn x%x, State/Flags x%x/x%x, pVc x%x, Pty x%x, Status x%x\n",
|
|
pConnObject, pConnObject->State, pConnObject->Flags, pVc, pParty, Status));
|
|
|
|
//
|
|
// We would have saved context about the TdiConnect(). Get it.
|
|
//
|
|
pConnReq = pConnObject->pConnReq;
|
|
pConnObject->pConnReq = NULL;
|
|
|
|
pVc->AddingPartyCount --;
|
|
|
|
if (Status == NDIS_STATUS_SUCCESS)
|
|
{
|
|
pParty->NdisPartyHandle = NdisPartyHandle;
|
|
|
|
pConnObject->State = RWANS_CO_CONNECTED;
|
|
|
|
//
|
|
// Outgoing party successfully set up.
|
|
//
|
|
pVc->ActivePartyCount ++; // AddParty OK
|
|
|
|
if (!bIsConnClosing)
|
|
{
|
|
AfSpConnContext = pConnObject->AfSpConnContext;
|
|
|
|
RWAN_RELEASE_CONN_LOCK(pConnObject);
|
|
|
|
RWanCompleteConnReq( // AddParty OK
|
|
pAf,
|
|
pConnReq,
|
|
TRUE,
|
|
pCallParameters,
|
|
AfSpConnContext,
|
|
TDI_SUCCESS
|
|
);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Abort this Party.
|
|
//
|
|
RWanDoTdiDisconnect(
|
|
pConnObject,
|
|
NULL, // pTdiRequest
|
|
NULL, // pTimeout
|
|
0, // Flags
|
|
NULL, // pDisconnInfo
|
|
NULL // pReturnInfo
|
|
);
|
|
|
|
//
|
|
// Conn Object lock is released above.
|
|
//
|
|
}
|
|
|
|
RWAN_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// AddParty failed.
|
|
//
|
|
|
|
INT rc;
|
|
|
|
//
|
|
// Unlink the Party from the VC.
|
|
//
|
|
RWAN_DELETE_FROM_LIST(&(pParty->PartyLink));
|
|
|
|
pAddrObject = pConnObject->pAddrObject;
|
|
|
|
rc = RWanDereferenceConnObject(pConnObject); // Party deref: AddParty fail
|
|
|
|
if (rc > 0)
|
|
{
|
|
//
|
|
// Reacquire some locks in the right order.
|
|
//
|
|
RWAN_RELEASE_CONN_LOCK(pConnObject);
|
|
|
|
RWAN_ACQUIRE_ADDRESS_LOCK(pAddrObject);
|
|
RWAN_ACQUIRE_CONN_LOCK_DPC(pConnObject);
|
|
|
|
//
|
|
// Move this Connection to the Idle list.
|
|
//
|
|
RWAN_DELETE_FROM_LIST(&(pConnObject->ConnLink));
|
|
RWAN_INSERT_TAIL_LIST(&(pAddrObject->IdleConnList),
|
|
&(pConnObject->ConnLink));
|
|
|
|
//
|
|
// Send this back to the state it was in before the TdiConnect.
|
|
//
|
|
pConnObject->State = RWANS_CO_ASSOCIATED;
|
|
|
|
AfSpConnContext = pConnObject->AfSpConnContext;
|
|
|
|
RWAN_RELEASE_CONN_LOCK_DPC(pConnObject);
|
|
|
|
RWAN_RELEASE_ADDRESS_LOCK(pAddrObject);
|
|
|
|
//
|
|
// Complete the TdiConnect() with a failure status.
|
|
//
|
|
TdiStatus = RWanNdisToTdiStatus(Status);
|
|
|
|
if (TdiStatus == TDI_NOT_ACCEPTED)
|
|
{
|
|
TdiStatus = TDI_CONN_REFUSED;
|
|
}
|
|
|
|
RWanCompleteConnReq( // JoinLeaf Fail
|
|
pAf,
|
|
pConnReq,
|
|
TRUE,
|
|
NULL,
|
|
AfSpConnContext,
|
|
TdiStatus
|
|
);
|
|
}
|
|
//
|
|
// else the ConnObject is gone.
|
|
//
|
|
|
|
RWAN_FREE_MEM(pParty); // AddParty fail
|
|
|
|
RWAN_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
|
|
}
|
|
|
|
//
|
|
// Return the Call Parameters structure to the AF-specific module.
|
|
//
|
|
(*pAf->pAfInfo->AfChars.pAfSpReturnNdisOptions)(
|
|
pAf->AfSpAFContext,
|
|
pOriginalParams
|
|
);
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NDIS_STATUS
|
|
RWanNdisIncomingCall(
|
|
IN NDIS_HANDLE ProtocolSapContext,
|
|
IN NDIS_HANDLE ProtocolVcContext,
|
|
IN OUT PCO_CALL_PARAMETERS pCallParameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the NDIS entry point announcing a new Incoming call request,
|
|
on the specified SAP.
|
|
|
|
The SAP corresponds to an Address Object. If there are no Listens posted
|
|
on the Address object, we reject this call. Otherwise, we pick up an
|
|
arbitrary listening connection object and indicate this call on that.
|
|
|
|
TBD: support selection of listening conn object based on specified
|
|
remote criteria.
|
|
|
|
Arguments:
|
|
|
|
ProtocolSapContext - Our SAP context is a pointer to an NDIS SAP structure
|
|
ProtocolVcContext - Actually a pointer to our NDIS VC structure
|
|
pCallParameters - Points to Incoming call parameters.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PRWAN_NDIS_SAP pSap;
|
|
PRWAN_NDIS_VC pVc;
|
|
PRWAN_NDIS_AF pAf;
|
|
PRWAN_TDI_ADDRESS pAddrObject;
|
|
BOOLEAN IsAddrLockAcquired;
|
|
PRWAN_TDI_CONNECTION pConnObject;
|
|
PLIST_ENTRY pConnEntry;
|
|
NDIS_STATUS Status;
|
|
TDI_STATUS TdiStatus;
|
|
RWAN_STATUS RWanStatus;
|
|
PRWAN_CONN_REQUEST pConnReq;
|
|
|
|
PConnectEvent pConnInd;
|
|
PTDI_CONNECTION_INFORMATION pTdiInfo;
|
|
RWAN_HANDLE AfSpTdiOptionsContext;
|
|
PVOID pTdiQoS;
|
|
ULONG TdiQoSLength;
|
|
|
|
PVOID ConnIndContext;
|
|
PVOID AcceptConnContext;
|
|
RWAN_HANDLE AfSpConnContext;
|
|
#ifdef NT
|
|
PIO_STACK_LOCATION pIrpSp;
|
|
PTDI_REQUEST_KERNEL_ACCEPT pAcceptReq;
|
|
ConnectEventInfo *EventInfo;
|
|
#else
|
|
ConnectEventInfo EventInfo;
|
|
#endif // NT
|
|
|
|
|
|
pSap = (PRWAN_NDIS_SAP)ProtocolSapContext;
|
|
RWAN_STRUCT_ASSERT(pSap, nsp);
|
|
|
|
pAddrObject = pSap->pAddrObject;
|
|
RWAN_ASSERT(pAddrObject != NULL);
|
|
|
|
pVc = (PRWAN_NDIS_VC)ProtocolVcContext;
|
|
RWAN_STRUCT_ASSERT(pVc, nvc);
|
|
|
|
RWAN_SET_VC_EVENT(pVc, RWANF_VC_EVT_INCALL);
|
|
|
|
pAf = pVc->pNdisAf;
|
|
|
|
RWANDEBUGP(DL_INFO, DC_CONNECT,
|
|
("IncomingCall: pVc x%x, pAddrObj x%x/x%x, pConnInd x%x\n",
|
|
pVc, pAddrObject, pAddrObject->Flags, pAddrObject->pConnInd));
|
|
|
|
//
|
|
// Initialize.
|
|
//
|
|
pTdiInfo = NULL;
|
|
AfSpTdiOptionsContext = NULL;
|
|
pConnReq = NULL;
|
|
|
|
IsAddrLockAcquired = TRUE;
|
|
RWAN_ACQUIRE_ADDRESS_LOCK(pAddrObject);
|
|
|
|
do
|
|
{
|
|
if (RWAN_IS_BIT_SET(pAddrObject->Flags, RWANF_AO_CLOSING))
|
|
{
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
if (pVc->pConnObject != NULL)
|
|
{
|
|
RWAN_ASSERT(FALSE);
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Convert from NDIS Call Parameters to TDI Options.
|
|
//
|
|
RWanStatus = (*pAf->pAfInfo->AfChars.pAfSpNdis2TdiOptions)(
|
|
pAf->AfSpAFContext,
|
|
RWAN_CALLF_INCOMING_CALL|RWAN_CALLF_POINT_TO_POINT,
|
|
pCallParameters,
|
|
&pTdiInfo,
|
|
&pTdiQoS,
|
|
&TdiQoSLength,
|
|
&AfSpTdiOptionsContext
|
|
);
|
|
|
|
if (RWanStatus != RWAN_STATUS_SUCCESS)
|
|
{
|
|
RWANDEBUGP(DL_LOUD, DC_CONNECT,
|
|
("IncomingCall: conversion from NDIS to TDI failed, status x%x\n",
|
|
RWanStatus));
|
|
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
RWAN_ASSERT(pTdiInfo != NULL);
|
|
RWAN_ASSERT(AfSpTdiOptionsContext != NULL);
|
|
|
|
//
|
|
// It has been decided to pass QOS and any provider-specific info
|
|
// as part of TDI options.
|
|
//
|
|
pTdiInfo->Options = pTdiQoS;
|
|
pTdiInfo->OptionsLength = TdiQoSLength;
|
|
|
|
pVc->pCallParameters = pCallParameters;
|
|
RWAN_SET_VC_CALL_PARAMS(pVc, pCallParameters);
|
|
|
|
//
|
|
// Find a listening connection.
|
|
//
|
|
for (pConnEntry = pAddrObject->ListenConnList.Flink;
|
|
pConnEntry != &pAddrObject->ListenConnList;
|
|
pConnEntry = pConnEntry->Flink)
|
|
{
|
|
pConnObject = CONTAINING_RECORD(pConnEntry, RWAN_TDI_CONNECTION, ConnLink);
|
|
RWAN_STRUCT_ASSERT(pConnObject, ntc);
|
|
|
|
RWANDEBUGP(DL_EXTRA_LOUD, DC_CONNECT,
|
|
("Incoming Call: looking at pConnObj x%x, state %d\n",
|
|
pConnObject, pConnObject->State));
|
|
|
|
if (pConnObject->State == RWANS_CO_LISTENING)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pConnEntry != &pAddrObject->ListenConnList)
|
|
{
|
|
//
|
|
// Found a listening connection.
|
|
//
|
|
RWAN_ACQUIRE_CONN_LOCK_DPC(pConnObject);
|
|
|
|
//
|
|
// Move the Connection from the Idle list to the Active list.
|
|
//
|
|
RWAN_DELETE_FROM_LIST(&pConnObject->ConnLink);
|
|
RWAN_INSERT_TAIL_LIST(&pAddrObject->ActiveConnList,
|
|
&pConnObject->ConnLink);
|
|
|
|
RWAN_LINK_CONNECTION_TO_VC(pConnObject, pVc);
|
|
|
|
RWanReferenceConnObject(pConnObject); // VC ref - InCall, Listening conn
|
|
|
|
RWANDEBUGP(DL_LOUD, DC_CONNECT,
|
|
("IncomingCall: pVc x%x, pConnObj x%x is listening, ConnReqFlags x%x\n",
|
|
pVc, pConnObject, pConnObject->pConnReq->Flags));
|
|
|
|
if (pConnObject->pConnReq->pConnInfo)
|
|
{
|
|
*pConnObject->pConnReq->pConnInfo = *pTdiInfo;
|
|
}
|
|
|
|
//
|
|
// Check if it is pre-accepted. If so, tell NDIS that we have
|
|
// accepted the call.
|
|
//
|
|
if (!(pConnObject->pConnReq->Flags & TDI_QUERY_ACCEPT))
|
|
{
|
|
pConnObject->State = RWANS_CO_IN_CALL_ACCEPTING;
|
|
|
|
RWAN_RELEASE_CONN_LOCK_DPC(pConnObject);
|
|
|
|
//
|
|
// Request the media-specific module to update NDIS call parameters.
|
|
//
|
|
if (pAf->pAfInfo->AfChars.pAfSpUpdateNdisOptions)
|
|
{
|
|
(VOID)(*pAf->pAfInfo->AfChars.pAfSpUpdateNdisOptions)(
|
|
pAf->AfSpAFContext,
|
|
pConnObject->AfSpConnContext,
|
|
RWAN_CALLF_INCOMING_CALL|RWAN_CALLF_POINT_TO_POINT,
|
|
pTdiInfo,
|
|
pTdiQoS,
|
|
TdiQoSLength,
|
|
&pCallParameters
|
|
);
|
|
}
|
|
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// It isn't pre-accepted. Complete the pended listen.
|
|
//
|
|
|
|
pConnReq = pConnObject->pConnReq;
|
|
pConnObject->pConnReq = NULL;
|
|
|
|
pConnObject->State = RWANS_CO_IN_CALL_INDICATED;
|
|
|
|
AfSpConnContext = pConnObject->AfSpConnContext;
|
|
|
|
RWAN_RELEASE_CONN_LOCK_DPC(pConnObject);
|
|
|
|
RWAN_RELEASE_ADDRESS_LOCK(pAddrObject);
|
|
|
|
IsAddrLockAcquired = FALSE;
|
|
|
|
RWanCompleteConnReq( // InCall: Listen OK
|
|
pSap->pNdisAf,
|
|
pConnReq,
|
|
FALSE,
|
|
NULL,
|
|
AfSpConnContext,
|
|
TDI_SUCCESS
|
|
);
|
|
|
|
pConnReq = NULL;
|
|
|
|
Status = NDIS_STATUS_PENDING;
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// There wasn't a listening connection available.
|
|
// See if there is a Connect Indication event handler on this
|
|
// Address Object.
|
|
//
|
|
if (pAddrObject->pConnInd == NULL)
|
|
{
|
|
//
|
|
// No event handler. Reject this call.
|
|
//
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Get some resources.
|
|
//
|
|
pConnReq = RWanAllocateConnReq();
|
|
if (pConnReq == NULL)
|
|
{
|
|
Status = NDIS_STATUS_RESOURCES;
|
|
break;
|
|
}
|
|
|
|
pConnInd = pAddrObject->pConnInd;
|
|
ConnIndContext = pAddrObject->ConnIndContext;
|
|
|
|
RWAN_RELEASE_ADDRESS_LOCK(pAddrObject);
|
|
IsAddrLockAcquired = FALSE;
|
|
|
|
RWANDEBUGP(DL_VERY_LOUD, DC_CONNECT,
|
|
("IncomingCall: Will Indicate: pVc x%x, RemAddr x%x/%d, Options x%x/%d\n",
|
|
pVc,
|
|
pTdiInfo->RemoteAddress,
|
|
pTdiInfo->RemoteAddressLength,
|
|
pTdiInfo->Options,
|
|
pTdiInfo->OptionsLength));
|
|
|
|
//
|
|
// Indicate the call to the user.
|
|
//
|
|
TdiStatus = (*pConnInd)(
|
|
ConnIndContext,
|
|
pTdiInfo->RemoteAddressLength,
|
|
pTdiInfo->RemoteAddress,
|
|
pTdiInfo->UserDataLength,
|
|
pTdiInfo->UserData,
|
|
pTdiInfo->OptionsLength,
|
|
pTdiInfo->Options,
|
|
&AcceptConnContext,
|
|
&EventInfo
|
|
);
|
|
|
|
RWANDEBUGP(DL_LOUD, DC_CONNECT,
|
|
("IncomingCall: pVc x%x, pAddrObj x%x, Connect Ind returned x%x\n",
|
|
pVc, pAddrObject, TdiStatus));
|
|
|
|
if (TdiStatus != TDI_MORE_PROCESSING)
|
|
{
|
|
//
|
|
// Connection rejected.
|
|
//
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
|
|
//
|
|
// This connection has been accepted. Collect all information
|
|
// about this implicit TdiAccept Request.
|
|
//
|
|
#ifdef NT
|
|
pIrpSp = IoGetCurrentIrpStackLocation(EventInfo);
|
|
|
|
Status = RWanPrepareIrpForCancel(
|
|
(PRWAN_ENDPOINT) pIrpSp->FileObject->FsContext,
|
|
EventInfo,
|
|
RWanCancelRequest
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// Reject this incoming call.
|
|
//
|
|
break;
|
|
}
|
|
|
|
pAcceptReq = (PTDI_REQUEST_KERNEL_ACCEPT) &(pIrpSp->Parameters);
|
|
|
|
pConnReq->Request.pReqComplete = (PVOID)RWanRequestComplete;
|
|
pConnReq->Request.ReqContext = EventInfo;
|
|
pConnReq->pConnInfo = pAcceptReq->ReturnConnectionInformation;
|
|
#else
|
|
pConnReq->Request.pReqComplete = EventInfo.cei_rtn;
|
|
pConnReq->Request.ReqContext = EventInfo.cei_context;
|
|
pConnReq->pConnInfo = EventInfo.cei_conninfo;
|
|
#endif // NT
|
|
|
|
//
|
|
// Find the connection object on which it has been accepted.
|
|
//
|
|
IsAddrLockAcquired = TRUE;
|
|
RWAN_ACQUIRE_ADDRESS_LOCK(pAddrObject);
|
|
|
|
for (pConnEntry = pAddrObject->IdleConnList.Flink;
|
|
pConnEntry != &pAddrObject->IdleConnList;
|
|
pConnEntry = pConnEntry->Flink)
|
|
{
|
|
pConnObject = CONTAINING_RECORD(pConnEntry, RWAN_TDI_CONNECTION, ConnLink);
|
|
RWAN_STRUCT_ASSERT(pConnObject, ntc);
|
|
|
|
if ((pConnObject->ConnectionHandle == AcceptConnContext) &&
|
|
!(RWAN_IS_BIT_SET(pConnObject->Flags, RWANF_CO_CLOSING)))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (pConnEntry == &pAddrObject->IdleConnList)
|
|
{
|
|
//
|
|
// Invalid connection context!
|
|
//
|
|
TdiStatus = TDI_INVALID_CONNECTION;
|
|
RWAN_RELEASE_ADDRESS_LOCK(pAddrObject);
|
|
|
|
IsAddrLockAcquired = FALSE;
|
|
|
|
//
|
|
// Fail the Accept req
|
|
//
|
|
RWanCompleteConnReq( // InCall: Accept is bad
|
|
pAf,
|
|
pConnReq,
|
|
FALSE,
|
|
NULL,
|
|
NULL,
|
|
TdiStatus
|
|
);
|
|
|
|
pConnReq = NULL;
|
|
|
|
//
|
|
// Reject the incoming call
|
|
//
|
|
Status = NDIS_STATUS_FAILURE;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Request the media-specific module to update NDIS call parameters.
|
|
//
|
|
if (pAf->pAfInfo->AfChars.pAfSpUpdateNdisOptions)
|
|
{
|
|
(VOID)(*pAf->pAfInfo->AfChars.pAfSpUpdateNdisOptions)(
|
|
pAf->AfSpAFContext,
|
|
pConnObject->AfSpConnContext,
|
|
RWAN_CALLF_INCOMING_CALL|RWAN_CALLF_POINT_TO_POINT,
|
|
pTdiInfo,
|
|
pTdiQoS,
|
|
TdiQoSLength,
|
|
&pCallParameters
|
|
);
|
|
}
|
|
|
|
//
|
|
// Set up the Connection Object for accepting this call.
|
|
//
|
|
RWAN_ACQUIRE_CONN_LOCK_DPC(pConnObject);
|
|
|
|
pConnObject->State = RWANS_CO_IN_CALL_ACCEPTING;
|
|
|
|
//
|
|
// Save info to help us complete the Accept Req when
|
|
// we get a CallConnected from NDIS.
|
|
//
|
|
RWAN_ASSERT(pConnObject->pConnReq == NULL);
|
|
pConnObject->pConnReq = pConnReq;
|
|
|
|
//
|
|
// Move the Connection from the Idle list to the Active list.
|
|
//
|
|
RWAN_DELETE_FROM_LIST(&pConnObject->ConnLink);
|
|
RWAN_INSERT_TAIL_LIST(&pAddrObject->ActiveConnList,
|
|
&pConnObject->ConnLink);
|
|
|
|
RWAN_LINK_CONNECTION_TO_VC(pConnObject, pVc);
|
|
|
|
RWanReferenceConnObject(pConnObject); // VC ref
|
|
|
|
RWAN_RELEASE_CONN_LOCK_DPC(pConnObject);
|
|
|
|
//
|
|
// Accept the call.
|
|
//
|
|
Status = NDIS_STATUS_SUCCESS;
|
|
break;
|
|
|
|
}
|
|
while (FALSE);
|
|
|
|
if (IsAddrLockAcquired)
|
|
{
|
|
RWAN_RELEASE_ADDRESS_LOCK(pAddrObject);
|
|
}
|
|
|
|
//
|
|
// If we are rejecting this call, clean up.
|
|
//
|
|
if ((Status != NDIS_STATUS_SUCCESS) &&
|
|
(Status != NDIS_STATUS_PENDING))
|
|
{
|
|
if (pConnReq != NULL)
|
|
{
|
|
RWanFreeConnReq(pConnReq);
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Return TDI options space to the media-specific module.
|
|
//
|
|
if (pTdiInfo != NULL)
|
|
{
|
|
RWAN_ASSERT(pAf);
|
|
RWAN_ASSERT(AfSpTdiOptionsContext);
|
|
|
|
(*pAf->pAfInfo->AfChars.pAfSpReturnTdiOptions)(
|
|
pAf->AfSpAFContext,
|
|
AfSpTdiOptionsContext
|
|
);
|
|
}
|
|
|
|
RWANDEBUGP(DL_LOUD, DC_CONNECT,
|
|
("IncomingCall: pVc x%x, returning status x%x\n", pVc, Status));
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
RWanNdisCallConnected(
|
|
IN NDIS_HANDLE ProtocolVcContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the NDIS entry point signifying successful setup of an
|
|
incoming call. If required, we complete the TDI user's Accept Request
|
|
here.
|
|
|
|
This primitive can happen only when the call is in the "Accepting" state.
|
|
|
|
Arguments:
|
|
|
|
ProtocolVcContext - Actually a pointer to our NDIS VC structure
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PRWAN_NDIS_VC pVc;
|
|
PRWAN_TDI_CONNECTION pConnObject;
|
|
PRWAN_TDI_ADDRESS pAddrObject;
|
|
NDIS_HANDLE NdisVcHandle;
|
|
NDIS_STATUS Status;
|
|
PRWAN_CONN_REQUEST pConnReq;
|
|
RWAN_HANDLE AfSpConnContext;
|
|
ULONG rc;
|
|
BOOLEAN IsAborting = FALSE;
|
|
|
|
|
|
pVc = (PRWAN_NDIS_VC) ProtocolVcContext;
|
|
RWAN_STRUCT_ASSERT(pVc, nvc);
|
|
RWAN_ASSERT(pVc->pConnObject != NULL_PRWAN_TDI_CONNECTION);
|
|
|
|
pConnObject = pVc->pConnObject;
|
|
RWAN_STRUCT_ASSERT(pConnObject, ntc);
|
|
|
|
pAddrObject = pConnObject->pAddrObject;
|
|
|
|
RWAN_ACQUIRE_CONN_LOCK(pConnObject);
|
|
|
|
RWAN_SET_VC_EVENT(pVc, RWANF_VC_EVT_CALLCONN);
|
|
|
|
IsAborting = ((pConnObject->State != RWANS_CO_IN_CALL_ACCEPTING) ||
|
|
RWAN_IS_BIT_SET(pConnObject->Flags, RWANF_CO_CLOSING));
|
|
|
|
//
|
|
// Incoming Connection setup successfully.
|
|
//
|
|
if (!IsAborting)
|
|
{
|
|
pConnObject->State = RWANS_CO_CONNECTED;
|
|
}
|
|
|
|
//
|
|
// Add a temp ref to keep the conn object from going away.
|
|
//
|
|
RWanReferenceConnObject(pConnObject); // Temp ref, CallConn
|
|
|
|
//
|
|
// If we have an Accept Request to complete, complete it
|
|
// now. Note that we might not have one pending in case
|
|
// we had a pre-accepted listen.
|
|
//
|
|
pConnReq = pConnObject->pConnReq;
|
|
pConnObject->pConnReq = NULL;
|
|
|
|
AfSpConnContext = pConnObject->AfSpConnContext;
|
|
|
|
RWAN_RELEASE_CONN_LOCK(pConnObject);
|
|
|
|
if (pConnReq != NULL)
|
|
{
|
|
//
|
|
// Complete the Accept request.
|
|
//
|
|
RWanCompleteConnReq( // CallConnected: Accept OK
|
|
pVc->pNdisAf,
|
|
pConnReq,
|
|
FALSE,
|
|
NULL,
|
|
AfSpConnContext,
|
|
TDI_SUCCESS
|
|
);
|
|
}
|
|
|
|
//
|
|
// Trigger off data indications for any packets that were received and queued
|
|
// while we were in the process of accepting the call.
|
|
//
|
|
RWAN_ACQUIRE_CONN_LOCK(pConnObject);
|
|
|
|
rc = RWanDereferenceConnObject(pConnObject); // Temp ref - CallConn
|
|
|
|
//
|
|
// But first make sure that the connection still exists and is in a good
|
|
// state.
|
|
//
|
|
if (rc != 0)
|
|
{
|
|
if (!IsAborting)
|
|
{
|
|
RWanIndicateData(pConnObject);
|
|
}
|
|
else
|
|
{
|
|
RWAN_RELEASE_CONN_LOCK(pConnObject);
|
|
|
|
RWANDEBUGP(DL_FATAL, DC_WILDCARD,
|
|
("CallConn: ConnObj %x/%x, State %d, aborting\n",
|
|
pConnObject, pConnObject->Flags, pConnObject->State));
|
|
RWanDoAbortConnection(pConnObject);
|
|
}
|
|
}
|
|
//
|
|
// else the Connection is gone!
|
|
//
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
RWanNdisIncomingCloseCall(
|
|
IN NDIS_STATUS CloseStatus,
|
|
IN NDIS_HANDLE ProtocolVcContext,
|
|
IN PVOID pCloseData,
|
|
IN UINT CloseDataLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the NDIS entry point called when a connection is torn
|
|
down by the remote peer or network. We mark the affected endpoint,
|
|
and if possible, indicate a Disconnect Event to the user. If we
|
|
do indicate to the user, call teardown is continued when the
|
|
user calls TdiDisconnect.
|
|
|
|
This primitive can happen while the endpoint is in one of these
|
|
states:
|
|
(1) Connected
|
|
(2) Accepting incoming call (TdiAccept pending)
|
|
|
|
Arguments:
|
|
|
|
CloseStatus - Status for the incoming close
|
|
ProtocolVcContext - Actually a pointer to our NDIS VC structure
|
|
pCloseData - Data/options associated with the close - NOT USED
|
|
CloseDataLength - Length of the above - NOT USED
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PRWAN_NDIS_VC pVc;
|
|
PRWAN_NDIS_PARTY pParty;
|
|
PRWAN_NDIS_AF pAf;
|
|
PRWAN_TDI_CONNECTION pConnObject;
|
|
PRWAN_CONN_REQUEST pConnReq;
|
|
NDIS_HANDLE NdisVcHandle;
|
|
BOOLEAN bIsConnClosing; // TdiCloseConnection?
|
|
BOOLEAN bScheduleDisconnect;
|
|
RWAN_HANDLE AfSpConnContext;
|
|
|
|
pVc = (PRWAN_NDIS_VC)ProtocolVcContext;
|
|
RWAN_STRUCT_ASSERT(pVc, nvc);
|
|
|
|
if (!RWAN_IS_BIT_SET(pVc->Flags, RWANF_VC_PMP))
|
|
{
|
|
pConnObject = pVc->pConnObject;
|
|
pParty = NULL;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Locate the connection object for the last leaf.
|
|
//
|
|
pParty = CONTAINING_RECORD(pVc->NdisPartyList.Flink, RWAN_NDIS_PARTY, PartyLink);
|
|
RWAN_STRUCT_ASSERT(pParty, npy);
|
|
|
|
pConnObject = pParty->pConnObject;
|
|
}
|
|
|
|
RWAN_ASSERT(pConnObject != NULL_PRWAN_TDI_CONNECTION);
|
|
RWAN_STRUCT_ASSERT(pConnObject, ntc);
|
|
|
|
RWANDEBUGP(DL_INFO, DC_DISCON,
|
|
("IncomingClose: pVc x%x, pConnObj x%x/x%x, pParty x%x\n",
|
|
pVc, pConnObject, pConnObject->Flags, pParty));
|
|
|
|
RWAN_ACQUIRE_CONN_LOCK(pConnObject);
|
|
|
|
RWAN_SET_VC_EVENT(pVc, RWANF_VC_EVT_INCLOSE);
|
|
|
|
NdisVcHandle = pVc->NdisVcHandle;
|
|
|
|
bIsConnClosing = RWAN_IS_BIT_SET(pConnObject->Flags, RWANF_CO_CLOSING);
|
|
|
|
if (bIsConnClosing)
|
|
{
|
|
//
|
|
// The user has initiated a TdiCloseConnection.
|
|
// Continue NDIS call teardown. When this completes,
|
|
// we'll complete the CloseConnection.
|
|
//
|
|
RWanStartCloseCall(pConnObject, pVc);
|
|
return;
|
|
}
|
|
|
|
pAf = pVc->pNdisAf;
|
|
|
|
switch (pConnObject->State)
|
|
{
|
|
case RWANS_CO_IN_CALL_ACCEPTING:
|
|
//
|
|
// If we have a pended Accept Request, fail it now.
|
|
// Otherwise, we must have had a pre-accepted listen,
|
|
// so we fall through and indicate a Disconnect.
|
|
//
|
|
pConnReq = pConnObject->pConnReq;
|
|
pConnObject->pConnReq = NULL;
|
|
|
|
if (pConnReq != NULL)
|
|
{
|
|
//
|
|
// Fix the state so that TdiDisconnect does the right thing
|
|
//
|
|
pConnObject->State = RWANS_CO_DISCON_INDICATED;
|
|
|
|
AfSpConnContext = pConnObject->AfSpConnContext;
|
|
|
|
RWanScheduleDisconnect(pConnObject);
|
|
//
|
|
// Conn Lock is released within the above.
|
|
//
|
|
|
|
RWanCompleteConnReq( // Incoming Close during IN_CALL_ACCEPT
|
|
pAf,
|
|
pConnReq,
|
|
FALSE,
|
|
NULL,
|
|
AfSpConnContext,
|
|
TDI_CONNECTION_ABORTED
|
|
);
|
|
break;
|
|
}
|
|
//
|
|
// else this must be a pre-accepted listen.
|
|
//
|
|
// FALLTHRU on "else" to RWANS_CO_CONNECTED
|
|
//
|
|
|
|
case RWANS_CO_CONNECTED:
|
|
//
|
|
// If there is a Disconnect Event handler, call it.
|
|
// Otherwise, simply mark this endpoint as having
|
|
// seen a Disconnect.
|
|
//
|
|
bScheduleDisconnect = TRUE;
|
|
if (pConnObject->pAddrObject != NULL_PRWAN_TDI_ADDRESS)
|
|
{
|
|
PDisconnectEvent pDisconInd;
|
|
PVOID IndContext;
|
|
PVOID ConnectionHandle;
|
|
|
|
pDisconInd = pConnObject->pAddrObject->pDisconInd;
|
|
IndContext = pConnObject->pAddrObject->DisconIndContext;
|
|
|
|
//
|
|
// Don't send up a Disconnect Indication if we are in the
|
|
// middle of indicating data.
|
|
//
|
|
if ((pDisconInd != NULL) &&
|
|
!(RWAN_IS_BIT_SET(pConnObject->Flags, RWANF_CO_INDICATING_DATA)))
|
|
{
|
|
RWANDEBUGP(DL_INFO, DC_WILDCARD,
|
|
("IncomingClose: pConnObj %x/%x, st %x, will discon ind\n",
|
|
pConnObject, pConnObject->Flags, pConnObject->State));
|
|
|
|
pConnObject->State = RWANS_CO_DISCON_INDICATED;
|
|
ConnectionHandle = pConnObject->ConnectionHandle;
|
|
|
|
//
|
|
// Schedule a work item to continue Disconnect
|
|
// first. This is because the call to DiscInd can
|
|
// lead to a call to CloseConnection and block there.
|
|
//
|
|
bScheduleDisconnect = FALSE;
|
|
RWanScheduleDisconnect(pConnObject);
|
|
|
|
(*pDisconInd)(
|
|
IndContext,
|
|
ConnectionHandle,
|
|
0, // Disconnect Data Length
|
|
NULL, // Disconnect Data
|
|
0, // Disconnect Info Length
|
|
NULL, // Disconnect Info
|
|
TDI_DISCONNECT_RELEASE
|
|
);
|
|
|
|
}
|
|
else
|
|
{
|
|
RWANDEBUGP(DL_FATAL, DC_DISCON,
|
|
("IncomingClose: pConnObj %x/%x, pending discon\n",
|
|
pConnObject, pConnObject->Flags));
|
|
|
|
pConnObject->State = RWANS_CO_DISCON_HELD;
|
|
RWAN_SET_BIT(pConnObject->Flags, RWANF_CO_PENDED_DISCON);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pConnObject->State = RWANS_CO_DISCON_HELD;
|
|
}
|
|
|
|
if (bScheduleDisconnect)
|
|
{
|
|
RWanScheduleDisconnect(pConnObject);
|
|
//
|
|
// Conn Object lock is released within the above.
|
|
//
|
|
}
|
|
|
|
break;
|
|
|
|
case RWANS_CO_ABORTING:
|
|
case RWANS_CO_DISCON_REQUESTED:
|
|
//
|
|
// Ignore this.
|
|
//
|
|
RWAN_RELEASE_CONN_LOCK(pConnObject);
|
|
break;
|
|
|
|
default:
|
|
|
|
RWAN_ASSERT(FALSE);
|
|
RWAN_RELEASE_CONN_LOCK(pConnObject);
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
RWanNdisCloseCallComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolVcContext,
|
|
IN NDIS_HANDLE ProtocolPartyContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The NDIS entry point that is called when a previous pended call
|
|
we made to NdisClCloseCall has completed.
|
|
|
|
Arguments:
|
|
|
|
Status - Final status of CloseCall
|
|
ProtocolVcContext - Actually a pointer to our NDIS VC structure
|
|
ProtocolPartyContext- Last party context, points to NDIS PARTY structure
|
|
if this is a point-to-multipoint call.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PRWAN_NDIS_VC pVc;
|
|
PRWAN_NDIS_PARTY pParty;
|
|
PRWAN_NDIS_AF pAf;
|
|
PRWAN_TDI_CONNECTION pConnObject;
|
|
PRWAN_TDI_CONNECTION pRootConnObject;
|
|
INT rc;
|
|
PRWAN_CONN_REQUEST pConnReq;
|
|
BOOLEAN IsOutgoingCall;
|
|
RWAN_HANDLE AfSpConnContext;
|
|
|
|
#ifndef NO_POST_DISCON
|
|
PDisconnectEvent pDisconInd;
|
|
PVOID IndContext;
|
|
PVOID ConnectionHandle;
|
|
#endif // !NO_POST_DISCON
|
|
|
|
RWAN_ASSERT(Status == NDIS_STATUS_SUCCESS);
|
|
|
|
pVc = (PRWAN_NDIS_VC)ProtocolVcContext;
|
|
RWAN_STRUCT_ASSERT(pVc, nvc);
|
|
|
|
RWAN_SET_VC_EVENT(pVc, RWANF_VC_EVT_CLOSECOMP);
|
|
|
|
//
|
|
// Check if this is a point-to-multipoint call.
|
|
//
|
|
pParty = (PRWAN_NDIS_PARTY)ProtocolPartyContext;
|
|
|
|
if (ProtocolPartyContext == NULL)
|
|
{
|
|
//
|
|
// Point to point call.
|
|
//
|
|
pConnObject = pVc->pConnObject;
|
|
pRootConnObject = NULL;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// PMP Call.
|
|
//
|
|
RWAN_STRUCT_ASSERT(pParty, npy);
|
|
|
|
pConnObject = pParty->pConnObject;
|
|
pRootConnObject = pConnObject->pRootConnObject;
|
|
}
|
|
|
|
RWANDEBUGP(DL_INFO, DC_DISCON,
|
|
("CloseCallComplete: pVc x%x, pPty x%x, pConnObj x%x, pRoot x%x\n",
|
|
pVc, pParty, pVc->pConnObject, pRootConnObject));
|
|
|
|
if (pConnObject != NULL)
|
|
{
|
|
RWAN_ACQUIRE_CONN_LOCK(pConnObject);
|
|
|
|
//
|
|
// A pended Disconnect Request may be around.
|
|
//
|
|
pConnReq = pConnObject->pConnReq;
|
|
pConnObject->pConnReq = NULL;
|
|
|
|
pAf = pVc->pNdisAf;
|
|
|
|
IsOutgoingCall = RWAN_IS_BIT_SET(pVc->Flags, RWANF_VC_OUTGOING);
|
|
|
|
//
|
|
// State change:
|
|
//
|
|
if (pConnObject->State != RWANS_CO_ABORTING)
|
|
{
|
|
pConnObject->State = ((pConnObject->pAddrObject != NULL) ?
|
|
RWANS_CO_ASSOCIATED:
|
|
RWANS_CO_CREATED);
|
|
}
|
|
|
|
if (pParty == NULL)
|
|
{
|
|
//
|
|
// Unlink the VC from the Connection Object.
|
|
//
|
|
RWAN_UNLINK_CONNECTION_AND_VC(pConnObject, pVc); // CloseCallComplete
|
|
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// PMP Call. The VC is linked to the root Conn Object.
|
|
//
|
|
RWAN_STRUCT_ASSERT(pRootConnObject, ntc);
|
|
|
|
RWAN_ACQUIRE_CONN_LOCK(pRootConnObject);
|
|
|
|
pRootConnObject->State = ((pRootConnObject->pAddrObject != NULL) ?
|
|
RWANS_CO_ASSOCIATED:
|
|
RWANS_CO_CREATED);
|
|
|
|
pVc->DroppingPartyCount --; // CloseCallComplete (PMP)
|
|
|
|
RWAN_UNLINK_CONNECTION_AND_VC(pRootConnObject, pVc); // CloseCallCompletePMP
|
|
|
|
rc = RWanDereferenceConnObject(pRootConnObject); // VC deref in CloseCallCompletePMP
|
|
|
|
if (rc > 0)
|
|
{
|
|
RWAN_RELEASE_CONN_LOCK(pRootConnObject);
|
|
}
|
|
|
|
//
|
|
// Unlink the Party from the VC and Leaf Conn Object.
|
|
//
|
|
pParty->pVc = NULL;
|
|
RWAN_DELETE_FROM_LIST(&(pParty->PartyLink));
|
|
|
|
pParty->pConnObject = NULL;
|
|
pConnObject->NdisConnection.pNdisParty = NULL;
|
|
}
|
|
|
|
AfSpConnContext = pConnObject->AfSpConnContext;
|
|
|
|
#ifndef NO_POST_DISCON
|
|
if (pConnObject->pAddrObject != NULL_PRWAN_TDI_ADDRESS)
|
|
{
|
|
|
|
pDisconInd = pConnObject->pAddrObject->pDisconInd;
|
|
IndContext = pConnObject->pAddrObject->DisconIndContext;
|
|
|
|
ConnectionHandle = pConnObject->ConnectionHandle;
|
|
}
|
|
else
|
|
{
|
|
pDisconInd = NULL;
|
|
}
|
|
#endif // NO_POST_DISCON
|
|
|
|
rc = RWanDereferenceConnObject(pConnObject); // VC/Pty deref in CloseCallComplete
|
|
|
|
if (rc > 0)
|
|
{
|
|
RWAN_RELEASE_CONN_LOCK(pConnObject);
|
|
}
|
|
|
|
if (pConnReq != NULL)
|
|
{
|
|
#ifndef NO_POST_DISCON
|
|
if (pDisconInd != NULL)
|
|
{
|
|
(*pDisconInd)(
|
|
IndContext,
|
|
ConnectionHandle,
|
|
0, // Disconnect Data Length
|
|
NULL, // Disconnect Data
|
|
0, // Disconnect Info Length
|
|
NULL, // Disconnect Info
|
|
TDI_DISCONNECT_ABORT
|
|
);
|
|
}
|
|
#endif // !NO_POST_DISCON
|
|
|
|
RWanCompleteConnReq( // CloseCallComplete - completing discon req
|
|
pAf,
|
|
pConnReq,
|
|
IsOutgoingCall,
|
|
NULL,
|
|
AfSpConnContext,
|
|
TDI_SUCCESS
|
|
);
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// See if the VC was created by us. If so, call NDIS to delete it,
|
|
// and free it.
|
|
//
|
|
if (RWAN_IS_BIT_SET(pVc->Flags, RWANF_VC_OUTGOING))
|
|
{
|
|
NDIS_HANDLE NdisVcHandle;
|
|
|
|
NdisVcHandle = pVc->NdisVcHandle;
|
|
|
|
//
|
|
// Unlink the VC from the list of VCs on the AF block
|
|
//
|
|
RWanUnlinkVcFromAf(pVc);
|
|
|
|
Status = NdisCoDeleteVc(NdisVcHandle);
|
|
RWAN_ASSERT(Status == NDIS_STATUS_SUCCESS);
|
|
|
|
RWanFreeVc(pVc);
|
|
}
|
|
//
|
|
// Otherwise this VC was created by the Call Manager.
|
|
// Leave it as it is.
|
|
//
|
|
|
|
if (pParty != NULL)
|
|
{
|
|
RWAN_FREE_MEM(pParty); // CloseCallComplete PMP
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
RWanNdisDropPartyComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE ProtocolPartyContext
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the NDIS entry point signifying completion of a previous
|
|
call to NdisClDropParty that had pended.
|
|
|
|
We locate and complete the TDI Disconnect, if any, that lead to this.
|
|
|
|
Arguments:
|
|
|
|
Status - Final status of the Drop party request
|
|
ProtocolPartyContext- Actually a pointer to our NDIS PARTY structure
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PRWAN_NDIS_PARTY pParty;
|
|
PRWAN_NDIS_VC pVc;
|
|
PRWAN_NDIS_AF pAf;
|
|
PRWAN_TDI_CONNECTION pConnObject;
|
|
PRWAN_TDI_CONNECTION pRootConnObject;
|
|
PRWAN_CONN_REQUEST pConnReq;
|
|
ULONG rc;
|
|
BOOLEAN IsOutgoingCall = TRUE;
|
|
BOOLEAN bVcNeedsClose;
|
|
RWAN_HANDLE AfSpConnContext;
|
|
#ifndef NO_POST_DISCON
|
|
PDisconnectEvent pDisconInd;
|
|
PVOID IndContext;
|
|
PVOID ConnectionHandle;
|
|
#endif // !NO_POST_DISCON
|
|
|
|
RWAN_ASSERT(Status == NDIS_STATUS_SUCCESS);
|
|
|
|
pParty = (PRWAN_NDIS_PARTY)ProtocolPartyContext;
|
|
RWAN_STRUCT_ASSERT(pParty, npy);
|
|
|
|
pVc = pParty->pVc;
|
|
|
|
pConnObject = pParty->pConnObject;
|
|
|
|
if (pConnObject != NULL)
|
|
{
|
|
RWAN_ACQUIRE_CONN_LOCK(pConnObject);
|
|
|
|
//
|
|
// A pended Disconnect Request may be around.
|
|
//
|
|
pConnReq = pConnObject->pConnReq;
|
|
pConnObject->pConnReq = NULL;
|
|
|
|
pAf = pVc->pNdisAf;
|
|
|
|
//
|
|
// State change:
|
|
//
|
|
if (pConnObject->State != RWANS_CO_ABORTING)
|
|
{
|
|
pConnObject->State = ((pConnObject->pAddrObject != NULL) ?
|
|
RWANS_CO_ASSOCIATED:
|
|
RWANS_CO_CREATED);
|
|
}
|
|
|
|
AfSpConnContext = pConnObject->AfSpConnContext;
|
|
|
|
pRootConnObject = pVc->pConnObject;
|
|
RWAN_STRUCT_ASSERT(pRootConnObject, ntc);
|
|
|
|
#if DBG
|
|
if (pConnObject->pAddrObject != NULL)
|
|
{
|
|
RWAN_ASSERT(pRootConnObject == pConnObject->pAddrObject->pRootConnObject);
|
|
}
|
|
#endif // DBG
|
|
|
|
#ifndef NO_POST_DISCON
|
|
if (pConnObject->pAddrObject != NULL_PRWAN_TDI_ADDRESS)
|
|
{
|
|
|
|
pDisconInd = pConnObject->pAddrObject->pDisconInd;
|
|
IndContext = pConnObject->pAddrObject->DisconIndContext;
|
|
|
|
ConnectionHandle = pConnObject->ConnectionHandle;
|
|
}
|
|
else
|
|
{
|
|
pDisconInd = NULL;
|
|
}
|
|
#endif // NO_POST_DISCON
|
|
|
|
pConnObject->NdisConnection.pNdisParty = NULL;
|
|
rc = RWanDereferenceConnObject(pConnObject); // Pty deref in DropPartyComplete
|
|
|
|
if (rc > 0)
|
|
{
|
|
RWAN_RELEASE_CONN_LOCK(pConnObject);
|
|
}
|
|
|
|
if (pConnReq != NULL)
|
|
{
|
|
#ifndef NO_POST_DISCON
|
|
if (pDisconInd != NULL)
|
|
{
|
|
(*pDisconInd)(
|
|
IndContext,
|
|
ConnectionHandle,
|
|
0, // Disconnect Data Length
|
|
NULL, // Disconnect Data
|
|
0, // Disconnect Info Length
|
|
NULL, // Disconnect Info
|
|
TDI_DISCONNECT_ABORT
|
|
);
|
|
}
|
|
#endif // NO_POST_DISCON
|
|
RWanCompleteConnReq( // DropPartyComplete - completing discon req
|
|
pAf,
|
|
pConnReq,
|
|
IsOutgoingCall,
|
|
NULL,
|
|
AfSpConnContext,
|
|
TDI_SUCCESS
|
|
);
|
|
}
|
|
|
|
//
|
|
// The Root Connection object lock controls access to
|
|
// the VC structure.
|
|
//
|
|
RWAN_ACQUIRE_CONN_LOCK(pRootConnObject);
|
|
|
|
//
|
|
// Unlink the Party from the VC.
|
|
//
|
|
RWAN_DELETE_FROM_LIST(&(pParty->PartyLink));
|
|
pVc->DroppingPartyCount --; // DropPartyComplete
|
|
|
|
//
|
|
// We may be in the process of shutting down this connection.
|
|
// This may be the penultimate Party going away. If so,
|
|
// continue the call close.
|
|
//
|
|
if (RWAN_IS_BIT_SET(pVc->Flags, RWANF_VC_NEEDS_CLOSE))
|
|
{
|
|
RWanStartCloseCall(pRootConnObject, pVc);
|
|
//
|
|
// Root Conn lock is released within the above.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
RWAN_RELEASE_CONN_LOCK(pRootConnObject);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Not sure if we can be here.
|
|
//
|
|
RWAN_ASSERT(FALSE);
|
|
}
|
|
|
|
|
|
//
|
|
// End of the road for this Party structure.
|
|
//
|
|
RWAN_FREE_MEM(pParty); // DropParty Complete
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
RWanNdisIncomingDropParty(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE OurPartyContext,
|
|
IN PVOID pBuffer,
|
|
IN UINT BufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the NDIS entry point notifying us that a leaf of a PMP call is
|
|
being dropped, either because the remote station terminated its session
|
|
or because of network conditions.
|
|
|
|
We simply inform the TDI client of a Disconnect on the Connection Object
|
|
representing this leaf, similar to an incoming Close on a VC.
|
|
|
|
Arguments:
|
|
|
|
Status - Status code for the Drop party
|
|
OurPartyContext - Pointer to our Party structure
|
|
pBuffer - Optional accompanying info (ignored)
|
|
BufferLength - Length of above (ignored)
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PRWAN_NDIS_PARTY pParty;
|
|
PRWAN_NDIS_VC pVc;
|
|
PRWAN_TDI_CONNECTION pConnObject;
|
|
PRWAN_CONN_REQUEST pConnReq;
|
|
NDIS_HANDLE NdisPartyHandle;
|
|
BOOLEAN bIsConnClosing; // TdiCloseConnection?
|
|
BOOLEAN bIsLastLeaf;
|
|
BOOLEAN bScheduleDisconnect;
|
|
|
|
pParty = (PRWAN_NDIS_PARTY)OurPartyContext;
|
|
RWAN_STRUCT_ASSERT(pParty, npy);
|
|
|
|
pVc = pParty->pVc;
|
|
RWAN_STRUCT_ASSERT(pVc, nvc);
|
|
|
|
RWANDEBUGP(DL_INFO, DC_DISCON,
|
|
("IncomingDrop: pPty x%x, pVc x%x, pConnObj x%x, AddingCnt %d, ActiveCnt %d\n",
|
|
pParty, pVc, pParty->pConnObject, pVc->AddingPartyCount, pVc->ActivePartyCount));
|
|
|
|
pConnObject = pParty->pConnObject;
|
|
|
|
RWAN_ASSERT(pConnObject != NULL_PRWAN_TDI_CONNECTION);
|
|
RWAN_STRUCT_ASSERT(pConnObject, ntc);
|
|
|
|
RWAN_ACQUIRE_CONN_LOCK(pConnObject);
|
|
|
|
bIsLastLeaf = (pVc->AddingPartyCount + pVc->ActivePartyCount == 0);
|
|
|
|
bIsConnClosing = RWAN_IS_BIT_SET(pConnObject->Flags, RWANF_CO_CLOSING);
|
|
|
|
if (bIsConnClosing)
|
|
{
|
|
//
|
|
// The user has initiated a TdiCloseConnection.
|
|
// Continue NDIS call teardown. When this completes,
|
|
// we'll complete the CloseConnection.
|
|
//
|
|
if (bIsLastLeaf)
|
|
{
|
|
RWanStartCloseCall(pConnObject, pVc);
|
|
|
|
//
|
|
// Conn Lock is released within the above.
|
|
//
|
|
}
|
|
else
|
|
{
|
|
NdisPartyHandle = pParty->NdisPartyHandle;
|
|
|
|
RWAN_RELEASE_CONN_LOCK(pConnObject);
|
|
|
|
Status = NdisClDropParty(
|
|
NdisPartyHandle,
|
|
NULL, // No Drop Data
|
|
0 // Length of above
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
RWanNdisDropPartyComplete(
|
|
Status,
|
|
(NDIS_HANDLE)pParty
|
|
);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
switch (pConnObject->State)
|
|
{
|
|
case RWANS_CO_IN_CALL_ACCEPTING:
|
|
|
|
RWAN_ASSERT(FALSE);
|
|
RWAN_RELEASE_CONN_LOCK(pConnObject);
|
|
break;
|
|
|
|
case RWANS_CO_CONNECTED:
|
|
//
|
|
// If there is a Disconnect Event handler, call it.
|
|
// Otherwise, simply mark this endpoint as having
|
|
// seen a Disconnect.
|
|
//
|
|
bScheduleDisconnect = TRUE;
|
|
if (pConnObject->pAddrObject != NULL_PRWAN_TDI_ADDRESS)
|
|
{
|
|
PDisconnectEvent pDisconInd;
|
|
PVOID IndContext;
|
|
PVOID ConnectionHandle;
|
|
|
|
pDisconInd = pConnObject->pAddrObject->pDisconInd;
|
|
IndContext = pConnObject->pAddrObject->DisconIndContext;
|
|
|
|
if (pDisconInd != NULL)
|
|
{
|
|
pConnObject->State = RWANS_CO_DISCON_INDICATED;
|
|
ConnectionHandle = pConnObject->ConnectionHandle;
|
|
|
|
bScheduleDisconnect = FALSE;
|
|
|
|
RWanScheduleDisconnect(pConnObject);
|
|
//
|
|
// Conn Object lock is released within the above.
|
|
//
|
|
|
|
RWANDEBUGP(DL_EXTRA_LOUD, DC_DISCON,
|
|
("IncomingDrop: will indicate Discon, pConnObj x%x, pAddrObj x%x\n",
|
|
pConnObject, pConnObject->pAddrObject));
|
|
|
|
(*pDisconInd)(
|
|
IndContext,
|
|
ConnectionHandle,
|
|
0, // Disconnect Data Length
|
|
NULL, // Disconnect Data
|
|
0, // Disconnect Info Length
|
|
NULL, // Disconnect Info
|
|
TDI_DISCONNECT_ABORT
|
|
);
|
|
}
|
|
else
|
|
{
|
|
pConnObject->State = RWANS_CO_DISCON_HELD;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pConnObject->State = RWANS_CO_DISCON_HELD;
|
|
}
|
|
|
|
if (bScheduleDisconnect)
|
|
{
|
|
RWanScheduleDisconnect(pConnObject);
|
|
//
|
|
// Conn Object lock is released within the above.
|
|
//
|
|
}
|
|
|
|
break;
|
|
|
|
case RWANS_CO_ABORTING:
|
|
case RWANS_CO_DISCON_REQUESTED:
|
|
//
|
|
// Ignore this.
|
|
//
|
|
RWAN_RELEASE_CONN_LOCK(pConnObject);
|
|
break;
|
|
|
|
default:
|
|
|
|
RWAN_ASSERT(FALSE);
|
|
RWAN_RELEASE_CONN_LOCK(pConnObject);
|
|
break;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
RWanNdisModifyQoSComplete(
|
|
IN NDIS_STATUS Status,
|
|
IN NDIS_HANDLE OurVcContext,
|
|
IN PCO_CALL_PARAMETERS pCallParameters
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
//
|
|
// Not expected, since we don't call NdisClModifyCallQoS
|
|
//
|
|
RWAN_ASSERT(FALSE);
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
RWanNdisRejectIncomingCall(
|
|
IN PRWAN_TDI_CONNECTION pConnObject,
|
|
IN NDIS_STATUS RejectStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reject the incoming call present on the specified Connection Object.
|
|
|
|
Arguments:
|
|
|
|
pConnObject - Points to the TDI Connection
|
|
RejectStatus - Reason for rejecting the call
|
|
|
|
Locks on Entry:
|
|
|
|
pConnObject
|
|
|
|
Locks on Exit:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PRWAN_NDIS_VC pVc;
|
|
NDIS_HANDLE NdisVcHandle;
|
|
PCO_CALL_PARAMETERS pCallParameters;
|
|
INT rc;
|
|
PRWAN_CONN_REQUEST pConnReq;
|
|
PRWAN_NDIS_AF pAf;
|
|
RWAN_HANDLE AfSpConnContext;
|
|
|
|
pVc = pConnObject->NdisConnection.pNdisVc;
|
|
|
|
NdisVcHandle = pVc->NdisVcHandle;
|
|
pCallParameters = pVc->pCallParameters;
|
|
pVc->pCallParameters = NULL;
|
|
pAf = pVc->pNdisAf;
|
|
|
|
//
|
|
// Unlink the VC from the Conn Object.
|
|
//
|
|
RWAN_UNLINK_CONNECTION_AND_VC(pConnObject, pVc); // Reject incoming call
|
|
|
|
RWAN_SET_BIT(pVc->Flags, RWANF_VC_CLOSING_CALL);
|
|
|
|
pConnReq = pConnObject->pConnReq;
|
|
pConnObject->pConnReq = NULL;
|
|
|
|
//
|
|
// State change.
|
|
//
|
|
if (pConnObject->State != RWANS_CO_ABORTING)
|
|
{
|
|
pConnObject->State = ((pConnObject->pAddrObject != NULL) ?
|
|
RWANS_CO_ASSOCIATED:
|
|
RWANS_CO_CREATED);
|
|
}
|
|
|
|
AfSpConnContext = pConnObject->AfSpConnContext;
|
|
|
|
rc = RWanDereferenceConnObject(pConnObject); // Unlinking VC in reject in-call
|
|
|
|
if (rc > 0)
|
|
{
|
|
RWAN_RELEASE_CONN_LOCK(pConnObject);
|
|
}
|
|
|
|
NdisClIncomingCallComplete(
|
|
RejectStatus,
|
|
NdisVcHandle,
|
|
pCallParameters
|
|
);
|
|
|
|
if (pConnReq != NULL)
|
|
{
|
|
RWanCompleteConnReq( // Discon Req for rejecting in call
|
|
pAf,
|
|
pConnReq,
|
|
FALSE,
|
|
NULL, // No Call Parameters
|
|
AfSpConnContext,
|
|
TDI_SUCCESS
|
|
);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
RWanStartCloseCall(
|
|
IN PRWAN_TDI_CONNECTION pConnObject,
|
|
IN PRWAN_NDIS_VC pVc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Start NDIS call teardown on the VC associated with the given
|
|
connection object, if all pre-conditions are met:
|
|
|
|
0. An NDIS CloseCall isn't already going on
|
|
1. No outstanding sends
|
|
|
|
Arguments:
|
|
|
|
pConnObject - Points to TDI Connection object
|
|
pVc - Points to corresponding VC
|
|
|
|
Locks on Entry:
|
|
|
|
pConnObject
|
|
|
|
Locks on Exit:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PRWAN_NDIS_PARTY pParty;
|
|
NDIS_HANDLE NdisVcHandle;
|
|
NDIS_HANDLE NdisPartyHandle;
|
|
NDIS_STATUS Status;
|
|
PRWAN_RECEIVE_INDICATION pRcvIndHead;
|
|
PRWAN_RECEIVE_INDICATION pRcvInd;
|
|
|
|
RWANDEBUGP(DL_INFO, DC_DISCON,
|
|
("StartCloseCall: pVc x%x/x%x, PendingCount %d, pConnObj x%x\n",
|
|
pVc,
|
|
pVc->Flags,
|
|
pVc->PendingPacketCount,
|
|
pConnObject));
|
|
|
|
//
|
|
// Free up any pending receives.
|
|
//
|
|
pRcvIndHead = pVc->pRcvIndHead;
|
|
if (pRcvIndHead != NULL)
|
|
{
|
|
pVc->pRcvIndHead = NULL;
|
|
pVc->pRcvIndTail = NULL;
|
|
|
|
//
|
|
// Update the count of pending packets on this VC.
|
|
//
|
|
for (pRcvInd = pRcvIndHead; pRcvInd != NULL; pRcvInd = pRcvInd->pNextRcvInd)
|
|
{
|
|
pVc->PendingPacketCount--;
|
|
}
|
|
|
|
//
|
|
// We will free this list below.
|
|
//
|
|
}
|
|
|
|
|
|
if ((pVc != NULL) &&
|
|
(pVc->PendingPacketCount == 0) &&
|
|
(pVc->DroppingPartyCount == 0) &&
|
|
(!RWAN_IS_BIT_SET(pVc->Flags, RWANF_VC_CLOSING_CALL)))
|
|
{
|
|
NdisVcHandle = pVc->NdisVcHandle;
|
|
RWAN_SET_BIT(pVc->Flags, RWANF_VC_CLOSING_CALL);
|
|
|
|
RWAN_RESET_BIT(pVc->Flags, RWANF_VC_NEEDS_CLOSE);
|
|
|
|
if (RWAN_IS_LIST_EMPTY(&(pVc->NdisPartyList)))
|
|
{
|
|
pParty = NULL_PRWAN_NDIS_PARTY;
|
|
NdisPartyHandle = NULL;
|
|
RWAN_ASSERT(!RWAN_IS_BIT_SET(pVc->Flags, RWANF_VC_PMP));
|
|
}
|
|
else
|
|
{
|
|
pParty = CONTAINING_RECORD(pVc->NdisPartyList.Flink, RWAN_NDIS_PARTY, PartyLink);
|
|
NdisPartyHandle = pParty->NdisPartyHandle;
|
|
|
|
RWAN_SET_BIT(pParty->Flags, RWANF_PARTY_DROPPING);
|
|
|
|
pVc->DroppingPartyCount ++; // StartCloseCall PMP
|
|
pVc->ActivePartyCount --; // StartCloseCall PMP
|
|
}
|
|
|
|
RWAN_RELEASE_CONN_LOCK(pConnObject);
|
|
|
|
Status = NdisClCloseCall(
|
|
NdisVcHandle,
|
|
NdisPartyHandle,
|
|
NULL, // No CloseData
|
|
0
|
|
);
|
|
|
|
if (Status != NDIS_STATUS_PENDING)
|
|
{
|
|
RWanNdisCloseCallComplete(
|
|
Status,
|
|
(NDIS_HANDLE)pVc, // ProtocolVcContext
|
|
(NDIS_HANDLE)pParty // ProtocolPartyContext
|
|
);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pVc != NULL)
|
|
{
|
|
RWAN_SET_BIT(pVc->Flags, RWANF_VC_NEEDS_CLOSE);
|
|
}
|
|
RWAN_RELEASE_CONN_LOCK(pConnObject);
|
|
}
|
|
|
|
|
|
if (pRcvIndHead != NULL)
|
|
{
|
|
RWANDEBUGP(DL_INFO, DC_DISCON,
|
|
("RWanStartCloseCall: will free rcv ind list x%x on VC x%x\n",
|
|
pRcvIndHead, pVc));
|
|
|
|
RWanFreeReceiveIndList(pRcvIndHead);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
VOID
|
|
RWanUnlinkVcFromAf(
|
|
IN PRWAN_NDIS_VC pVc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Unlink a VC from the AF it belongs to.
|
|
|
|
Arguments:
|
|
|
|
pVc - Points to VC to be unlinked
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
PRWAN_NDIS_AF pAf;
|
|
INT rc;
|
|
|
|
pAf = pVc->pNdisAf;
|
|
|
|
RWAN_STRUCT_ASSERT(pAf, naf);
|
|
|
|
RWAN_ACQUIRE_AF_LOCK(pAf);
|
|
|
|
RWAN_DELETE_FROM_LIST(&(pVc->VcLink));
|
|
|
|
rc = RWanDereferenceAf(pAf); // VC unlink deref
|
|
|
|
if (rc != 0)
|
|
{
|
|
RWAN_RELEASE_AF_LOCK(pAf);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
RWanCompleteConnReq(
|
|
IN PRWAN_NDIS_AF pAf,
|
|
IN PRWAN_CONN_REQUEST pConnReq,
|
|
IN BOOLEAN IsOutgoingCall,
|
|
IN PCO_CALL_PARAMETERS pCallParameters OPTIONAL,
|
|
IN RWAN_HANDLE AfSpConnContext,
|
|
IN TDI_STATUS TdiStatus
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Call the completion routine for a pended TDI request on a connection.
|
|
Set up the options and completion status based on what's given to us.
|
|
|
|
Arguments:
|
|
|
|
pAf - The AF block on which the request was made
|
|
pConnReq - the pended request to be completed
|
|
IsOutgoingCall - Is this an outgoing call?
|
|
pCallParameters - if applicable, this should be mapped to connection info
|
|
AfSpConnContext - Connection context, if applicable, for the media-specific
|
|
module.
|
|
TdiStatus - completion status for the request
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
{
|
|
RWAN_STATUS RWanStatus;
|
|
ULONG TdiQoSLength = 0;
|
|
|
|
if (pConnReq == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
RWAN_STRUCT_ASSERT(pConnReq, nrc);
|
|
|
|
//
|
|
// Update Connection Information if we need to.
|
|
//
|
|
if ((pConnReq->pConnInfo != NULL) &&
|
|
(pCallParameters != NULL))
|
|
{
|
|
RWanStatus = (*pAf->pAfInfo->AfChars.pAfSpUpdateTdiOptions)(
|
|
pAf->AfSpAFContext,
|
|
AfSpConnContext,
|
|
IsOutgoingCall,
|
|
pCallParameters,
|
|
&pConnReq->pConnInfo,
|
|
pConnReq->pConnInfo->Options,
|
|
&pConnReq->pConnInfo->OptionsLength
|
|
);
|
|
}
|
|
|
|
//
|
|
// Call the completion routine.
|
|
//
|
|
(*pConnReq->Request.pReqComplete)(
|
|
pConnReq->Request.ReqContext,
|
|
TdiStatus,
|
|
0
|
|
);
|
|
|
|
RWanFreeConnReq(pConnReq);
|
|
}
|
|
|
|
|