Source code of Windows XP (NT5)
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.

3389 lines
100 KiB

  1. // Copyright (c) 1997, Microsoft Corporation, all rights reserved
  2. //
  3. // cm.c
  4. // RAS L2TP WAN mini-port/call-manager driver
  5. // Call Manager routines
  6. //
  7. // 01/07/97 Steve Cobb
  8. #include "l2tpp.h"
  9. // Debug counts of client oddities that should not be happening.
  10. //
  11. ULONG g_ulUnexpectedInCallCompletes = 0;
  12. ULONG g_ulCallsNotClosable = 0;
  13. ULONG g_ulCompletingVcCorruption = 0;
  14. //-----------------------------------------------------------------------------
  15. // Local prototypes (alphabetically)
  16. //-----------------------------------------------------------------------------
  17. VOID
  18. BuildCallParametersShell(
  19. IN ADAPTERCB* pAdapter,
  20. IN ULONG ulIpAddress,
  21. IN ULONG ulBufferLength,
  22. OUT CHAR* pBuffer,
  23. OUT CO_AF_TAPI_INCOMING_CALL_PARAMETERS UNALIGNED** ppTiParams,
  24. OUT LINE_CALL_INFO** ppTcInfo,
  25. OUT L2TP_CALL_PARAMETERS** ppLcParams );
  26. VOID
  27. CallSetupComplete(
  28. IN VCCB* pVc );
  29. TUNNELCB*
  30. CreateTunnelCb(
  31. IN ADAPTERCB* pAdapter );
  32. VOID
  33. InactiveCallCleanUp(
  34. IN VCCB* pVc );
  35. VOID
  36. IncomingCallCompletePassive(
  37. IN TUNNELWORK* pWork,
  38. IN TUNNELCB* pTunnel,
  39. IN VCCB* pVc,
  40. IN ULONG_PTR* punpArgs );
  41. VOID
  42. DereferenceAf(
  43. IN ADAPTERCB* pAdapter );
  44. VOID
  45. DeregisterSapPassive(
  46. IN NDIS_WORK_ITEM* pWork,
  47. IN VOID* pContext );
  48. VOID
  49. LockIcs(
  50. IN VCCB* pVc,
  51. IN BOOLEAN fGrace );
  52. NDIS_STATUS
  53. QueryCmInformation(
  54. IN ADAPTERCB* pAdapter,
  55. IN VCCB* pVc,
  56. IN NDIS_OID Oid,
  57. IN PVOID InformationBuffer,
  58. IN ULONG InformationBufferLength,
  59. OUT PULONG BytesWritten,
  60. OUT PULONG BytesNeeded );
  61. VOID
  62. ReferenceAf(
  63. IN ADAPTERCB* pAdapter );
  64. VOID
  65. RegisterSapPassive(
  66. IN NDIS_WORK_ITEM* pWork,
  67. IN VOID* pContext );
  68. VOID
  69. SetupVcComplete(
  70. IN TUNNELCB* pTunnel,
  71. IN VCCB* pVc );
  72. VOID
  73. TimerQTerminateComplete(
  74. IN TIMERQ* pTimerQ,
  75. IN VOID* pContext );
  76. VOID
  77. TunnelTqTerminateComplete(
  78. IN TIMERQ* pTimerQ,
  79. IN VOID* pContext );
  80. VOID
  81. UnlockIcs(
  82. IN VCCB* pVc,
  83. IN BOOLEAN fGrace );
  84. //-----------------------------------------------------------------------------
  85. // Call-manager handlers and completers
  86. //-----------------------------------------------------------------------------
  87. NDIS_STATUS
  88. LcmCmOpenAf(
  89. IN NDIS_HANDLE CallMgrBindingContext,
  90. IN PCO_ADDRESS_FAMILY AddressFamily,
  91. IN NDIS_HANDLE NdisAfHandle,
  92. OUT PNDIS_HANDLE CallMgrAfContext )
  93. // Standard 'CmCmOpenAfHandler' routine called by NDIS when a client
  94. // requests to open an address family. See DDK doc.
  95. //
  96. {
  97. ADAPTERCB* pAdapter;
  98. NDIS_HANDLE hExistingAf;
  99. TRACE( TL_I, TM_Cm, ( "LcmCmOpenAf" ) );
  100. pAdapter = (ADAPTERCB* )CallMgrBindingContext;
  101. if (pAdapter->ulTag != MTAG_ADAPTERCB)
  102. {
  103. ASSERT( !"Atag?" );
  104. return NDIS_STATUS_INVALID_DATA;
  105. }
  106. if (AddressFamily->AddressFamily != CO_ADDRESS_FAMILY_TAPI_PROXY
  107. || AddressFamily->MajorVersion != NDIS_MajorVersion
  108. || AddressFamily->MinorVersion != NDIS_MinorVersion)
  109. {
  110. return NDIS_STATUS_BAD_VERSION;
  111. }
  112. // Save NDIS's AF handle in the adapter control block. Interlock just in
  113. // case multiple clients attempt to open the AF, though don't expect this.
  114. //
  115. hExistingAf =
  116. InterlockedCompareExchangePointer(
  117. &pAdapter->NdisAfHandle, NdisAfHandle, NULL );
  118. if (hExistingAf)
  119. {
  120. // Our AF has already been opened. Don't accept another open since
  121. // only only one would be able to register a SAP anyway. This way we
  122. // don't have to be in the business of tracking multiple AF handles.
  123. //
  124. ASSERT( !"AF exists?" );
  125. return NDIS_STATUS_FAILURE;
  126. }
  127. ReferenceAdapter( pAdapter );
  128. ReferenceAf( pAdapter );
  129. // Since we support only a single address family, just return the adapter
  130. // as the address family context.
  131. //
  132. *CallMgrAfContext = (PNDIS_HANDLE )pAdapter;
  133. TRACE( TL_I, TM_Cm, ( "LcmCmOpenAf OK" ) );
  134. return NDIS_STATUS_SUCCESS;
  135. }
  136. NDIS_STATUS
  137. LcmCmCloseAf(
  138. IN NDIS_HANDLE CallMgrAfContext )
  139. // Standard 'CmCloseAfHandler' routine called by NDIS when a client
  140. // requests to close an address family. See DDK doc.
  141. //
  142. {
  143. ADAPTERCB* pAdapter;
  144. TRACE( TL_I, TM_Cm, ( "LcmCmCloseAf" ) );
  145. pAdapter = (ADAPTERCB* )CallMgrAfContext;
  146. if (pAdapter->ulTag != MTAG_ADAPTERCB)
  147. {
  148. ASSERT( !"Atag?" );
  149. return NDIS_STATUS_INVALID_DATA;
  150. }
  151. // This dereference will eventually lead to us calling
  152. // NdisMCmCloseAfComplete.
  153. //
  154. DereferenceAf( pAdapter );
  155. TRACE( TL_V, TM_Cm, ( "LcmCmCloseAf pending" ) );
  156. return NDIS_STATUS_PENDING;
  157. }
  158. NDIS_STATUS
  159. LcmCmRegisterSap(
  160. IN NDIS_HANDLE CallMgrAfContext,
  161. IN PCO_SAP Sap,
  162. IN NDIS_HANDLE NdisSapHandle,
  163. OUT PNDIS_HANDLE CallMgrSapContext )
  164. // Standard 'LcmCmRegisterSapHandler' routine called by NDIS when the a
  165. // client registers a service access point. See DDK doc.
  166. //
  167. {
  168. NDIS_STATUS status;
  169. ADAPTERCB* pAdapter;
  170. BOOLEAN fSapExists;
  171. BOOLEAN fInvalidSapData;
  172. TRACE( TL_I, TM_Cm, ( "LcmCmRegSap" ) );
  173. pAdapter = (ADAPTERCB* )CallMgrAfContext;
  174. // Our SAP context is just the address of the owning adapter control
  175. // block. Set it now before scheduling work as NDIS doesn't handle the
  176. // case of SAP completion correctly otherwise (though it should).
  177. //
  178. *CallMgrSapContext = (NDIS_HANDLE )pAdapter;
  179. if (pAdapter->ulTag != MTAG_ADAPTERCB)
  180. {
  181. ASSERT( !"Atag?" );
  182. return NDIS_STATUS_INVALID_DATA;
  183. }
  184. NdisAcquireSpinLock( &pAdapter->lockSap );
  185. {
  186. if (pAdapter->NdisSapHandle)
  187. {
  188. fSapExists = TRUE;
  189. }
  190. else
  191. {
  192. // Save NDIS's SAP handle in the adapter control block.
  193. //
  194. fSapExists = FALSE;
  195. pAdapter->NdisSapHandle = NdisSapHandle;
  196. // Extract the SAP line and address IDs and store for
  197. // regurgitation in incoming call dispatches.
  198. //
  199. if (Sap->SapType == AF_TAPI_SAP_TYPE
  200. && Sap->SapLength >= sizeof(CO_AF_TAPI_SAP))
  201. {
  202. CO_AF_TAPI_SAP* pSap;
  203. pSap = (CO_AF_TAPI_SAP* )(Sap->Sap);
  204. pAdapter->ulSapLineId = pSap->ulLineID;
  205. if (pSap->ulAddressID == 0xFFFFFFFF)
  206. {
  207. // This means "any ID is OK" but when indicated back up
  208. // NDPROXY doesn't recognize this code, so translate it to
  209. // 0 here.
  210. //
  211. pAdapter->ulSapAddressId = 0;
  212. }
  213. else
  214. {
  215. pAdapter->ulSapAddressId = pSap->ulAddressID;
  216. }
  217. fInvalidSapData = FALSE;
  218. }
  219. else
  220. {
  221. fInvalidSapData = TRUE;
  222. }
  223. }
  224. }
  225. NdisReleaseSpinLock( &pAdapter->lockSap );
  226. if (fSapExists)
  227. {
  228. TRACE( TL_A, TM_Cm, ( "SAP exists?" ) );
  229. return NDIS_STATUS_SAP_IN_USE;
  230. }
  231. if (fInvalidSapData)
  232. {
  233. TRACE( TL_A, TM_Cm, ( "SAP data?" ) );
  234. return NDIS_STATUS_INVALID_DATA;
  235. }
  236. // TDI setup must be done at PASSIVE IRQL so schedule a routine to do it.
  237. //
  238. status = ScheduleWork( pAdapter, RegisterSapPassive, pAdapter );
  239. if (status != NDIS_STATUS_SUCCESS)
  240. {
  241. ASSERT( FALSE );
  242. NdisAcquireSpinLock( &pAdapter->lockSap );
  243. {
  244. pAdapter->NdisSapHandle = NULL;
  245. }
  246. NdisReleaseSpinLock( &pAdapter->lockSap );
  247. return status;
  248. }
  249. TRACE( TL_V, TM_Cm, ( "LcmCmRegSap pending" ) );
  250. return NDIS_STATUS_PENDING;
  251. }
  252. VOID
  253. RegisterSapPassive(
  254. IN NDIS_WORK_ITEM* pWork,
  255. IN VOID* pContext )
  256. // An NDIS_PROC routine to complete the registering of a SAP begun in
  257. // LcmCmRegisterSap.
  258. //
  259. {
  260. NDIS_STATUS status;
  261. ADAPTERCB* pAdapter;
  262. NDIS_HANDLE hSap;
  263. TRACE( TL_N, TM_Cm, ( "RegSapPassive" ) );
  264. // Unpack context information then free the work item.
  265. //
  266. pAdapter = (ADAPTERCB* )pContext;
  267. ASSERT( pAdapter->ulTag == MTAG_ADAPTERCB );
  268. FREE_NDIS_WORK_ITEM( pAdapter, pWork );
  269. // Open the TDI transport and start receiving datagrams.
  270. //
  271. status = TdixOpen( &pAdapter->tdix );
  272. NdisAcquireSpinLock( &pAdapter->lockSap );
  273. {
  274. hSap = pAdapter->NdisSapHandle;
  275. if (status == NDIS_STATUS_SUCCESS)
  276. {
  277. // Mark the SAP active allowing references to be taken, and take
  278. // the initial reference for SAP registry, plus those for address
  279. // family and adapter.
  280. //
  281. SetFlags( &pAdapter->ulFlags, ACBF_SapActive );
  282. ASSERT( pAdapter->lSapRef == 0 );
  283. TRACE( TL_N, TM_Ref, ( "RefSap-ish to 1" ) );
  284. pAdapter->lSapRef = 1;
  285. ReferenceAdapter( pAdapter );
  286. ReferenceAf( pAdapter );
  287. }
  288. else
  289. {
  290. // Failed to get TDI set up, so NULL the SAP handle in the adapter
  291. // control block.
  292. //
  293. TRACE( TL_A, TM_Cm, ( "TdixOpen=$%08x?", status ) );
  294. pAdapter->NdisSapHandle = NULL;
  295. }
  296. }
  297. NdisReleaseSpinLock( &pAdapter->lockSap );
  298. // Remove the reference for scheduled work. Do this before telling NDIS
  299. // the SAP completed because if it failed it can call Halt and unload the
  300. // driver before we run again here which gives a C4 bugcheck.
  301. //
  302. DereferenceAdapter( pAdapter );
  303. // Report result to client.
  304. //
  305. TRACE( TL_I, TM_Cm, ( "NdisMCmRegSapComp" ) );
  306. NdisMCmRegisterSapComplete( status, hSap, (NDIS_HANDLE )pAdapter );
  307. TRACE( TL_I, TM_Cm, ( "NdisMCmRegSapComp done" ) );
  308. }
  309. NDIS_STATUS
  310. LcmCmDeregisterSap(
  311. NDIS_HANDLE CallMgrSapContext )
  312. // Standard 'CmDeregisterSapHandler' routine called by NDIS when the a
  313. // client has requested to de-register a service access point. See DDK
  314. // doc.
  315. //
  316. {
  317. NDIS_STATUS status;
  318. ADAPTERCB* pAdapter;
  319. TRACE( TL_I, TM_Cm, ( "LcmCmDeregSap" ) );
  320. pAdapter = (ADAPTERCB* )CallMgrSapContext;
  321. if (pAdapter->ulTag != MTAG_ADAPTERCB)
  322. {
  323. ASSERT( !"Atag?" );
  324. return NDIS_STATUS_INVALID_DATA;
  325. }
  326. NdisAcquireSpinLock( &pAdapter->lockSap );
  327. {
  328. if (ReadFlags( &pAdapter->ulFlags ) & ACBF_SapActive)
  329. {
  330. ASSERT( pAdapter->NdisSapHandle );
  331. ClearFlags( &pAdapter->ulFlags, ACBF_SapActive );
  332. status = NDIS_STATUS_PENDING;
  333. }
  334. else
  335. {
  336. TRACE( TL_A, TM_Cm, ( "No SAP active?" ) );
  337. status = NDIS_STATUS_FAILURE;
  338. }
  339. }
  340. NdisReleaseSpinLock( &pAdapter->lockSap );
  341. if (status == NDIS_STATUS_PENDING)
  342. {
  343. // Remove the reference for SAP registry. Eventually, the SAP
  344. // references will fall to 0 and DereferenceSap will schedule
  345. // DeregisterSapPassive to complete the de-registry.
  346. //
  347. DereferenceSap( pAdapter );
  348. }
  349. TRACE( TL_V, TM_Cm, ( "LcmCmDeregSap=$%08x", status ) );
  350. return status;
  351. }
  352. VOID
  353. DeregisterSapPassive(
  354. IN NDIS_WORK_ITEM* pWork,
  355. IN VOID* pContext )
  356. // An NDIS_PROC routine to complete the de-registering of a SAP begun in
  357. // LcmCmDeregisterSap.
  358. //
  359. {
  360. ADAPTERCB* pAdapter;
  361. NDIS_HANDLE hOldSap;
  362. TRACE( TL_I, TM_Cm, ( "DeregSapPassive" ) );
  363. // Unpack context information then free the work item.
  364. //
  365. pAdapter = (ADAPTERCB* )pContext;
  366. ASSERT( pAdapter->ulTag == MTAG_ADAPTERCB );
  367. FREE_NDIS_WORK_ITEM( pAdapter, pWork );
  368. // Stop receiving datagrams (at least on behalf of this SAP) and
  369. // deregister the SAP.
  370. //
  371. NdisAcquireSpinLock( &pAdapter->lockSap );
  372. {
  373. hOldSap = pAdapter->NdisSapHandle;
  374. pAdapter->NdisSapHandle = NULL;
  375. }
  376. NdisReleaseSpinLock( &pAdapter->lockSap );
  377. TdixClose( &pAdapter->tdix );
  378. // Remove the adapter references for the NdisSapHandle and for scheduled
  379. // work. Remove the address family reference for the NdisSapHandle. Do
  380. // all this before telling NDIS the deregister has completed because it
  381. // can call Halt and unload the driver before we run again here giving a
  382. // C4 bugcheck.
  383. //
  384. DereferenceAdapter( pAdapter );
  385. DereferenceAdapter( pAdapter );
  386. DereferenceAf( pAdapter );
  387. // Report result to client.
  388. //
  389. TRACE( TL_I, TM_Cm, ( "NdisMCmDeregSapComp" ) );
  390. NdisMCmDeregisterSapComplete( NDIS_STATUS_SUCCESS, hOldSap );
  391. TRACE( TL_I, TM_Cm, ( "NdisMCmDeregSapComp done" ) );
  392. }
  393. NDIS_STATUS
  394. LcmCmCreateVc(
  395. IN NDIS_HANDLE ProtocolAfContext,
  396. IN NDIS_HANDLE NdisVcHandle,
  397. OUT PNDIS_HANDLE ProtocolVcContext )
  398. // Standard 'CmCreateVc' routine called by NDIS in response to a
  399. // client's request to create a virtual circuit. This
  400. // call must return synchronously.
  401. //
  402. {
  403. NDIS_STATUS status;
  404. ADAPTERCB* pAdapter;
  405. VCCB* pVc;
  406. pAdapter = (ADAPTERCB* )ProtocolAfContext;
  407. if (pAdapter->ulTag != MTAG_ADAPTERCB)
  408. {
  409. ASSERT( !"Atag?" );
  410. return NDIS_STATUS_INVALID_DATA;
  411. }
  412. // Allocate and zero a VC control block, then make any non-zero
  413. // initializations.
  414. //
  415. pVc = ALLOC_VCCB( pAdapter );
  416. if (!pVc)
  417. {
  418. ASSERT( !"Alloc VC?" );
  419. return NDIS_STATUS_RESOURCES;
  420. }
  421. NdisZeroMemory( pVc, sizeof(*pVc) );
  422. TRACE( TL_I, TM_Cm, ( "LcmCmCreateVc $%p", pVc ) );
  423. // Zero the back pointer to the tunnel control block (above) and
  424. // initialize the detached link since clean-up may be required before this
  425. // block is ever linked into a tunnel chain.
  426. //
  427. InitializeListHead( &pVc->linkVcs );
  428. InitializeListHead( &pVc->linkRequestingVcs );
  429. InitializeListHead( &pVc->linkCompletingVcs );
  430. // Set a marker for easier memory dump browsing.
  431. //
  432. pVc->ulTag = MTAG_VCCB;
  433. // Save a back pointer to the adapter for use in LcmCmDeleteVc later.
  434. //
  435. ReferenceAdapter( pAdapter );
  436. pVc->pAdapter = pAdapter;
  437. // Initialize the VC and call spinlock and send/receive lists.
  438. //
  439. NdisAllocateSpinLock( &pVc->lockV );
  440. NdisAllocateSpinLock( &pVc->lockCall );
  441. InitializeListHead( &pVc->listSendsOut );
  442. InitializeListHead( &pVc->listOutOfOrder );
  443. // Save the NDIS handle of this VC for use in indications to NDIS later.
  444. //
  445. pVc->NdisVcHandle = NdisVcHandle;
  446. // Initialize the estimated round trip time and send timeout per the
  447. // suggestions in the draft/RFC.
  448. //
  449. pVc->ulRoundTripMs = L2TP_LnsDefaultPpd * 100;
  450. pVc->ulSendTimeoutMs = pVc->ulRoundTripMs;
  451. // Initialize link capabilities to the defaults for the adapter.
  452. //
  453. {
  454. NDIS_WAN_CO_INFO* pwci = &pAdapter->info;
  455. NDIS_WAN_CO_GET_LINK_INFO* pwcgli = &pVc->linkinfo;
  456. NdisZeroMemory( &pVc->linkinfo, sizeof(pVc->linkinfo) );
  457. pwcgli->MaxSendFrameSize = pwci->MaxFrameSize;
  458. pwcgli->MaxRecvFrameSize = pwci->MaxFrameSize;
  459. pwcgli->SendFramingBits = pwci->FramingBits;
  460. pwcgli->RecvFramingBits = pwci->FramingBits;
  461. pwcgli->SendACCM = pwci->DesiredACCM;
  462. pwcgli->RecvACCM = pwci->DesiredACCM;
  463. }
  464. // Default send window, "slow started". This is typically adjusted based
  465. // on peer's Receive Window AVP when the call is created.
  466. //
  467. pVc->ulSendWindow = pAdapter->info.MaxSendWindow >> 1;
  468. if (pVc->ulSendWindow == 0)
  469. {
  470. pVc->ulSendWindow = 1;
  471. }
  472. // The VC control block's address is the VC context we return to NDIS.
  473. //
  474. *ProtocolVcContext = (NDIS_HANDLE )pVc;
  475. // Add a reference to the control block and the associated address family
  476. // that is removed by LmpCoDeleteVc.
  477. //
  478. ReferenceVc( pVc );
  479. ReferenceAf( pAdapter );
  480. TRACE( TL_V, TM_Cm, ( "LcmCmCreateVc=0" ) );
  481. return NDIS_STATUS_SUCCESS;
  482. }
  483. NDIS_STATUS
  484. LcmCmDeleteVc(
  485. IN NDIS_HANDLE ProtocolVcContext )
  486. // Standard 'CmDeleteVc' routine called by NDIS in response to a
  487. // client's request to delete a virtual circuit. This
  488. // call must return synchronously.
  489. //
  490. {
  491. VCCB* pVc;
  492. TRACE( TL_I, TM_Cm, ( "LcmCmDelVc($%p)", ProtocolVcContext ) );
  493. pVc = (VCCB* )ProtocolVcContext;
  494. if (pVc->ulTag != MTAG_VCCB)
  495. {
  496. ASSERT( !"Vtag?" );
  497. return NDIS_STATUS_INVALID_DATA;
  498. }
  499. // This flag catches attempts by the client to delete the VC twice.
  500. //
  501. if (ReadFlags( &pVc->ulFlags ) & VCBF_VcDeleted)
  502. {
  503. TRACE( TL_A, TM_Cm, ( "VC $%p re-deleted?", pVc ) );
  504. return NDIS_STATUS_FAILURE;
  505. }
  506. SetFlags( &pVc->ulFlags, VCBF_VcDeleted );
  507. // Remove the references added by LcmCmCreateVc.
  508. //
  509. DereferenceAf( pVc->pAdapter );
  510. DereferenceVc( pVc );
  511. TRACE( TL_V, TM_Cm, ( "LcmCmDelVc=0" ) );
  512. return NDIS_STATUS_SUCCESS;
  513. }
  514. NDIS_STATUS
  515. LcmCmMakeCall(
  516. IN NDIS_HANDLE CallMgrVcContext,
  517. IN OUT PCO_CALL_PARAMETERS CallParameters,
  518. IN NDIS_HANDLE NdisPartyHandle,
  519. OUT PNDIS_HANDLE CallMgrPartyContext )
  520. // Standard 'CmMakeCallHandler' routine called by NDIS when the a client
  521. // has requested to connect to a remote end-point. See DDK doc.
  522. //
  523. {
  524. NDIS_STATUS status;
  525. CO_SPECIFIC_PARAMETERS* pMSpecifics;
  526. CO_AF_TAPI_MAKE_CALL_PARAMETERS UNALIGNED* pTmParams;
  527. LINE_CALL_PARAMS* pTcParams;
  528. L2TP_CALL_PARAMETERS* pLcParams;
  529. VCCB* pVc;
  530. TUNNELCB* pTunnel;
  531. ADAPTERCB* pAdapter;
  532. ULONG ulIpAddress;
  533. BOOLEAN fDefaultLcParams;
  534. BOOLEAN fExclusiveTunnel;
  535. TRACE( TL_I, TM_Cm, ( "LcmCmMakeCall" ) );
  536. pVc = (VCCB* )CallMgrVcContext;
  537. if (pVc->ulTag != MTAG_VCCB)
  538. {
  539. ASSERT( "!Vtag?" );
  540. return NDIS_STATUS_INVALID_DATA;
  541. }
  542. pAdapter = pVc->pAdapter;
  543. // L2TP has no concept of point-to-multi-point "parties".
  544. //
  545. if (CallMgrPartyContext)
  546. {
  547. *CallMgrPartyContext = NULL;
  548. }
  549. // Validate call parameters.
  550. //
  551. do
  552. {
  553. // Validate base call parameters.
  554. //
  555. {
  556. // L2TP provides switched VCs only.
  557. //
  558. if (CallParameters->Flags &
  559. (PERMANENT_VC | BROADCAST_VC | MULTIPOINT_VC))
  560. {
  561. status = NDIS_STATUS_NOT_SUPPORTED;
  562. break;
  563. }
  564. // We're supposed to set CALL_PARAMETERS_CHANGED on return if we
  565. // changed the call parameters, leaving a catch-22 if caller
  566. // already has it set. Also, for TAPI address family, media call
  567. // parameters must be present, though call manager call parameters
  568. // are not.
  569. //
  570. if ((CallParameters->Flags & CALL_PARAMETERS_CHANGED)
  571. || !CallParameters->MediaParameters)
  572. {
  573. status = NDIS_STATUS_INVALID_DATA;
  574. break;
  575. }
  576. pMSpecifics = &CallParameters->MediaParameters->MediaSpecific;
  577. if (pMSpecifics->Length < sizeof(CO_AF_TAPI_MAKE_CALL_PARAMETERS))
  578. {
  579. status = NDIS_STATUS_INVALID_DATA;
  580. break;
  581. }
  582. pTmParams =
  583. (CO_AF_TAPI_MAKE_CALL_PARAMETERS UNALIGNED* )&pMSpecifics->Parameters;
  584. if (pTmParams->LineCallParams.Length < sizeof(LINE_CALL_PARAMS))
  585. {
  586. status = NDIS_STATUS_INVALID_DATA;
  587. break;
  588. }
  589. pTcParams = (LINE_CALL_PARAMS* )
  590. (((CHAR UNALIGNED* )&pTmParams->LineCallParams)
  591. + pTmParams->LineCallParams.Offset);
  592. }
  593. // Validate call parameters.
  594. //
  595. {
  596. CHAR* pszAddress;
  597. // Caller must provide a destination IP address. The address is
  598. // ANSI as are all non-format-coded strings to/from TAPI.
  599. //
  600. pszAddress =
  601. StrDupNdisVarDataDescStringToA( &pTmParams->DestAddress );
  602. if (!pszAddress)
  603. {
  604. status = NDIS_STATUS_RESOURCES;
  605. break;
  606. }
  607. ulIpAddress = IpAddressFromDotted( pszAddress );
  608. FREE_NONPAGED( pszAddress );
  609. if (ulIpAddress == 0)
  610. {
  611. status = NDIS_STATUS_INVALID_ADDRESS;
  612. break;
  613. }
  614. // Reject if unknown WAN-type bits are set.
  615. //
  616. if (pTcParams->ulMediaMode
  617. & ~(LINEMEDIAMODE_DATAMODEM | LINEMEDIAMODE_DIGITALDATA))
  618. {
  619. status = NDIS_STATUS_INVALID_DATA;
  620. break;
  621. }
  622. }
  623. // Validate L2TP call parameters.
  624. //
  625. // When caller doesn't provide L2TP-specific parameters a local block
  626. // with default values is substituted for the convenience of the rest
  627. // of the code.
  628. //
  629. {
  630. if (pTcParams->ulDevSpecificSize == sizeof(*pLcParams))
  631. {
  632. pLcParams = (L2TP_CALL_PARAMETERS* )
  633. ((CHAR* )pTcParams) + pTcParams->ulDevSpecificOffset;
  634. fDefaultLcParams = FALSE;
  635. }
  636. else
  637. {
  638. pLcParams =
  639. (L2TP_CALL_PARAMETERS* )ALLOC_NONPAGED(
  640. sizeof(*pLcParams), MTAG_L2TPPARAMS );
  641. if (!pLcParams)
  642. {
  643. status = NDIS_STATUS_RESOURCES;
  644. break;
  645. }
  646. fDefaultLcParams = TRUE;
  647. NdisZeroMemory( pLcParams, sizeof(*pLcParams) );
  648. pLcParams->ulPhysicalChannelId = 0xFFFFFFFF;
  649. }
  650. }
  651. status = NDIS_STATUS_SUCCESS;
  652. }
  653. while (FALSE);
  654. if (status != NDIS_STATUS_SUCCESS)
  655. {
  656. return status;
  657. }
  658. // Stash the call parameters in the VC block. Simultaneous MakeCalls on
  659. // the same VC is a client error, but it's easy to guard against so do
  660. // that here.
  661. //
  662. if (InterlockedCompareExchangePointer(
  663. &pVc->pMakeCall, CallParameters, NULL ))
  664. {
  665. ASSERT( !"Double MakeCall?" );
  666. if (fDefaultLcParams)
  667. {
  668. FREE_NONPAGED( pLcParams );
  669. }
  670. return NDIS_STATUS_CALL_ACTIVE;
  671. }
  672. pVc->pTmParams = pTmParams;
  673. pVc->pTcParams = pTcParams;
  674. pVc->pLcParams = pLcParams;
  675. // This VC's call is now cleanable, i.e. the base call clean up routine,
  676. // InactiveCallCleanUp, will now eventually be called.
  677. //
  678. do
  679. {
  680. // Convert parameter and configuration information to VC flags where
  681. // appropriate.
  682. //
  683. {
  684. ULONG ulMask = 0;
  685. if (CallParameters->MediaParameters->Flags
  686. & RECEIVE_TIME_INDICATION)
  687. {
  688. ulMask |= VCBF_IndicateTimeReceived;
  689. }
  690. if (pAdapter->ulFlags & ACBF_OutgoingRoleLac)
  691. {
  692. ulMask |= VCBF_IncomingFsm;
  693. }
  694. if (fDefaultLcParams)
  695. {
  696. ulMask |= VCBF_DefaultLcParams;
  697. }
  698. if (ulMask)
  699. {
  700. SetFlags( &pVc->ulFlags, ulMask );
  701. }
  702. }
  703. // Take the next progressively increasing call serial number string.
  704. //
  705. NdisInterlockedIncrement( &pAdapter->ulCallSerialNumber );
  706. // Reserve a Call-ID slot in the adapter's table.
  707. //
  708. status = ReserveCallIdSlot( pVc );
  709. if (status != NDIS_STATUS_SUCCESS)
  710. {
  711. break;
  712. }
  713. // Create a new or find an existing tunnel control block for caller's
  714. // specified IP address in the adapter's list. The returned block is
  715. // linked to the adapter and referenced. The reference is the one for
  716. // linkage in the list, i.e. case (a).
  717. //
  718. fExclusiveTunnel = (BOOLEAN )
  719. ((fDefaultLcParams)
  720. ? !!(pAdapter->ulFlags & ACBF_ExclusiveTunnels)
  721. : !!(pLcParams->ulFlags & L2TPCPF_ExclusiveTunnel));
  722. pTunnel = SetupTunnel( pAdapter, ulIpAddress, 0, fExclusiveTunnel );
  723. if (!pTunnel)
  724. {
  725. status = NDIS_STATUS_RESOURCES;
  726. break;
  727. }
  728. NdisAcquireSpinLock( &pTunnel->lockT );
  729. {
  730. if (ReadFlags( &pTunnel->ulFlags ) & TCBF_Closing)
  731. {
  732. // This is unlikely because SetupTunnel only finds non-closing
  733. // tunnels, but this check and linkage must occur atomically
  734. // under 'lockT'. New VCs must not be linked onto closing
  735. // tunnels.
  736. //
  737. status = NDIS_STATUS_TAPI_DISCONNECTMODE_UNKNOWN;
  738. }
  739. else
  740. {
  741. // The call has an open operation pending and can accept close
  742. // requests.
  743. //
  744. SetFlags( &pVc->ulFlags,
  745. VCBF_ClientOpenPending
  746. | VCBF_CallClosableByClient
  747. | VCBF_CallClosableByPeer );
  748. NdisAcquireSpinLock( &pTunnel->lockVcs );
  749. {
  750. // Set the back pointer to it's tunnel. The associated
  751. // tunnel reference was taken by SetupTunnel above.
  752. //
  753. pVc->pTunnel = pTunnel;
  754. // Link the VC into the tunnel's list of associated VCs.
  755. //
  756. InsertTailList( &pTunnel->listVcs, &pVc->linkVcs );
  757. }
  758. NdisReleaseSpinLock( &pTunnel->lockVcs );
  759. }
  760. }
  761. NdisReleaseSpinLock( &pTunnel->lockT );
  762. }
  763. while (FALSE);
  764. if (status != NDIS_STATUS_SUCCESS)
  765. {
  766. CallCleanUp( pVc );
  767. return status;
  768. }
  769. // Schedule FsmOpenTunnel to kick off the combination of tunnel and call
  770. // creation state machines that will eventually call NdisMakeCallComplete
  771. // to notify caller of the result. A happy side effect of the scheduling
  772. // is that the callback will occur at PASSIVE IRQL, the level at which TDI
  773. // clients must run.
  774. //
  775. pVc->state = CS_WaitTunnel;
  776. ScheduleTunnelWork(
  777. pTunnel, pVc, FsmOpenTunnel,
  778. 0, 0, 0, 0, FALSE, FALSE );
  779. TRACE( TL_V, TM_Cm, ( "LcmCmMakeCall pending" ) );
  780. return NDIS_STATUS_PENDING;
  781. }
  782. NDIS_STATUS
  783. LcmCmCloseCall(
  784. IN NDIS_HANDLE CallMgrVcContext,
  785. IN NDIS_HANDLE CallMgrPartyContext,
  786. IN PVOID CloseData,
  787. IN UINT Size )
  788. // Standard 'CmCloseCallHandler' routine called by NDIS when the a client
  789. // has requested to tear down a call. See DDK doc.
  790. //
  791. {
  792. NDIS_STATUS status;
  793. ADAPTERCB* pAdapter;
  794. VCCB* pVc;
  795. ULONG ulFlags;
  796. BOOLEAN fCallClosable;
  797. TRACE( TL_I, TM_Cm, ( "LcmCmCloseCall($%p)", CallMgrVcContext ) );
  798. pVc = (VCCB* )CallMgrVcContext;
  799. if (pVc->ulTag != MTAG_VCCB)
  800. {
  801. ASSERT( !"Vtag?" );
  802. return NDIS_STATUS_INVALID_DATA;
  803. }
  804. pAdapter = pVc->pAdapter;
  805. NdisAcquireSpinLock( &pVc->lockV );
  806. {
  807. ulFlags = ReadFlags( &pVc->ulFlags );
  808. if (ulFlags & VCBF_WaitCloseCall)
  809. {
  810. // Note that we got the close from the client we were expecting.
  811. // This is helpful information when debugging, but is not
  812. // otherwise used.
  813. //
  814. ClearFlags( &pVc->ulFlags, VCBF_WaitCloseCall );
  815. }
  816. if (ulFlags & VCBF_CallClosableByClient)
  817. {
  818. fCallClosable = TRUE;
  819. // Accepting this close makes the call no longer closable by
  820. // client or peer. Any peer operation that was pending is
  821. // cleared, and a client close becomes pending. It is possible to
  822. // have both a client open and close pending at the same time.
  823. //
  824. ClearFlags( &pVc->ulFlags,
  825. (VCBF_CallClosableByClient
  826. | VCBF_CallClosableByPeer
  827. | VCBF_PeerClosePending
  828. | VCBF_PeerOpenPending) );
  829. SetFlags( &pVc->ulFlags, VCBF_ClientClosePending );
  830. // If a client open is pending, it fails.
  831. //
  832. if (ulFlags & VCBF_ClientOpenPending)
  833. {
  834. pVc->status = NDIS_STATUS_TAPI_DISCONNECTMODE_NORMAL;
  835. }
  836. // Close the call, being graceful if possible.
  837. //
  838. ASSERT( pVc->pTunnel );
  839. ScheduleTunnelWork(
  840. pVc->pTunnel, pVc, FsmCloseCall,
  841. (ULONG_PTR )CRESULT_Administrative, (ULONG_PTR )GERR_None,
  842. 0, 0, FALSE, FALSE );
  843. }
  844. else
  845. {
  846. TRACE( TL_I, TM_Cm, ( "Call not closable" ) );
  847. fCallClosable = FALSE;
  848. }
  849. }
  850. NdisReleaseSpinLock( &pVc->lockV );
  851. if (!fCallClosable)
  852. {
  853. // The call is not in a closable state. Just fail the request
  854. // immediately. Since the docs say the call must return PENDING, this
  855. // is done by calling the completion routine here, in typical NDIS
  856. // fashion.
  857. //
  858. ++g_ulCallsNotClosable;
  859. TRACE( TL_I, TM_Recv, ( "NdisMCmCloseCallComp(FAIL)" ) );
  860. NdisMCmCloseCallComplete(
  861. NDIS_STATUS_FAILURE, pVc->NdisVcHandle, NULL );
  862. TRACE( TL_I, TM_Recv, ( "NdisMCmCloseCallComp done" ) );
  863. // Careful, client may have deleted the VC, so 'pVc' must not be
  864. // referenced hereafter.
  865. //
  866. }
  867. TRACE( TL_V, TM_Cm, ( "LcmCmCloseCall pending" ) );
  868. return NDIS_STATUS_PENDING;
  869. }
  870. VOID
  871. LcmCmIncomingCallComplete(
  872. IN NDIS_STATUS Status,
  873. IN NDIS_HANDLE CallMgrVcContext,
  874. IN PCO_CALL_PARAMETERS CallParameters )
  875. // Standard 'CmIncomingCallCompleteHandler' routine called by NDIS when
  876. // a client has responded to the call-managers's previously dispatched
  877. // incoming call. See DDK doc.
  878. //
  879. {
  880. VCCB* pVc;
  881. TRACE( TL_I, TM_Cm,
  882. ( "LcmCmInCallComp($%p,s=$%08x)", CallMgrVcContext, Status ) );
  883. pVc = (VCCB* )CallMgrVcContext;
  884. if (pVc->ulTag != MTAG_VCCB)
  885. {
  886. ASSERT( !"VTag" );
  887. return;
  888. }
  889. // The work is scheduled to avoid a possible recursive loop of completing
  890. // VCs that could overrun the stack. See bug 370996.
  891. //
  892. ASSERT( pVc->pTunnel );
  893. ScheduleTunnelWork(
  894. pVc->pTunnel, pVc, IncomingCallCompletePassive,
  895. (ULONG )Status, 0, 0, 0, FALSE, FALSE );
  896. TRACE( TL_V, TM_Cm, ( "LcmCmInCallComp done" ) );
  897. }
  898. VOID
  899. IncomingCallCompletePassive(
  900. IN TUNNELWORK* pWork,
  901. IN TUNNELCB* pTunnel,
  902. IN VCCB* pVc,
  903. IN ULONG_PTR* punpArgs )
  904. // A PTUNNELWORK routine to complete an LcmCmIncomingCallComplete.
  905. //
  906. // This routine is called only at PASSIVE IRQL.
  907. //
  908. {
  909. NDIS_STATUS status;
  910. ADAPTERCB* pAdapter;
  911. TRACE( TL_N, TM_Cm, ( "InCallCompApc" ) );
  912. // Unpack context information then free the work item.
  913. //
  914. pAdapter = pVc->pAdapter;
  915. status = (NDIS_STATUS )(punpArgs[ 0 ]);
  916. FREE_TUNNELWORK( pAdapter, pWork );
  917. // Guard against a double-complete error by the client.
  918. //
  919. if (ReadFlags( &pVc->ulFlags ) & VCBF_WaitInCallComplete)
  920. {
  921. ClearFlags( &pVc->ulFlags, VCBF_WaitInCallComplete );
  922. if (status != NDIS_STATUS_SUCCESS)
  923. {
  924. pVc->usResult = CRESULT_Busy;
  925. pVc->usError = GERR_None;
  926. // Turn off the "call NdisMCmDispatchIncomingCloseCall if peer
  927. // terminates the call" flag. It was turned on even though peer
  928. // pended, per JameelH.
  929. //
  930. ClearFlags( &pVc->ulFlags, VCBF_VcDispatched );
  931. }
  932. SetupVcComplete( pTunnel, pVc );
  933. }
  934. else
  935. {
  936. ASSERT( !"Not expecting InCallComp?" );
  937. ++g_ulUnexpectedInCallCompletes;
  938. }
  939. // Remove the VC and call references covering the dispatched incoming
  940. // call.
  941. //
  942. DereferenceCall( pVc );
  943. DereferenceVc( pVc );
  944. }
  945. VOID
  946. LcmCmActivateVcComplete(
  947. IN NDIS_STATUS Status,
  948. IN NDIS_HANDLE CallMgrVcContext,
  949. IN PCO_CALL_PARAMETERS CallParameters )
  950. // Standard 'CmActivateVcCompleteHandler' routine called by NDIS when the
  951. // mini-port has completed the call-manager's previous request to activate
  952. // a virtual circuit. See DDK doc.
  953. //
  954. {
  955. ASSERT( !"LcmCmActVcComp?" );
  956. }
  957. VOID
  958. LcmCmDeactivateVcComplete(
  959. IN NDIS_STATUS Status,
  960. IN NDIS_HANDLE CallMgrVcContext )
  961. // Standard 'CmDeactivateVcCompleteHandler' routine called by NDIS when
  962. // the mini-port has completed the call-manager's previous request to
  963. // de-activate a virtual circuit. See DDK doc.
  964. //
  965. {
  966. ASSERT( !"LcmCmDeactVcComp?" );
  967. }
  968. NDIS_STATUS
  969. LcmCmModifyCallQoS(
  970. IN NDIS_HANDLE CallMgrVcContext,
  971. IN PCO_CALL_PARAMETERS CallParameters )
  972. // Standard 'CmModifyQoSCallHandler' routine called by NDIS when a client
  973. // requests a modification in the quality of service provided by the
  974. // virtual circuit. See DDK doc.
  975. //
  976. {
  977. TRACE( TL_N, TM_Cm, ( "LcmCmModQoS" ) );
  978. // There is no useful concept of quality of service for IP media.
  979. //
  980. return NDIS_STATUS_NOT_SUPPORTED;
  981. }
  982. NDIS_STATUS
  983. LcmCmRequest(
  984. IN NDIS_HANDLE CallMgrAfContext,
  985. IN NDIS_HANDLE CallMgrVcContext,
  986. IN NDIS_HANDLE CallMgrPartyContext,
  987. IN OUT PNDIS_REQUEST NdisRequest )
  988. // Standard 'CmRequestHandler' routine called by NDIS in response to a
  989. // client's request for information from the call manager.
  990. //
  991. {
  992. ADAPTERCB* pAdapter;
  993. VCCB* pVc;
  994. NDIS_STATUS status;
  995. TRACE( TL_I, TM_Cm, ( "LcmCmReq" ) );
  996. pAdapter = (ADAPTERCB* )CallMgrAfContext;
  997. if (pAdapter->ulTag != MTAG_ADAPTERCB)
  998. {
  999. ASSERT( !"Atag?" );
  1000. return NDIS_STATUS_INVALID_DATA;
  1001. }
  1002. pVc = (VCCB* )CallMgrVcContext;
  1003. if (pVc && pVc->ulTag != MTAG_VCCB)
  1004. {
  1005. ASSERT( !"Vtag?" );
  1006. return NDIS_STATUS_INVALID_DATA;
  1007. }
  1008. switch (NdisRequest->RequestType)
  1009. {
  1010. case NdisRequestQueryInformation:
  1011. {
  1012. status = QueryCmInformation(
  1013. pAdapter,
  1014. pVc,
  1015. NdisRequest->DATA.QUERY_INFORMATION.Oid,
  1016. NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
  1017. NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
  1018. &NdisRequest->DATA.QUERY_INFORMATION.BytesWritten,
  1019. &NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded );
  1020. break;
  1021. }
  1022. case NdisRequestSetInformation:
  1023. {
  1024. TRACE( TL_A, TM_Cm,
  1025. ( "CmSetOID=%d?", NdisRequest->DATA.SET_INFORMATION.Oid ) );
  1026. status = NDIS_STATUS_NOT_SUPPORTED;
  1027. break;
  1028. }
  1029. default:
  1030. {
  1031. status = NDIS_STATUS_NOT_SUPPORTED;
  1032. TRACE( TL_A, TM_Cm, ( "CmType=%d?", NdisRequest->RequestType ) );
  1033. break;
  1034. }
  1035. }
  1036. return status;
  1037. }
  1038. //-----------------------------------------------------------------------------
  1039. // Call utility routines (alphabetically)
  1040. // Some are used externally
  1041. //-----------------------------------------------------------------------------
  1042. VOID
  1043. ActivateCallIdSlot(
  1044. IN VCCB* pVc )
  1045. // Sets the address of the VC, 'pVc', in the adapter's table of Call-IDs
  1046. // enabling receives on the Call-ID.
  1047. //
  1048. {
  1049. ADAPTERCB* pAdapter;
  1050. pAdapter = pVc->pAdapter;
  1051. if (pVc->usCallId > 0 && pVc->usCallId <= pAdapter->usMaxVcs)
  1052. {
  1053. ASSERT( pAdapter->ppVcs[ pVc->usCallId - 1 ] == (VCCB* )-1 );
  1054. NdisAcquireSpinLock( &pAdapter->lockVcs );
  1055. {
  1056. pAdapter->ppVcs[ pVc->usCallId - 1 ] = pVc;
  1057. }
  1058. NdisReleaseSpinLock( &pAdapter->lockVcs );
  1059. }
  1060. }
  1061. VOID
  1062. BuildCallParametersShell(
  1063. IN ADAPTERCB* pAdapter,
  1064. IN ULONG ulIpAddress,
  1065. IN ULONG ulBufferLength,
  1066. OUT CHAR* pBuffer,
  1067. OUT CO_AF_TAPI_INCOMING_CALL_PARAMETERS UNALIGNED ** ppTiParams,
  1068. OUT LINE_CALL_INFO** ppTcInfo,
  1069. OUT L2TP_CALL_PARAMETERS** ppLcParams )
  1070. // Loads caller's buffer 'pBuffer' of length 'ulBufferLength' bytes with a
  1071. // CO_CALL_PARAMETERS structure containing default values. Loads caller's
  1072. // '*ppTiParams', '*ppTcInfo', and '*ppLcParams' with shortcut pointers to
  1073. // the TAPI call and L2TP specific structures within the built
  1074. // CO_CALL_PARAMETERS. 'PAdapter' is the adapter context. 'pUlIpAddress'
  1075. // is the IP address of the peer in network byte order.
  1076. //
  1077. {
  1078. CO_CALL_PARAMETERS* pCp;
  1079. CO_CALL_MANAGER_PARAMETERS* pCmp;
  1080. CO_MEDIA_PARAMETERS* pMp;
  1081. CO_AF_TAPI_INCOMING_CALL_PARAMETERS UNALIGNED * pTip;
  1082. LINE_CALL_INFO* pLci;
  1083. L2TP_CALL_PARAMETERS* pLcp;
  1084. CHAR* pszCallerId;
  1085. ULONG ulLciTotalSize;
  1086. ULONG ulMediaSpecificSize;
  1087. ULONG ulBytesPerSec;
  1088. WCHAR* pszCallerID;
  1089. NdisZeroMemory( pBuffer, ulBufferLength );
  1090. pCp = (CO_CALL_PARAMETERS* )pBuffer;
  1091. pCmp = (PCO_CALL_MANAGER_PARAMETERS ) ( (PUCHAR)(pCp + 1) + sizeof(PVOID) );
  1092. (ULONG_PTR) pCmp &= ~( (ULONG_PTR) sizeof(PVOID) - 1 );
  1093. pCp->CallMgrParameters = pCmp;
  1094. pMp = (PCO_MEDIA_PARAMETERS ) ( (PUCHAR) (pCmp + 1) + sizeof(PVOID) );
  1095. (ULONG_PTR) pMp &= ~( (ULONG_PTR) sizeof(PVOID) - 1 );
  1096. pCp->MediaParameters = pMp;
  1097. // This needs to be dynamic based on speed reported by TDI.
  1098. //
  1099. ulBytesPerSec = L2TP_LanBps / 8;
  1100. pCmp->Transmit.TokenRate = ulBytesPerSec;
  1101. pCmp->Transmit.PeakBandwidth = ulBytesPerSec;
  1102. pCmp->Transmit.MaxSduSize = L2TP_MaxFrameSize;
  1103. pCmp->Receive.TokenRate = ulBytesPerSec;
  1104. pCmp->Receive.PeakBandwidth = ulBytesPerSec;
  1105. pCmp->Receive.MaxSduSize = L2TP_MaxFrameSize;
  1106. ulLciTotalSize =
  1107. sizeof(*pLci)
  1108. + sizeof(PVOID)
  1109. + sizeof(*pLcp)
  1110. + ((L2TP_MaxDottedIpLen + 1) * sizeof(WCHAR));
  1111. ulMediaSpecificSize = sizeof(*pTip) + sizeof(PVOID) + ulLciTotalSize;
  1112. pTip =
  1113. (CO_AF_TAPI_INCOMING_CALL_PARAMETERS UNALIGNED* )pMp->MediaSpecific.Parameters;
  1114. pLci = (LINE_CALL_INFO*) ( (PUCHAR) (pTip + 1) + sizeof(PVOID) );
  1115. (ULONG_PTR) pLci &= ~( (ULONG_PTR) sizeof(PVOID) - 1 );
  1116. pLcp = (L2TP_CALL_PARAMETERS*) ( (PUCHAR) (pLci + 1) + sizeof(PVOID) );
  1117. (ULONG_PTR) pLcp &= ~( (ULONG_PTR) sizeof(PVOID) - 1 );
  1118. pMp->ReceiveSizeHint = L2TP_MaxFrameSize;
  1119. pMp->MediaSpecific.Length = ulMediaSpecificSize;
  1120. pTip->LineCallInfo.Length = (USHORT )ulLciTotalSize;
  1121. pTip->LineCallInfo.MaximumLength = (USHORT )ulLciTotalSize;
  1122. pTip->LineCallInfo.Offset = (ULONG) ((CHAR*) pLci - (CHAR*) &pTip->LineCallInfo);
  1123. pLci->ulTotalSize = ulLciTotalSize;
  1124. pLci->ulNeededSize = ulLciTotalSize;
  1125. pLci->ulUsedSize = ulLciTotalSize;
  1126. pLci->ulLineDeviceID = pAdapter->ulSapLineId;
  1127. pLci->ulAddressID = pAdapter->ulSapAddressId;
  1128. pLci->ulDevSpecificSize = sizeof(*pLcp);
  1129. pLci->ulDevSpecificOffset = (ULONG) ((CHAR*) pLcp - (CHAR*) pLci);
  1130. pLci->ulBearerMode = LINEBEARERMODE_DATA;
  1131. pLci->ulCallerIDOffset = pLci->ulDevSpecificOffset + pLci->ulDevSpecificSize;
  1132. pszCallerID = (WCHAR*)(((CHAR* )pLci) + pLci->ulCallerIDOffset);
  1133. DottedFromIpAddress( ulIpAddress, (CHAR* )pszCallerID, TRUE );
  1134. pLci->ulCallerIDSize = (StrLenW( pszCallerID ) + 1) * sizeof(WCHAR);
  1135. pLci->ulCallerIDFlags = LINECALLPARTYID_ADDRESS;
  1136. pLcp->ulPhysicalChannelId = 0xFFFFFFFF;
  1137. // Fill in shortcut outputs.
  1138. //
  1139. *ppTiParams = pTip;
  1140. *ppTcInfo = pLci;
  1141. *ppLcParams = pLcp;
  1142. }
  1143. VOID
  1144. CallCleanUp(
  1145. IN VCCB* pVc )
  1146. // De-associates the VC from the tunnel, preparing for and de-activating
  1147. // the call.
  1148. //
  1149. {
  1150. NDIS_STATUS status;
  1151. ULONG ulFlags;
  1152. ulFlags = ReadFlags( &pVc->ulFlags );
  1153. TRACE( TL_I, TM_Cm, ( "CallCleanUp(pV=$%p,cid=%d,act=%d)",
  1154. pVc, (ULONG )pVc->usCallId, !!(ulFlags & VCBF_VcActivated) ) );
  1155. ASSERT( pVc->ulTag == MTAG_VCCB );
  1156. if (ReadFlags( &pVc->ulFlags ) & VCBF_VcActivated)
  1157. {
  1158. TRACE( TL_I, TM_Recv, ( "NdisMCmDeactVc" ) );
  1159. status = NdisMCmDeactivateVc( pVc->NdisVcHandle );
  1160. TRACE( TL_I, TM_Recv, ( "NdisMCmDeactVc=$%x", status ) );
  1161. ASSERT( status == NDIS_STATUS_SUCCESS );
  1162. ClearFlags( &pVc->ulFlags, VCBF_VcActivated );
  1163. DereferenceCall( pVc );
  1164. // The above actions lead to the call reference eventually going to 0,
  1165. // at which time clean up resumes in DereferenceCall.
  1166. //
  1167. }
  1168. else
  1169. {
  1170. InactiveCallCleanUp( pVc );
  1171. }
  1172. }
  1173. VOID
  1174. CallSetupComplete(
  1175. IN VCCB* pVc )
  1176. // Clean up 'pVc' allocations used only at call setup, if any.
  1177. //
  1178. {
  1179. if (InterlockedExchangePointer( &pVc->pMakeCall, NULL ))
  1180. {
  1181. ASSERT( pVc->pTmParams );
  1182. ASSERT( pVc->pTcParams );
  1183. ASSERT( pVc->pLcParams );
  1184. if (ReadFlags( &pVc->ulFlags ) & VCBF_DefaultLcParams)
  1185. {
  1186. // Caller did not provide any LcParams. Free the 'default' version we
  1187. // created for convenience.
  1188. //
  1189. FREE_NONPAGED( pVc->pLcParams );
  1190. }
  1191. pVc->pTmParams = NULL;
  1192. pVc->pTcParams = NULL;
  1193. pVc->pLcParams = NULL;
  1194. }
  1195. UnlockIcs( pVc, FALSE );
  1196. }
  1197. VOID
  1198. CloseCall(
  1199. IN TUNNELWORK* pWork,
  1200. IN TUNNELCB* pTunnel,
  1201. IN VCCB* pVc,
  1202. IN ULONG_PTR* punpArgs )
  1203. // A PTUNNELWORK routine to close the call on 'pVc'.
  1204. //
  1205. // This routine is called only at PASSIVE IRQL.
  1206. //
  1207. {
  1208. BOOLEAN fCompleteVcs;
  1209. TRACE( TL_I, TM_Fsm, ( "CloseCall(pV=$%p)", pVc ) );
  1210. // No context information so just free the work item.
  1211. //
  1212. FREE_TUNNELWORK( pTunnel->pAdapter, pWork );
  1213. // Close down the call.
  1214. //
  1215. NdisAcquireSpinLock( &pTunnel->lockT );
  1216. {
  1217. NdisAcquireSpinLock( &pVc->lockV );
  1218. {
  1219. fCompleteVcs = CloseCall2(
  1220. pTunnel, pVc, TRESULT_Shutdown, GERR_None );
  1221. }
  1222. NdisReleaseSpinLock( &pVc->lockV );
  1223. if (fCompleteVcs)
  1224. {
  1225. CompleteVcs( pTunnel );
  1226. }
  1227. }
  1228. NdisReleaseSpinLock( &pTunnel->lockT );
  1229. }
  1230. BOOLEAN
  1231. CloseCall2(
  1232. IN TUNNELCB* pTunnel,
  1233. IN VCCB* pVc,
  1234. IN USHORT usResult,
  1235. IN USHORT usError )
  1236. // Close the call on VC 'pVc' of tunnel 'pTunnel'. 'UsResult' and
  1237. // 'usError' are the TRESULT_* and GERR_* codes to be reported in the
  1238. // StopCCN message, if applicable.
  1239. //
  1240. // Returns true if caller should call CompleteVcs after releasing 'lockV'
  1241. // or false if not.
  1242. //
  1243. // IMPORTANT: Caller must hold 'lockT' and 'lockV'.
  1244. //
  1245. {
  1246. ULONG ulFlags;
  1247. // Check if another path has completed the VC already. If so, there's no
  1248. // reason to continue. Without the local tunnel cancel optimization
  1249. // below, this check can be removed entirely and everything safely falls
  1250. // through. This check should include all "non-completing" conditions in
  1251. // CallTransitionComplete.
  1252. //
  1253. ulFlags = ReadFlags( &pVc->ulFlags );
  1254. if (!(ulFlags & VCBM_Pending))
  1255. {
  1256. if (!(ulFlags & VCBF_CallClosableByPeer))
  1257. {
  1258. TRACE( TL_A, TM_Cm, ( "Not closable" ) );
  1259. return FALSE;
  1260. }
  1261. }
  1262. // For locally initiated tunnels, check if this VC is the only one on the
  1263. // tunnel, and if so, close the tunnel directly which slams this call.
  1264. // Without this, the call closure would still bring down the tunnel.
  1265. // However, the tunnel would complete it's transition normally, then be
  1266. // dropped. This speeds things up a little, giving quick response in the
  1267. // case where user cancels an attempt to connect to a wrong address or
  1268. // non-responsive server.
  1269. //
  1270. if (!(ReadFlags( &pTunnel->ulFlags) & TCBF_PeerInitiated))
  1271. {
  1272. BOOLEAN fMultipleVcs;
  1273. NdisAcquireSpinLock( &pTunnel->lockVcs );
  1274. {
  1275. fMultipleVcs =
  1276. (pTunnel->listVcs.Flink != pTunnel->listVcs.Blink);
  1277. }
  1278. NdisReleaseSpinLock( &pTunnel->lockVcs );
  1279. if (!fMultipleVcs)
  1280. {
  1281. ScheduleTunnelWork(
  1282. pTunnel, NULL, FsmCloseTunnel,
  1283. (ULONG_PTR )usResult,
  1284. (ULONG_PTR )usError,
  1285. 0, 0, FALSE, FALSE );
  1286. return FALSE;
  1287. }
  1288. }
  1289. // Slam the call closed.
  1290. //
  1291. CallTransitionComplete( pTunnel, pVc, CS_Idle );
  1292. return TRUE;
  1293. }
  1294. VOID
  1295. CloseTunnel(
  1296. IN TUNNELWORK* pWork,
  1297. IN TUNNELCB* pTunnel,
  1298. IN VCCB* pVc,
  1299. IN ULONG_PTR* punpArgs )
  1300. // A PTUNNELWORK routine to slam closed tunnel 'pTunnel'. See also
  1301. // FsmCloseTunnel, which is often more appropriate.
  1302. //
  1303. // This routine is called only at PASSIVE IRQL.
  1304. //
  1305. {
  1306. TRACE( TL_I, TM_Fsm, ( "CloseTunnel(pT=$%p)", pTunnel ) );
  1307. // No context information so just free the work item.
  1308. //
  1309. FREE_TUNNELWORK( pTunnel->pAdapter, pWork );
  1310. // Close down the tunnel.
  1311. //
  1312. NdisAcquireSpinLock( &pTunnel->lockT );
  1313. {
  1314. CloseTunnel2( pTunnel );
  1315. }
  1316. NdisReleaseSpinLock( &pTunnel->lockT );
  1317. }
  1318. VOID
  1319. CloseTunnel2(
  1320. IN TUNNELCB* pTunnel )
  1321. // Close the tunnel 'pTunnel'.
  1322. //
  1323. // IMPORTANT: Caller must hold 'lockT'.
  1324. //
  1325. {
  1326. SetFlags( &pTunnel->ulFlags, TCBF_Closing );
  1327. TunnelTransitionComplete( pTunnel, CCS_Idle );
  1328. CompleteVcs( pTunnel );
  1329. }
  1330. VOID
  1331. CompleteVcs(
  1332. IN TUNNELCB* pTunnel )
  1333. // Complete the pending operation for each of the VCs on the completing
  1334. // list of tunnel 'pTunnel'.
  1335. //
  1336. // IMPORTANT: Caller must hold 'lockT'. This routine may release and
  1337. // re-acquire 'lockT'.
  1338. //
  1339. {
  1340. while (!IsListEmpty( &pTunnel->listCompletingVcs ))
  1341. {
  1342. LIST_ENTRY* pLink;
  1343. VCCB* pVc;
  1344. NDIS_STATUS status;
  1345. LINKSTATUSINFO info;
  1346. ULONG ulFlags;
  1347. NDIS_STATUS statusVc;
  1348. if (pTunnel->listCompletingVcs.Flink->Flink
  1349. == pTunnel->listCompletingVcs.Flink)
  1350. {
  1351. // This is a hack to work around a rare listCompletingVcs
  1352. // corruption problem whose cause has me baffled. When the
  1353. // problem occurs, a VCCB with it's link initialized appears in
  1354. // the list. This code removes the corrupted case hopefully
  1355. // resulting in exactly the same state as the normal path in the
  1356. // "else" clause.
  1357. //
  1358. pLink = pTunnel->listCompletingVcs.Flink;
  1359. InitializeListHead( &pTunnel->listCompletingVcs );
  1360. ASSERT( FALSE );
  1361. ++g_ulCompletingVcCorruption;
  1362. }
  1363. else
  1364. {
  1365. // Pop the next completing VC from the list.
  1366. //
  1367. pLink = RemoveHeadList( &pTunnel->listCompletingVcs );
  1368. }
  1369. InitializeListHead( pLink );
  1370. // Take a reference covering use of the VC pointer obtained from the
  1371. // completing list.
  1372. //
  1373. pVc = CONTAINING_RECORD( pLink, VCCB, linkCompletingVcs );
  1374. ReferenceVc( pVc );
  1375. TRACE( TL_V, TM_Recv, ( "CompleteVc $%p", pVc ) );
  1376. NdisAcquireSpinLock( &pVc->lockV );
  1377. {
  1378. // Note the pending flags then clear them, to ensure that all
  1379. // pending operations are completed exactly once. This is
  1380. // necessary since ClientOpen and ClientClose events may be
  1381. // pending simultaneously. (Thanks a lot NDIS guys).
  1382. //
  1383. ulFlags = ReadFlags( &pVc->ulFlags );
  1384. ClearFlags( &pVc->ulFlags, VCBM_Pending );
  1385. // Convert client close pending to client close completion,
  1386. // for reference later when call references reach zero. The
  1387. // flag determines if NdisMCmCloseCallComplete must be called.
  1388. //
  1389. if (ulFlags & VCBF_ClientClosePending)
  1390. {
  1391. SetFlags( &pVc->ulFlags, VCBF_ClientCloseCompletion );
  1392. }
  1393. // Before releasing the lock, make "safe" copies of any VC
  1394. // parameters we might need.
  1395. //
  1396. TransferLinkStatusInfo( pVc, &info );
  1397. statusVc = pVc->status;
  1398. }
  1399. NdisReleaseSpinLock( &pVc->lockV );
  1400. NdisReleaseSpinLock( &pTunnel->lockT );
  1401. {
  1402. if (ulFlags & VCBF_PeerOpenPending)
  1403. {
  1404. TRACE( TL_N, TM_Recv,
  1405. ( "PeerOpen complete, s=$%x", statusVc ) );
  1406. if (statusVc == NDIS_STATUS_SUCCESS)
  1407. {
  1408. // Peer initiated call succeeded.
  1409. //
  1410. ASSERT( ulFlags & VCBF_VcDispatched );
  1411. TRACE( TL_I, TM_Recv, ( "NdisMCmDispCallConn" ) );
  1412. NdisMCmDispatchCallConnected( pVc->NdisVcHandle );
  1413. TRACE( TL_I, TM_Recv, ( "NdisMCmDispCallConn done" ) );
  1414. IndicateLinkStatus( pVc, &info );
  1415. CallSetupComplete( pVc );
  1416. }
  1417. else
  1418. {
  1419. // Peer initiated call failed.
  1420. //
  1421. if (ulFlags & VCBF_VcDispatched)
  1422. {
  1423. SetFlags( &pVc->ulFlags, VCBF_WaitCloseCall );
  1424. TRACE( TL_I, TM_Recv,
  1425. ( "NdisMCmDispInCloseCall(s=$%x)", statusVc ) );
  1426. NdisMCmDispatchIncomingCloseCall(
  1427. statusVc, pVc->NdisVcHandle, NULL, 0 );
  1428. TRACE( TL_I, TM_Recv,
  1429. ( "NdisMCmDispInCloseCall done" ) );
  1430. // Client will call NdisClCloseCall which will get
  1431. // our LcmCloseCall handler called to clean up
  1432. // call setup, de-activate and delete the VC, as
  1433. // necessary.
  1434. //
  1435. }
  1436. else
  1437. {
  1438. // Return the VC to "just created" state.
  1439. //
  1440. CallCleanUp( pVc );
  1441. }
  1442. }
  1443. }
  1444. else if (ulFlags & VCBF_ClientOpenPending)
  1445. {
  1446. TRACE( TL_N, TM_Recv,
  1447. ( "ClientOpen complete, s=$%x", statusVc ) );
  1448. if (statusVc == NDIS_STATUS_SUCCESS)
  1449. {
  1450. // Client initiated open, i.e. MakeCall, succeeded.
  1451. //
  1452. // Activating the VC is a CoNDIS preliminary to reporting
  1453. // the MakeCall complete. For L2TP, all it does is get
  1454. // the NDIS state flags set correctly.
  1455. //
  1456. TRACE( TL_I, TM_Recv, ( "NdisMCmActivateVc" ) );
  1457. ASSERT( pVc->pMakeCall );
  1458. status = NdisMCmActivateVc(
  1459. pVc->NdisVcHandle, pVc->pMakeCall );
  1460. TRACE( TL_I, TM_Recv, ( "NdisMCmActivateVc=$%x", status ) );
  1461. ASSERT( status == NDIS_STATUS_SUCCESS );
  1462. {
  1463. BOOLEAN fCallActive;
  1464. SetFlags( &pVc->ulFlags, VCBF_VcActivated );
  1465. fCallActive = ReferenceCall( pVc );
  1466. ASSERT( fCallActive );
  1467. }
  1468. }
  1469. // Update the call parameters
  1470. pVc->pMakeCall->CallMgrParameters->Transmit.PeakBandwidth =
  1471. pVc->pMakeCall->CallMgrParameters->Transmit.TokenRate =
  1472. pVc->pMakeCall->CallMgrParameters->Receive.PeakBandwidth =
  1473. pVc->pMakeCall->CallMgrParameters->Receive.TokenRate = pVc->ulConnectBps / 8;
  1474. TRACE( TL_I, TM_Recv,
  1475. ( "NdisMCmMakeCallComp(s=$%x)", statusVc ) );
  1476. ASSERT( pVc->pMakeCall );
  1477. NdisMCmMakeCallComplete(
  1478. statusVc, pVc->NdisVcHandle, NULL, NULL, pVc->pMakeCall );
  1479. TRACE( TL_I, TM_Recv, ( "NdisMCmMakeCallComp done" ) );
  1480. if (statusVc == NDIS_STATUS_SUCCESS)
  1481. {
  1482. IndicateLinkStatus( pVc, &info );
  1483. CallSetupComplete( pVc );
  1484. }
  1485. else
  1486. {
  1487. // Return the VC to "just created" state.
  1488. //
  1489. InactiveCallCleanUp( pVc );
  1490. }
  1491. }
  1492. else if (ulFlags & VCBF_PeerClosePending )
  1493. {
  1494. TRACE( TL_N, TM_Recv,
  1495. ( "PeerClose complete, s=$%x", statusVc ) );
  1496. // Peer initiated close completed.
  1497. //
  1498. SetFlags( &pVc->ulFlags, VCBF_WaitCloseCall );
  1499. TRACE( TL_I, TM_Recv, ( "NdisMCmDispInCloseCall(s=$%x)",
  1500. statusVc ) );
  1501. NdisMCmDispatchIncomingCloseCall(
  1502. statusVc, pVc->NdisVcHandle, NULL, 0 );
  1503. TRACE( TL_I, TM_Recv, ( "NdisMCmDispInCloseCall done" ) );
  1504. // Client will call NdisClCloseCall while processing the above
  1505. // which will get our LcmCloseCall handler called to
  1506. // de-activate and delete the VC, as necessary.
  1507. //
  1508. }
  1509. else if (ulFlags & VCBF_ClientClosePending)
  1510. {
  1511. // This section eventually runs for all successful unclosed
  1512. // calls, whether peer or client initiated or closed.
  1513. //
  1514. TRACE( TL_N, TM_Recv, ( "ClientClose complete" ) );
  1515. // Deactivate the VC and return all sent packets to the client
  1516. // above. These events will eventually lead to the call being
  1517. // dereferenced to zero, at which time the close is completed,
  1518. // and if peer initiated, the VC is deleted.
  1519. //
  1520. // Note: When MakeCall is cancelled by a Close request, these
  1521. // actions occur during the InactiveCallCleanUp in the
  1522. // ClientOpenPending completion code handling, rather
  1523. // than the CallCleanUp (which leads to
  1524. // InactiveCallCleanUp) here. In this case, this block
  1525. // does NOT run even though the ClientClosePending flag
  1526. // is set. Consider this before adding code here.
  1527. //
  1528. CallCleanUp( pVc );
  1529. }
  1530. }
  1531. NdisAcquireSpinLock( &pTunnel->lockT );
  1532. // Remove the reference for use of the VC pointer from the completing
  1533. // list.
  1534. //
  1535. DereferenceVc( pVc );
  1536. }
  1537. }
  1538. TUNNELCB*
  1539. CreateTunnelCb(
  1540. IN ADAPTERCB* pAdapter )
  1541. // Allocates and initializes a tunnel control block from the pool
  1542. // associated with 'pAdapter'. Tunnels are created unreferenced.
  1543. //
  1544. // Returns the allocated control block or NULL if allocation failed. The
  1545. // allocated block must eventually be freed with FREE_TUNNELCB, typically
  1546. // via DereferenceTunnel.
  1547. //
  1548. // IMPORTANT: Caller must hold the 'pAdapter->lockTunnels'.
  1549. //
  1550. {
  1551. TUNNELCB* pTunnel;
  1552. pTunnel = ALLOC_TUNNELCB( pAdapter );
  1553. if (pTunnel)
  1554. {
  1555. NdisZeroMemory( pTunnel, sizeof(*pTunnel ) );
  1556. InitializeListHead( &pTunnel->linkTunnels );
  1557. InitializeListHead( &pTunnel->listRequestingVcs );
  1558. InitializeListHead( &pTunnel->listCompletingVcs );
  1559. InitializeListHead( &pTunnel->listSendsOut );
  1560. InitializeListHead( &pTunnel->listOutOfOrder );
  1561. InitializeListHead( &pTunnel->listVcs );
  1562. InitializeListHead( &pTunnel->listWork );
  1563. NdisAllocateSpinLock( &pTunnel->lockT );
  1564. NdisAllocateSpinLock( &pTunnel->lockWork );
  1565. pTunnel->ulTag = MTAG_TUNNELCB;
  1566. pTunnel->state = CCS_Idle;
  1567. // Choose the next non-zero sequential tunnel identifier.
  1568. //
  1569. pTunnel->usTunnelId = GetNextTunnelId( pAdapter );
  1570. // Default send window, "slow started". This is typically adjusted
  1571. // based on peer's Receive Window AVP when the tunnel is created, but
  1572. // if he doesn't include one this default is used.
  1573. //
  1574. pTunnel->ulSendWindow = pAdapter->info.MaxSendWindow >> 1;
  1575. if (pTunnel->ulSendWindow == 0)
  1576. {
  1577. pTunnel->ulSendWindow = 1;
  1578. }
  1579. // Initialize the estimated round trip time and send timeout per the
  1580. // suggestions in the draft/RFC.
  1581. //
  1582. pTunnel->ulRoundTripMs = pAdapter->ulInitialSendTimeoutMs;
  1583. pTunnel->ulSendTimeoutMs = pTunnel->ulRoundTripMs;
  1584. pTunnel->ulMediaSpeed = L2TP_LanBps;
  1585. pTunnel->pTimerQ = ALLOC_TIMERQ( pAdapter );
  1586. if (!pTunnel->pTimerQ)
  1587. {
  1588. pTunnel->ulTag = MTAG_FREED;
  1589. FREE_TUNNELCB( pAdapter, pTunnel );
  1590. return NULL;
  1591. }
  1592. TimerQInitialize( pTunnel->pTimerQ );
  1593. ++pAdapter->ulTimers;
  1594. if (pAdapter->pszPassword)
  1595. {
  1596. UNALIGNED ULONG* pul;
  1597. // Password specified so peer should be authenticated. Choose a
  1598. // random challenge to send to peer.
  1599. //
  1600. pul = (UNALIGNED ULONG* )(pTunnel->achChallengeToSend);
  1601. NdisGetCurrentSystemTime( (LARGE_INTEGER* )pul );
  1602. pul[ 1 ] = PtrToUlong( pAdapter );
  1603. pul[ 2 ] = PtrToUlong( pTunnel );
  1604. pul[ 3 ] = PtrToUlong( &pul );
  1605. }
  1606. ReferenceAdapter( pAdapter );
  1607. pTunnel->pAdapter = pAdapter;
  1608. TRACE( TL_I, TM_Misc, ( "CreateTcb=$%p", pTunnel ) );
  1609. }
  1610. return pTunnel;
  1611. }
  1612. VOID
  1613. DereferenceAf(
  1614. IN ADAPTERCB* pAdapter )
  1615. // Removes a reference from the address family of adapter control block
  1616. // 'pAdapter', and when frees the block when the last reference is
  1617. // removed.
  1618. //
  1619. {
  1620. LONG lRef;
  1621. lRef = NdisInterlockedDecrement( &pAdapter->lAfRef );
  1622. TRACE( TL_N, TM_Ref, ( "DerefAf to %d", lRef ) );
  1623. ASSERT( lRef >= 0 );
  1624. if (lRef == 0)
  1625. {
  1626. // Tell NDIS it's close is complete.
  1627. //
  1628. TRACE( TL_I, TM_Cm, ( "NdisMCmCloseAfComp" ) );
  1629. NdisMCmCloseAddressFamilyComplete(
  1630. NDIS_STATUS_SUCCESS, pAdapter->NdisAfHandle );
  1631. TRACE( TL_I, TM_Cm, ( "NdisMCmCloseAfComp done" ) );
  1632. // Remove the reference for the NdisAfHandle.
  1633. //
  1634. InterlockedExchangePointer( &pAdapter->NdisAfHandle, NULL );
  1635. DereferenceAdapter( pAdapter );
  1636. }
  1637. }
  1638. VOID
  1639. DereferenceCall(
  1640. IN VCCB* pVc )
  1641. // Removes a reference from the call active on 'pVc', invoking call clean
  1642. // up when the value reaches zero.
  1643. //
  1644. {
  1645. LONG lRef;
  1646. NDIS_STATUS status;
  1647. ADAPTERCB* pAdapter;
  1648. LIST_ENTRY* pLink;
  1649. pAdapter = pVc->pAdapter;
  1650. NdisAcquireSpinLock( &pVc->lockCall );
  1651. {
  1652. lRef = --pVc->lCallRef;
  1653. TRACE( TL_N, TM_Ref, ( "DerefC to %d", pVc->lCallRef ) );
  1654. }
  1655. NdisReleaseSpinLock( &pVc->lockCall );
  1656. if (lRef == 0)
  1657. {
  1658. InactiveCallCleanUp( pVc );
  1659. }
  1660. }
  1661. VOID
  1662. DereferenceSap(
  1663. IN ADAPTERCB* pAdapter )
  1664. // Removes a reference from the SAP active on 'pAdapter', invoking
  1665. // Deregiter SAP completion handling when the value reaches zero.
  1666. //
  1667. {
  1668. LONG lRef;
  1669. NDIS_STATUS status;
  1670. NdisAcquireSpinLock( &pAdapter->lockSap );
  1671. {
  1672. lRef = --pAdapter->lSapRef;
  1673. TRACE( TL_N, TM_Ref, ( "DerefSap to %d", pAdapter->lSapRef ) );
  1674. }
  1675. NdisReleaseSpinLock( &pAdapter->lockSap );
  1676. if (lRef == 0)
  1677. {
  1678. status = ScheduleWork( pAdapter, DeregisterSapPassive, pAdapter );
  1679. ASSERT( status == NDIS_STATUS_SUCCESS );
  1680. }
  1681. }
  1682. LONG
  1683. DereferenceTunnel(
  1684. IN TUNNELCB* pTunnel )
  1685. // Dereference the tunnel control block 'pTunnel'. If no longer
  1686. // referenced, unlink, undo any TDIX reference, and free the tunnel
  1687. // control block.
  1688. //
  1689. // This routine will not try to acquire 'lockT' or any 'lockV'.
  1690. //
  1691. // Returns the reference count after the dereference.
  1692. //
  1693. {
  1694. ADAPTERCB* pAdapter;
  1695. LIST_ENTRY* pLink;
  1696. LONG lRef;
  1697. pAdapter = pTunnel->pAdapter;
  1698. NdisAcquireSpinLock( &pAdapter->lockTunnels );
  1699. {
  1700. lRef = --(pTunnel->lRef);
  1701. TRACE( TL_N, TM_Ref, ( "DerefTcb to %d", lRef ) );
  1702. ASSERT( lRef >= 0 );
  1703. if (lRef == 0)
  1704. {
  1705. if (!(ReadFlags( &pTunnel->ulFlags )
  1706. & (TCBF_PeerInitiated | TCBF_Closing)))
  1707. {
  1708. // We initiated this tunnel and all it's calls have terminated
  1709. // gracefully. Initiate a graceful tunnel closing exchange.
  1710. // We'll wind up back here with TCBF_Closing set.
  1711. //
  1712. ReferenceTunnel( pTunnel, TRUE );
  1713. ScheduleTunnelWork(
  1714. pTunnel, NULL, FsmCloseTunnel,
  1715. (ULONG_PTR )TRESULT_General,
  1716. (ULONG_PTR )GERR_None,
  1717. 0, 0, TRUE, FALSE );
  1718. }
  1719. else if (pTunnel->linkTunnels.Flink != &pTunnel->linkTunnels)
  1720. {
  1721. // The graceful closing exchange has completed or none is
  1722. // indicated. Time to stop all activity on the tunnel.
  1723. //
  1724. // Remove the tunnel from the adapter's list of active
  1725. // tunnels. Initialize the list link so it won't be done
  1726. // again following the APCed TDIX clean up below. Since there
  1727. // are no VC references on the tunnel, no further receive path
  1728. // events will touch this control block.
  1729. //
  1730. RemoveEntryList( &pTunnel->linkTunnels );
  1731. InitializeListHead( &pTunnel->linkTunnels );
  1732. if (ReadFlags( &pTunnel->ulFlags ) & TCBF_HostRouteAdded)
  1733. {
  1734. // Undo the host route we added.
  1735. //
  1736. ReferenceTunnel( pTunnel, TRUE );
  1737. ScheduleTunnelWork(
  1738. pTunnel, NULL, DeleteHostRoute,
  1739. 0, 0, 0, 0, TRUE, FALSE );
  1740. }
  1741. if (ReadFlags( &pTunnel->ulFlags ) & TCBF_TdixReferenced)
  1742. {
  1743. // Undo our TDI extension context reference.
  1744. //
  1745. ReferenceTunnel( pTunnel, TRUE );
  1746. ScheduleTunnelWork(
  1747. pTunnel, NULL, CloseTdix,
  1748. 0, 0, 0, 0, TRUE, FALSE );
  1749. }
  1750. }
  1751. lRef = pTunnel->lRef;
  1752. }
  1753. }
  1754. NdisReleaseSpinLock( &pAdapter->lockTunnels );
  1755. if (lRef > 0)
  1756. {
  1757. return lRef;
  1758. }
  1759. TRACE( TL_N, TM_Misc, ( "Freeing TCB..." ) );
  1760. // Stop the timer queue, which causes a TE_Terminate event for any timers
  1761. // still running.
  1762. //
  1763. TimerQTerminate(
  1764. pTunnel->pTimerQ, TunnelTqTerminateComplete, pAdapter );
  1765. // No references and all PASSIVE IRQL termination completed. Finish
  1766. // cleaning up the tunnel control block.
  1767. //
  1768. ASSERT( !pTunnel->pTqiHello );
  1769. ASSERT( IsListEmpty( &pTunnel->listVcs ) );
  1770. ASSERT( IsListEmpty( &pTunnel->listRequestingVcs ) );
  1771. ASSERT( IsListEmpty( &pTunnel->listCompletingVcs ) );
  1772. ASSERT( IsListEmpty( &pTunnel->listWork ) );
  1773. ASSERT( IsListEmpty( &pTunnel->listSendsOut ) );
  1774. ASSERT( IsListEmpty( &pTunnel->listOutOfOrder ) );
  1775. // Free the tunnel control block.
  1776. //
  1777. pTunnel->ulTag = MTAG_FREED;
  1778. FREE_TUNNELCB( pAdapter, pTunnel );
  1779. TRACE( TL_I, TM_Misc, ( "TCB freed $%p", pTunnel ) );
  1780. DereferenceAdapter( pAdapter );
  1781. return 0;
  1782. }
  1783. VOID
  1784. DereferenceVc(
  1785. IN VCCB* pVc )
  1786. // Removes a reference to the VC control block 'pVc', and when frees the
  1787. // block when the last reference is removed.
  1788. //
  1789. {
  1790. LONG lRef;
  1791. lRef = NdisInterlockedDecrement( &pVc->lRef );
  1792. TRACE( TL_N, TM_Ref, ( "DerefV to %d", lRef ) );
  1793. ASSERT( lRef >= 0 );
  1794. if (lRef == 0)
  1795. {
  1796. ADAPTERCB* pAdapter;
  1797. pAdapter = pVc->pAdapter;
  1798. // Can make these assumptions because NDIS will not call the delete-VC
  1799. // handler while the VC is active. All the nasty VC clean up occurs
  1800. // before the VC is deactivated and the call closed.
  1801. //
  1802. ASSERT( IsListEmpty( &pVc->listSendsOut ) );
  1803. ASSERT( IsListEmpty( &pVc->listOutOfOrder ) );
  1804. ASSERT( !pVc->pTqiDelayedAck );
  1805. ASSERT( pVc->ulTag == MTAG_VCCB );
  1806. pVc->ulTag = MTAG_FREED;
  1807. FREE_VCCB( pAdapter, pVc );
  1808. DereferenceAdapter( pAdapter );
  1809. TRACE( TL_I, TM_Mp, ( "VCB freed $%p", pVc ) );
  1810. }
  1811. }
  1812. VOID
  1813. InactiveCallCleanUp(
  1814. IN VCCB* pVc )
  1815. // Cleans up a deactivated call. To clean up a call that might be active,
  1816. // use CallCleanUp instead. Returns the VC to "just created" state, in
  1817. // case client decides to make another call without deleting the VC.
  1818. //
  1819. {
  1820. NDIS_STATUS status;
  1821. ULONG ulFlags;
  1822. BOOLEAN fVcCreated;
  1823. ADAPTERCB* pAdapter;
  1824. TUNNELCB* pTunnel;
  1825. BOOLEAN fForceGarbageCollect;
  1826. TRACE( TL_I, TM_Cm, ( "InactiveCallCleanUp(pV=$%p)", pVc ) );
  1827. pAdapter = pVc->pAdapter;
  1828. // Release any call parameter allocations and the call-ID slot, if any.
  1829. //
  1830. CallSetupComplete( pVc );
  1831. fForceGarbageCollect = ReleaseCallIdSlot( pVc );
  1832. // Disassociate the VC from the tunnel. It is possible the no tunnel is
  1833. // associated, though only if short of memory.
  1834. //
  1835. pTunnel = pVc->pTunnel;
  1836. if (!pTunnel)
  1837. {
  1838. TRACE( TL_A, TM_Cm, ( "Inactive VC w/o tunnel" ) );
  1839. return;
  1840. }
  1841. NdisAcquireSpinLock( &pTunnel->lockT );
  1842. {
  1843. RemoveEntryList( &pVc->linkRequestingVcs );
  1844. InitializeListHead( &pVc->linkRequestingVcs );
  1845. NdisAcquireSpinLock( &pTunnel->lockVcs );
  1846. {
  1847. pVc->pTunnel = NULL;
  1848. RemoveEntryList( &pVc->linkVcs );
  1849. InitializeListHead( &pVc->linkVcs );
  1850. }
  1851. NdisReleaseSpinLock( &pTunnel->lockVcs );
  1852. }
  1853. NdisReleaseSpinLock( &pTunnel->lockT );
  1854. // Flush queues, timers, and statistics.
  1855. //
  1856. NdisAcquireSpinLock( &pVc->lockV );
  1857. {
  1858. LIST_ENTRY* pLink;
  1859. ulFlags = ReadFlags( &pVc->ulFlags );
  1860. ASSERT( !(ulFlags & VCBF_VcActivated) );
  1861. // Terminate any delayed acknowledge timer.
  1862. //
  1863. if (pVc->pTqiDelayedAck)
  1864. {
  1865. TimerQTerminateItem( pTunnel->pTimerQ, pVc->pTqiDelayedAck );
  1866. pVc->pTqiDelayedAck = NULL;
  1867. }
  1868. // Flush any payloads from the "out" list.
  1869. //
  1870. while (!IsListEmpty( &pVc->listSendsOut ))
  1871. {
  1872. PAYLOADSENT* pPs;
  1873. pLink = RemoveHeadList( &pVc->listSendsOut );
  1874. InitializeListHead( pLink );
  1875. pPs = CONTAINING_RECORD( pLink, PAYLOADSENT, linkSendsOut );
  1876. TRACE( TL_I, TM_Cm, ( "Flush pPs=$%p", pPs ) );
  1877. // Terminate the timer. Doesn't matter if the terminate fails as
  1878. // the expire handler will fail to get a call reference and do
  1879. // nothing.
  1880. //
  1881. ASSERT( pPs->pTqiSendTimeout );
  1882. TimerQTerminateItem( pTunnel->pTimerQ, pPs->pTqiSendTimeout );
  1883. // Remove the context reference for linkage in the "out" queue.
  1884. //
  1885. pPs->status = NDIS_STATUS_FAILURE;
  1886. DereferencePayloadSent( pPs );
  1887. }
  1888. // Discard any out-of-order packets.
  1889. //
  1890. while (!IsListEmpty( &pVc->listOutOfOrder ))
  1891. {
  1892. PAYLOADRECEIVED* pPr;
  1893. pLink = RemoveHeadList( &pVc->listOutOfOrder );
  1894. InitializeListHead( pLink );
  1895. pPr = CONTAINING_RECORD(
  1896. pLink, PAYLOADRECEIVED, linkOutOfOrder );
  1897. TRACE( TL_I, TM_Cm, ( "Flush pPr=$%p", pPr ) );
  1898. FreeBufferToPool(
  1899. &pAdapter->poolFrameBuffers, pPr->pBuffer, TRUE );
  1900. FREE_PAYLOADRECEIVED( pAdapter, pPr );
  1901. }
  1902. // Update the global statistics by adding in the values tabulated for
  1903. // this call. Also prints the statistics in some trace modes.
  1904. //
  1905. UpdateGlobalCallStats( pVc );
  1906. }
  1907. NdisReleaseSpinLock( &pVc->lockV );
  1908. // Dereference the tunnel. Careful, this makes 'pTunnel' invalid from
  1909. // this point forward.
  1910. //
  1911. DereferenceTunnel( pTunnel );
  1912. // Return the VC to "just created" state.
  1913. //
  1914. pVc->usAssignedCallId = 0;
  1915. pVc->state = CS_Idle;
  1916. ClearFlags( &pVc->ulFlags, 0xFFFFFFFF );
  1917. pVc->usResult = 0;
  1918. pVc->usError = 0;
  1919. pVc->status = NDIS_STATUS_SUCCESS;
  1920. pVc->ulConnectBps = 0;
  1921. pVc->usNs = 0;
  1922. pVc->ulMaxSendWindow = 0;
  1923. pVc->ulAcksSinceSendTimeout = 0;
  1924. pVc->lDeviationMs = 0;
  1925. pVc->usNr = 0;
  1926. NdisZeroMemory( &pVc->stats, sizeof(pVc->stats) );
  1927. pVc->ulRoundTripMs = pAdapter->ulInitialSendTimeoutMs;
  1928. pVc->ulSendTimeoutMs = pVc->ulRoundTripMs;
  1929. pVc->ulSendWindow = pAdapter->info.MaxSendWindow >> 1;
  1930. if (pVc->ulSendWindow == 0)
  1931. {
  1932. pVc->ulSendWindow = 1;
  1933. }
  1934. if (ulFlags & VCBF_ClientCloseCompletion)
  1935. {
  1936. TRACE( TL_I, TM_Recv, ( "NdisMCmCloseCallComp(OK)" ) );
  1937. NdisMCmCloseCallComplete(
  1938. NDIS_STATUS_SUCCESS, pVc->NdisVcHandle, NULL );
  1939. TRACE( TL_I, TM_Recv, ( "NdisMCmCloseCallComp done" ) );
  1940. // Careful, if this was a client created VC, client may have deleted
  1941. // it, so 'pVc' must not be referenced hereafter in that case.
  1942. //
  1943. }
  1944. // When peer initiates the call, we create the VC and so delete it
  1945. // here. Otherwise, client created it and we leave it to him to
  1946. // delete it when he's ready.
  1947. //
  1948. if (ulFlags & VCBF_VcCreated)
  1949. {
  1950. NDIS_STATUS status;
  1951. TRACE( TL_I, TM_Recv, ( "NdisMCmDelVc" ) );
  1952. status = NdisMCmDeleteVc( pVc->NdisVcHandle );
  1953. TRACE( TL_I, TM_Recv, ( "NdisMCmDelVc=$%x", status ) );
  1954. ASSERT( status == NDIS_STATUS_SUCCESS );
  1955. LcmCmDeleteVc( pVc );
  1956. // Careful, 'pVc' has been deleted and must not be referenced
  1957. // hereafter.
  1958. //
  1959. }
  1960. // Create garbage collection events on all the pools if it was determined
  1961. // above to be an appropriate time to do so, i.e. we just deactivated the
  1962. // last active VC.
  1963. //
  1964. if (fForceGarbageCollect)
  1965. {
  1966. CollectBufferPoolGarbage( &pAdapter->poolFrameBuffers );
  1967. CollectBufferPoolGarbage( &pAdapter->poolHeaderBuffers );
  1968. CollectPacketPoolGarbage( &pAdapter->poolPackets );
  1969. }
  1970. }
  1971. VOID
  1972. LockIcs(
  1973. IN VCCB* pVc,
  1974. IN BOOLEAN fGrace )
  1975. // Lock the 'pVc->pInCallSetup' pointer. If 'fGrace' is set, the "grace
  1976. // period" reference is locked, and if not the "alloc" reference is
  1977. // locked. See also UnlockIcs.
  1978. //
  1979. {
  1980. SetFlags( &pVc->ulFlags, (fGrace) ? VCBF_IcsGrace : VCBF_IcsAlloc );
  1981. }
  1982. NDIS_STATUS
  1983. QueryCmInformation(
  1984. IN ADAPTERCB* pAdapter,
  1985. IN VCCB* pVc,
  1986. IN NDIS_OID Oid,
  1987. IN PVOID InformationBuffer,
  1988. IN ULONG InformationBufferLength,
  1989. OUT PULONG BytesWritten,
  1990. OUT PULONG BytesNeeded )
  1991. // Handle Call Manager QueryInformation requests. Arguments are as for
  1992. // the standard NDIS 'MiniportQueryInformation' handler except this
  1993. // routine does not count on being serialized with respect to other
  1994. // requests.
  1995. //
  1996. {
  1997. #define L2TP_MaxLineName 64
  1998. typedef struct
  1999. L2TP_CO_TAPI_LINE_CAPS
  2000. {
  2001. CO_TAPI_LINE_CAPS caps;
  2002. WCHAR achLineName[ L2TP_MaxLineName + 1 ];
  2003. }
  2004. L2TP_CO_TAPI_LINE_CAPS;
  2005. NDIS_STATUS status;
  2006. ULONG ulInfo;
  2007. VOID* pInfo;
  2008. ULONG ulInfoLen;
  2009. ULONG extension;
  2010. ULONG ulPortIndex;
  2011. CO_TAPI_CM_CAPS cmcaps;
  2012. L2TP_CO_TAPI_LINE_CAPS l2tpcaps;
  2013. CO_TAPI_ADDRESS_CAPS addrcaps;
  2014. CO_TAPI_CALL_DIAGNOSTICS diags;
  2015. status = NDIS_STATUS_SUCCESS;
  2016. // The cases in this switch statement find or create a buffer containing
  2017. // the requested information and point 'pInfo' at it, noting it's length
  2018. // in 'ulInfoLen'. Since many of the OIDs return a ULONG, a 'ulInfo'
  2019. // buffer is set up as the default.
  2020. //
  2021. ulInfo = 0;
  2022. pInfo = &ulInfo;
  2023. ulInfoLen = sizeof(ulInfo);
  2024. switch (Oid)
  2025. {
  2026. case OID_CO_TAPI_CM_CAPS:
  2027. {
  2028. TRACE( TL_N, TM_Cm, ( "QCm(OID_CO_TAPI_CM_CAPS)" ) );
  2029. NdisZeroMemory( &cmcaps, sizeof(cmcaps) );
  2030. // The LINE and ADDRESS CAPS OIDs will be requested after this
  2031. // one.
  2032. //
  2033. cmcaps.ulCoTapiVersion = CO_TAPI_VERSION;
  2034. cmcaps.ulNumLines = 1;
  2035. // caps.ulFlags = 0;
  2036. pInfo = &cmcaps;
  2037. ulInfoLen = sizeof(cmcaps);
  2038. break;
  2039. }
  2040. case OID_CO_TAPI_LINE_CAPS:
  2041. {
  2042. ULONG ulLineNameLen;
  2043. WCHAR* pszLineName;
  2044. CO_TAPI_LINE_CAPS* pInCaps;
  2045. LINE_DEV_CAPS* pldc;
  2046. TRACE( TL_N, TM_Cm, ( "QCm(OID_CO_TAPI_LINE_CAPS)" ) );
  2047. if (InformationBufferLength < sizeof(L2TP_CO_TAPI_LINE_CAPS))
  2048. {
  2049. status = NDIS_STATUS_INVALID_DATA;
  2050. ulInfoLen = 0;
  2051. break;
  2052. }
  2053. ASSERT( InformationBuffer );
  2054. pInCaps = (CO_TAPI_LINE_CAPS* )InformationBuffer;
  2055. NdisZeroMemory( &l2tpcaps, sizeof(l2tpcaps) );
  2056. pldc = &l2tpcaps.caps.LineDevCaps;
  2057. l2tpcaps.caps.ulLineID = pInCaps->ulLineID;
  2058. pldc->ulTotalSize = pInCaps->LineDevCaps.ulTotalSize;
  2059. pldc->ulNeededSize =
  2060. (ULONG )((CHAR* )(&l2tpcaps + 1)
  2061. - (CHAR* )(&l2tpcaps.caps.LineDevCaps));
  2062. pldc->ulUsedSize = pldc->ulNeededSize;
  2063. // pldc->ulProviderInfoSize = 0;
  2064. // pldc->ulProviderInfoOffset = 0;
  2065. // pldc->ulSwitchInfoSize = 0;
  2066. // pldc->ulSwitchInfoOffset = 0;
  2067. pldc->ulPermanentLineID = l2tpcaps.caps.ulLineID;
  2068. // Pass the DriverDesc from the registry as the line name. TAPI
  2069. // requires that this be a localizable string.
  2070. //
  2071. if (pAdapter->pszDriverDesc)
  2072. {
  2073. pszLineName = pAdapter->pszDriverDesc;
  2074. }
  2075. else
  2076. {
  2077. pszLineName = L"L2TP";
  2078. }
  2079. ulLineNameLen = StrLenW( pszLineName ) + 1;
  2080. if (ulLineNameLen > L2TP_MaxLineName)
  2081. {
  2082. ulLineNameLen = L2TP_MaxLineName;
  2083. }
  2084. NdisMoveMemory(
  2085. l2tpcaps.achLineName, pszLineName,
  2086. ulLineNameLen * sizeof(WCHAR) );
  2087. l2tpcaps.achLineName[ ulLineNameLen ] = L'\0';
  2088. pldc->ulLineNameSize = ulLineNameLen * sizeof(WCHAR);
  2089. pldc->ulLineNameOffset = (ULONG )
  2090. ((CHAR* )l2tpcaps.achLineName - (CHAR* )pldc);
  2091. pldc->ulStringFormat = STRINGFORMAT_UNICODE;
  2092. // pldc->ulAddressModes = 0;
  2093. pldc->ulNumAddresses = 1;
  2094. pldc->ulBearerModes = LINEBEARERMODE_DATA;
  2095. pldc->ulMaxRate = L2TP_LanBps;
  2096. pldc->ulMediaModes = LINEMEDIAMODE_UNKNOWN | LINEMEDIAMODE_DIGITALDATA;
  2097. // pldc->ulGenerateToneModes = 0;
  2098. // pldc->ulGenerateToneMaxNumFreq = 0;
  2099. // pldc->ulGenerateDigitModes = 0;
  2100. // pldc->ulMonitorToneMaxNumFreq = 0;
  2101. // pldc->ulMonitorToneMaxNumEntries = 0;
  2102. // pldc->ulMonitorDigitModes = 0;
  2103. // pldc->ulGatherDigitsMinTimeout = 0;
  2104. // pldc->ulGatherDigitsMaxTimeout = 0;
  2105. // pldc->ulMedCtlDigitMaxListSize = 0;
  2106. // pldc->ulMedCtlMediaMaxListSize = 0;
  2107. // pldc->ulMedCtlToneMaxListSize = 0;
  2108. // pldc->ulMedCtlCallStateMaxListSize = 0;
  2109. // pldc->ulDevCapFlags = 0;
  2110. pldc->ulMaxNumActiveCalls = 1;
  2111. // pldc->ulAnswerMode = 0;
  2112. // pldc->ulRingModes = 0;
  2113. // pldc->ulLineStates = 0;
  2114. // pldc->ulUUIAcceptSize = 0;
  2115. // pldc->ulUUIAnswerSize = 0;
  2116. // pldc->ulUUIMakeCallSize = 0;
  2117. // pldc->ulUUIDropSize = 0;
  2118. // pldc->ulUUISendUserUserInfoSize = 0;
  2119. // pldc->ulUUICallInfoSize = 0;
  2120. // pldc->MinDialParams = 0;
  2121. // pldc->MaxDialParams = 0;
  2122. // pldc->DefaultDialParams = 0;
  2123. // pldc->ulNumTerminals = 0;
  2124. // pldc->ulTerminalCapsSize = 0;
  2125. // pldc->ulTerminalCapsOffset = 0;
  2126. // pldc->ulTerminalTextEntrySize = 0;
  2127. // pldc->ulTerminalTextSize = 0;
  2128. // pldc->ulTerminalTextOffset = 0;
  2129. // pldc->ulDevSpecificSize = 0;
  2130. // pldc->ulDevSpecificOffset = 0;
  2131. // pldc->ulLineFeatures;
  2132. // pldc->ulSettableDevStatus;
  2133. // pldc->ulDeviceClassesSize;
  2134. // pldc->ulDeviceClassesOffset;
  2135. // pldc->PermanentLineGuid;
  2136. pldc->ulAddressTypes = LINEADDRESSTYPE_IPADDRESS;
  2137. // pldc->ProtocolGuid;
  2138. // pldc->ulAvailableTracking;
  2139. pInfo = &l2tpcaps;
  2140. ulInfoLen = sizeof(l2tpcaps);
  2141. break;
  2142. }
  2143. case OID_CO_TAPI_ADDRESS_CAPS:
  2144. {
  2145. CO_TAPI_ADDRESS_CAPS* pInCaps;
  2146. LINE_ADDRESS_CAPS* plac;
  2147. TRACE( TL_N, TM_Cm, ( "QCm(OID_CO_TAPI_ADDRESS_CAPS)" ) );
  2148. if (InformationBufferLength < sizeof(CO_TAPI_ADDRESS_CAPS))
  2149. {
  2150. status = NDIS_STATUS_INVALID_DATA;
  2151. ulInfoLen = 0;
  2152. break;
  2153. }
  2154. ASSERT( InformationBuffer );
  2155. pInCaps = (CO_TAPI_ADDRESS_CAPS* )InformationBuffer;
  2156. NdisZeroMemory( &addrcaps, sizeof(addrcaps) );
  2157. addrcaps.ulLineID = pInCaps->ulLineID;
  2158. addrcaps.ulAddressID = pInCaps->ulAddressID;
  2159. plac = &addrcaps.LineAddressCaps;
  2160. plac->ulTotalSize = sizeof(LINE_ADDRESS_CAPS);
  2161. plac->ulNeededSize = sizeof(LINE_ADDRESS_CAPS);
  2162. plac->ulUsedSize = sizeof(LINE_ADDRESS_CAPS);
  2163. plac->ulLineDeviceID = addrcaps.ulLineID;
  2164. // plac->ulAddressSize = 0;
  2165. // plac->ulAddressOffset = 0;
  2166. // plac->ulDevSpecificSize = 0;
  2167. // plac->ulDevSpecificOffset = 0;
  2168. // plac->ulAddressSharing = 0;
  2169. // plac->ulAddressStates = 0;
  2170. // plac->ulCallInfoStates = 0;
  2171. // plac->ulCallerIDFlags = 0;
  2172. // plac->ulCalledIDFlags = 0;
  2173. // plac->ulConnectedIDFlags = 0;
  2174. // plac->ulRedirectionIDFlags = 0;
  2175. // plac->ulRedirectingIDFlags = 0;
  2176. // plac->ulCallStates = 0;
  2177. // plac->ulDialToneModes = 0;
  2178. // plac->ulBusyModes = 0;
  2179. // plac->ulSpecialInfo = 0;
  2180. // plac->ulDisconnectModes = 0;
  2181. plac->ulMaxNumActiveCalls = (ULONG )pAdapter->usMaxVcs;
  2182. // plac->ulMaxNumOnHoldCalls = 0;
  2183. // plac->ulMaxNumOnHoldPendingCalls = 0;
  2184. // plac->ulMaxNumConference = 0;
  2185. // plac->ulMaxNumTransConf = 0;
  2186. // plac->ulAddrCapFlags = 0;
  2187. // plac->ulCallFeatures = 0;
  2188. // plac->ulRemoveFromConfCaps = 0;
  2189. // plac->ulRemoveFromConfState = 0;
  2190. // plac->ulTransferModes = 0;
  2191. // plac->ulParkModes = 0;
  2192. // plac->ulForwardModes = 0;
  2193. // plac->ulMaxForwardEntries = 0;
  2194. // plac->ulMaxSpecificEntries = 0;
  2195. // plac->ulMinFwdNumRings = 0;
  2196. // plac->ulMaxFwdNumRings = 0;
  2197. // plac->ulMaxCallCompletions = 0;
  2198. // plac->ulCallCompletionConds = 0;
  2199. // plac->ulCallCompletionModes = 0;
  2200. // plac->ulNumCompletionMessages = 0;
  2201. // plac->ulCompletionMsgTextEntrySize = 0;
  2202. // plac->ulCompletionMsgTextSize = 0;
  2203. // plac->ulCompletionMsgTextOffset = 0;
  2204. pInfo = &addrcaps;
  2205. ulInfoLen = sizeof(addrcaps);
  2206. break;
  2207. }
  2208. case OID_CO_TAPI_GET_CALL_DIAGNOSTICS:
  2209. {
  2210. TRACE( TL_N, TM_Cm, ( "QCm(OID_CO_TAPI_GET_CALL_DIAGS)" ) );
  2211. if (!pVc)
  2212. {
  2213. status = NDIS_STATUS_INVALID_DATA;
  2214. ulInfoLen = 0;
  2215. break;
  2216. }
  2217. NdisZeroMemory( &diags, sizeof(diags) );
  2218. diags.ulOrigin =
  2219. (ReadFlags( &pVc->ulFlags ) & VCBF_PeerInitiatedCall)
  2220. ? LINECALLORIGIN_EXTERNAL
  2221. : LINECALLORIGIN_OUTBOUND;
  2222. diags.ulReason = LINECALLREASON_DIRECT;
  2223. pInfo = &diags;
  2224. ulInfoLen = sizeof(diags);
  2225. break;
  2226. }
  2227. default:
  2228. {
  2229. TRACE( TL_A, TM_Cm, ( "QCm-OID=$%08x?", Oid ) );
  2230. status = NDIS_STATUS_NOT_SUPPORTED;
  2231. ulInfoLen = 0;
  2232. break;
  2233. }
  2234. }
  2235. if (ulInfoLen > InformationBufferLength)
  2236. {
  2237. // Caller's buffer is too small. Tell him what he needs.
  2238. //
  2239. *BytesNeeded = ulInfoLen;
  2240. status = NDIS_STATUS_INVALID_LENGTH;
  2241. }
  2242. else
  2243. {
  2244. // Copy the found result to caller's buffer.
  2245. //
  2246. if (ulInfoLen > 0)
  2247. {
  2248. NdisMoveMemory( InformationBuffer, pInfo, ulInfoLen );
  2249. DUMPDW( TL_N, TM_Mp, pInfo, ulInfoLen );
  2250. }
  2251. *BytesNeeded = *BytesWritten = ulInfoLen;
  2252. }
  2253. return status;
  2254. }
  2255. VOID
  2256. ReferenceAf(
  2257. IN ADAPTERCB* pAdapter )
  2258. // Adds areference to the address family of adapter block, 'pAdapter'.
  2259. //
  2260. {
  2261. LONG lRef;
  2262. lRef = NdisInterlockedIncrement( &pAdapter->lAfRef );
  2263. TRACE( TL_N, TM_Ref, ( "RefAf to %d", lRef ) );
  2264. }
  2265. BOOLEAN
  2266. ReferenceCall(
  2267. IN VCCB* pVc )
  2268. // Returns true if a reference is added to the active call on VC control
  2269. // block, 'pVc', or false if no reference was added because no call is
  2270. // active.
  2271. //
  2272. {
  2273. BOOLEAN fActive;
  2274. NdisAcquireSpinLock( &pVc->lockCall );
  2275. {
  2276. if (ReadFlags( &pVc->ulFlags ) & VCBF_VcActivated)
  2277. {
  2278. fActive = TRUE;
  2279. ++pVc->lCallRef;
  2280. TRACE( TL_N, TM_Ref, ( "RefC to %d", pVc->lCallRef ) );
  2281. }
  2282. else
  2283. {
  2284. TRACE( TL_N, TM_Ref, ( "RefC denied" ) );
  2285. fActive = FALSE;
  2286. }
  2287. }
  2288. NdisReleaseSpinLock( &pVc->lockCall );
  2289. return fActive;
  2290. }
  2291. BOOLEAN
  2292. ReferenceSap(
  2293. IN ADAPTERCB* pAdapter )
  2294. // Returns true if a reference is added to the active SAP on adapter
  2295. // 'pAdapter', or false if no reference was added because no SAP is
  2296. // active.
  2297. //
  2298. {
  2299. BOOLEAN fActive;
  2300. NdisAcquireSpinLock( &pAdapter->lockSap );
  2301. {
  2302. if (ReadFlags( &pAdapter->ulFlags ) & ACBF_SapActive)
  2303. {
  2304. fActive = TRUE;
  2305. ++pAdapter->lSapRef;
  2306. TRACE( TL_N, TM_Ref, ( "RefSap to %d", pAdapter->lSapRef ) );
  2307. }
  2308. else
  2309. {
  2310. TRACE( TL_N, TM_Ref, ( "RefSap denied" ) );
  2311. fActive = FALSE;
  2312. }
  2313. }
  2314. NdisReleaseSpinLock( &pAdapter->lockSap );
  2315. return fActive;
  2316. }
  2317. LONG
  2318. ReferenceTunnel(
  2319. IN TUNNELCB* pTunnel,
  2320. IN BOOLEAN fHaveLockTunnels )
  2321. // Reference the tunnel control block 'pTunnel'. 'FHaveLockTunnels' is
  2322. // set when the caller holds 'ADAPTERCB.lockTunnels'.
  2323. //
  2324. // Returns the reference count after the reference.
  2325. //
  2326. {
  2327. LONG lRef;
  2328. ADAPTERCB* pAdapter;
  2329. if (!fHaveLockTunnels)
  2330. {
  2331. pAdapter = pTunnel->pAdapter;
  2332. NdisAcquireSpinLock( &pAdapter->lockTunnels );
  2333. }
  2334. lRef = ++(pTunnel->lRef);
  2335. TRACE( TL_N, TM_Ref, ( "RefT to %d", lRef ) );
  2336. if (!fHaveLockTunnels)
  2337. {
  2338. NdisReleaseSpinLock( &pAdapter->lockTunnels );
  2339. }
  2340. return lRef;
  2341. }
  2342. VOID
  2343. ReferenceVc(
  2344. IN VCCB* pVc )
  2345. // Adds a reference to the VC control block 'pVc'.
  2346. //
  2347. {
  2348. LONG lRef;
  2349. lRef = NdisInterlockedIncrement( &pVc->lRef );
  2350. TRACE( TL_N, TM_Ref, ( "RefV to %d", lRef ) );
  2351. }
  2352. BOOLEAN
  2353. ReleaseCallIdSlot(
  2354. IN VCCB* pVc )
  2355. // Releases 'pVc's reserved Call-ID slot in the adapter's VC table.
  2356. //
  2357. // Returns true if a release occurs and results in all slots being
  2358. // available, false otherwise.
  2359. //
  2360. {
  2361. ADAPTERCB* pAdapter;
  2362. USHORT usCallId;
  2363. BOOLEAN fAllSlotsAvailable;
  2364. pAdapter = pVc->pAdapter;
  2365. usCallId = pVc->usCallId;
  2366. pVc->usCallId = 0;
  2367. fAllSlotsAvailable = FALSE;
  2368. if (usCallId > 0 && usCallId <= pAdapter->usMaxVcs)
  2369. {
  2370. NdisAcquireSpinLock( &pAdapter->lockVcs );
  2371. {
  2372. pAdapter->ppVcs[ usCallId - 1 ] = NULL;
  2373. ++(pAdapter->lAvailableVcSlots);
  2374. if (pAdapter->lAvailableVcSlots >= (LONG )pAdapter->usMaxVcs)
  2375. {
  2376. fAllSlotsAvailable = TRUE;
  2377. }
  2378. }
  2379. NdisReleaseSpinLock( &pAdapter->lockVcs );
  2380. }
  2381. return fAllSlotsAvailable;
  2382. }
  2383. NDIS_STATUS
  2384. ReserveCallIdSlot(
  2385. IN VCCB* pVc )
  2386. // Reserves a Call-ID slot for 'pVc' in the adapter's table.
  2387. //
  2388. // Returns NDIS_STATUS_SUCCESS if successful, or an error code.
  2389. //
  2390. {
  2391. NDIS_STATUS status;
  2392. ADAPTERCB* pAdapter;
  2393. VCCB** ppVc;
  2394. USHORT i;
  2395. pAdapter = pVc->pAdapter;
  2396. NdisAcquireSpinLock( &pAdapter->lockVcs );
  2397. {
  2398. // At this point, we have a VC for the received call request that's
  2399. // been successfully activated and dispatched to the client. Reserve
  2400. // a Call-ID in the adapter's look-up table.
  2401. //
  2402. if (pAdapter->lAvailableVcSlots > 0)
  2403. {
  2404. for (i = 0, ppVc = pAdapter->ppVcs;
  2405. i < pAdapter->usMaxVcs;
  2406. ++i, ++ppVc)
  2407. {
  2408. if (!*ppVc)
  2409. {
  2410. // The -1 reserves the ID. If/when the call negotiation
  2411. // completes successfully it will be changed to the
  2412. // address of the VCCB. Call-IDs are 1-based because L2TP
  2413. // reserves Call-ID 0 to mean the tunnel itself.
  2414. //
  2415. *ppVc = (VCCB* )-1;
  2416. pVc->usCallId = i + 1;
  2417. break;
  2418. }
  2419. }
  2420. ASSERT( i < pAdapter->usMaxVcs );
  2421. --(pAdapter->lAvailableVcSlots);
  2422. status = NDIS_STATUS_SUCCESS;
  2423. }
  2424. else
  2425. {
  2426. // No Call-ID slots available. This means the client accepted the
  2427. // VC even though it put us over our configured limit. Something
  2428. // is mismatched in the configuration. Assign a Call-ID above the
  2429. // table size for use only in terminating the call gracefully.
  2430. //
  2431. TRACE( TL_N, TM_Misc, ( "No Call-ID slots?" ) );
  2432. pVc->usCallId = GetNextTerminationCallId( pAdapter );
  2433. status = NDIS_STATUS_NOT_ACCEPTED;
  2434. }
  2435. }
  2436. NdisReleaseSpinLock( &pAdapter->lockVcs );
  2437. return status;
  2438. }
  2439. TUNNELCB*
  2440. SetupTunnel(
  2441. IN ADAPTERCB* pAdapter,
  2442. IN ULONG ulIpAddress,
  2443. IN USHORT usAssignedTunnelId,
  2444. IN BOOLEAN fExclusive )
  2445. // Sets up a tunnel to remote peer with IP address 'ulIpAddress' and
  2446. // prepares it for sending or receiving messages. 'PAdapter' is the
  2447. // owning adapter control block. 'UlIpAddress' is the remote peer's IP
  2448. // address in network byte-order. 'UsAssignedTunnelId', if non-0,
  2449. // indicates the assigned Tunnel-ID that must match in addition to the IP
  2450. // address. If 'FExclusive' is clear an existing tunnel to the peer is
  2451. // acceptable. If set, a new tunnel is created even if a matching one
  2452. // already exists.
  2453. //
  2454. // Returns the address of the tunnel control block if successful, or NULL
  2455. // if not. If successful the block is already linked into the adapters
  2456. // list of active tunnels and referenced, i.e. DereferenceTunnel must be
  2457. // called during clean-up.
  2458. //
  2459. {
  2460. TUNNELCB* pTunnel;
  2461. TRACE( TL_V, TM_Misc, ( "SetupTunnel" ) );
  2462. NdisAcquireSpinLock( &pAdapter->lockTunnels );
  2463. {
  2464. // If an existing tunnel would be acceptable, find the first existing
  2465. // tunnel with peer's IP address and, if non-0, assigned Tunnel-ID.
  2466. // Typically, none will be found and we go on to create a new one
  2467. // anyway.
  2468. //
  2469. pTunnel = (fExclusive)
  2470. ? NULL
  2471. : TunnelCbFromIpAddressAndAssignedTunnelId(
  2472. pAdapter, ulIpAddress, usAssignedTunnelId );
  2473. if (!pTunnel)
  2474. {
  2475. pTunnel = CreateTunnelCb( pAdapter );
  2476. if (!pTunnel)
  2477. {
  2478. ASSERT( !"Alloc TCB?" );
  2479. NdisReleaseSpinLock( &pAdapter->lockTunnels );
  2480. return NULL;
  2481. }
  2482. // Associate peer's IP address with the tunnel.
  2483. //
  2484. pTunnel->address.ulIpAddress = ulIpAddress;
  2485. // Link the block into the adapter's list of active tunnels.
  2486. //
  2487. InsertHeadList(
  2488. &pAdapter->listTunnels, &pTunnel->linkTunnels );
  2489. }
  2490. DBG_else
  2491. {
  2492. TRACE( TL_A, TM_Misc, ( "Tunnel $%p exists", pTunnel ) );
  2493. }
  2494. // Reference the tunnel control block. Hereafter, clean-up must
  2495. // include a call to DereferenceTunnel.
  2496. //
  2497. ReferenceTunnel( pTunnel, TRUE );
  2498. }
  2499. NdisReleaseSpinLock( &pAdapter->lockTunnels );
  2500. return pTunnel;
  2501. }
  2502. VOID
  2503. SetupVcAsynchronously(
  2504. IN TUNNELCB* pTunnel,
  2505. IN ULONG ulIpAddress,
  2506. IN CHAR* pBuffer,
  2507. IN CONTROLMSGINFO* pControl )
  2508. // Called by ReceiveControl to set up a VC for the incoming call described
  2509. // in 'pInfo', 'pControl', and 'pBuffer' using the necessary asynchronous
  2510. // CoNdis calls.
  2511. //
  2512. {
  2513. NDIS_STATUS status;
  2514. ADAPTERCB* pAdapter;
  2515. VCCB* pVc;
  2516. INCALLSETUP* pIcs;
  2517. NDIS_HANDLE NdisVcHandle;
  2518. ULONG ulMask;
  2519. BOOLEAN fTunnelClosing;
  2520. BOOLEAN fCallActive;
  2521. TRACE( TL_V, TM_Misc, ( "SetupVcAsync" ) );
  2522. pAdapter = pTunnel->pAdapter;
  2523. // Call our own CreateVc handler directly to allocate and initialize the
  2524. // incoming call's VC.
  2525. //
  2526. status = LcmCmCreateVc( pAdapter, NULL, &pVc );
  2527. if (status != NDIS_STATUS_SUCCESS)
  2528. {
  2529. ASSERT( !"CreateVc?" );
  2530. ScheduleTunnelWork(
  2531. pTunnel, NULL, FsmCloseTunnel,
  2532. (ULONG_PTR )TRESULT_GeneralWithError,
  2533. (ULONG_PTR )GERR_NoResources,
  2534. 0, 0, FALSE, FALSE );
  2535. FreeBufferToPool( &pAdapter->poolFrameBuffers, pBuffer, TRUE );
  2536. return;
  2537. }
  2538. // Allocate an "incoming call setup" context and initialize it from the
  2539. // receive buffer information arguments.
  2540. //
  2541. pIcs = ALLOC_INCALLSETUP( pAdapter );
  2542. if (!pIcs)
  2543. {
  2544. ASSERT( !"Alloc ICS?" );
  2545. LcmCmDeleteVc( pVc );
  2546. ScheduleTunnelWork(
  2547. pTunnel, NULL, FsmCloseTunnel,
  2548. (ULONG_PTR )TRESULT_GeneralWithError,
  2549. (ULONG_PTR )GERR_NoResources,
  2550. 0, 0, FALSE, FALSE );
  2551. FreeBufferToPool( &pAdapter->poolFrameBuffers, pBuffer, TRUE );
  2552. return;
  2553. }
  2554. pIcs->pBuffer = pBuffer;
  2555. NdisMoveMemory( &pIcs->control, pControl, sizeof(pIcs->control) );
  2556. BuildCallParametersShell(
  2557. pAdapter, ulIpAddress,
  2558. sizeof(pIcs->achCallParams), pIcs->achCallParams,
  2559. &pVc->pTiParams, &pVc->pTcInfo, &pVc->pLcParams );
  2560. LockIcs( pVc, FALSE );
  2561. pVc->pInCall = pIcs;
  2562. // Default is success with errors filled in if they occur.
  2563. //
  2564. pVc->usResult = 0;
  2565. pVc->usError = GERR_None;
  2566. // Mark the call as initiated by the peer so we know which notifications
  2567. // to give when the result is known.
  2568. //
  2569. ulMask = (VCBF_PeerInitiatedCall | VCBF_PeerOpenPending);
  2570. if (*(pControl->pusMsgType) == CMT_ICRQ)
  2571. {
  2572. ulMask |= VCBF_IncomingFsm;
  2573. }
  2574. SetFlags( &pVc->ulFlags, ulMask );
  2575. // Add a tunnel reference for this call on this VC, set the back pointer
  2576. // to the owning tunnel, and link the VC into the tunnel's list of
  2577. // associated VCs.
  2578. //
  2579. ReferenceTunnel( pTunnel, FALSE );
  2580. NdisAcquireSpinLock( &pTunnel->lockT );
  2581. {
  2582. if (ReadFlags( &pTunnel->ulFlags ) & TCBF_Closing)
  2583. {
  2584. // This is unlikely because SetupTunnel only finds non-closing
  2585. // tunnels, but this check and linkage must occur atomically under
  2586. // 'lockT'. New VCs must not be linked onto closing tunnels.
  2587. //
  2588. fTunnelClosing = TRUE;
  2589. }
  2590. else
  2591. {
  2592. fTunnelClosing = FALSE;
  2593. NdisAcquireSpinLock( &pTunnel->lockVcs );
  2594. {
  2595. pVc->pTunnel = pTunnel;
  2596. InsertTailList( &pTunnel->listVcs, &pVc->linkVcs );
  2597. }
  2598. NdisReleaseSpinLock( &pTunnel->lockVcs );
  2599. }
  2600. }
  2601. NdisReleaseSpinLock( &pTunnel->lockT );
  2602. if (fTunnelClosing)
  2603. {
  2604. CallSetupComplete( pVc );
  2605. LcmCmDeleteVc( pVc );
  2606. FreeBufferToPool( &pAdapter->poolFrameBuffers, pBuffer, TRUE );
  2607. DereferenceTunnel( pTunnel );
  2608. return;
  2609. }
  2610. // Peer MUST provide a Call-ID to pass back in the L2TP header of call
  2611. // control and payload packets.
  2612. //
  2613. if (!pControl->pusAssignedCallId || *(pControl->pusAssignedCallId) == 0)
  2614. {
  2615. TRACE( TL_A, TM_Misc, ( "No assigned CID?" ) );
  2616. pVc->usResult = CRESULT_GeneralWithError;
  2617. pVc->usError = GERR_BadCallId;
  2618. SetupVcComplete( pTunnel, pVc );
  2619. return;
  2620. }
  2621. // Check if the request has a chance of succeeding before getting the
  2622. // client involved.
  2623. //
  2624. if (!(ReadFlags( &pVc->ulFlags ) & VCBF_IncomingFsm))
  2625. {
  2626. // Fail requests to our LAC requiring asynchronous PPP framing or an
  2627. // analog or digital WAN connection. NDISWAN doesn't provide
  2628. // asynchronous PPP framing, and we don't currently support non-LAN
  2629. // WAN relays.
  2630. //
  2631. if (!pControl->pulFramingType
  2632. || !(*(pControl->pulFramingType) & FBM_Sync))
  2633. {
  2634. TRACE( TL_A, TM_Misc, ( "Not sync framing type?" ) );
  2635. if (!(pAdapter->ulFlags & ACBF_IgnoreFramingMismatch))
  2636. {
  2637. pVc->usResult = CRESULT_NoFacilitiesPermanent;
  2638. pVc->usError = GERR_None;
  2639. SetupVcComplete( pTunnel, pVc );
  2640. return;
  2641. }
  2642. }
  2643. if (pControl->pulBearerType
  2644. && *(pControl->pulBearerType) != 0)
  2645. {
  2646. TRACE( TL_A, TM_Misc, ( "Cannot do bearer type" ) );
  2647. pVc->usResult = CRESULT_NoFacilitiesPermanent;
  2648. pVc->usError = GERR_None;
  2649. SetupVcComplete( pTunnel, pVc );
  2650. return;
  2651. }
  2652. }
  2653. // Tell NDIS to notify the client of the new VC and give us it's handle.
  2654. //
  2655. ASSERT( pAdapter->NdisAfHandle );
  2656. TRACE( TL_I, TM_Recv, ( "NdisMCmCreateVc" ) );
  2657. status = NdisMCmCreateVc(
  2658. pAdapter->MiniportAdapterHandle,
  2659. pAdapter->NdisAfHandle,
  2660. pVc,
  2661. &pVc->NdisVcHandle );
  2662. TRACE( TL_I, TM_Recv, ( "NdisMCmCreateVc=$%x,h=$%p",
  2663. status, pVc->NdisVcHandle ) );
  2664. if (status != NDIS_STATUS_SUCCESS)
  2665. {
  2666. pVc->usResult = CRESULT_GeneralWithError;
  2667. pVc->usError = GERR_NoResources;
  2668. SetupVcComplete( pTunnel, pVc );
  2669. return;
  2670. }
  2671. SetFlags( &pVc->ulFlags, VCBF_VcCreated );
  2672. // Tell NDIS the VC is active.
  2673. //
  2674. TRACE( TL_I, TM_Recv, ( "NdisMCmActivateVc" ) );
  2675. status = NdisMCmActivateVc(
  2676. pVc->NdisVcHandle, (PCO_CALL_PARAMETERS )pVc->pInCall->achCallParams );
  2677. TRACE( TL_I, TM_Recv, ( "NdisMCmActivateVc=$%x", status ) );
  2678. if (status != NDIS_STATUS_SUCCESS )
  2679. {
  2680. pVc->usResult = CRESULT_GeneralWithError;
  2681. pVc->usError = GERR_NoResources;
  2682. SetupVcComplete( pTunnel, pVc );
  2683. return;
  2684. }
  2685. // Mark that the call is active, a state where both client and peer close
  2686. // requests should be accepted.
  2687. //
  2688. SetFlags( &pVc->ulFlags,
  2689. (VCBF_VcActivated
  2690. | VCBF_CallClosableByClient
  2691. | VCBF_CallClosableByPeer) );
  2692. fCallActive = ReferenceCall( pVc );
  2693. ASSERT( fCallActive );
  2694. // Tell NDIS to tell the client about the call. The dispatched flag is
  2695. // set here rather in the completion because, according to JameelH, it is
  2696. // valid to call NdisMCmDispatchIncomingCloseCall even if client pends on
  2697. // the dispatch. A reference on the SAP must be held during the operation
  2698. // since it uses the NdisSapHandle. The reference is released as soon as
  2699. // the call returns. A VC reference is taken to prevent the VC from being
  2700. // deleted before the completion handler is called. The VC reference is
  2701. // removed by the completion handler.
  2702. //
  2703. if (!ReferenceSap( pAdapter ))
  2704. {
  2705. pVc->usResult = CRESULT_NoFacilitiesTemporary;
  2706. pVc->usError = GERR_None;
  2707. SetupVcComplete( pTunnel, pVc );
  2708. return;
  2709. }
  2710. fCallActive = ReferenceCall( pVc );
  2711. ReferenceVc( pVc );
  2712. ASSERT( fCallActive );
  2713. SetFlags( &pVc->ulFlags, VCBF_WaitInCallComplete );
  2714. TRACE( TL_I, TM_Recv, ( "NdisMCmDispInCall" ) );
  2715. status = NdisMCmDispatchIncomingCall(
  2716. pAdapter->NdisSapHandle,
  2717. pVc->NdisVcHandle,
  2718. (CO_CALL_PARAMETERS* )pVc->pInCall->achCallParams );
  2719. TRACE( TL_I, TM_Recv, ( "NdisMCmDispInCall=$%x", status ) );
  2720. DereferenceSap( pAdapter );
  2721. if (status == NDIS_STATUS_SUCCESS
  2722. || status == NDIS_STATUS_PENDING)
  2723. {
  2724. SetFlags( &pVc->ulFlags, VCBF_VcDispatched );
  2725. }
  2726. if (status != NDIS_STATUS_PENDING)
  2727. {
  2728. LcmCmIncomingCallComplete( status, pVc, NULL );
  2729. }
  2730. // Next stop is our LcmCmIncomingCallComplete handler which will call
  2731. // SetupVcComplete with client's reported status.
  2732. //
  2733. }
  2734. VOID
  2735. SetupVcComplete(
  2736. IN TUNNELCB* pTunnel,
  2737. IN VCCB* pVc )
  2738. // Called when the asynchronous incoming call VC setup result is known.
  2739. // 'PVc' is the non-NULL set up VC, with 'usResult' and 'usError' fields
  2740. // indicating the status thus far. 'PTunnel' is the associated tunnel.
  2741. //
  2742. {
  2743. NDIS_STATUS status;
  2744. ADAPTERCB* pAdapter;
  2745. BOOLEAN fCallerFreesBuffer;
  2746. ULONG ulcpVcs;
  2747. VCCB** ppVcs;
  2748. TRACE( TL_V, TM_Misc, ( "SetupVcComp,cid=%d,r=%d,e=%d",
  2749. (ULONG )pVc->usCallId, (ULONG )pVc->usResult, (ULONG )pVc->usError ) );
  2750. pAdapter = pVc->pAdapter;
  2751. // Lock up 'pInCall' because as soon as the call is activated the call can
  2752. // be torn down and 'pInCall' destroyed. See also comments in UnlockIcs.
  2753. //
  2754. LockIcs( pVc, TRUE );
  2755. {
  2756. // OK, we're done trying to to set up the VC asynchronously. A VCCB
  2757. // and INCALLSETUP were successfully allocated, which is the minimum
  2758. // required to be graceful with peer. Reserve a Call-ID in the
  2759. // adapter's look-up table.
  2760. //
  2761. status = ReserveCallIdSlot( pVc );
  2762. if (status == NDIS_STATUS_SUCCESS)
  2763. {
  2764. ActivateCallIdSlot( pVc );
  2765. }
  2766. else
  2767. {
  2768. pVc->usResult = CRESULT_Busy;
  2769. pVc->usError = GERR_None;
  2770. }
  2771. // Duplicate the tail of the receive path processing that would have
  2772. // occurred if we'd not been forced to go asynchronous.
  2773. //
  2774. NdisAcquireSpinLock( &pTunnel->lockT );
  2775. {
  2776. fCallerFreesBuffer =
  2777. ReceiveControlExpected(
  2778. pTunnel, pVc,
  2779. pVc->pInCall->pBuffer, &pVc->pInCall->control );
  2780. CompleteVcs( pTunnel );
  2781. }
  2782. NdisReleaseSpinLock( &pTunnel->lockT );
  2783. if (fCallerFreesBuffer)
  2784. {
  2785. FreeBufferToPool(
  2786. &pVc->pAdapter->poolFrameBuffers,
  2787. pVc->pInCall->pBuffer, TRUE );
  2788. }
  2789. DBG_else
  2790. {
  2791. ASSERT( FALSE );
  2792. }
  2793. }
  2794. UnlockIcs( pVc, TRUE );
  2795. }
  2796. VOID
  2797. TunnelTqTerminateComplete(
  2798. IN TIMERQ* pTimerQ,
  2799. IN VOID* pContext )
  2800. // TIMERQTERMINATECOMPLETE handler for 'TUNNELCB.pTimerQ'.
  2801. //
  2802. {
  2803. ADAPTERCB* pAdapter;
  2804. pAdapter = (ADAPTERCB* )pContext;
  2805. --pAdapter->ulTimers;
  2806. FREE_TIMERQ( pAdapter, pTimerQ );
  2807. }
  2808. VOID
  2809. UnlockIcs(
  2810. IN VCCB* pVc,
  2811. IN BOOLEAN fGrace )
  2812. // Unlock the 'pVc->pInCallSetup' pointer. If 'fGrace' is set, the "grace
  2813. // period" reference is unlocked, and if not the "alloc" reference is
  2814. // unlocked. If both references are gone, then do the actual cleanup.
  2815. //
  2816. // Note: Regular reference counts don't work well here because there are
  2817. // several possible causes of the "alloc" unlock and they are not
  2818. // necessarily mutually exclusive. However, we need to prevent the
  2819. // 'pInCall' pointer from being freed until the incoming call
  2820. // response has been sent out, which in turn requires knowledge of
  2821. // whether the "activate for receive" succeeded.
  2822. //
  2823. {
  2824. INCALLSETUP *pInCall = NULL;
  2825. ADAPTERCB *pAdapter;
  2826. ClearFlags( &pVc->ulFlags, (fGrace) ? VCBF_IcsGrace : VCBF_IcsAlloc );
  2827. if (!(ReadFlags( &pVc->ulFlags ) & (VCBF_IcsGrace | VCBF_IcsAlloc)))
  2828. {
  2829. NdisAcquireSpinLock(&pVc->lockV);
  2830. if(pVc->pInCall)
  2831. {
  2832. pInCall = pVc->pInCall;
  2833. pAdapter = pVc->pAdapter;
  2834. pVc->pInCall = NULL;
  2835. pVc->pTmParams = NULL;
  2836. pVc->pTcParams = NULL;
  2837. pVc->pLcParams = NULL;
  2838. }
  2839. NdisReleaseSpinLock(&pVc->lockV);
  2840. if(pInCall != NULL)
  2841. {
  2842. FREE_INCALLSETUP( pAdapter, pInCall );
  2843. }
  2844. }
  2845. #if 0
  2846. if (!(ReadFlags( &pVc->ulFlags ) & (VCBF_IcsGrace | VCBF_IcsAlloc))
  2847. && pVc->pInCall)
  2848. {
  2849. FREE_INCALLSETUP( pAdapter, pInCall );
  2850. pVc->pInCall = NULL;
  2851. pVc->pTmParams = NULL;
  2852. pVc->pTcParams = NULL;
  2853. pVc->pLcParams = NULL;
  2854. }
  2855. #endif
  2856. }