Leaked source code of windows server 2003
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.

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