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.

2848 lines
84 KiB

  1. // Copyright (c) 1997, Microsoft Corporation, all rights reserved
  2. // Copyright (c) 1997, Parallel Technologies, Inc., all rights reserved
  3. //
  4. // cm.c
  5. // RAS DirectParallel WAN mini-port/call-manager driver
  6. // Call Manager routines
  7. //
  8. // 01/07/97 Steve Cobb
  9. // 09/15/97 Jay Lowe, Parallel Technologies, Inc.
  10. #include "ptiwan.h"
  11. #include "ptilink.h"
  12. //-----------------------------------------------------------------------------
  13. // Local prototypes (alphabetically)
  14. //-----------------------------------------------------------------------------
  15. VOID
  16. CallSetupComplete(
  17. IN VCCB* pVc );
  18. VOID
  19. InactiveCallCleanUp(
  20. IN VCCB* pVc );
  21. ULONG
  22. LineIdAdd(
  23. IN ADAPTERCB* pAdapter,
  24. IN ULONG LineId );
  25. ULONG
  26. LineIdPortLookup(
  27. IN ADAPTERCB* pAdapter,
  28. IN ULONG LineId );
  29. VOID
  30. OpenAfPassive(
  31. IN NDIS_WORK_ITEM* pWork,
  32. IN VOID* pContext );
  33. NDIS_STATUS
  34. PtiOpenPtiLink(
  35. IN VCCB* pVc,
  36. IN ULONG ParallelPortIndex);
  37. NDIS_STATUS
  38. PtiClosePtiLink(
  39. IN VCCB* pVc );
  40. NDIS_STATUS
  41. QueryCmInformation(
  42. IN ADAPTERCB* pAdapter,
  43. IN VCCB* pVc,
  44. IN NDIS_OID Oid,
  45. IN PVOID InformationBuffer,
  46. IN ULONG InformationBufferLength,
  47. OUT PULONG BytesWritten,
  48. OUT PULONG BytesNeeded );
  49. VOID
  50. QueryPtiPorts(
  51. IN ADAPTERCB* pAdapter );
  52. VOID
  53. SetupVcComplete(
  54. IN VCCB* pVc );
  55. VOID
  56. WriteEndpointsToRegistry(
  57. IN ULONG ulVcs );
  58. //-----------------------------------------------------------------------------
  59. // Call-manager handlers and completers
  60. //-----------------------------------------------------------------------------
  61. NDIS_STATUS
  62. PtiCmOpenAf(
  63. IN NDIS_HANDLE CallMgrBindingContext,
  64. IN PCO_ADDRESS_FAMILY AddressFamily,
  65. IN NDIS_HANDLE NdisAfHandle,
  66. OUT PNDIS_HANDLE CallMgrAfContext )
  67. // Standard 'CmOpenAfHandler' routine called by NDIS when the a client
  68. // requests to open an address family. See DDK doc.
  69. //
  70. {
  71. ADAPTERCB* pAdapter;
  72. NDIS_HANDLE hExistingAf;
  73. NDIS_STATUS status;
  74. TRACE( TL_I, TM_Cm,
  75. ( "PtiCmOpenAf: AF=$%p", AddressFamily->AddressFamily ) );
  76. pAdapter = (ADAPTERCB* )CallMgrBindingContext;
  77. if (pAdapter->ulTag != MTAG_ADAPTERCB)
  78. {
  79. ASSERT( !"Atag?" );
  80. return NDIS_STATUS_INVALID_DATA;
  81. }
  82. if (AddressFamily->AddressFamily != CO_ADDRESS_FAMILY_TAPI_PROXY
  83. || AddressFamily->MajorVersion != NDIS_MajorVersion
  84. || AddressFamily->MinorVersion != NDIS_MinorVersion)
  85. {
  86. TRACE( TL_A, TM_Cm, ( "PtiCmOpenAf: Bad AF or NDIS version" ) );
  87. return NDIS_STATUS_BAD_VERSION;
  88. }
  89. // Save NDIS's AF handle in the adapter control block. Interlock just in
  90. // case multiple clients attempt to open the AF, though don't expect this.
  91. //
  92. hExistingAf =
  93. InterlockedCompareExchangePointer(
  94. &pAdapter->NdisAfHandle, NdisAfHandle, NULL );
  95. if (hExistingAf)
  96. {
  97. // Our AF has already been opened and it doesn't make any sense to
  98. // accept another since there is no way to distinguish which should
  99. // receive incoming calls.
  100. //
  101. ASSERT( !"AF exists?" );
  102. return NDIS_STATUS_FAILURE;
  103. }
  104. ReferenceAdapter( pAdapter );
  105. ReferenceAf( pAdapter );
  106. // Since we support only a single address family, just return the adapter
  107. // as the address family context.
  108. //
  109. *CallMgrAfContext = CallMgrBindingContext;
  110. // If this is the first reference then schedule work to stall around
  111. // waiting for PARPORT to initialize the parallel ports. Unfortunately,
  112. // according to Doug Fritz there is no way in the PnP model to know when
  113. // all ports that are coming have come.
  114. //
  115. TRACE( TL_I, TM_Cm, ( "PtiCmOpenAf sched delay" ) );
  116. status = ScheduleWork( pAdapter, OpenAfPassive, pAdapter );
  117. if (status != NDIS_STATUS_SUCCESS)
  118. {
  119. TRACE( TL_I, TM_Cm, ( "PtiCmOpenAf: Sched fail" ) );
  120. return status;
  121. }
  122. TRACE( TL_V, TM_Cm, ( "PtiCmOpenAf: pend" ) );
  123. return NDIS_STATUS_PENDING;
  124. }
  125. VOID
  126. OpenAfPassive(
  127. IN NDIS_WORK_ITEM* pWork,
  128. IN VOID* pContext )
  129. // An NDIS_PROC routine to complete the Address Family open begun in
  130. // LcmCmOpenAf.
  131. {
  132. ADAPTERCB* pAdapter;
  133. // Unpack context information then free the work item.
  134. //
  135. pAdapter = (ADAPTERCB* )pContext;
  136. ASSERT( pAdapter->ulTag == MTAG_ADAPTERCB );
  137. FREE_NDIS_WORK_ITEM( pAdapter, pWork );
  138. if (pAdapter->lAfRef <= 1)
  139. {
  140. if (pAdapter->ulParportDelayMs > 0)
  141. {
  142. TRACE( TL_I, TM_Cm, ( "NdisMSleep(openAF)" ) );
  143. NdisMSleep( pAdapter->ulParportDelayMs * 1000 );
  144. TRACE( TL_I, TM_Cm, ( "NdisMSleep(openAF) done" ) );
  145. }
  146. // Count the actual number of VCs we must be able to provide and write
  147. // the result to the registry.
  148. //
  149. QueryPtiPorts( pAdapter );
  150. if (pAdapter->ulActualVcs == 0 && pAdapter->ulExtraParportDelayMs > 0)
  151. {
  152. // No ports were found,but a secondary wait is configured. Wait,
  153. // then count the ports again.
  154. //
  155. TRACE( TL_I, TM_Cm, ( "NdisMSleep(openAFx)" ) );
  156. NdisMSleep( pAdapter->ulExtraParportDelayMs * 1000 );
  157. TRACE( TL_I, TM_Cm, ( "NdisMSleep(openAFx) done" ) );
  158. QueryPtiPorts( pAdapter );
  159. }
  160. WriteEndpointsToRegistry( pAdapter->ulActualVcs );
  161. }
  162. TRACE( TL_I, TM_Cm, ( "NdisMCmOpenAddressFamilyComplete" ) );
  163. NdisMCmOpenAddressFamilyComplete(
  164. NDIS_STATUS_SUCCESS, pAdapter->NdisAfHandle, (NDIS_HANDLE )pAdapter );
  165. TRACE( TL_I, TM_Cm, ( "NdisMCmOpenAddressFamilyComplete done" ) );
  166. }
  167. NDIS_STATUS
  168. PtiCmCreateVc(
  169. IN NDIS_HANDLE ProtocolAfContext,
  170. IN NDIS_HANDLE NdisVcHandle,
  171. OUT PNDIS_HANDLE ProtocolVcContext )
  172. // Standard 'CmCreateVc' routine called by NDIS in response to a
  173. // client's request to create a virtual circuit. This
  174. // call must return synchronously.
  175. //
  176. {
  177. NDIS_STATUS status;
  178. ADAPTERCB* pAdapter;
  179. VCCB* pVc;
  180. TRACE( TL_I, TM_Cm, ( "PtiCmCreateVc" ) );
  181. pAdapter = (ADAPTERCB* )ProtocolAfContext;
  182. if (pAdapter->ulTag != MTAG_ADAPTERCB)
  183. {
  184. ASSERT( !"Atag?" );
  185. return NDIS_STATUS_INVALID_DATA;
  186. }
  187. // Allocate and zero a VC control block, then make any non-zero
  188. // initializations.
  189. //
  190. pVc = ALLOC_VCCB( pAdapter );
  191. if (!pVc)
  192. {
  193. ASSERT( !"Alloc VC?" );
  194. return NDIS_STATUS_RESOURCES;
  195. }
  196. NdisZeroMemory( pVc, sizeof(*pVc) );
  197. // Set a marker for easier memory dump browsing.
  198. //
  199. pVc->ulTag = MTAG_VCCB;
  200. // Save a back pointer to the adapter for use in PtiCmDeleteVc later.
  201. //
  202. pVc->pAdapter = pAdapter;
  203. ReferenceAdapter( pAdapter );
  204. // Initialize the VC and call spinlock and send/receive lists.
  205. //
  206. NdisAllocateSpinLock( &pVc->lockV );
  207. NdisAllocateSpinLock( &pVc->lockCall );
  208. // Save the NDIS handle of this VC for use in indications to NDIS later.
  209. //
  210. pVc->NdisVcHandle = NdisVcHandle;
  211. // Initialize link capabilities to the defaults for the adapter, except
  212. // for the ACCM mask which defaults to "all stuffed" per PPP spec. We
  213. // desire no stuffing so 0 what is in the adapter block, and passed up to
  214. // NDISWAN, but can't use that until/unless it's negotiated and passed
  215. // back down to us in an OID_WAN_CO_SET_LINK_INFO.
  216. //
  217. {
  218. NDIS_WAN_CO_INFO* pwci = &pAdapter->info;
  219. NDIS_WAN_CO_GET_LINK_INFO* pwcgli = &pVc->linkinfo;
  220. NdisZeroMemory( &pVc->linkinfo, sizeof(pVc->linkinfo) );
  221. pwcgli->MaxSendFrameSize = pwci->MaxFrameSize;
  222. pwcgli->MaxRecvFrameSize = pwci->MaxFrameSize;
  223. pwcgli->SendFramingBits = pwci->FramingBits;
  224. pwcgli->RecvFramingBits = pwci->FramingBits;
  225. pwcgli->SendACCM = (ULONG )-1;
  226. pwcgli->RecvACCM = (ULONG )-1;
  227. }
  228. // The VC control block's address is the VC context we return to NDIS.
  229. //
  230. *ProtocolVcContext = (NDIS_HANDLE )pVc;
  231. // Add a reference to the control block and the associated address family
  232. // that is removed by LmpCoDeleteVc.
  233. //
  234. ReferenceVc( pVc );
  235. ReferenceAf( pAdapter );
  236. TRACE( TL_V, TM_Mp, ( "PtiCmCreateVc: Exit: pVc=$%p", pVc ) );
  237. return NDIS_STATUS_SUCCESS;
  238. }
  239. NDIS_STATUS
  240. PtiCmDeleteVc(
  241. IN NDIS_HANDLE ProtocolVcContext )
  242. // Standard 'CmDeleteVc' routine called by NDIS in response to a
  243. // client's request to delete a virtual circuit. This
  244. // call must return synchronously.
  245. //
  246. {
  247. VCCB* pVc;
  248. TRACE( TL_I, TM_Cm, ( "PtiCmDelVc: pVc=$%p", ProtocolVcContext ) );
  249. pVc = (VCCB* )ProtocolVcContext;
  250. if (pVc->ulTag != MTAG_VCCB)
  251. {
  252. ASSERT( !"Vtag?" );
  253. return NDIS_STATUS_INVALID_DATA;
  254. }
  255. // Remove the references added by PtiCmCreateVc.
  256. //
  257. DereferenceAf( pVc->pAdapter );
  258. DereferenceVc( pVc );
  259. TRACE( TL_V, TM_Cm, ( "PtiCmDelVc: Exit, pVc=$%p", pVc ) );
  260. return NDIS_STATUS_SUCCESS;
  261. }
  262. NDIS_STATUS
  263. PtiCmRegisterSap(
  264. IN NDIS_HANDLE CallMgrAfContext,
  265. IN PCO_SAP Sap,
  266. IN NDIS_HANDLE NdisSapHandle,
  267. OUT PNDIS_HANDLE CallMgrSapContext )
  268. // Standard 'CmRegisterSapHandler' routine called by NDIS when the
  269. // client registers a service access point. See DDK doc.
  270. //
  271. {
  272. NDIS_STATUS status;
  273. ADAPTERCB* pAdapter;
  274. VCCB* pVc;
  275. BOOLEAN fSapExists;
  276. BOOLEAN fBadSapPort;
  277. BOOLEAN fBadSapLength;
  278. CO_AF_TAPI_SAP* pSap;
  279. TRACE( TL_I, TM_Cm, ( "PtiCmRegSap" ) );
  280. pAdapter = (ADAPTERCB* )CallMgrAfContext;
  281. // Our SAP context is just the address of the owning adapter control
  282. // block. Set it now before scheduling work as NDIS doesn't handle the
  283. // case of SAP completion correctly otherwise (though it should).
  284. //
  285. *CallMgrSapContext = (NDIS_HANDLE )pAdapter;
  286. if (pAdapter->ulTag != MTAG_ADAPTERCB)
  287. {
  288. ASSERT( !"Atag?" );
  289. return NDIS_STATUS_INVALID_DATA;
  290. }
  291. fSapExists = FALSE;
  292. fBadSapLength = FALSE;
  293. fBadSapPort = FALSE;
  294. NdisAcquireSpinLock( &pAdapter->lockSap );
  295. do
  296. {
  297. ULONG ulSapPort;
  298. if (pAdapter->NdisSapHandle)
  299. {
  300. fSapExists = TRUE;
  301. break;
  302. }
  303. if (Sap->SapLength != sizeof(CO_AF_TAPI_SAP))
  304. {
  305. fBadSapLength = TRUE;
  306. break;
  307. }
  308. pSap = (CO_AF_TAPI_SAP* )&Sap->Sap[ 0 ];
  309. if (pSap->ulLineID >= pAdapter->ulActualVcs)
  310. {
  311. fBadSapPort = TRUE;
  312. break;
  313. }
  314. // Save NDIS's SAP handle in the adapter control block. Extract
  315. // "listen" port from SAP parameters.
  316. //
  317. ulSapPort = LineIdPortLookup( pAdapter, pSap->ulLineID );
  318. if (ulSapPort >= NPORTS)
  319. {
  320. fBadSapPort = TRUE;
  321. break;
  322. }
  323. pAdapter->NdisSapHandle = NdisSapHandle;
  324. pAdapter->ulSapPort = ulSapPort;
  325. }
  326. while (FALSE);
  327. NdisReleaseSpinLock( &pAdapter->lockSap );
  328. if (fSapExists)
  329. {
  330. TRACE( TL_A, TM_Cm, ( "SAP exists?" ) );
  331. return NDIS_STATUS_SAP_IN_USE;
  332. }
  333. if (fBadSapLength)
  334. {
  335. ASSERT( !"Bad SAP length?" );
  336. return NDIS_STATUS_INVALID_DATA;
  337. }
  338. if (fBadSapPort)
  339. {
  340. ASSERT( !"Bad SAP port?" );
  341. return NDIS_STATUS_INVALID_DATA;
  342. }
  343. // Allocate and zero a VC control block, then make any non-zero
  344. // initializations.
  345. //
  346. pVc = ALLOC_VCCB( pAdapter );
  347. if (!pVc)
  348. {
  349. ASSERT( !"Alloc VC?" );
  350. return NDIS_STATUS_RESOURCES;
  351. }
  352. NdisZeroMemory( pVc, sizeof(*pVc) );
  353. ReferenceVc( pVc );
  354. pVc->ulTag = MTAG_VCCB;
  355. pVc->pAdapter = pAdapter;
  356. ReferenceAdapter( pAdapter );
  357. // Now we have a temporary "Vc" to listen on ... save it
  358. //
  359. pAdapter->pListenVc = pVc;
  360. // PtiOpen must be called at PASSIVE IRQL so schedule an APC to do it.
  361. //
  362. status = ScheduleWork( pAdapter, RegisterSapPassive, pAdapter );
  363. if (status != NDIS_STATUS_SUCCESS)
  364. {
  365. DereferenceVc( pAdapter->pListenVc );
  366. pAdapter->pListenVc = NULL;
  367. NdisAcquireSpinLock( &pAdapter->lockSap );
  368. {
  369. pAdapter->NdisSapHandle = NULL;
  370. pAdapter->ulSapPort = 0;
  371. }
  372. NdisReleaseSpinLock( &pAdapter->lockSap );
  373. return status;
  374. }
  375. TRACE( TL_V, TM_Cm, ( "PtiCmRegSap: Exit: pListenVc=$%p", pVc ) );
  376. return NDIS_STATUS_PENDING;
  377. }
  378. VOID
  379. RegisterSapPassive(
  380. IN NDIS_WORK_ITEM* pWork,
  381. IN VOID* pContext )
  382. // An NDIS_PROC procedure to complete the registering of a SAP begun in
  383. // PtiCmRegisterSap.
  384. //
  385. {
  386. NDIS_STATUS status;
  387. ADAPTERCB* pAdapter;
  388. NDIS_HANDLE hSap;
  389. TRACE( TL_N, TM_Cm, ( "RegSapPassive" ) );
  390. // Unpack context information then free the work item.
  391. //
  392. pAdapter = (ADAPTERCB* )pContext;
  393. ASSERT( pAdapter->ulTag == MTAG_ADAPTERCB );
  394. FREE_NDIS_WORK_ITEM( pAdapter, pWork );
  395. // Start listening ...
  396. //
  397. TRACE( TL_I, TM_Cm,
  398. ( "PtiCmRegSap: New SAP, Port=$%x", pAdapter->ulSapPort ) );
  399. status = PtiOpenPtiLink( pAdapter->pListenVc, pAdapter->ulSapPort );
  400. NdisAcquireSpinLock( &pAdapter->lockSap );
  401. {
  402. hSap = pAdapter->NdisSapHandle;
  403. if (NT_SUCCESS( status ))
  404. {
  405. // Mark the SAP active allowing references to be taken, and take
  406. // the initial reference for SAP registry, plus those for address
  407. // family and adapter.
  408. //
  409. SetFlags( &pAdapter->ulFlags, ACBF_SapActive );
  410. ASSERT( pAdapter->lSapRef == 0 );
  411. TRACE( TL_N, TM_Ref, ( "RefSap-ish to 1" ) );
  412. pAdapter->lSapRef = 1;
  413. ReferenceAdapter( pAdapter );
  414. ReferenceAf( pAdapter );
  415. }
  416. else
  417. {
  418. // Failed to get TDI set up, so NULL the SAP handle in the adapter
  419. // control block.
  420. //
  421. TRACE( TL_A, TM_Cm,
  422. ( "PtiCmRegSap: Error: Open failed: status=$%x", status ) );
  423. DereferenceVc( pAdapter->pListenVc );
  424. pAdapter->pListenVc = NULL;
  425. pAdapter->NdisSapHandle = NULL;
  426. pAdapter->ulSapPort = 0;
  427. status = NDIS_STATUS_FAILURE;
  428. }
  429. }
  430. NdisReleaseSpinLock( &pAdapter->lockSap );
  431. if (status != STATUS_SUCCESS)
  432. {
  433. // Remove the NdisSapHandle reference since we NULLed it above while
  434. // locks were held.
  435. //
  436. DereferenceAdapter( pAdapter );
  437. }
  438. // Remove the reference for scheduled work. Must occur before telling
  439. // NDIS because it could call Halt and unload the driver before we ever
  440. // get control again resulting in a C4 bugcheck. (Yes, this actually
  441. // happened)
  442. //
  443. DereferenceAdapter( pAdapter );
  444. // Report result to client.
  445. //
  446. TRACE( TL_I, TM_Cm, ( "NdisMCmRegSapComp=$%08x", status ) );
  447. NdisMCmRegisterSapComplete( status, hSap, (NDIS_HANDLE )pAdapter );
  448. TRACE( TL_I, TM_Cm, ( "NdisMCmRegSapComp done" ) );
  449. }
  450. NDIS_STATUS
  451. PtiCmDeregisterSap(
  452. NDIS_HANDLE CallMgrSapContext )
  453. // Standard 'CmDeregisterSapHandler' routine called by NDIS when the a
  454. // client has requested to de-register a service access point. See DDK
  455. // doc.
  456. //
  457. {
  458. NDIS_STATUS status;
  459. ADAPTERCB* pAdapter;
  460. TRACE( TL_I, TM_Cm, ( "PtiCmDeregSap" ) );
  461. pAdapter = (ADAPTERCB* )CallMgrSapContext;
  462. if (pAdapter->ulTag != MTAG_ADAPTERCB)
  463. {
  464. ASSERT( !"Atag?" );
  465. return NDIS_STATUS_INVALID_DATA;
  466. }
  467. NdisAcquireSpinLock( &pAdapter->lockSap );
  468. {
  469. if (ReadFlags( &pAdapter->ulFlags ) & ACBF_SapActive)
  470. {
  471. ASSERT( pAdapter->NdisSapHandle );
  472. ClearFlags( &pAdapter->ulFlags, ACBF_SapActive );
  473. status = NDIS_STATUS_PENDING;
  474. }
  475. else
  476. {
  477. ASSERT( !"No SAP active?" );
  478. status = NDIS_STATUS_FAILURE;
  479. }
  480. }
  481. NdisReleaseSpinLock( &pAdapter->lockSap );
  482. if (status == NDIS_STATUS_PENDING)
  483. {
  484. // Remove the reference for SAP registry. Eventually, the SAP
  485. // references will fall to 0 and DereferenceSap will call
  486. // DeregisterSapWork to complete the de-registry.
  487. //
  488. DereferenceSap( pAdapter );
  489. }
  490. TRACE( TL_V, TM_Cm, ( "PtiCmDeregSap=$%x", status ) );
  491. return status;
  492. }
  493. VOID
  494. DeregisterSapPassive(
  495. IN NDIS_WORK_ITEM* pWork,
  496. IN VOID* pContext )
  497. // An NDIS_PROC routine to complete the de-registering of a SAP begun in
  498. // PtiCmDeregisterSap.
  499. //
  500. {
  501. ADAPTERCB* pAdapter;
  502. NDIS_HANDLE hOldSap;
  503. VCCB* pVc;
  504. TRACE( TL_I, TM_Cm, ( "DeregSapPassive" ) );
  505. // Unpack context information then free the work item.
  506. //
  507. pAdapter = (ADAPTERCB* )pContext;
  508. ASSERT( pAdapter->ulTag == MTAG_ADAPTERCB );
  509. FREE_NDIS_WORK_ITEM( pAdapter, pWork );
  510. // Stop receiving datagrams (at least on behalf of this SAP) and
  511. // deregister the SAP.
  512. //
  513. NdisAcquireSpinLock( &pAdapter->lockSap );
  514. {
  515. pVc = pAdapter->pListenVc;
  516. pAdapter->pListenVc = NULL;
  517. hOldSap = pAdapter->NdisSapHandle;
  518. pAdapter->NdisSapHandle = NULL;
  519. pAdapter->ulSapPort = 0;
  520. }
  521. NdisReleaseSpinLock( &pAdapter->lockSap );
  522. if (pVc)
  523. {
  524. TRACE( TL_I, TM_Cm,
  525. ( "PtiCmDeregSapPassive: Closing link for Dereg SAP" ) );
  526. PtiClosePtiLink( pVc );
  527. DereferenceVc( pVc );
  528. }
  529. else
  530. {
  531. TRACE( TL_A, TM_Cm, ( "PtiCmDeregSapPassive: !pListenVc?" ) );
  532. }
  533. // Remove the adapter references for the NdisSapHandle and for scheduled
  534. // work. Remove the address family reference for the NdisSapHandle. Do
  535. // all this before telling NDIS the deregister is complete as it may call
  536. // Halt and unload the driver before we run again, giving C4 bugcheck.
  537. //
  538. DereferenceAdapter( pAdapter );
  539. DereferenceAdapter( pAdapter );
  540. DereferenceAf( pAdapter );
  541. // Report result to client.
  542. //
  543. TRACE( TL_I, TM_Cm, ( "NdisMCmDeregSapComp" ) );
  544. NdisMCmDeregisterSapComplete( NDIS_STATUS_SUCCESS, hOldSap );
  545. TRACE( TL_I, TM_Cm, ( "NdisMCmDeregSapComp done" ) );
  546. }
  547. NDIS_STATUS
  548. PtiCmMakeCall(
  549. IN NDIS_HANDLE CallMgrVcContext,
  550. IN OUT PCO_CALL_PARAMETERS CallParameters,
  551. IN NDIS_HANDLE NdisPartyHandle,
  552. OUT PNDIS_HANDLE CallMgrPartyContext )
  553. // Standard 'CmMakeCallHandler' routine called by NDIS when the a client
  554. // has requested to connect to a remote end-point. See DDK doc.
  555. //
  556. {
  557. NDIS_STATUS status;
  558. CO_SPECIFIC_PARAMETERS* pMSpecifics;
  559. CO_AF_TAPI_MAKE_CALL_PARAMETERS UNALIGNED* pTmParams;
  560. VCCB* pVc;
  561. ADAPTERCB* pAdapter;
  562. ULONG ulIpAddress;
  563. TRACE( TL_I, TM_Cm, ( "PtiCmMakeCall" ) );
  564. pVc = (VCCB* )CallMgrVcContext;
  565. if (pVc->ulTag != MTAG_VCCB)
  566. {
  567. ASSERT( !"Vtag?" );
  568. return NDIS_STATUS_INVALID_DATA;
  569. }
  570. ReferenceVc( pVc );
  571. pAdapter = pVc->pAdapter;
  572. // PTI has no concept of point-to-multi-point "parties".
  573. //
  574. if (CallMgrPartyContext)
  575. {
  576. *CallMgrPartyContext = NULL;
  577. }
  578. // Validate call parameters.
  579. //
  580. do
  581. {
  582. // PTI provides switched VCs only.
  583. //
  584. if (CallParameters->Flags &
  585. (PERMANENT_VC | BROADCAST_VC | MULTIPOINT_VC))
  586. {
  587. status = NDIS_STATUS_NOT_SUPPORTED;
  588. break;
  589. }
  590. // Make sure caller provided the TAPI call parameters we expect.
  591. // Currently, the only parameter in the TAPI call parameters actually
  592. // used is the 'ulLineID' identifying the LPTx port. No validating of
  593. // the LINE_CALL_PARAMS is done at all as we choose not to be picky
  594. // about arguments we intend to ignore.
  595. //
  596. if (!CallParameters->MediaParameters)
  597. {
  598. status = NDIS_STATUS_INVALID_DATA;
  599. break;
  600. }
  601. pMSpecifics = &CallParameters->MediaParameters->MediaSpecific;
  602. if (pMSpecifics->Length < sizeof(CO_AF_TAPI_MAKE_CALL_PARAMETERS))
  603. {
  604. status = NDIS_STATUS_INVALID_LENGTH;
  605. break;
  606. }
  607. pTmParams = (CO_AF_TAPI_MAKE_CALL_PARAMETERS* )&pMSpecifics->Parameters;
  608. if (pTmParams->ulLineID >= pAdapter->ulActualVcs)
  609. {
  610. status = NDIS_STATUS_INVALID_DATA;
  611. break;
  612. }
  613. status = NDIS_STATUS_SUCCESS;
  614. }
  615. while (FALSE);
  616. if (status != NDIS_STATUS_SUCCESS)
  617. {
  618. DereferenceVc( pVc );
  619. return status;
  620. }
  621. // Simultaneous MakeCalls on the same VC is a client error, but it's easy
  622. // to guard against so do that here.
  623. //
  624. if (InterlockedCompareExchangePointer(
  625. &pVc->pMakeCall, CallParameters, NULL ))
  626. {
  627. ASSERT( !"Double MakeCall?" );
  628. DereferenceVc( pVc );
  629. return NDIS_STATUS_CALL_ACTIVE;
  630. }
  631. pVc->pTmParams = pTmParams;
  632. // Mark that the call is in a state where close requests can be accepted,
  633. // but incoming packets should not trigger a new incoming call. Mark the
  634. // call that an open is pending.
  635. //
  636. SetFlags( &pVc->ulFlags,
  637. (VCBF_ClientOpenPending
  638. | VCBF_CallClosableByClient
  639. | VCBF_CallClosableByPeer
  640. | VCBF_CallInProgress) );
  641. status = ScheduleWork( pAdapter, MakeCallPassive, pVc );
  642. if (status != NDIS_STATUS_SUCCESS)
  643. {
  644. ASSERT( !"SchedWork?" );
  645. CallCleanUp( pVc );
  646. DereferenceVc( pVc );
  647. return status;
  648. }
  649. // The VC reference will be removed by MakeCallPassive.
  650. //
  651. TRACE( TL_V, TM_Cm, ( "PtiCmMakeCall pending" ) );
  652. return NDIS_STATUS_PENDING;
  653. }
  654. VOID
  655. MakeCallPassive(
  656. IN NDIS_WORK_ITEM* pWork,
  657. IN VOID* pContext )
  658. // An NDIS_PROC routine to complete the call initiation begun in
  659. // LcmCmMakeCall.
  660. //
  661. {
  662. ADAPTERCB* pAdapter;
  663. VCCB* pVc;
  664. NTSTATUS PtiLinkStatus;
  665. ULONG PortIndex;
  666. TRACE( TL_I, TM_Cm, ( "MakeCallPassive" ) );
  667. // Unpack context information then free the work item.
  668. //
  669. pVc = (VCCB* )pContext;
  670. ASSERT( pVc->ulTag == MTAG_VCCB );
  671. pAdapter = pVc->pAdapter;
  672. FREE_NDIS_WORK_ITEM( pAdapter, pWork );
  673. // Make the call...
  674. //
  675. TRACE( TL_N, TM_Cm,
  676. ( "PtiCmMakeCall: Make Call on TAPI Line Id $%x ...",
  677. pVc->pTmParams->ulLineID ) );
  678. // Map TAPI Line Id to Port Index
  679. //
  680. PortIndex = LineIdPortLookup( pAdapter, pVc->pTmParams->ulLineID );
  681. if ( PortIndex > NPORTS )
  682. {
  683. TRACE( TL_A, TM_Cm,
  684. ( "PtiCmMakeCall: Cannot find Port for Line Id",
  685. pVc->pTmParams->ulLineID ) );
  686. pVc->status = NDIS_STATUS_TAPI_INVALLINEHANDLE;
  687. return;
  688. }
  689. TRACE( TL_N, TM_Cm,
  690. ( "PtiCmMakeCall: Making Call on Port $%x ...",
  691. PortIndex ) );
  692. PtiLinkStatus = PtiOpenPtiLink( pVc, PortIndex );
  693. if (ReferenceSap( pAdapter ))
  694. {
  695. // Listen VC mechanism-dependent.
  696. //
  697. SetFlags( &pAdapter->pListenVc->ulFlags, VCBF_CallInProgress );
  698. DereferenceSap( pAdapter );
  699. }
  700. if (IsWin9xPeer( pVc ))
  701. {
  702. SendClientString( pVc->PtiExtension );
  703. }
  704. pVc->status = PtiLinkStatus;
  705. CompleteVc( pVc );
  706. DereferenceVc( pVc );
  707. // Remove the reference for scheduled work.
  708. //
  709. DereferenceAdapter( pAdapter );
  710. TRACE( TL_V, TM_Cm,
  711. ( "PtiCmMakeCall: Exit: Link Status=$%x", PtiLinkStatus ) );
  712. }
  713. NDIS_STATUS
  714. PtiCmCloseCall(
  715. IN NDIS_HANDLE CallMgrVcContext,
  716. IN NDIS_HANDLE CallMgrPartyContext,
  717. IN PVOID CloseData,
  718. IN UINT Size )
  719. // Standard 'CmCloseCallHandler' routine called by NDIS when the a client
  720. // has requested to tear down a call. See DDK doc.
  721. //
  722. {
  723. NDIS_STATUS status;
  724. ADAPTERCB* pAdapter;
  725. VCCB* pVc;
  726. ULONG ulFlags;
  727. BOOLEAN fCallClosable;
  728. TRACE( TL_I, TM_Cm, ( "PtiCmCloseCall: pVc=$%p", CallMgrVcContext ) );
  729. pVc = (VCCB* )CallMgrVcContext;
  730. if (pVc->ulTag != MTAG_VCCB)
  731. {
  732. ASSERT( !"Vtag?" );
  733. return NDIS_STATUS_INVALID_DATA;
  734. }
  735. ReferenceVc( pVc );
  736. status = NDIS_STATUS_SUCCESS;
  737. pAdapter = pVc->pAdapter;
  738. NdisAcquireSpinLock( &pVc->lockV );
  739. {
  740. ulFlags = ReadFlags( &pVc->ulFlags );
  741. if (ulFlags & VCBF_CallClosableByClient)
  742. {
  743. fCallClosable = TRUE;
  744. // Accepting this close makes the call no longer closable by
  745. // client or peer. Any peer operation that was pending is
  746. // cleared, and a client close becomes pending. It is possible to
  747. // have both a client open and close pending at the same time.
  748. //
  749. ClearFlags( &pVc->ulFlags,
  750. (VCBF_CallClosableByClient
  751. | VCBF_CallClosableByPeer
  752. | VCBF_PeerClosePending
  753. | VCBF_PeerOpenPending) );
  754. SetFlags( &pVc->ulFlags, VCBF_ClientClosePending );
  755. // If a client open is pending, it fails.
  756. //
  757. if (ulFlags & VCBF_ClientOpenPending)
  758. {
  759. pVc->status = NDIS_STATUS_TAPI_DISCONNECTMODE_NORMAL;
  760. }
  761. }
  762. else
  763. {
  764. TRACE( TL_A, TM_Cm, ( "Call not closable" ) );
  765. fCallClosable = FALSE;
  766. }
  767. }
  768. NdisReleaseSpinLock( &pVc->lockV );
  769. if (fCallClosable)
  770. {
  771. // Close the call, being graceful if possible.
  772. //
  773. status = ScheduleWork( pAdapter, CloseCallPassive, pVc );
  774. }
  775. if (status != NDIS_STATUS_SUCCESS)
  776. {
  777. DereferenceVc( pVc );
  778. return status;
  779. }
  780. TRACE( TL_V, TM_Cm, ( "PtiCmCloseCall: Exit: Pending" ) );
  781. return NDIS_STATUS_PENDING;
  782. }
  783. VOID
  784. PtiCmIncomingCallComplete(
  785. IN NDIS_STATUS Status,
  786. IN NDIS_HANDLE CallMgrVcContext,
  787. IN PCO_CALL_PARAMETERS CallParameters )
  788. // Standard 'CmIncomingCallCompleteHandler' routine called by NDIS when
  789. // a client has responded to the call-managers's previously dispatched
  790. // incoming call. See DDK doc.
  791. //
  792. {
  793. VCCB* pVc;
  794. TRACE( TL_I, TM_Cm,
  795. ( "PtiCmInCallComp, pVc=$%p, Status=$%08x",
  796. CallMgrVcContext, Status ) );
  797. pVc = (VCCB* )CallMgrVcContext;
  798. if (pVc->ulTag != MTAG_VCCB)
  799. {
  800. ASSERT( !"Vtag?" );
  801. return;
  802. }
  803. ReferenceVc( pVc );
  804. if (Status != NDIS_STATUS_SUCCESS)
  805. {
  806. pVc->status = Status;
  807. // Turn off the "call NdisMCmDispatchIncomingCloseCall if peer
  808. // terminates the call" flag. It was turned on even though peer
  809. // pended, per JameelH.
  810. //
  811. ClearFlags( &pVc->ulFlags, VCBF_VcDispatched );
  812. }
  813. SetupVcComplete( pVc );
  814. DereferenceVc( pVc );
  815. TRACE( TL_V, TM_Cm, ( "PtiCmInCallComp: Exit" ) );
  816. }
  817. VOID
  818. PtiCmActivateVcComplete(
  819. IN NDIS_STATUS Status,
  820. IN NDIS_HANDLE CallMgrVcContext,
  821. IN PCO_CALL_PARAMETERS CallParameters )
  822. // Standard 'CmActivateVcCompleteHandler' routine called by NDIS when the
  823. // mini-port has completed the call-manager's previous request to activate
  824. // a virtual circuit. See DDK doc.
  825. //
  826. {
  827. ASSERT( !"PtiCmActVcComp?" );
  828. }
  829. VOID
  830. PtiCmDeactivateVcComplete(
  831. IN NDIS_STATUS Status,
  832. IN NDIS_HANDLE CallMgrVcContext )
  833. // Standard 'CmDeactivateVcCompleteHandler' routine called by NDIS when
  834. // the mini-port has completed the call-manager's previous request to
  835. // de-activate a virtual circuit. See DDK doc.
  836. //
  837. {
  838. ASSERT( !"PtiCmDeactVcComp?" );
  839. }
  840. NDIS_STATUS
  841. PtiCmModifyCallQoS(
  842. IN NDIS_HANDLE CallMgrVcContext,
  843. IN PCO_CALL_PARAMETERS CallParameters )
  844. // Standard 'CmModifyQoSCallHandler' routine called by NDIS when a client
  845. // requests a modification in the quality of service provided by the
  846. // virtual circuit. See DDK doc.
  847. //
  848. {
  849. TRACE( TL_N, TM_Cm, ( "PtiCmModQoS" ) );
  850. // There is no useful concept of quality of service for DirectParallel.
  851. //
  852. return NDIS_STATUS_NOT_SUPPORTED;
  853. }
  854. NDIS_STATUS
  855. PtiCmRequest(
  856. IN NDIS_HANDLE CallMgrAfContext,
  857. IN NDIS_HANDLE CallMgrVcContext,
  858. IN NDIS_HANDLE CallMgrPartyContext,
  859. IN OUT PNDIS_REQUEST NdisRequest )
  860. // Standard 'CmRequestHandler' routine called by NDIS in response to a
  861. // client's request for information from the mini-port.
  862. //
  863. {
  864. ADAPTERCB* pAdapter;
  865. VCCB* pVc;
  866. NDIS_STATUS status;
  867. TRACE( TL_I, TM_Cm, ( "PtiCmReq" ) );
  868. pAdapter = (ADAPTERCB* )CallMgrAfContext;
  869. if (pAdapter->ulTag != MTAG_ADAPTERCB)
  870. {
  871. ASSERT( !"Atag?" );
  872. return NDIS_STATUS_INVALID_DATA;
  873. }
  874. pVc = (VCCB* )CallMgrVcContext;
  875. if (pVc && pVc->ulTag != MTAG_VCCB)
  876. {
  877. ASSERT( !"Vtag?" );
  878. return NDIS_STATUS_INVALID_DATA;
  879. }
  880. switch (NdisRequest->RequestType)
  881. {
  882. case NdisRequestQueryInformation:
  883. {
  884. status = QueryCmInformation(
  885. pAdapter,
  886. pVc,
  887. NdisRequest->DATA.QUERY_INFORMATION.Oid,
  888. NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
  889. NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
  890. &NdisRequest->DATA.QUERY_INFORMATION.BytesWritten,
  891. &NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded );
  892. break;
  893. }
  894. case NdisRequestSetInformation:
  895. {
  896. TRACE( TL_A, TM_Cm,
  897. ( "CmSetOID=%d?", NdisRequest->DATA.SET_INFORMATION.Oid ) );
  898. status = NDIS_STATUS_NOT_SUPPORTED;
  899. break;
  900. }
  901. default:
  902. {
  903. status = NDIS_STATUS_NOT_SUPPORTED;
  904. TRACE( TL_A, TM_Cm, ( "CmType=%d?", NdisRequest->RequestType ) );
  905. break;
  906. }
  907. }
  908. return status;
  909. }
  910. //-----------------------------------------------------------------------------
  911. // Call utility routines (almost alphabetically)
  912. // Some are used externally
  913. //-----------------------------------------------------------------------------
  914. NDIS_STATUS
  915. PtiOpenPtiLink(
  916. IN VCCB* pVc,
  917. IN ULONG ulPort)
  918. // Opens the PTILINK device
  919. //
  920. // IMPORTANT: Must only be called at PASSIVE IRQL.
  921. //
  922. {
  923. UNICODE_STRING name, prefix, digits;
  924. WCHAR nameBuffer[40], digitsBuffer[10];
  925. NTSTATUS ntStatus;
  926. OBJECT_ATTRIBUTES oa;
  927. IO_STATUS_BLOCK iosb;
  928. LONG lRef;
  929. ADAPTERCB* pAdapter;
  930. TRACE( TL_N, TM_Cm, ( "PtiOpenPtiLink: Port=$%x", ulPort ) );
  931. if ( pVc->ulTag != MTAG_VCCB )
  932. {
  933. ASSERT( !"Vtag?" );
  934. return NDIS_STATUS_INVALID_DATA;
  935. }
  936. pAdapter = pVc->pAdapter;
  937. // If PtiLink[ulPort] is already open, do nothing
  938. // It may have already been opened by SAP actions
  939. if ( pAdapter->hPtiLinkTable[ulPort] == 0 )
  940. {
  941. TRACE( TL_V, TM_Cm, ( "PtiOpenPtiLink: Making name for Port=$%x", ulPort ) );
  942. // convert integer port number into unicode string
  943. //
  944. RtlZeroMemory( digitsBuffer, sizeof(digitsBuffer) );
  945. digits.Length = 0;
  946. digits.MaximumLength = 20;
  947. digits.Buffer = digitsBuffer;
  948. ntStatus = RtlIntegerToUnicodeString( ulPort + 1, 10, &digits );
  949. if ( !NT_SUCCESS(ntStatus) )
  950. {
  951. TRACE( TL_A, TM_Cm, ( "PtiOpenPtiLink: Port=$%x invalid?", ulPort ) );
  952. return NDIS_STATUS_INVALID_DATA;
  953. }
  954. RtlZeroMemory( nameBuffer, sizeof(nameBuffer) );
  955. name.Length = 0;
  956. name.MaximumLength = 80;
  957. name.Buffer = nameBuffer;
  958. TRACE( TL_V, TM_Cm, ( "PtiOpenPtiLink: Name should be NULL: %wZ", &name ) );
  959. RtlInitUnicodeString( &prefix, L"\\DosDevices\\PTILINK" );
  960. TRACE( TL_V, TM_Cm, ( "PtiOpenPtiLink: Prefix part : %wZ", &prefix ) );
  961. TRACE( TL_V, TM_Cm, ( "PtiOpenPtiLink: Digits part : %wZ", &digits ) );
  962. RtlAppendUnicodeStringToString( &name, &prefix );
  963. TRACE( TL_V, TM_Cm, ( "PtiOpenPtiLink: Name with prefix : %wZ", &name ) );
  964. RtlAppendUnicodeStringToString( &name, &digits );
  965. TRACE( TL_V, TM_Cm, ( "PtiOpenPtiLink: Name with digits : %wZ", &name ) );
  966. InitializeObjectAttributes(
  967. &oa, &name, OBJ_CASE_INSENSITIVE, NULL, NULL );
  968. // Open the link device
  969. //
  970. TRACE( TL_V, TM_Cm, ( "PtiOpenPtiLink: Opening %wZ", &name ) );
  971. ntStatus = ZwCreateFile(
  972. &pVc->hPtiLink, // pointer to desired handle
  973. FILE_READ_DATA | FILE_WRITE_DATA,
  974. &oa,
  975. &iosb,
  976. NULL,
  977. FILE_ATTRIBUTE_NORMAL,
  978. 0,
  979. FILE_OPEN,
  980. 0,
  981. NULL,
  982. 0 );
  983. if ( !NT_SUCCESS( ntStatus ) )
  984. {
  985. TRACE( TL_A, TM_Cm, ( "PtiOpenPtiLink: %wZ Open Failure = $%x",
  986. &name, ntStatus ) );
  987. return NDIS_STATUS_RESOURCES;
  988. }
  989. // save a copy of the PtiLink handle in ADAPTERCB
  990. //
  991. pAdapter->hPtiLinkTable[ulPort] = pVc->hPtiLink;
  992. TRACE( TL_N, TM_Cm, ( "PtiOpenPtilink: h=$%p",
  993. pAdapter->hPtiLinkTable[ulPort] ) );
  994. RtlInitUnicodeString( &name, NULL );
  995. }
  996. // Init the PtiLink API ... getting the extension pointers
  997. //
  998. pVc->ulVcParallelPort = ulPort;
  999. ntStatus = PtiInitialize( ulPort,
  1000. &pVc->Extension,
  1001. &pVc->PtiExtension); // get PTILINKx extension
  1002. // also fires ECPdetect
  1003. // and enables port IRQ
  1004. TRACE( TL_V, TM_Cm, ( "PtiOpenPtilink: PtiLink Init: Ext=$%p, PtiExt=$%p",
  1005. pVc->Extension,
  1006. pVc->PtiExtension ) );
  1007. if ( (pVc->Extension == NULL) || (pVc->PtiExtension == NULL) )
  1008. {
  1009. TRACE( TL_A, TM_Cm, (
  1010. "PtiOpenPtiLink: Null Pointer Detected: Ext=$%p, PtiExt=$%p",
  1011. pVc->Extension,
  1012. pVc->PtiExtension ) );
  1013. return NDIS_STATUS_RESOURCES;
  1014. }
  1015. if ( !NT_SUCCESS( ntStatus ) )
  1016. {
  1017. TRACE( TL_V, TM_Cm, ( "PtiInitialize Failure = $%08x", ntStatus ) );
  1018. return NDIS_STATUS_RESOURCES;
  1019. }
  1020. // Register our callbacks with PtiLink
  1021. //
  1022. TRACE( TL_V, TM_Cm, ( "PtiOpenPtiLink: RegCb pV=$%p", pVc ) );
  1023. PtiRegisterCallbacks(pVc->Extension, // the PTILINKx extension
  1024. PtiCbGetReadBuffer, // our get buffer routine
  1025. PtiRx, // our receive complete routine
  1026. PtiCbLinkEventHandler, // our link event handler
  1027. pVc); // our context
  1028. // Zero the counters
  1029. //
  1030. pVc->ulTotalPackets = 0;
  1031. TRACE( TL_V, TM_Cm, ( "PtiOpenPtiLink: Exit" ) );
  1032. return NDIS_STATUS_SUCCESS;
  1033. }
  1034. NDIS_STATUS
  1035. PtiClosePtiLink(
  1036. IN VCCB* pVc )
  1037. // Closes the PTILINK device
  1038. //
  1039. // IMPORTANT: This routine must only be called at PASSIVE IRQL.
  1040. //
  1041. {
  1042. NTSTATUS ntStatus;
  1043. ADAPTERCB* pAdapter;
  1044. if (pVc->ulTag != MTAG_VCCB)
  1045. {
  1046. ASSERT( !"Vtag?" );
  1047. return NDIS_STATUS_INVALID_DATA;
  1048. }
  1049. pAdapter = pVc->pAdapter;
  1050. TRACE( TL_N, TM_Cm, ( "PtiClosePtiLink: pVc=$%p, Port$%x, h=$%p",
  1051. pVc, pVc->ulVcParallelPort,
  1052. pAdapter->hPtiLinkTable[ pVc->ulVcParallelPort ] ));
  1053. // dispose of the connection
  1054. //
  1055. ntStatus = ZwClose( pAdapter->hPtiLinkTable[ pVc->ulVcParallelPort ] );
  1056. pVc->hPtiLink = NULL;
  1057. pAdapter->hPtiLinkTable[ pVc->ulVcParallelPort ] = NULL;
  1058. pVc->ulVcParallelPort = 0;
  1059. if (ReferenceSap( pAdapter ))
  1060. {
  1061. pAdapter->pListenVc->hPtiLink = NULL;
  1062. DereferenceSap( pAdapter );
  1063. }
  1064. if ( !NT_SUCCESS( ntStatus ) )
  1065. {
  1066. // close failed
  1067. TRACE( TL_V, TM_Cm,
  1068. ( "PtiClosePtiLink: Error: CloseFailure=$%08x", ntStatus ) );
  1069. return ntStatus;
  1070. }
  1071. TRACE( TL_V, TM_Cm, ( "PtiClosePtiLink: Exit" ) );
  1072. return NDIS_STATUS_SUCCESS;
  1073. }
  1074. VOID
  1075. CallCleanUp(
  1076. IN VCCB* pVc )
  1077. // De-associates the VC from the tunnel, preparing for and de-activating
  1078. // the call.
  1079. //
  1080. {
  1081. NDIS_STATUS status;
  1082. ULONG ulFlags;
  1083. ulFlags = ReadFlags( &pVc->ulFlags );
  1084. TRACE( TL_A, TM_Cm,
  1085. ( "CallCleanUp: pVc=$%p, fActivated=%x",
  1086. pVc,
  1087. ulFlags & VCBF_VcActivated ) );
  1088. ASSERT( pVc->ulTag == MTAG_VCCB );
  1089. // Client initiated close completed.
  1090. //
  1091. if (ulFlags & VCBF_VcActivated)
  1092. {
  1093. TRACE( TL_I, TM_Recv, ( "NdisMCmDeactVc" ) );
  1094. status = NdisMCmDeactivateVc( pVc->NdisVcHandle );
  1095. TRACE( TL_I, TM_Recv, ( "NdisMCmDeactVc=$%x", status ) );
  1096. ASSERT( status == NDIS_STATUS_SUCCESS );
  1097. ClearFlags( &pVc->ulFlags, VCBF_VcActivated );
  1098. DereferenceCall( pVc );
  1099. // The above actions lead to the call reference eventually going to 0,
  1100. // at which time clean up resumes in DereferenceCall.
  1101. //
  1102. }
  1103. else
  1104. {
  1105. InactiveCallCleanUp( pVc );
  1106. }
  1107. }
  1108. VOID
  1109. CallSetupComplete(
  1110. IN VCCB* pVc )
  1111. // Clean up 'pVc' allocations used only at call setup.
  1112. //
  1113. {
  1114. if (InterlockedExchangePointer( &pVc->pMakeCall, NULL ))
  1115. {
  1116. ASSERT( pVc->pTmParams );
  1117. pVc->pTmParams = NULL;
  1118. }
  1119. if (pVc->pInCall)
  1120. {
  1121. FREE_NONPAGED( pVc->pInCall );
  1122. pVc->pInCall = NULL;
  1123. pVc->pTiParams = NULL;
  1124. }
  1125. }
  1126. VOID
  1127. CallTransitionComplete(
  1128. IN VCCB* pVc )
  1129. // Sets 'pVc's state to it's idle state and sets up for reporting the
  1130. // result to the client after the lock is released.
  1131. //
  1132. // IMPORTANT: Caller must hold 'pVc->lockV'.
  1133. //
  1134. {
  1135. ULONG ulFlags;
  1136. ulFlags = ReadFlags( &pVc->ulFlags );
  1137. if (!(ulFlags & VCBM_Pending))
  1138. {
  1139. if (ulFlags & VCBF_CallClosableByPeer)
  1140. {
  1141. // Nothing else was pending and the call is closable so either
  1142. // peer initiated a close or some fatal error occurred which will
  1143. // be cleaned up as if peer initiated a close.
  1144. //
  1145. ASSERT( pVc->status != NDIS_STATUS_SUCCESS );
  1146. SetFlags( &pVc->ulFlags, VCBF_PeerClosePending );
  1147. ClearFlags( &pVc->ulFlags, VCBF_CallClosableByPeer );
  1148. }
  1149. else
  1150. {
  1151. // Nothing was pending and the call's not closable, so there's no
  1152. // action required for this transition.
  1153. //
  1154. TRACE( TL_A, TM_Fsm, ( "Call not closable" ) );
  1155. return;
  1156. }
  1157. }
  1158. else if (ulFlags & VCBF_ClientOpenPending)
  1159. {
  1160. if (pVc->status != NDIS_STATUS_SUCCESS)
  1161. {
  1162. // A pending client open just failed and will bring down the call.
  1163. // From this point on we will fail new attempts to close the call
  1164. // from both client and peer.
  1165. //
  1166. ClearFlags( &pVc->ulFlags,
  1167. (VCBF_CallClosableByClient | VCBF_CallClosableByPeer ));
  1168. }
  1169. }
  1170. else if (ulFlags & VCBF_PeerOpenPending)
  1171. {
  1172. if (pVc->status != NDIS_STATUS_SUCCESS)
  1173. {
  1174. // A pending peer open just failed and will bring down the call.
  1175. // From this point on we will fail new attempts to close the call
  1176. // from the peer. Client closes must be accepted because of the
  1177. // way CoNDIS loops dispatched close calls back to the CM's close
  1178. // handler.
  1179. //
  1180. ClearFlags( &pVc->ulFlags, VCBF_CallClosableByPeer );
  1181. }
  1182. }
  1183. }
  1184. VOID
  1185. CloseCallPassive(
  1186. IN NDIS_WORK_ITEM* pWork,
  1187. IN VOID* pContext )
  1188. // An NDIS_PROC routine to complete the call close begun in
  1189. // LcmCmCloseCall.
  1190. //
  1191. {
  1192. ADAPTERCB* pAdapter;
  1193. VCCB* pVc;
  1194. NTSTATUS PtiLinkStatus;
  1195. // Unpack context information then free the work item.
  1196. //
  1197. pVc = (VCCB* )pContext;
  1198. ASSERT( pVc->ulTag == MTAG_VCCB );
  1199. pAdapter = pVc->pAdapter;
  1200. FREE_NDIS_WORK_ITEM( pAdapter, pWork );
  1201. TRACE( TL_I, TM_Cm, ( "CloseCallPassive: Closing link for Close Call" ) );
  1202. PtiClosePtiLink( pVc );
  1203. if (ReferenceSap( pAdapter ))
  1204. {
  1205. TRACE( TL_N, TM_Cm, ( "CloseCall: reOpening link, SAP exists" ) );
  1206. PtiOpenPtiLink( pAdapter->pListenVc, pAdapter->ulSapPort );
  1207. DereferenceSap( pAdapter );
  1208. }
  1209. NdisAcquireSpinLock( &pVc->lockV );
  1210. {
  1211. CallTransitionComplete( pVc );
  1212. }
  1213. NdisReleaseSpinLock( &pVc->lockV );
  1214. CompleteVc( pVc );
  1215. // Remove the reference added by PtiCmCloseCall.
  1216. //
  1217. DereferenceVc( pVc );
  1218. // Remove the reference for scheduled work.
  1219. //
  1220. DereferenceAdapter( pAdapter );
  1221. TRACE( TL_V, TM_Cm, ( "CloseCall: Exit" ) );
  1222. }
  1223. VOID
  1224. CompleteVc(
  1225. IN VCCB* pVc )
  1226. // Complete the pending operation for a specific VC
  1227. //
  1228. {
  1229. NDIS_STATUS status;
  1230. ADAPTERCB* pAdapter;
  1231. LIST_ENTRY* pLink;
  1232. ULONG ulFlags;
  1233. pAdapter = pVc->pAdapter;
  1234. TRACE( TL_V, TM_Recv, ( "CompleteVc: pVc=$%p", pVc ) );
  1235. NdisAcquireSpinLock( &pVc->lockV );
  1236. {
  1237. // Note the pending flags then clear them, to ensure that all
  1238. // pending operations are completed exactly once. This is
  1239. // necessary since ClientOpen and ClientClose events may be
  1240. // pending simultaneously. (Thanks a lot NDIS guys).
  1241. //
  1242. ulFlags = ReadFlags( &pVc->ulFlags );
  1243. ClearFlags( &pVc->ulFlags, VCBM_Pending );
  1244. // Convert client close pending to client close completion,
  1245. // for reference later when call references reach zero. The
  1246. // flag determines if NdisMCmCloseCallComplete must be called.
  1247. //
  1248. if (ulFlags & VCBF_ClientClosePending)
  1249. {
  1250. SetFlags( &pVc->ulFlags, VCBF_ClientCloseCompletion );
  1251. }
  1252. }
  1253. NdisReleaseSpinLock( &pVc->lockV );
  1254. if (ulFlags & VCBF_PeerOpenPending)
  1255. {
  1256. TRACE( TL_N, TM_Recv,
  1257. ( "CompleteVc: PeerOpen complete, Status=$%x", pVc->status ) );
  1258. if (pVc->status == NDIS_STATUS_SUCCESS)
  1259. {
  1260. // Peer initiated call succeeded.
  1261. //
  1262. ASSERT( ulFlags & VCBF_VcDispatched );
  1263. TRACE( TL_I, TM_Recv, ( "CompleteVc: NdisMCmDispCallConn" ) );
  1264. NdisMCmDispatchCallConnected( pVc->NdisVcHandle );
  1265. TRACE( TL_I, TM_Recv, ( "CompleteVc: NdisMCmDispCallConn done" ) );
  1266. CallSetupComplete( pVc );
  1267. }
  1268. else
  1269. {
  1270. // Peer initiated call failed.
  1271. //
  1272. if (ulFlags & VCBF_VcDispatched)
  1273. {
  1274. ClearFlags( &pVc->ulFlags, VCBF_VcDispatched );
  1275. TRACE( TL_I, TM_Recv,
  1276. ( "CompleteVc: NdisMCmDispInCloseCall: status=$%x", pVc->status ) );
  1277. NdisMCmDispatchIncomingCloseCall(
  1278. pVc->status, pVc->NdisVcHandle, NULL, 0 );
  1279. TRACE( TL_I, TM_Recv,
  1280. ( "CompleteVc: NdisMCmDispInCloseCall done" ) );
  1281. // Client will call NdisClCloseCall which will get our
  1282. // PtiCloseCall handler called to clean up call setup,
  1283. // de-activate and delete the VC, as necessary.
  1284. //
  1285. }
  1286. else
  1287. {
  1288. // Return the VC to "just created" state.
  1289. //
  1290. CallCleanUp( pVc );
  1291. }
  1292. }
  1293. }
  1294. else if (ulFlags & VCBF_ClientOpenPending)
  1295. {
  1296. TRACE( TL_N, TM_Recv,
  1297. ( "CompleteVc: ClientOpen complete: status=$%x", pVc->status ) );
  1298. // Pick the call parameters out of the VC block now. See non-success
  1299. // case below.
  1300. //
  1301. //
  1302. // Set our flowspec params based on the actual
  1303. // connection speed
  1304. //
  1305. {
  1306. CO_CALL_PARAMETERS* pCp;
  1307. CO_CALL_MANAGER_PARAMETERS* pCmp;
  1308. LINE_CALL_INFO* pLci;
  1309. CO_MEDIA_PARAMETERS* pMp;
  1310. CO_AF_TAPI_MAKE_CALL_PARAMETERS* pTi;
  1311. LINE_CALL_PARAMS* pLcp;
  1312. ASSERT( pVc->pMakeCall );
  1313. pCp = pVc->pMakeCall;
  1314. pCmp = pCp->CallMgrParameters;
  1315. //
  1316. // Might want to make this report the actual
  1317. // connection speed in the future
  1318. //
  1319. pCmp->Transmit.TokenRate =
  1320. pCmp->Transmit.PeakBandwidth =
  1321. pCmp->Receive.TokenRate =
  1322. pCmp->Receive.PeakBandwidth = PTI_LanBps/8;
  1323. pMp = pCp->MediaParameters;
  1324. pTi = (CO_AF_TAPI_MAKE_CALL_PARAMETERS*)
  1325. &pMp->MediaSpecific.Parameters[0];
  1326. pLcp = (LINE_CALL_PARAMS*)
  1327. ((ULONG_PTR)pTi->LineCallParams.Offset +
  1328. (ULONG_PTR)pTi);
  1329. //
  1330. // Might want to make this report the actual
  1331. // connection speed in the future
  1332. //
  1333. pLcp->ulMinRate =
  1334. pLcp->ulMaxRate = PTI_LanBps/8;
  1335. }
  1336. if (pVc->status == NDIS_STATUS_SUCCESS)
  1337. {
  1338. // Client initiated open, i.e. MakeCall, succeeded.
  1339. //
  1340. // Activating the VC is a CoNDIS preliminary to reporting the
  1341. // MakeCall complete. For L2TP, all it does is get the NDIS
  1342. // state flags set correctly.
  1343. //
  1344. TRACE( TL_I, TM_Recv, ( "CompleteVc: NdisMCmActivateVc" ) );
  1345. ASSERT( pVc->pMakeCall );
  1346. status = NdisMCmActivateVc(
  1347. pVc->NdisVcHandle, pVc->pMakeCall );
  1348. TRACE( TL_I, TM_Recv, ( "CompleteVc: NdisMCmActivateVc: status=$%x", status ) );
  1349. ASSERT( status == NDIS_STATUS_SUCCESS );
  1350. SetFlags( &pVc->ulFlags, VCBF_VcActivated );
  1351. ReferenceCall( pVc );
  1352. }
  1353. else
  1354. {
  1355. // Clean up the call parameters before calling MakeCallComplete
  1356. // because they must not be referenced after that call.
  1357. //
  1358. CallSetupComplete( pVc );
  1359. }
  1360. TRACE( TL_I, TM_Recv, ( "CompleteVc: NdisMCmMakeCallComp, status=$%x",
  1361. pVc->status ) );
  1362. NdisMCmMakeCallComplete(
  1363. pVc->status, pVc->NdisVcHandle, NULL, NULL, pVc->pMakeCall );
  1364. TRACE( TL_I, TM_Recv, ( "CompleteVc: NdisMCmMakeCallComp done" ) );
  1365. if (pVc->status != NDIS_STATUS_SUCCESS)
  1366. {
  1367. // Return the VC to "just created" state.
  1368. //
  1369. InactiveCallCleanUp( pVc );
  1370. }
  1371. }
  1372. else if (ulFlags & VCBF_PeerClosePending )
  1373. {
  1374. TRACE( TL_N, TM_Recv, ( "CompleteVc: PeerClose complete, status=$%x", pVc->status ) );
  1375. // Peer initiated close completed.
  1376. //
  1377. TRACE( TL_I, TM_Recv, ( "CompleteVc: NdisMCmDispInCloseCall, status=$%x",
  1378. pVc->status ) );
  1379. NdisMCmDispatchIncomingCloseCall(
  1380. pVc->status, pVc->NdisVcHandle, NULL, 0 );
  1381. TRACE( TL_I, TM_Recv, ( "CompleteVc: NdisMCmDispInCloseCall done" ) );
  1382. // Client will call NdisClCloseCall while processing the above
  1383. // which will get our PtiCloseCall handler called to de-activate
  1384. // and delete the VC, as necessary.
  1385. //
  1386. }
  1387. else if (ulFlags & VCBF_ClientClosePending)
  1388. {
  1389. // This section eventually runs for all successful unclosed
  1390. // calls, whether peer or client initiated or closed.
  1391. //
  1392. TRACE( TL_N, TM_Recv,
  1393. ( "CompleteVc: ClientClose complete, status=$%x", pVc->status ) );
  1394. // Deactivate the VC and return all sent packets to the client above.
  1395. // These events will eventually lead to the call being dereferenced to
  1396. // zero, at which time the close is completed, and if peer initiated,
  1397. // the VC is deleted.
  1398. //
  1399. // Note: When MakeCall is cancelled by a Close request, these actions
  1400. // occur during the InactiveCallCleanUp in the ClientOpenPending
  1401. // completion code handling, rather than the CallCleanUp (which
  1402. // leads to InactiveCallCleanUp) here. In this case, this block
  1403. // does NOT run even though the ClientClosePending flag is set.
  1404. // Consider this before adding code here.
  1405. //
  1406. CallCleanUp( pVc );
  1407. }
  1408. TRACE( TL_N, TM_Recv,( "CompleteVc: Exit" ) );
  1409. }
  1410. VOID
  1411. DereferenceAf(
  1412. IN ADAPTERCB* pAdapter )
  1413. // Removes a reference from the address family of adapter control block
  1414. // 'pAdapter', and when frees the block when the last reference is
  1415. // removed.
  1416. //
  1417. {
  1418. LONG lRef;
  1419. lRef = NdisInterlockedDecrement( &pAdapter->lAfRef );
  1420. TRACE( TL_N, TM_Ref, ( "DerefAf to %d", lRef ) );
  1421. ASSERT( lRef >= 0 );
  1422. if (lRef == 0)
  1423. {
  1424. HANDLE h;
  1425. // Remove the reference for the NdisAfHandle. Must do this *before*
  1426. // telling NDIS the close succeeded as it may Halt and unload the
  1427. // driver before we run again here, giving C4 bugcheck.
  1428. //
  1429. h = pAdapter->NdisAfHandle;
  1430. InterlockedExchangePointer( &pAdapter->NdisAfHandle, NULL );
  1431. DereferenceAdapter( pAdapter );
  1432. // Tell NDIS it's close is complete.
  1433. //
  1434. TRACE( TL_I, TM_Cm, ( "NdisMCmCloseAfComp" ) );
  1435. NdisMCmCloseAddressFamilyComplete( NDIS_STATUS_SUCCESS, h );
  1436. TRACE( TL_I, TM_Cm, ( "NdisMCmCloseAfComp done" ) );
  1437. }
  1438. }
  1439. VOID
  1440. DereferenceCall(
  1441. IN VCCB* pVc )
  1442. // Removes a reference from the call active on 'pVc', invoking call clean
  1443. // up when the value reaches zero.
  1444. //
  1445. {
  1446. LONG lRef;
  1447. NDIS_STATUS status;
  1448. ADAPTERCB* pAdapter;
  1449. LIST_ENTRY* pLink;
  1450. pAdapter = pVc->pAdapter;
  1451. NdisAcquireSpinLock( &pVc->lockCall );
  1452. {
  1453. lRef = --pVc->lCallRef;
  1454. TRACE( TL_N, TM_Ref, ( "DerefCall to %d", pVc->lCallRef ) );
  1455. }
  1456. NdisReleaseSpinLock( &pVc->lockCall );
  1457. if (lRef == 0)
  1458. {
  1459. CallCleanUp( pVc );
  1460. }
  1461. }
  1462. VOID
  1463. DereferenceSap(
  1464. IN ADAPTERCB* pAdapter )
  1465. // Removes a reference from the SAP active on 'pAdapter', invoking
  1466. // Deregiter SAP completion handling when the value reaches zero.
  1467. //
  1468. {
  1469. LONG lRef;
  1470. NDIS_STATUS status;
  1471. NdisAcquireSpinLock( &pAdapter->lockSap );
  1472. {
  1473. lRef = --pAdapter->lSapRef;
  1474. TRACE( TL_N, TM_Ref, ( "DerefSap to %d", pAdapter->lSapRef ) );
  1475. }
  1476. NdisReleaseSpinLock( &pAdapter->lockSap );
  1477. if (lRef == 0)
  1478. {
  1479. status = ScheduleWork( pAdapter, DeregisterSapPassive, pAdapter );
  1480. ASSERT( status == NDIS_STATUS_SUCCESS );
  1481. }
  1482. }
  1483. VOID
  1484. InactiveCallCleanUp(
  1485. IN VCCB* pVc )
  1486. // Cleans up a deactivated call. To clean up a call that might be active,
  1487. // use CallCleanUp instead. Returns the VC to "just created" state, in
  1488. // case client decides to make another call without deleting the VC.
  1489. //
  1490. {
  1491. ULONG ulFlags;
  1492. BOOLEAN fVcCreated;
  1493. ADAPTERCB* pAdapter;
  1494. LIST_ENTRY* pLink;
  1495. TRACE( TL_N, TM_Cm, ( "InactiveCallCleanUp, pVc=$%p", pVc ) );
  1496. pAdapter = pVc->pAdapter;
  1497. // Release any call parameter allocations and disable receives.
  1498. //
  1499. CallSetupComplete( pVc );
  1500. ClearFlags( &pVc->ulFlags, VCBF_CallInProgress );
  1501. ulFlags = ReadFlags( &pVc->ulFlags );
  1502. #if 0
  1503. if (ulFlags & VCBF_PeerInitiatedCall)
  1504. {
  1505. DereferenceSap( pAdapter );
  1506. }
  1507. #endif
  1508. // Return the VC to "just created" state.
  1509. //
  1510. ClearFlags( &pVc->ulFlags, 0xFFFFFFFF );
  1511. pVc->status = NDIS_STATUS_SUCCESS;
  1512. pVc->usResult = 0;
  1513. pVc->usError = 0;
  1514. pVc->ulConnectBps = 0;
  1515. if (ulFlags & VCBF_ClientCloseCompletion)
  1516. {
  1517. TRACE( TL_I, TM_Recv, ( "NdisMCmCloseCallComp(OK)" ) );
  1518. NdisMCmCloseCallComplete(
  1519. NDIS_STATUS_SUCCESS, pVc->NdisVcHandle, NULL );
  1520. TRACE( TL_I, TM_Recv, ( "NdisMCmCloseCallComp done" ) );
  1521. // Careful, if this was a client created VC, client may have deleted
  1522. // it, so 'pVc' must not be referenced hereafter in that case.
  1523. //
  1524. }
  1525. // When peer initiates the call, we create the VC and so delete it
  1526. // here. Otherwise, client created it and we leave it to him to
  1527. // delete it when he's ready.
  1528. //
  1529. if (ulFlags & VCBF_VcCreated)
  1530. {
  1531. NDIS_STATUS status;
  1532. TRACE( TL_I, TM_Recv, ( "InactiveCallCleanUp: NdisMCmDelVc" ) );
  1533. status = NdisMCmDeleteVc( pVc->NdisVcHandle );
  1534. TRACE( TL_I, TM_Recv, ( "InactiveCallCleanUp: NdisMCmDelVc: status=$%x", status ) );
  1535. ASSERT( status == NDIS_STATUS_SUCCESS );
  1536. PtiCmDeleteVc( pVc );
  1537. // Careful, 'pVc' has been deleted and must not be referenced
  1538. // hereafter.
  1539. //
  1540. }
  1541. }
  1542. #if 0
  1543. ULONG
  1544. LineIdAdd(
  1545. IN ADAPTERCB* pAdapter,
  1546. IN ULONG LineId )
  1547. // Insert the LineId in the first available slot in ulLineIds
  1548. // Return the port index associated with the new LineId,
  1549. // or an invalid port index if the LineId cannot be added
  1550. //
  1551. {
  1552. ULONG ulPortIndex;
  1553. for (ulPortIndex = 0; ulPortIndex < NPORTS; ulPortIndex++)
  1554. {
  1555. // If the port exists and has no assigned LineId
  1556. //
  1557. if ( ( pAdapter->ulPtiLinkState[ulPortIndex] & PLSF_PortExists ) &&
  1558. !( pAdapter->ulPtiLinkState[ulPortIndex] & PLSF_LineIdValid))
  1559. {
  1560. // assign the TAPI Line Id to this port
  1561. // and return the port index
  1562. //
  1563. pAdapter->ulLineIds[ulPortIndex] = LineId;
  1564. pAdapter->ulPtiLinkState[ulPortIndex] |= PLSF_LineIdValid;
  1565. break;
  1566. }
  1567. }
  1568. return ulPortIndex;
  1569. }
  1570. #endif
  1571. ULONG
  1572. LineIdPortLookup(
  1573. IN ADAPTERCB* pAdapter,
  1574. IN ULONG LineId )
  1575. // Find the LineId in ulLineIds
  1576. // Return the port index associated with the LineId,
  1577. // or an invalid port index if the LineId cannot be found
  1578. //
  1579. {
  1580. ULONG ulPortIndex;
  1581. for (ulPortIndex = 0; ulPortIndex < NPORTS; ulPortIndex++)
  1582. {
  1583. // If the port exists and
  1584. //
  1585. if ( ( pAdapter->ulPtiLinkState[ulPortIndex] & PLSF_PortExists ) &&
  1586. ( pAdapter->ulPtiLinkState[ulPortIndex] & PLSF_LineIdValid) &&
  1587. ( LineId == pAdapter->ulLineIds[ulPortIndex] ))
  1588. {
  1589. // return the port index
  1590. //
  1591. break;
  1592. }
  1593. }
  1594. return ulPortIndex;
  1595. }
  1596. NDIS_STATUS
  1597. QueryCmInformation(
  1598. IN ADAPTERCB* pAdapter,
  1599. IN VCCB* pVc,
  1600. IN NDIS_OID Oid,
  1601. IN PVOID InformationBuffer,
  1602. IN ULONG InformationBufferLength,
  1603. OUT PULONG BytesWritten,
  1604. OUT PULONG BytesNeeded )
  1605. // Handle Call Manager QueryInformation requests. Arguments are as for
  1606. // the standard NDIS 'MiniportQueryInformation' handler except this
  1607. // routine does not count on being serialized with respect to other
  1608. // requests.
  1609. //
  1610. {
  1611. #define PTI_PORT_NAME_LEN 4
  1612. typedef struct
  1613. PTI_CO_TAPI_LINE_CAPS
  1614. {
  1615. CO_TAPI_LINE_CAPS caps;
  1616. WCHAR achLineName[ MAXLPTXNAME + 1 ];
  1617. }
  1618. PTI_CO_TAPI_LINE_CAPS;
  1619. NDIS_STATUS status;
  1620. ULONG ulInfo;
  1621. VOID* pInfo;
  1622. ULONG ulInfoLen;
  1623. ULONG extension;
  1624. ULONG ulPortIndex;
  1625. CO_TAPI_CM_CAPS cmcaps;
  1626. PTI_CO_TAPI_LINE_CAPS pticaps;
  1627. CO_TAPI_ADDRESS_CAPS addrcaps;
  1628. CO_TAPI_CALL_DIAGNOSTICS diags;
  1629. status = NDIS_STATUS_SUCCESS;
  1630. // The cases in this switch statement find or create a buffer containing
  1631. // the requested information and point 'pInfo' at it, noting it's length
  1632. // in 'ulInfoLen'. Since many of the OIDs return a ULONG, a 'ulInfo'
  1633. // buffer is set up as the default.
  1634. //
  1635. ulInfo = 0;
  1636. pInfo = &ulInfo;
  1637. ulInfoLen = sizeof(ulInfo);
  1638. switch (Oid)
  1639. {
  1640. case OID_CO_TAPI_CM_CAPS:
  1641. {
  1642. TRACE( TL_N, TM_Cm, ( "QCm(OID_CO_TAPI_CM_CAPS)" ) );
  1643. NdisZeroMemory( &cmcaps, sizeof(cmcaps) );
  1644. // Assumes that the LINE and ADDRESS CAPS OIDs will be requested
  1645. // after this one. TAPI LineIDs are associated with LPTx ports at
  1646. // that time. This should be OK since named ports cannot
  1647. // reasonably be chosen based on an arbitrary LineID.
  1648. //
  1649. cmcaps.ulCoTapiVersion = CO_TAPI_VERSION;
  1650. cmcaps.ulNumLines = pAdapter->ulActualVcs;
  1651. cmcaps.ulFlags = CO_TAPI_FLAG_PER_LINE_CAPS;
  1652. pInfo = &cmcaps;
  1653. ulInfoLen = sizeof(cmcaps);
  1654. break;
  1655. }
  1656. case OID_CO_TAPI_LINE_CAPS:
  1657. {
  1658. CO_TAPI_LINE_CAPS* pInCaps;
  1659. LINE_DEV_CAPS* pldc;
  1660. ULONG ulPortForLineId;
  1661. TRACE( TL_N, TM_Cm, ( "QCm(OID_CO_TAPI_LINE_CAPS)" ) );
  1662. if (InformationBufferLength < sizeof(PTI_CO_TAPI_LINE_CAPS))
  1663. {
  1664. status = NDIS_STATUS_INVALID_DATA;
  1665. ulInfoLen = 0;
  1666. break;
  1667. }
  1668. ASSERT( InformationBuffer );
  1669. pInCaps = (CO_TAPI_LINE_CAPS* )InformationBuffer;
  1670. NdisZeroMemory( &pticaps, sizeof(pticaps) );
  1671. pldc = &pticaps.caps.LineDevCaps;
  1672. // get the LineId from the incoming pInCaps (CO_TAPI_LINE_CAPS)
  1673. //
  1674. pticaps.caps.ulLineID = pInCaps->ulLineID;
  1675. // Find the LineId in the ulLineIds table (Replaces LineIdAdd as
  1676. // part of the STATIC LINEID workaround)
  1677. //
  1678. ulPortForLineId =
  1679. LineIdPortLookup( pAdapter, pticaps.caps.ulLineID );
  1680. if ( ulPortForLineId >= NPORTS )
  1681. {
  1682. status = NDIS_STATUS_TAPI_INVALLINEHANDLE;
  1683. ulInfoLen = 0;
  1684. break;
  1685. }
  1686. pldc->ulTotalSize = pInCaps->LineDevCaps.ulTotalSize;
  1687. pldc->ulNeededSize = (ULONG )
  1688. ((CHAR* )(&pticaps + 1) - (CHAR* )(&pticaps.caps.LineDevCaps));
  1689. pldc->ulUsedSize = pldc->ulNeededSize;
  1690. // pldc->ulProviderInfoSize = 0;
  1691. // pldc->ulProviderInfoOffset = 0;
  1692. // pldc->ulSwitchInfoSize = 0;
  1693. // pldc->ulSwitchInfoOffset = 0;
  1694. pldc->ulPermanentLineID = pticaps.caps.ulLineID;
  1695. StrCpyW( pticaps.achLineName,
  1696. pAdapter->szPortName[ ulPortForLineId ] );
  1697. pldc->ulLineNameSize =
  1698. StrLenW( pticaps.achLineName ) * sizeof(WCHAR);
  1699. pldc->ulLineNameOffset = (ULONG )
  1700. ((CHAR* )pticaps.achLineName - (CHAR* )pldc);
  1701. pldc->ulStringFormat = STRINGFORMAT_ASCII;
  1702. // pldc->ulAddressModes = 0;
  1703. pldc->ulNumAddresses = 1;
  1704. pldc->ulBearerModes = LINEBEARERMODE_DATA;
  1705. pldc->ulMaxRate = PTI_LanBps;
  1706. pldc->ulMediaModes = LINEMEDIAMODE_UNKNOWN | LINEMEDIAMODE_DIGITALDATA;
  1707. // pldc->ulGenerateToneModes = 0;
  1708. // pldc->ulGenerateToneMaxNumFreq = 0;
  1709. // pldc->ulGenerateDigitModes = 0;
  1710. // pldc->ulMonitorToneMaxNumFreq = 0;
  1711. // pldc->ulMonitorToneMaxNumEntries = 0;
  1712. // pldc->ulMonitorDigitModes = 0;
  1713. // pldc->ulGatherDigitsMinTimeout = 0;
  1714. // pldc->ulGatherDigitsMaxTimeout = 0;
  1715. // pldc->ulMedCtlDigitMaxListSize = 0;
  1716. // pldc->ulMedCtlMediaMaxListSize = 0;
  1717. // pldc->ulMedCtlToneMaxListSize = 0;
  1718. // pldc->ulMedCtlCallStateMaxListSize = 0;
  1719. // pldc->ulDevCapFlags = 0;
  1720. pldc->ulMaxNumActiveCalls = 1;
  1721. // pldc->ulAnswerMode = 0;
  1722. // pldc->ulRingModes = 0;
  1723. // pldc->ulLineStates = 0;
  1724. // pldc->ulUUIAcceptSize = 0;
  1725. // pldc->ulUUIAnswerSize = 0;
  1726. // pldc->ulUUIMakeCallSize = 0;
  1727. // pldc->ulUUIDropSize = 0;
  1728. // pldc->ulUUISendUserUserInfoSize = 0;
  1729. // pldc->ulUUICallInfoSize = 0;
  1730. // pldc->MinDialParams = 0;
  1731. // pldc->MaxDialParams = 0;
  1732. // pldc->DefaultDialParams = 0;
  1733. // pldc->ulNumTerminals = 0;
  1734. // pldc->ulTerminalCapsSize = 0;
  1735. // pldc->ulTerminalCapsOffset = 0;
  1736. // pldc->ulTerminalTextEntrySize = 0;
  1737. // pldc->ulTerminalTextSize = 0;
  1738. // pldc->ulTerminalTextOffset = 0;
  1739. // pldc->ulDevSpecificSize = 0;
  1740. // pldc->ulDevSpecificOffset = 0;
  1741. // pldc->ulLineFeatures;
  1742. // pldc->ulSettableDevStatus;
  1743. // pldc->ulDeviceClassesSize;
  1744. // pldc->ulDeviceClassesOffset;
  1745. // pldc->PermanentLineGuid;
  1746. pldc->ulAddressTypes = LINEADDRESSTYPE_IPADDRESS;
  1747. // pldc->ProtocolGuid;
  1748. // pldc->ulAvailableTracking;
  1749. pInfo = &pticaps;
  1750. ulInfoLen = sizeof(pticaps);
  1751. break;
  1752. }
  1753. case OID_CO_TAPI_ADDRESS_CAPS:
  1754. {
  1755. CO_TAPI_ADDRESS_CAPS* pInCaps;
  1756. LINE_ADDRESS_CAPS* plac;
  1757. TRACE( TL_N, TM_Cm, ( "QCm(OID_CO_TAPI_ADDRESS_CAPS)" ) );
  1758. if (InformationBufferLength < sizeof(CO_TAPI_ADDRESS_CAPS))
  1759. {
  1760. status = NDIS_STATUS_INVALID_DATA;
  1761. ulInfoLen = 0;
  1762. break;
  1763. }
  1764. ASSERT( InformationBuffer );
  1765. pInCaps = (CO_TAPI_ADDRESS_CAPS* )InformationBuffer;
  1766. NdisZeroMemory( &addrcaps, sizeof(addrcaps) );
  1767. addrcaps.ulLineID = pInCaps->ulLineID;
  1768. addrcaps.ulAddressID = pInCaps->ulAddressID;
  1769. plac = &addrcaps.LineAddressCaps;
  1770. plac->ulTotalSize = sizeof(LINE_ADDRESS_CAPS);
  1771. plac->ulNeededSize = sizeof(LINE_ADDRESS_CAPS);
  1772. plac->ulUsedSize = sizeof(LINE_ADDRESS_CAPS);
  1773. plac->ulLineDeviceID = addrcaps.ulLineID;
  1774. // plac->ulAddressSize = 0;
  1775. // plac->ulAddressOffset = 0;
  1776. // plac->ulDevSpecificSize = 0;
  1777. // plac->ulDevSpecificOffset = 0;
  1778. // plac->ulAddressSharing = 0;
  1779. // plac->ulAddressStates = 0;
  1780. // plac->ulCallInfoStates = 0;
  1781. // plac->ulCallerIDFlags = 0;
  1782. // plac->ulCalledIDFlags = 0;
  1783. // plac->ulConnectedIDFlags = 0;
  1784. // plac->ulRedirectionIDFlags = 0;
  1785. // plac->ulRedirectingIDFlags = 0;
  1786. // plac->ulCallStates = 0;
  1787. // plac->ulDialToneModes = 0;
  1788. // plac->ulBusyModes = 0;
  1789. // plac->ulSpecialInfo = 0;
  1790. // plac->ulDisconnectModes = 0;
  1791. plac->ulMaxNumActiveCalls = 1;
  1792. // plac->ulMaxNumOnHoldCalls = 0;
  1793. // plac->ulMaxNumOnHoldPendingCalls = 0;
  1794. // plac->ulMaxNumConference = 0;
  1795. // plac->ulMaxNumTransConf = 0;
  1796. // plac->ulAddrCapFlags = 0;
  1797. // plac->ulCallFeatures = 0;
  1798. // plac->ulRemoveFromConfCaps = 0;
  1799. // plac->ulRemoveFromConfState = 0;
  1800. // plac->ulTransferModes = 0;
  1801. // plac->ulParkModes = 0;
  1802. // plac->ulForwardModes = 0;
  1803. // plac->ulMaxForwardEntries = 0;
  1804. // plac->ulMaxSpecificEntries = 0;
  1805. // plac->ulMinFwdNumRings = 0;
  1806. // plac->ulMaxFwdNumRings = 0;
  1807. // plac->ulMaxCallCompletions = 0;
  1808. // plac->ulCallCompletionConds = 0;
  1809. // plac->ulCallCompletionModes = 0;
  1810. // plac->ulNumCompletionMessages = 0;
  1811. // plac->ulCompletionMsgTextEntrySize = 0;
  1812. // plac->ulCompletionMsgTextSize = 0;
  1813. // plac->ulCompletionMsgTextOffset = 0;
  1814. pInfo = &addrcaps;
  1815. ulInfoLen = sizeof(addrcaps);
  1816. break;
  1817. }
  1818. case OID_CO_TAPI_GET_CALL_DIAGNOSTICS:
  1819. {
  1820. TRACE( TL_N, TM_Cm, ( "QCm(OID_CO_TAPI_GET_CALL_DIAGS)" ) );
  1821. if (!pVc)
  1822. {
  1823. status = NDIS_STATUS_INVALID_DATA;
  1824. ulInfoLen = 0;
  1825. break;
  1826. }
  1827. NdisZeroMemory( &diags, sizeof(diags) );
  1828. diags.ulOrigin =
  1829. (ReadFlags( &pVc->ulFlags ) & VCBF_PeerInitiatedCall)
  1830. ? LINECALLORIGIN_EXTERNAL
  1831. : LINECALLORIGIN_OUTBOUND;
  1832. diags.ulReason = LINECALLREASON_DIRECT;
  1833. pInfo = &diags;
  1834. ulInfoLen = sizeof(diags);
  1835. break;
  1836. }
  1837. default:
  1838. {
  1839. TRACE( TL_A, TM_Cm, ( "QCm-OID=$%08x?", Oid ) );
  1840. status = NDIS_STATUS_NOT_SUPPORTED;
  1841. ulInfoLen = 0;
  1842. break;
  1843. }
  1844. }
  1845. if (ulInfoLen > InformationBufferLength)
  1846. {
  1847. // Caller's buffer is too small. Tell him what he needs.
  1848. //
  1849. *BytesNeeded = ulInfoLen;
  1850. status = NDIS_STATUS_INVALID_LENGTH;
  1851. }
  1852. else
  1853. {
  1854. // Copy the found result to caller's buffer.
  1855. //
  1856. if (ulInfoLen > 0)
  1857. {
  1858. NdisMoveMemory( InformationBuffer, pInfo, ulInfoLen );
  1859. DUMPDW( TL_N, TM_Mp, pInfo, ulInfoLen );
  1860. }
  1861. *BytesNeeded = *BytesWritten = ulInfoLen;
  1862. }
  1863. return status;
  1864. }
  1865. VOID
  1866. QueryPtiPorts(
  1867. IN ADAPTERCB* pAdapter )
  1868. // Query which PTI ports are available and fill in the count and status of
  1869. // each in the adapter context block 'pAdapter'.
  1870. //
  1871. {
  1872. ULONG ulPortIndex;
  1873. ULONG ulLineId;
  1874. PTI_EXTENSION* pPtiExtension;
  1875. NTSTATUS statusDevice;
  1876. // Ask PtiLink which devices exist.
  1877. //
  1878. pAdapter->ulActualVcs = 0;
  1879. ulLineId = 0;
  1880. for (ulPortIndex = 0; ulPortIndex < NPORTS; ++ulPortIndex)
  1881. {
  1882. TRACE( TL_V, TM_Mp,
  1883. ( "PtiQueryDeviceStatus(%d)", ulPortIndex ) );
  1884. statusDevice = PtiQueryDeviceStatus(
  1885. ulPortIndex, pAdapter->szPortName[ ulPortIndex ] );
  1886. if (NT_SUCCESS( statusDevice ))
  1887. {
  1888. // An actual parallel port device object exists for this
  1889. // logical port. Increment the available VCs and set
  1890. // ulPtiLinkState which will be used in the CAPS OIDs to
  1891. // associate a TAPI LineId.
  1892. //
  1893. pAdapter->ulActualVcs++;
  1894. pAdapter->ulPtiLinkState[ulPortIndex] = PLSF_PortExists;
  1895. pAdapter->ulLineIds[ ulPortIndex ] = ulLineId;
  1896. ++ulLineId;
  1897. pAdapter->ulPtiLinkState[ ulPortIndex ] |= PLSF_LineIdValid;
  1898. }
  1899. TRACE( TL_N, TM_Mp,
  1900. ( "PtiQueryDeviceStatus(%d), status=$%x, port=%S",
  1901. ulPortIndex,
  1902. statusDevice,
  1903. pAdapter->szPortName[ ulPortIndex ] ) );
  1904. }
  1905. }
  1906. VOID
  1907. ReferenceAf(
  1908. IN ADAPTERCB* pAdapter )
  1909. // Adds areference to the address family of adapter block, 'pAdapter'.
  1910. //
  1911. {
  1912. LONG lRef;
  1913. lRef = NdisInterlockedIncrement( &pAdapter->lAfRef );
  1914. TRACE( TL_N, TM_Ref, ( "RefAf to %d", lRef ) );
  1915. }
  1916. BOOLEAN
  1917. ReferenceCall(
  1918. IN VCCB* pVc )
  1919. // Returns true if a reference is added to the active call on VC control
  1920. // block, 'pVc', or false if no reference was added because no call is
  1921. // active.
  1922. //
  1923. {
  1924. BOOLEAN fActive;
  1925. NdisAcquireSpinLock( &pVc->lockCall );
  1926. {
  1927. if (ReadFlags( &pVc->ulFlags ) & VCBF_VcActivated)
  1928. {
  1929. fActive = TRUE;
  1930. ++pVc->lCallRef;
  1931. TRACE( TL_N, TM_Ref, ( "RefCall to %d", pVc->lCallRef ) );
  1932. }
  1933. else
  1934. {
  1935. TRACE( TL_N, TM_Ref, ( "RefCall denied" ) );
  1936. fActive = FALSE;
  1937. }
  1938. }
  1939. NdisReleaseSpinLock( &pVc->lockCall );
  1940. return fActive;
  1941. }
  1942. BOOLEAN
  1943. ReferenceSap(
  1944. IN ADAPTERCB* pAdapter )
  1945. // Returns true if a reference is added to the active SAP on adapter
  1946. // 'pAdapter', or false if no reference was added because no SAP is
  1947. // active.
  1948. //
  1949. {
  1950. BOOLEAN fActive;
  1951. NdisAcquireSpinLock( &pAdapter->lockSap );
  1952. {
  1953. if (ReadFlags( &pAdapter->ulFlags ) & ACBF_SapActive)
  1954. {
  1955. fActive = TRUE;
  1956. ++pAdapter->lSapRef;
  1957. TRACE( TL_N, TM_Ref, ( "RefSap to %d", pAdapter->lSapRef ) );
  1958. }
  1959. else
  1960. {
  1961. TRACE( TL_N, TM_Ref, ( "RefSap denied" ) );
  1962. fActive = FALSE;
  1963. }
  1964. }
  1965. NdisReleaseSpinLock( &pAdapter->lockSap );
  1966. return fActive;
  1967. }
  1968. VOID
  1969. SetupVcAsynchronously(
  1970. IN ADAPTERCB* pAdapter )
  1971. // Called by ReceiveControl to set up a VC for the incoming call
  1972. // using the necessary asynchronous CoNdis calls.
  1973. //
  1974. {
  1975. NDIS_STATUS status;
  1976. VCCB* pVc;
  1977. NDIS_HANDLE NdisVcHandle;
  1978. ULONG ulMask;
  1979. TRACE( TL_V, TM_Misc, ( "SetupVcAsync" ) );
  1980. // Call our own CreateVc handler directly to allocate and
  1981. // initialize the incoming call's VC.
  1982. //
  1983. status = PtiCmCreateVc( pAdapter, NULL, &pVc );
  1984. TRACE( TL_V, TM_Misc, ( "SetupVcAsync: PtiCmCreateVc: Vc Created: pVc=$%p", pVc ) );
  1985. if (status != NDIS_STATUS_SUCCESS)
  1986. {
  1987. ASSERT( !"CreateVc?" );
  1988. // ??? Add code to intiate protocol to terminate link
  1989. return;
  1990. }
  1991. // Allocate an "incoming call setup" context and initialize it from the
  1992. // receive buffer information arguments.
  1993. //
  1994. {
  1995. CHAR* pCallParamBuf;
  1996. ULONG ulCallParamLength;
  1997. CO_CALL_PARAMETERS* pCp;
  1998. CO_CALL_MANAGER_PARAMETERS* pCmp;
  1999. CO_MEDIA_PARAMETERS* pMp;
  2000. CO_AF_TAPI_INCOMING_CALL_PARAMETERS* pTi;
  2001. LINE_CALL_INFO* pLci;
  2002. ulCallParamLength =
  2003. sizeof(CO_CALL_PARAMETERS)
  2004. + sizeof(CO_CALL_MANAGER_PARAMETERS)
  2005. + sizeof(CO_MEDIA_PARAMETERS)
  2006. + sizeof(CO_AF_TAPI_INCOMING_CALL_PARAMETERS)
  2007. + sizeof(LINE_CALL_INFO);
  2008. pCallParamBuf = ALLOC_NONPAGED( ulCallParamLength, MTAG_INCALLBUF );
  2009. if (!pCallParamBuf)
  2010. {
  2011. ASSERT( !"Alloc pCpBuf?" );
  2012. PtiCmDeleteVc( pVc );
  2013. return;
  2014. }
  2015. NdisZeroMemory( pCallParamBuf, ulCallParamLength );
  2016. pCp = (CO_CALL_PARAMETERS* )pCallParamBuf;
  2017. pCmp = (CO_CALL_MANAGER_PARAMETERS* )(pCp + 1);
  2018. pCp->CallMgrParameters = pCmp;
  2019. //
  2020. // Might want to make this report the actual
  2021. // connection speed in the future
  2022. //
  2023. pCmp->Transmit.TokenRate =
  2024. pCmp->Transmit.PeakBandwidth =
  2025. pCmp->Receive.TokenRate =
  2026. pCmp->Receive.PeakBandwidth = PTI_LanBps/8;
  2027. pMp = (CO_MEDIA_PARAMETERS* )(pCmp + 1);
  2028. pCp->MediaParameters = pMp;
  2029. pMp->ReceiveSizeHint = PTI_MaxFrameSize;
  2030. pMp->MediaSpecific.Length =
  2031. sizeof(CO_AF_TAPI_INCOMING_CALL_PARAMETERS)
  2032. + sizeof(LINE_CALL_INFO);
  2033. pTi = (CO_AF_TAPI_INCOMING_CALL_PARAMETERS* )
  2034. pMp->MediaSpecific.Parameters;
  2035. pTi->ulLineID = pAdapter->ulSapPort;
  2036. pTi->ulAddressID = CO_TAPI_ADDRESS_ID_UNSPECIFIED;
  2037. pTi->ulFlags = CO_TAPI_FLAG_INCOMING_CALL;
  2038. pTi->LineCallInfo.Length = sizeof(LINE_CALL_INFO);
  2039. pTi->LineCallInfo.MaximumLength = sizeof(LINE_CALL_INFO);
  2040. pTi->LineCallInfo.Offset = sizeof(pTi->LineCallInfo);
  2041. pLci = (LINE_CALL_INFO* )(pTi + 1);
  2042. pLci->ulTotalSize = sizeof(LINE_CALL_INFO);
  2043. pLci->ulNeededSize = sizeof(LINE_CALL_INFO);
  2044. pLci->ulUsedSize = sizeof(LINE_CALL_INFO);
  2045. pLci->ulLineDeviceID = pTi->ulLineID;
  2046. pLci->ulBearerMode = LINEBEARERMODE_DATA;
  2047. pLci->ulMediaMode = LINEMEDIAMODE_DIGITALDATA;
  2048. //
  2049. // Might want to make this report the actual
  2050. // connection speed in the future
  2051. //
  2052. pLci->ulRate = PTI_LanBps;
  2053. pVc->pTiParams = pTi;
  2054. pVc->pInCall = pCp;
  2055. }
  2056. // Mark the call as initiated by the peer so we know which notifications
  2057. // to give when the result is known.
  2058. //
  2059. ulMask = (VCBF_PeerInitiatedCall | VCBF_PeerOpenPending);
  2060. SetFlags( &pVc->ulFlags, ulMask );
  2061. ASSERT( !(ReadFlags( &pVc->ulFlags ) & VCBM_VcState) );
  2062. // Check if the request has a chance of succeeding before getting the
  2063. // client involved.
  2064. //
  2065. if (!pAdapter->NdisAfHandle || !pAdapter->NdisSapHandle)
  2066. {
  2067. TRACE( TL_A, TM_Misc, ( "No AF or SAP" ) );
  2068. pVc->status = NDIS_STATUS_INVALID_SAP;
  2069. SetupVcComplete( pVc );
  2070. return;
  2071. }
  2072. // Tell NDIS to notify the client of the new VC and give us it's handle.
  2073. //
  2074. TRACE( TL_I, TM_Recv, ( "SetupVcAsynch: NdisMCmCreateVc: pVc=$%p", pVc ) );
  2075. status = NdisMCmCreateVc(
  2076. pAdapter->MiniportAdapterHandle,
  2077. pAdapter->NdisAfHandle,
  2078. pVc,
  2079. &pVc->NdisVcHandle );
  2080. TRACE( TL_I, TM_Recv,
  2081. ( "SetupVcAsynch: NdisMCmCreateVc: Get VcHandle: pVc=$%p VcHandle=$%p, status=$%x",
  2082. pVc,
  2083. pVc->NdisVcHandle,
  2084. status ) );
  2085. if (status != NDIS_STATUS_SUCCESS)
  2086. {
  2087. pVc->status = status;
  2088. SetupVcComplete( pVc );
  2089. return;
  2090. }
  2091. SetFlags( &pVc->ulFlags, VCBF_VcCreated );
  2092. // Tell NDIS the VC is active.
  2093. //
  2094. TRACE( TL_I, TM_Recv,
  2095. ( "SetupVcAsynch: NdisMCmActivateVc, VcHandle=$%p",
  2096. pVc->NdisVcHandle) );
  2097. status = NdisMCmActivateVc(
  2098. pVc->NdisVcHandle, pVc->pInCall );
  2099. TRACE( TL_I, TM_Recv,
  2100. ( "SetupVcAsynch: NdisMCmActivateVc: status=$%x", status ) );
  2101. if (status != NDIS_STATUS_SUCCESS )
  2102. {
  2103. pVc->status = status;
  2104. TRACE( TL_I, TM_Recv, ( "SetupVcAsynch: Error: NoAccept" ) );
  2105. SetupVcComplete( pVc );
  2106. return;
  2107. }
  2108. // Activate the call
  2109. //
  2110. SetFlags( &pVc->ulFlags,
  2111. (VCBF_VcActivated
  2112. | VCBF_CallClosableByClient
  2113. | VCBF_CallClosableByPeer) );
  2114. ReferenceCall( pVc );
  2115. if (!ReferenceSap( pAdapter ))
  2116. {
  2117. pVc->status = NDIS_STATUS_INVALID_SAP;
  2118. TRACE( TL_I, TM_Recv, ( "SetupVcAsynch: Error: NoSap" ) );
  2119. SetupVcComplete( pVc );
  2120. return;
  2121. }
  2122. // Tell NDIS to tell the client about the call. The dispatched flag is
  2123. // set here rather in the completion because, according to JameelH, it is
  2124. // valid to call NdisMCmDispatchIncomingCloseCall even if client pends on
  2125. // the dispatch.
  2126. //
  2127. TRACE( TL_I, TM_Recv, ( "SetupVcAsynch: NdisMCmDispInCall" ) );
  2128. status = NdisMCmDispatchIncomingCall(
  2129. pAdapter->NdisSapHandle,
  2130. pVc->NdisVcHandle,
  2131. pVc->pInCall );
  2132. TRACE( TL_I, TM_Recv,
  2133. ( "SetupVcAsynch: NdisMCmDispInCall: status=$%x", status ) );
  2134. DereferenceSap( pAdapter );
  2135. if (status != NDIS_STATUS_PENDING)
  2136. {
  2137. PtiCmIncomingCallComplete( status, pVc, pVc->pInCall );
  2138. }
  2139. SetFlags( &pVc->ulFlags, VCBF_VcDispatched );
  2140. // Next stop is our PtiIncomingCallComplete handler which will call
  2141. // SetupVcComplete with clients reported status.
  2142. //
  2143. TRACE( TL_I, TM_Recv, ( "SetupVcAsynch: Exit" ) );
  2144. }
  2145. VOID
  2146. SetupVcComplete(
  2147. IN VCCB* pVc )
  2148. // Called when the asynchronous incoming call VC setup result is known.
  2149. // 'pVc' is the non-NULL set up VC, with 'status' field indicating the
  2150. // status thus far.
  2151. //
  2152. {
  2153. NDIS_STATUS status;
  2154. NTSTATUS ntStatus;
  2155. BOOLEAN fCallerFreesBuffer;
  2156. LIST_ENTRY list;
  2157. CHAR* pBuffer;
  2158. ADAPTERCB* pAdapter;
  2159. TRACE( TL_N, TM_Cm, ( "SetupVcComp: pVc=%p, Port=$%x, status=$%x",
  2160. pVc, pVc->ulVcParallelPort, pVc->status ) );
  2161. pAdapter = pVc->pAdapter;
  2162. do
  2163. {
  2164. if (pVc->status != NDIS_STATUS_SUCCESS)
  2165. {
  2166. break;
  2167. }
  2168. // Initialize the PtiLink API getting the extension pointers. Get
  2169. // PTILINKx extension also fires ECPdetect and enables port IRQ.
  2170. //
  2171. ntStatus = PtiInitialize( pAdapter->ulSapPort,
  2172. &pVc->Extension,
  2173. &pVc->PtiExtension);
  2174. TRACE( TL_V, TM_Cm, ( "SetupVcComp: PtiLink Init: Ext=$%p, PtiExt=$%p",
  2175. pVc->Extension,
  2176. pVc->PtiExtension ) );
  2177. if ( (pVc->Extension == NULL) ||
  2178. (pVc->PtiExtension == NULL) )
  2179. {
  2180. pVc->status = NDIS_STATUS_FAILURE;
  2181. TRACE( TL_V, TM_Cm, ( "SetupVcComplete: Error: PtiInitialize Returned NULL Pointer", ntStatus ) );
  2182. break;
  2183. }
  2184. if ( !NT_SUCCESS( ntStatus ) )
  2185. {
  2186. pVc->status = NDIS_STATUS_FAILURE;
  2187. TRACE( TL_V, TM_Cm, ( "SetupVcComplete: Error: PtiInitialize=%x", ntStatus ) );
  2188. break;
  2189. }
  2190. SetFlags( &pVc->ulFlags, VCBF_CallInProgress );
  2191. pVc->ulVcParallelPort = pAdapter->ulSapPort;
  2192. // now "privatize" the PtiLink Api ... making it's upper edge link to us
  2193. // this may have been done before
  2194. // in this case, we are associating a new Vc context with receives
  2195. //
  2196. TRACE( TL_V, TM_Cm, ( "SetupVcComplete: RegCb pV=$%p", pVc ) );
  2197. PtiRegisterCallbacks(pVc->Extension, // the PTILINKx extension
  2198. PtiCbGetReadBuffer, // our get buffer routine
  2199. PtiRx, // our receive complete routine
  2200. PtiCbLinkEventHandler, // our link event handler
  2201. pVc); // our context
  2202. }
  2203. while (FALSE);
  2204. // With no locks held, perform and VC completion processing including
  2205. // indications to client.
  2206. //
  2207. CompleteVc( pVc );
  2208. TRACE( TL_V, TM_Misc, ( "SetupVcComp: Exit" ) );
  2209. }
  2210. VOID
  2211. WriteEndpointsToRegistry(
  2212. IN ULONG ulVcs )
  2213. // Set the value of the "WanEndpoints", "MinWanEndpoints", and
  2214. // "MaxWanEndpoints" registry values to the 'ulVcs' value.
  2215. //
  2216. {
  2217. NTSTATUS status;
  2218. OBJECT_ATTRIBUTES objattr;
  2219. UNICODE_STRING uni;
  2220. HANDLE hNet;
  2221. HANDLE hAdapter;
  2222. ULONG i;
  2223. WCHAR szPath[ 256 ];
  2224. #define PSZ_NetAdapters L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}"
  2225. TRACE( TL_I, TM_Cm, ( "WriteEndpointsToRegistry(%d)", ulVcs ) );
  2226. hNet = NULL;
  2227. hAdapter = NULL;
  2228. do
  2229. {
  2230. // Get a handle to the network adapters registry key.
  2231. //
  2232. StrCpyW( szPath, PSZ_NetAdapters );
  2233. RtlInitUnicodeString( &uni, szPath );
  2234. InitializeObjectAttributes(
  2235. &objattr, &uni, OBJ_CASE_INSENSITIVE, NULL, NULL );
  2236. status = ZwOpenKey(
  2237. &hNet,
  2238. KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_SET_VALUE,
  2239. &objattr );
  2240. if (status != STATUS_SUCCESS)
  2241. {
  2242. TRACE( TL_A, TM_Cm, ( "ZwOpenKey(net)=$%08x?", status ) );
  2243. break;
  2244. }
  2245. // Walk the adapter subkeys looking for the RASPTI adapter.
  2246. //
  2247. for (i = 0; ; ++i)
  2248. {
  2249. CHAR szBuf[ 512 ];
  2250. KEY_BASIC_INFORMATION* pKey;
  2251. KEY_VALUE_PARTIAL_INFORMATION* pValue;
  2252. WCHAR* pch;
  2253. ULONG ulSize;
  2254. // Find the name of the next adapter subkey.
  2255. //
  2256. status = ZwEnumerateKey(
  2257. hNet, i, KeyBasicInformation,
  2258. szBuf, sizeof(szBuf), &ulSize );
  2259. if (status != STATUS_SUCCESS)
  2260. {
  2261. DBG_if (status != STATUS_NO_MORE_ENTRIES)
  2262. {
  2263. TRACE( TL_A, TM_Cm, ( "ZwEnumKey=$%08x?", status ) );
  2264. }
  2265. break;
  2266. }
  2267. // Open the adapter subkey.
  2268. //
  2269. pKey = (KEY_BASIC_INFORMATION* )szBuf;
  2270. StrCpyW( szPath, PSZ_NetAdapters );
  2271. pch = &szPath[ StrLenW( szPath ) ];
  2272. *pch = L'\\';
  2273. ++pch;
  2274. NdisMoveMemory( pch, pKey->Name, pKey->NameLength );
  2275. pch += pKey->NameLength / sizeof(WCHAR);
  2276. *pch = L'\0';
  2277. RtlInitUnicodeString( &uni, szPath );
  2278. InitializeObjectAttributes(
  2279. &objattr, &uni, OBJ_CASE_INSENSITIVE, NULL, NULL );
  2280. status = ZwOpenKey(
  2281. &hAdapter,
  2282. KEY_QUERY_VALUE | KEY_SET_VALUE,
  2283. &objattr );
  2284. if (status != STATUS_SUCCESS)
  2285. {
  2286. TRACE( TL_A, TM_Cm, ( "ZwOpenKey(adapter)=$%08x?", status ) );
  2287. break;
  2288. }
  2289. // Query the "ComponentID" value.
  2290. //
  2291. RtlInitUnicodeString( &uni, L"ComponentId" );
  2292. status = ZwQueryValueKey(
  2293. hAdapter, &uni, KeyValuePartialInformation,
  2294. szBuf, sizeof(szBuf), &ulSize );
  2295. if (status != STATUS_SUCCESS)
  2296. {
  2297. ZwClose( hAdapter );
  2298. hAdapter = NULL;
  2299. TRACE( TL_A, TM_Cm, ( "ZwQValueKey=$%08x?", status ) );
  2300. continue;
  2301. }
  2302. pValue = (KEY_VALUE_PARTIAL_INFORMATION* )szBuf;
  2303. if (pValue->Type != REG_SZ
  2304. || StrCmpW( (WCHAR* )pValue->Data, L"ms_ptiminiport" ) != 0)
  2305. {
  2306. ZwClose( hAdapter );
  2307. hAdapter = NULL;
  2308. continue;
  2309. }
  2310. // Found it. 'HAdapter' contains it's adapter key handle.
  2311. //
  2312. TRACE( TL_I, TM_Cm, ( "PTI adapter key found" ) );
  2313. // Write the "actual VC" count to the 3 endpoint registry values.
  2314. //
  2315. RtlInitUnicodeString( &uni, L"WanEndpoints" );
  2316. status = ZwSetValueKey(
  2317. hAdapter, &uni, 0, REG_DWORD, &ulVcs, sizeof(ulVcs) );
  2318. if (status != STATUS_SUCCESS)
  2319. {
  2320. TRACE( TL_A, TM_Cm,
  2321. ( "ZwSetValueKey(WE)=$%08x?", status ) );
  2322. }
  2323. RtlInitUnicodeString( &uni, L"MinWanEndpoints" );
  2324. status = ZwSetValueKey(
  2325. hAdapter, &uni, 0, REG_DWORD, &ulVcs, sizeof(ulVcs) );
  2326. if (status != STATUS_SUCCESS)
  2327. {
  2328. TRACE( TL_A, TM_Cm,
  2329. ( "ZwSetValueKey(MinWE)=$%08x?", status ) );
  2330. }
  2331. RtlInitUnicodeString( &uni, L"MaxWanEndpoints" );
  2332. status = ZwSetValueKey(
  2333. hAdapter, &uni, 0, REG_DWORD, &ulVcs, sizeof(ulVcs) );
  2334. if (status != STATUS_SUCCESS)
  2335. {
  2336. TRACE( TL_A, TM_Cm,
  2337. ( "ZwSetValueKey(MaxWE)=$%08x?", status ) );
  2338. }
  2339. }
  2340. }
  2341. while (FALSE);
  2342. if (hAdapter)
  2343. {
  2344. ZwClose( hAdapter );
  2345. }
  2346. if (hNet)
  2347. {
  2348. ZwClose( hNet );
  2349. }
  2350. }
  2351. NDIS_STATUS
  2352. PtiCmCloseAf(
  2353. IN NDIS_HANDLE CallMgrAfContext )
  2354. // Standard 'CmCloseAfHandler' routine called by NDIS when a client
  2355. // requests to close an address family. See DDK doc.
  2356. //
  2357. {
  2358. ADAPTERCB* pAdapter;
  2359. TRACE( TL_I, TM_Cm, ( "PtiCmCloseAf" ) );
  2360. pAdapter = (ADAPTERCB* )CallMgrAfContext;
  2361. if (pAdapter->ulTag != MTAG_ADAPTERCB)
  2362. {
  2363. ASSERT( !"Atag?" );
  2364. return NDIS_STATUS_INVALID_DATA;
  2365. }
  2366. // This dereference will eventually lead to us calling
  2367. // NdisMCmCloseAfComplete.
  2368. //
  2369. DereferenceAf( pAdapter );
  2370. TRACE( TL_V, TM_Cm, ( "PtiCmCloseAf: Exit" ) );
  2371. return NDIS_STATUS_PENDING;
  2372. }