Windows NT 4.0 source code leak
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.

3873 lines
85 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1990-1995 Microsoft Corporation
  3. Module Name:
  4. ndis_co.c
  5. Abstract:
  6. CO-NDIS miniport wrapper functions
  7. Author:
  8. Jameel Hyder (JameelH) 01-Feb-96
  9. Environment:
  10. Kernel mode, FSD
  11. Revision History:
  12. --*/
  13. #include <precomp.h>
  14. #include <atm.h>
  15. #pragma hdrstop
  16. //
  17. // Define the module number for debug code.
  18. //
  19. #define MODULE_NUMBER MODULE_NDIS_CO
  20. /*
  21. Connection-oriented section of NDIS exposes the following objects and apis to
  22. manipulate these objects.
  23. AF Address Family
  24. SAP Service Access Point
  25. VC Virtual Circuit
  26. Party A node in a point-multipoint VC
  27. There is a notion of a call-manager and a client on a per-binding basis. The
  28. call manager acts as a helper dll for NDIS wrapper to manage the aforementioned
  29. objects.
  30. The concept of AF makes possible the existence of multiple call-managers. An
  31. example of this is the UNI call-manager and a SPANS call-manager for the ATM
  32. media.
  33. SAPs provides a way for incoming calls to be routed to the right entity. A
  34. protocol can register for more than one SAPs. Its upto the call-manager to
  35. allow/dis-allow multiple protocol modules to register the same SAP.
  36. VCs are created either by a protocol module requesting to make an outbound call
  37. or by the call-manager dispatching an incoming call. VCs can either be point-point
  38. or point-multi-point. Leaf nodes can be added to VCs at any time provided the first
  39. leaf was created appropriately.
  40. References:
  41. An AF association results in the reference of file-object for the call-manager.
  42. A SAP registration results in the reference of the AF.
  43. A send or receive does not reference a VC. This is because miniports are required to
  44. pend DeactivateVc calls till all I/O completes. So when it calls NdisMCoDeactivateVcComplete
  45. no other packets will be indicated up and there are no sends outstanding.
  46. */
  47. NDIS_STATUS
  48. NdisCmRegisterAddressFamily(
  49. IN NDIS_HANDLE NdisBindingHandle,
  50. IN PCO_ADDRESS_FAMILY AddressFamily,
  51. IN PNDIS_CALL_MANAGER_CHARACTERISTICS CmCharacteristics,
  52. IN UINT SizeOfCmCharacteristics
  53. )
  54. /*++
  55. Routine Description:
  56. This is a call from the call-manager to register the address family
  57. supported by this call-manager.
  58. Arguments:
  59. NdisBindingHandle - Pointer to the call-managers NDIS_OPEN_BLOCK.
  60. AddressFamily - The address family being registered.
  61. CmCharacteristics - Call-Manager characteristics
  62. SizeOfCmCharacteristics - Size of Call-Manager characteristics
  63. Return Value:
  64. NDIS_STATUS_SUCCESS if the address family registration is successfully.
  65. NDIS_STATUS_FAILURE if the caller is not a call-manager or this address
  66. family is already registered for this miniport.
  67. --*/
  68. {
  69. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  70. KIRQL OldIrql;
  71. PNDIS_AF_LIST AfList;
  72. PNDIS_PROTOCOL_BLOCK Protocol;
  73. PNDIS_M_OPEN_BLOCK CallMgrOpen;
  74. PNDIS_MINIPORT_BLOCK Miniport;
  75. CallMgrOpen = (PNDIS_M_OPEN_BLOCK)(((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacBindingHandle);
  76. Miniport = CallMgrOpen->MiniportHandle;
  77. Protocol = CallMgrOpen->ProtocolHandle;
  78. CoReferencePackage();
  79. //
  80. // Make sure that the miniport is a CoNdis miniport and
  81. // there is no other module registering the same address family.
  82. //
  83. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  84. do
  85. {
  86. //
  87. // Make sure the binding is not closing down
  88. //
  89. if (CallMgrOpen->Flags & fMINIPORT_OPEN_CLOSING)
  90. {
  91. Status = NDIS_STATUS_FAILURE;
  92. break;
  93. }
  94. //
  95. // Make sure that the miniport is a CoNdis miniport and
  96. // protocol is also a NDIS 4.1 or later protocol.
  97. //
  98. if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
  99. {
  100. //
  101. // Not a NDIS 4.1 or later miniport
  102. //
  103. Status = NDIS_STATUS_FAILURE;
  104. break;
  105. }
  106. if ((Protocol->ProtocolCharacteristics.MajorNdisVersion < 4) ||
  107. ((Protocol->ProtocolCharacteristics.MajorNdisVersion == 4) &&
  108. (Protocol->ProtocolCharacteristics.MinorNdisVersion < 1)))
  109. {
  110. //
  111. // Not a NDIS 4.1 or later protocol
  112. //
  113. Status = NDIS_STATUS_FAILURE;
  114. break;
  115. }
  116. //
  117. // Make sure that the call-manager characteristics are 4.1 or later
  118. //
  119. if ((CmCharacteristics->MajorVersion != 4) ||
  120. (CmCharacteristics->MinorVersion != 1) ||
  121. (SizeOfCmCharacteristics < sizeof(NDIS_CALL_MANAGER_CHARACTERISTICS)))
  122. {
  123. //
  124. // Not a NDIS 4.1 or later protocol
  125. //
  126. Status = NDIS_STATUS_FAILURE;
  127. break;
  128. }
  129. //
  130. // Search registered call-managers for this miniport and make sure there is no
  131. // clash. A call-manager can only register one address family per-open. This
  132. // is due to the way we cache handlers. Can be over-come if the handlers are
  133. // identical for each address-family - but decided not to since it is un-interesting.
  134. //
  135. for (AfList = Miniport->CallMgrAfList;
  136. AfList != NULL;
  137. AfList = AfList->NextOpen)
  138. {
  139. if ((AfList->AddressFamily == AddressFamily->AddressFamily) ||
  140. (AfList->Open == CallMgrOpen))
  141. {
  142. Status = NDIS_STATUS_FAILURE;
  143. break;
  144. }
  145. }
  146. if (AfList == NULL)
  147. {
  148. //
  149. // No other entity has claimed this address family.
  150. //
  151. AfList = (PNDIS_AF_LIST)ALLOC_FROM_POOL(sizeof(NDIS_AF_LIST), NDIS_TAG_CO);
  152. if (AfList == NULL)
  153. {
  154. Status = NDIS_STATUS_RESOURCES;
  155. break;
  156. }
  157. AfList->AddressFamily = AddressFamily->AddressFamily;
  158. CopyMemory(&AfList->CmChars,
  159. CmCharacteristics,
  160. sizeof(NDIS_CALL_MANAGER_CHARACTERISTICS));
  161. //
  162. // link it in the miniport list
  163. //
  164. AfList->Open = CallMgrOpen;
  165. AfList->NextOpen = Miniport->CallMgrAfList;
  166. Miniport->CallMgrAfList = AfList;
  167. //
  168. // Now link it in the global list
  169. //
  170. ACQUIRE_SPIN_LOCK_DPC(&ndisGlobalOpenListLock);
  171. AfList->NextGlobal = ndisAfList;
  172. ndisAfList = AfList;
  173. RELEASE_SPIN_LOCK_DPC(&ndisGlobalOpenListLock);
  174. //
  175. // Finally cache some handlers in the open-block
  176. //
  177. CallMgrOpen->CoCreateVcHandler = CmCharacteristics->CmCreateVcHandler;
  178. CallMgrOpen->CoDeleteVcHandler = CmCharacteristics->CmDeleteVcHandler;
  179. CallMgrOpen->CmActivateVcCompleteHandler = CmCharacteristics->CmActivateVcCompleteHandler;
  180. CallMgrOpen->CmDeactivateVcCompleteHandler = CmCharacteristics->CmDeactivateVcCompleteHandler;
  181. //
  182. // Notify existing clients of this registration
  183. //
  184. ndisMNotifyAfRegistration(Miniport, AddressFamily);
  185. }
  186. } while (FALSE);
  187. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  188. if (!NT_SUCCESS(Status))
  189. {
  190. CoDereferencePackage();
  191. }
  192. return(Status);
  193. }
  194. NDIS_STATUS
  195. NdisMCmRegisterAddressFamily(
  196. IN NDIS_HANDLE MiniportAdapterHandle,
  197. IN PCO_ADDRESS_FAMILY AddressFamily,
  198. IN PNDIS_CALL_MANAGER_CHARACTERISTICS CmCharacteristics,
  199. IN UINT SizeOfCmCharacteristics
  200. )
  201. /*++
  202. Routine Description:
  203. This is a call from the miniport supported call-manager to register the address family
  204. supported by this call-manager.
  205. Arguments:
  206. MiniportAdapterHandle - Pointer to the miniports NDIS_MINIPORT_BLOCK.
  207. AddressFamily - The address family being registered.
  208. CmCharacteristics - Call-Manager characteristics
  209. SizeOfCmCharacteristics - Size of Call-Manager characteristics
  210. Return Value:
  211. NDIS_STATUS_SUCCESS if the address family registration is successfully.
  212. NDIS_STATUS_FAILURE if the caller is not a call-manager or this address
  213. family is already registered for this miniport.
  214. --*/
  215. {
  216. PNDIS_MINIPORT_BLOCK Miniport;
  217. NDIS_STATUS Status;
  218. PNDIS_AF_LIST AfList;
  219. KIRQL OldIrql;
  220. CoReferencePackage();
  221. Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
  222. //
  223. // Make sure that the miniport is a CoNdis miniport and
  224. // there is no other module registering the same address family.
  225. //
  226. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  227. do
  228. {
  229. //
  230. // Make sure that the miniport is a CoNdis miniport
  231. //
  232. if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
  233. {
  234. //
  235. // Not a NDIS 4.1 or later miniport
  236. //
  237. Status = NDIS_STATUS_FAILURE;
  238. break;
  239. }
  240. //
  241. // Make sure that the call-manager characteristics are 4.1 or later
  242. //
  243. if ((CmCharacteristics->MajorVersion != 4) ||
  244. (CmCharacteristics->MinorVersion != 1) ||
  245. (SizeOfCmCharacteristics < sizeof(NDIS_CALL_MANAGER_CHARACTERISTICS)))
  246. {
  247. //
  248. // Not a NDIS 4.1 or later protocol
  249. //
  250. Status = NDIS_STATUS_FAILURE;
  251. break;
  252. }
  253. //
  254. // Search registered call-managers for this miniport and make sure there is no
  255. // clash. A call-manager can only register one address family per-open. This
  256. // is due to the way we cache handlers. Can be over-come if the handlers are
  257. // identical for each address-family - but decided not to since it is un-interesting.
  258. //
  259. for (AfList = Miniport->CallMgrAfList;
  260. AfList != NULL;
  261. AfList = AfList->NextOpen)
  262. {
  263. if ((AfList->AddressFamily == AddressFamily->AddressFamily) ||
  264. (AfList->Open == NULL))
  265. {
  266. Status = NDIS_STATUS_FAILURE;
  267. break;
  268. }
  269. }
  270. if (AfList == NULL)
  271. {
  272. //
  273. // No other entity has claimed this address family.
  274. //
  275. AfList = (PNDIS_AF_LIST)ALLOC_FROM_POOL(sizeof(NDIS_AF_LIST), NDIS_TAG_CO);
  276. if (AfList == NULL)
  277. {
  278. Status = NDIS_STATUS_RESOURCES;
  279. break;
  280. }
  281. AfList->AddressFamily = AddressFamily->AddressFamily;
  282. CopyMemory(&AfList->CmChars,
  283. CmCharacteristics,
  284. sizeof(NDIS_CALL_MANAGER_CHARACTERISTICS));
  285. //
  286. // link it in the miniport list
  287. //
  288. AfList->Open = NULL;
  289. AfList->NextOpen = Miniport->CallMgrAfList;
  290. Miniport->CallMgrAfList = AfList;
  291. //
  292. // Now link it in the global list
  293. //
  294. ACQUIRE_SPIN_LOCK_DPC(&ndisGlobalOpenListLock);
  295. AfList->NextGlobal = ndisAfList;
  296. ndisAfList = AfList;
  297. RELEASE_SPIN_LOCK_DPC(&ndisGlobalOpenListLock);
  298. }
  299. } while (FALSE);
  300. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  301. if (!NT_SUCCESS(Status))
  302. {
  303. CoDereferencePackage();
  304. }
  305. return Status;
  306. }
  307. VOID
  308. ndisMNotifyAfRegistration(
  309. IN PNDIS_MINIPORT_BLOCK Miniport,
  310. IN PCO_ADDRESS_FAMILY AddressFamily OPTIONAL
  311. )
  312. /*++
  313. Routine Description:
  314. If a protocol has a handler for it, notify it that a new address family has
  315. been registered.
  316. Arguments:
  317. NdisBindingHandle - Pointer to the protocol's NDIS_OPEN_BLOCK.
  318. AddressFamily - Address family in question. If not specified all address
  319. families for the miniport are reported
  320. Return Value:
  321. None.
  322. --*/
  323. {
  324. }
  325. NDIS_STATUS
  326. NdisClOpenAddressFamily(
  327. IN NDIS_HANDLE NdisBindingHandle,
  328. IN PCO_ADDRESS_FAMILY AddressFamily,
  329. IN NDIS_HANDLE ClientAfContext,
  330. IN PNDIS_CLIENT_CHARACTERISTICS ClCharacteristics,
  331. IN UINT SizeOfClCharacteristics,
  332. OUT PNDIS_HANDLE NdisAfHandle
  333. )
  334. /*++
  335. Routine Description:
  336. This is a call from a NDIS 4.1 or later protocol to open a particular
  337. address familty - in essence getting a handle to the call-manager.
  338. Arguments:
  339. NdisBindingHandle - Pointer to the protocol's NDIS_OPEN_BLOCK.
  340. PCO_ADDRESS_FAMILY - The address family being registered.
  341. ClientAfContext - Protocol context associated with this handle.
  342. NdisAfHandle - Handle returned by NDIS for this address family.
  343. Return Value:
  344. NDIS_STATUS_SUCCESS if the address family open is successfully.
  345. NDIS_STATUS_PENDING if the call-manager pends this call. The caller will get
  346. called at the completion handler when done.
  347. NDIS_STATUS_FAILURE if the caller is not a NDIS 4.1 prototcol or this address
  348. family is not registered for this miniport.
  349. --*/
  350. {
  351. PNDIS_CO_AF_BLOCK pAf;
  352. PNDIS_AF_LIST AfList;
  353. PNDIS_M_OPEN_BLOCK CallMgrOpen, ClientOpen;
  354. PNDIS_MINIPORT_BLOCK Miniport;
  355. PNDIS_PROTOCOL_BLOCK Protocol;
  356. KIRQL OldIrql;
  357. NTSTATUS Status;
  358. *NdisAfHandle = NULL;
  359. ClientOpen = (PNDIS_M_OPEN_BLOCK)((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacBindingHandle;
  360. Miniport = ClientOpen->MiniportHandle;
  361. Protocol = ClientOpen->ProtocolHandle;
  362. CoReferencePackage();
  363. do
  364. {
  365. //
  366. // Make sure the binding is not closing down
  367. //
  368. if (ClientOpen->Flags & fMINIPORT_OPEN_CLOSING)
  369. {
  370. Status = NDIS_STATUS_FAILURE;
  371. break;
  372. }
  373. //
  374. // Make sure that the miniport is a CoNdis miniport and
  375. // protocol is also a NDIS 4.1 or later protocol.
  376. //
  377. if ((Miniport->DriverHandle->MiniportCharacteristics.MajorNdisVersion < 4) ||
  378. ((Miniport->DriverHandle->MiniportCharacteristics.MajorNdisVersion == 4) &&
  379. (Miniport->DriverHandle->MiniportCharacteristics.MinorNdisVersion < 1)) ||
  380. (Miniport->DriverHandle->MiniportCharacteristics.CoCreateVcHandler == NULL))
  381. {
  382. //
  383. // Not a NDIS 4.1 or later miniport
  384. //
  385. Status = NDIS_STATUS_FAILURE;
  386. break;
  387. }
  388. if ((Protocol->ProtocolCharacteristics.MajorNdisVersion < 4) ||
  389. ((Protocol->ProtocolCharacteristics.MajorNdisVersion == 4) &&
  390. (Protocol->ProtocolCharacteristics.MinorNdisVersion < 1)))
  391. {
  392. //
  393. // Not a NDIS 4.1 or later protocol
  394. //
  395. Status = NDIS_STATUS_FAILURE;
  396. break;
  397. }
  398. //
  399. // Make sure that the client characteristics are 4.1 or later
  400. //
  401. if ((ClCharacteristics->MajorVersion != 4) ||
  402. (ClCharacteristics->MinorVersion != 1) ||
  403. (SizeOfClCharacteristics < sizeof(NDIS_CLIENT_CHARACTERISTICS)))
  404. {
  405. //
  406. // Not a NDIS 4.1 or later protocol
  407. //
  408. Status = NDIS_STATUS_FAILURE;
  409. break;
  410. }
  411. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  412. //
  413. // Search the miniport block for a registered call-manager for this address family
  414. //
  415. for (AfList = Miniport->CallMgrAfList;
  416. AfList != NULL;
  417. AfList = AfList->NextOpen)
  418. {
  419. if (AfList->AddressFamily == AddressFamily->AddressFamily)
  420. {
  421. CallMgrOpen = AfList->Open;
  422. break;
  423. }
  424. }
  425. //
  426. // If we found a matching call manager, make sure that the callmgr
  427. // is not currently closing.
  428. //
  429. if ((AfList == NULL) ||
  430. ((AfList != NULL) && (AfList->Open->Flags & fMINIPORT_OPEN_CLOSING)) ||
  431. (Miniport->Flags & (fMINIPORT_CLOSING | fMINIPORT_HALTING)))
  432. {
  433. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  434. //
  435. // NOTE: We can possibly wait a little while here and retry
  436. // before actually failing this call if (AfList == NULL).
  437. //
  438. Status = NDIS_STATUS_FAILURE;
  439. break;
  440. }
  441. //
  442. // Allocate memory for the AF block.
  443. //
  444. pAf = ALLOC_FROM_POOL(sizeof(NDIS_CO_AF_BLOCK), NDIS_TAG_CO);
  445. if (pAf == NULL)
  446. {
  447. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  448. Status = NDIS_STATUS_RESOURCES;
  449. break;
  450. }
  451. pAf->References = 1;
  452. pAf->Flags = 0;
  453. pAf->Miniport = Miniport;
  454. pAf->ClientOpen = ClientOpen;
  455. pAf->CallMgrOpen = CallMgrOpen = AfList->Open;
  456. pAf->ClientContext = ClientAfContext;
  457. //
  458. // Reference the call-manager's file object - we do not want to let it
  459. // duck from under the client.
  460. //
  461. //
  462. // Reference the client and the call-manager opens
  463. //
  464. ClientOpen->References++;
  465. if (CallMgrOpen != NULL)
  466. {
  467. ObReferenceObject(CallMgrOpen->FileObject);
  468. CallMgrOpen->References++;
  469. }
  470. else
  471. {
  472. ObReferenceObject(Miniport->DeviceObject);
  473. Miniport->Ref.ReferenceCount ++;
  474. }
  475. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  476. INITIALIZE_SPIN_LOCK(&pAf->Lock);
  477. //
  478. // Cache in call-manager entry points
  479. //
  480. pAf->CallMgrEntries = &AfList->CmChars;
  481. //
  482. // And also Cache in client entry points
  483. //
  484. CopyMemory(&pAf->ClientEntries,
  485. ClCharacteristics,
  486. sizeof(NDIS_CLIENT_CHARACTERISTICS));
  487. //
  488. // Cache some handlers in the open-block
  489. //
  490. ClientOpen->CoCreateVcHandler = ClCharacteristics->ClCreateVcHandler;
  491. ClientOpen->CoDeleteVcHandler = ClCharacteristics->ClDeleteVcHandler;
  492. //
  493. // Now call the CallMgr's OpenAfHandler
  494. //
  495. Status = (*AfList->CmChars.CmOpenAfHandler)((CallMgrOpen != NULL) ?
  496. CallMgrOpen->ProtocolBindingContext :
  497. Miniport->MiniportAdapterContext,
  498. AddressFamily,
  499. pAf,
  500. &pAf->CallMgrContext);
  501. if (Status != NDIS_STATUS_PENDING)
  502. {
  503. NdisCmOpenAddressFamilyComplete(Status,
  504. pAf,
  505. pAf->CallMgrContext);
  506. Status = NDIS_STATUS_PENDING;
  507. }
  508. } while (FALSE);
  509. if (!NT_SUCCESS(Status))
  510. {
  511. CoDereferencePackage();
  512. }
  513. return Status;
  514. }
  515. VOID
  516. NdisCmOpenAddressFamilyComplete(
  517. IN NDIS_STATUS Status,
  518. IN NDIS_HANDLE NdisAfHandle,
  519. IN NDIS_HANDLE CallMgrAfContext
  520. )
  521. /*++
  522. Routine Description:
  523. Completion routine for the OpenAddressFamily call. The call manager had pended this
  524. call earlier (or will pend). If the call succeeded there is a valid CallMgrContext
  525. supplied here as well
  526. Arguments:
  527. Status - Completion status
  528. NdisAfHandle - Pointer to the AfBlock
  529. CallMgrAfContext - Call manager's context used in other calls into the call manager.
  530. Return Value:
  531. NONE. The client's completion handler is called.
  532. --*/
  533. {
  534. PNDIS_CO_AF_BLOCK pAf;
  535. PNDIS_M_OPEN_BLOCK ClientOpen;
  536. PNDIS_MINIPORT_BLOCK Miniport;
  537. KIRQL OldIrql;
  538. ASSERT (Status != NDIS_STATUS_PENDING);
  539. pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
  540. ClientOpen = pAf->ClientOpen;
  541. Miniport = pAf->Miniport;
  542. if (Status != NDIS_STATUS_SUCCESS)
  543. {
  544. if (pAf->CallMgrOpen != NULL)
  545. {
  546. ObDereferenceObject(pAf->CallMgrOpen->FileObject);
  547. }
  548. else
  549. {
  550. ObDereferenceObject(Miniport->DeviceObject);
  551. }
  552. }
  553. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  554. pAf->CallMgrContext = CallMgrAfContext;
  555. if (Status != NDIS_STATUS_SUCCESS)
  556. {
  557. //
  558. // OpenAfHandler failed
  559. //
  560. if (pAf->CallMgrOpen != NULL)
  561. {
  562. pAf->CallMgrOpen->References--;
  563. if (pAf->CallMgrOpen->References == 0)
  564. {
  565. ndisMFinishClose(Miniport, pAf->CallMgrOpen);
  566. }
  567. }
  568. else
  569. {
  570. ndisDereferenceMiniport(Miniport);
  571. }
  572. ClientOpen->References--;
  573. if (ClientOpen->References == 0)
  574. {
  575. ndisMFinishClose(Miniport, ClientOpen);
  576. }
  577. FREE_POOL(pAf);
  578. CoDereferencePackage();
  579. }
  580. else
  581. {
  582. //
  583. // queue this CallMgr open onto the miniport open
  584. //
  585. pAf->NextAf = ClientOpen->NextAf;
  586. ClientOpen->NextAf = pAf;
  587. }
  588. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  589. //
  590. // Finally call the client's completion handler
  591. //
  592. (*pAf->ClientEntries.ClOpenAfCompleteHandler)(Status,
  593. pAf->ClientContext,
  594. (Status == NDIS_STATUS_SUCCESS) ? pAf : NULL);
  595. }
  596. NDIS_STATUS
  597. NdisClCloseAddressFamily(
  598. IN NDIS_HANDLE NdisAfHandle
  599. )
  600. /*++
  601. Routine Description:
  602. This call closes the Af object which essentially tears down the client-callmanager
  603. 'binding'. Causes all open Vcs to be closed and saps to be de-registered "by the call
  604. manager".
  605. Arguments:
  606. NdisAfHandle - Pointer to the Af.
  607. Return Value:
  608. Status from Call Manager.
  609. --*/
  610. {
  611. PNDIS_CO_AF_BLOCK pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
  612. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  613. KIRQL OldIrql;
  614. //
  615. // Mark the address family as closing and call the call-manager to process.
  616. //
  617. ACQUIRE_SPIN_LOCK(&pAf->Lock, &OldIrql);
  618. if (pAf->Flags & AF_CLOSING)
  619. {
  620. Status = NDIS_STATUS_FAILURE;
  621. }
  622. pAf->Flags |= AF_CLOSING;
  623. RELEASE_SPIN_LOCK(&pAf->Lock, OldIrql);
  624. if (Status == NDIS_STATUS_SUCCESS)
  625. {
  626. Status = (*pAf->CallMgrEntries->CmCloseAfHandler)(pAf->CallMgrContext);
  627. if (Status != NDIS_STATUS_PENDING)
  628. {
  629. NdisCmCloseAddressFamilyComplete(Status, pAf);
  630. Status = NDIS_STATUS_PENDING;
  631. }
  632. }
  633. if (!NT_SUCCESS(Status))
  634. {
  635. CoDereferencePackage();
  636. }
  637. return Status;
  638. }
  639. VOID
  640. NdisCmCloseAddressFamilyComplete(
  641. IN NDIS_STATUS Status,
  642. IN NDIS_HANDLE NdisAfHandle
  643. )
  644. /*++
  645. Routine Description:
  646. Completion routine for the CloseAddressFamily call. The call manager had pended this
  647. call earlier (or will pend). If the call succeeded there is a valid CallMgrContext
  648. supplied here as well
  649. Arguments:
  650. Status - Completion status
  651. NdisAfHandle - Pointer to the AfBlock
  652. Return Value:
  653. NONE. The client's completion handler is called.
  654. --*/
  655. {
  656. PNDIS_CO_AF_BLOCK pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
  657. PNDIS_MINIPORT_BLOCK Miniport;
  658. KIRQL OldIrql;
  659. Miniport = pAf->Miniport;
  660. if (Status == NDIS_STATUS_SUCCESS)
  661. {
  662. //
  663. // Dereference the file object for the call-manager
  664. //
  665. if (pAf->CallMgrOpen != NULL)
  666. {
  667. ObDereferenceObject(pAf->CallMgrOpen->FileObject);
  668. }
  669. else
  670. {
  671. ObDereferenceObject(Miniport->DeviceObject);
  672. }
  673. Miniport = pAf->Miniport;
  674. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  675. if (pAf->CallMgrOpen != NULL)
  676. {
  677. pAf->CallMgrOpen->References--;
  678. if (pAf->CallMgrOpen->References == 0)
  679. {
  680. ndisMFinishClose(Miniport, pAf->CallMgrOpen);
  681. }
  682. }
  683. else
  684. {
  685. ndisDereferenceMiniport(Miniport);
  686. }
  687. pAf->ClientOpen->References--;
  688. if (pAf->ClientOpen->References == 0)
  689. {
  690. ndisMFinishClose(Miniport, pAf->ClientOpen);
  691. }
  692. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  693. CoDereferencePackage();
  694. }
  695. //
  696. // Complete the call to the client
  697. //
  698. (*pAf->ClientEntries.ClCloseAfCompleteHandler)(Status,
  699. pAf->ClientContext);
  700. //
  701. // Finally dereference the AF Block, if the call-manager successfully closed it.
  702. //
  703. if (Status == NDIS_STATUS_SUCCESS)
  704. {
  705. ndisDereferenceAf(pAf);
  706. }
  707. }
  708. BOOLEAN
  709. ndisReferenceAf(
  710. IN PNDIS_CO_AF_BLOCK pAf
  711. )
  712. /*++
  713. Routine Description:
  714. Arguments:
  715. Return Value:
  716. --*/
  717. {
  718. KIRQL OldIrql;
  719. BOOLEAN rc = FALSE;
  720. ACQUIRE_SPIN_LOCK(&pAf->Lock, &OldIrql);
  721. if ((pAf->Flags & AF_CLOSING) == 0)
  722. {
  723. pAf->References ++;
  724. rc = TRUE;
  725. }
  726. RELEASE_SPIN_LOCK(&pAf->Lock, OldIrql);
  727. return rc;
  728. }
  729. VOID
  730. ndisDereferenceAf(
  731. IN PNDIS_CO_AF_BLOCK pAf
  732. )
  733. /*++
  734. Routine Description:
  735. Arguments:
  736. Return Value:
  737. --*/
  738. {
  739. KIRQL OldIrql;
  740. BOOLEAN Done = FALSE;
  741. ACQUIRE_SPIN_LOCK(&pAf->Lock, &OldIrql);
  742. ASSERT (pAf->References > 0);
  743. pAf->References --;
  744. if (pAf->References == 0)
  745. {
  746. ASSERT (pAf->Flags & AF_CLOSING);
  747. Done = TRUE;
  748. }
  749. RELEASE_SPIN_LOCK(&pAf->Lock, OldIrql);
  750. if (Done)
  751. FREE_POOL(pAf);
  752. }
  753. NDIS_STATUS
  754. NdisClRegisterSap(
  755. IN NDIS_HANDLE NdisAfHandle,
  756. IN NDIS_HANDLE ProtocolSapContext,
  757. IN PCO_SAP Sap,
  758. OUT PNDIS_HANDLE NdisSapHandle
  759. )
  760. /*++
  761. Routine Description:
  762. This is a call from a NDIS 4.1 or later protocol to register its SAP
  763. with the call manager.
  764. Arguments:
  765. NdisBindingHandle - Pointer to the protocol's NDIS_OPEN_BLOCK.
  766. PCO_ADDRESS_FAMILY - The address family being registered.
  767. ClientAfContext - Protocol context associated with this handle.
  768. NdisAfHandle - Handle returned by NDIS for this address family.
  769. Return Value:
  770. NDIS_STATUS_SUCCESS if the address family open is successfully.
  771. NDIS_STATUS_PENDING if the call-manager pends this call. The caller will get
  772. NDIS_STATUS_FAILURE if the caller is not a NDIS 4.1 prototcol or this address
  773. family is not registered for this miniport.
  774. --*/
  775. {
  776. NDIS_STATUS Status;
  777. PNDIS_CO_AF_BLOCK pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
  778. PNDIS_CO_SAP_BLOCK pSap;
  779. *NdisSapHandle = NULL;
  780. do
  781. {
  782. //
  783. // Reference the Af for this SAP
  784. //
  785. if (!ndisReferenceAf(pAf))
  786. {
  787. Status = NDIS_STATUS_FAILURE;
  788. break;
  789. }
  790. pSap = (PNDIS_CO_SAP_BLOCK)ALLOC_FROM_POOL(sizeof(NDIS_CO_SAP_BLOCK), NDIS_TAG_CO);
  791. if (pSap == NULL)
  792. {
  793. *NdisSapHandle = NULL;
  794. Status = NDIS_STATUS_RESOURCES;
  795. break;
  796. }
  797. pSap->Flags = 0;
  798. pSap->References = 1;
  799. INITIALIZE_SPIN_LOCK(&pSap->Lock);
  800. pSap->AfBlock = pAf;
  801. pSap->Sap = Sap;
  802. pSap->ClientContext = ProtocolSapContext;
  803. Status = (*pAf->CallMgrEntries->CmRegisterSapHandler)(pAf->CallMgrContext,
  804. Sap,
  805. pSap,
  806. &pSap->CallMgrContext);
  807. if (Status != NDIS_STATUS_PENDING)
  808. {
  809. NdisCmRegisterSapComplete(Status, pSap, pSap->CallMgrContext);
  810. Status = NDIS_STATUS_PENDING;
  811. }
  812. } while (FALSE);
  813. return Status;
  814. }
  815. VOID
  816. NdisCmRegisterSapComplete(
  817. IN NDIS_STATUS Status,
  818. IN NDIS_HANDLE NdisSapHandle,
  819. IN NDIS_HANDLE CallMgrSapContext
  820. )
  821. /*++
  822. Routine Description:
  823. Completion routine for the registerSap call. The call manager had pended this
  824. call earlier (or will pend). If the call succeeded there is a valid CallMgrContext
  825. supplied here as well
  826. Arguments:
  827. Status - Completion status
  828. NdisAfHandle - Pointer to the AfBlock
  829. CallMgrAfContext - Call manager's context used in other calls into the call manager.
  830. Return Value:
  831. NONE. The client's completion handler is called.
  832. --*/
  833. {
  834. PNDIS_CO_SAP_BLOCK pSap = (PNDIS_CO_SAP_BLOCK)NdisSapHandle;
  835. PNDIS_CO_AF_BLOCK pAf;
  836. ASSERT (Status != NDIS_STATUS_PENDING);
  837. pAf = pSap->AfBlock;
  838. pSap->CallMgrContext = CallMgrSapContext;
  839. //
  840. // Call the clients completion handler
  841. //
  842. (*pAf->ClientEntries.ClRegisterSapCompleteHandler)(Status,
  843. pSap->ClientContext,
  844. pSap->Sap,
  845. pSap);
  846. if (Status != NDIS_STATUS_SUCCESS)
  847. {
  848. ndisDereferenceAf(pSap->AfBlock);
  849. FREE_POOL(pSap);
  850. }
  851. }
  852. NDIS_STATUS
  853. NdisClDeregisterSap(
  854. IN NDIS_HANDLE NdisSapHandle
  855. )
  856. /*++
  857. Routine Description:
  858. Arguments:
  859. Return Value:
  860. --*/
  861. {
  862. PNDIS_CO_SAP_BLOCK pSap = (PNDIS_CO_SAP_BLOCK)NdisSapHandle;
  863. NDIS_STATUS Status;
  864. KIRQL OldIrql;
  865. BOOLEAN fAlreadyClosing;
  866. ACQUIRE_SPIN_LOCK(&pSap->Lock, &OldIrql);
  867. fAlreadyClosing = FALSE;
  868. if (pSap->Flags & SAP_CLOSING)
  869. {
  870. fAlreadyClosing = TRUE;
  871. }
  872. pSap->Flags |= SAP_CLOSING;
  873. RELEASE_SPIN_LOCK(&pSap->Lock, OldIrql);
  874. if (fAlreadyClosing)
  875. {
  876. return NDIS_STATUS_FAILURE;
  877. }
  878. //
  879. // Notify the call-manager that this sap is being de-registered
  880. //
  881. Status = (*pSap->AfBlock->CallMgrEntries->CmDeregisterSapHandler)(pSap->CallMgrContext);
  882. if (Status != NDIS_STATUS_PENDING)
  883. {
  884. NdisCmDeregisterSapComplete(Status, pSap);
  885. Status = NDIS_STATUS_PENDING;
  886. }
  887. return Status;
  888. }
  889. VOID
  890. NdisCmDeregisterSapComplete(
  891. IN NDIS_STATUS Status,
  892. IN NDIS_HANDLE NdisSapHandle
  893. )
  894. /*++
  895. Routine Description:
  896. Arguments:
  897. Return Value:
  898. --*/
  899. {
  900. PNDIS_CO_SAP_BLOCK pSap = (PNDIS_CO_SAP_BLOCK)NdisSapHandle;
  901. ASSERT (Status != NDIS_STATUS_PENDING);
  902. //
  903. // Complete the call to the client and deref the sap
  904. //
  905. (*pSap->AfBlock->ClientEntries.ClDeregisterSapCompleteHandler)(Status,
  906. pSap->ClientContext);
  907. if (Status == NDIS_STATUS_SUCCESS)
  908. {
  909. ndisDereferenceAf(pSap->AfBlock);
  910. ndisDereferenceSap(pSap);
  911. }
  912. }
  913. BOOLEAN
  914. ndisReferenceSap(
  915. IN PNDIS_CO_SAP_BLOCK pSap
  916. )
  917. /*++
  918. Routine Description:
  919. Arguments:
  920. Return Value:
  921. --*/
  922. {
  923. KIRQL OldIrql;
  924. BOOLEAN rc = FALSE;
  925. ACQUIRE_SPIN_LOCK(&pSap->Lock, &OldIrql);
  926. if ((pSap->Flags & SAP_CLOSING) == 0)
  927. {
  928. pSap->References ++;
  929. rc = TRUE;
  930. }
  931. RELEASE_SPIN_LOCK(&pSap->Lock, OldIrql);
  932. return rc;
  933. }
  934. VOID
  935. ndisDereferenceSap(
  936. IN PNDIS_CO_SAP_BLOCK pSap
  937. )
  938. /*++
  939. Routine Description:
  940. Arguments:
  941. Return Value:
  942. --*/
  943. {
  944. KIRQL OldIrql;
  945. BOOLEAN Done = FALSE;
  946. ACQUIRE_SPIN_LOCK(&pSap->Lock, &OldIrql);
  947. ASSERT (pSap->References > 0);
  948. pSap->References --;
  949. if (pSap->References == 0)
  950. {
  951. ASSERT (pSap->Flags & SAP_CLOSING);
  952. Done = TRUE;
  953. }
  954. RELEASE_SPIN_LOCK(&pSap->Lock, OldIrql);
  955. if (Done)
  956. FREE_POOL(pSap);
  957. }
  958. NDIS_STATUS
  959. NdisCoCreateVc(
  960. IN NDIS_HANDLE NdisBindingHandle,
  961. IN NDIS_HANDLE NdisAfHandle OPTIONAL,
  962. IN NDIS_HANDLE ProtocolVcContext,
  963. IN OUT PNDIS_HANDLE NdisVcHandle
  964. )
  965. /*++
  966. Routine Description:
  967. This is a call from either the call-manager or from the client to create a vc.
  968. The vc would then be owned by call-manager (signalling vc) or the client.
  969. This is a synchronous call to all parties and simply creates an end-point over
  970. which either incoming calls can be dispatched or out-going calls can be made.
  971. Arguments:
  972. NdisBindingHandle - Pointer to the caller's NDIS_OPEN_BLOCK.
  973. NdisAfHandle - Pointer to the AF Block. Not specified for call-manager's private vcs.
  974. A miniport resident call-manager must never create call-manager vcs i.e.
  975. the NdisAfHandle must always be present
  976. NdisVcHandle - Where the handle to this Vc will be returned.
  977. Return Value:
  978. NDIS_STATUS_SUCCESS if all the components succeed.
  979. ErrorCode to signify why the call failed.
  980. --*/
  981. {
  982. PNDIS_M_OPEN_BLOCK Open;
  983. PNDIS_MINIPORT_BLOCK Miniport;
  984. PNDIS_CO_VC_BLOCK Vc;
  985. PNDIS_CO_AF_BLOCK pAf;
  986. NDIS_STATUS Status;
  987. Open = (PNDIS_M_OPEN_BLOCK)(((PNDIS_OPEN_BLOCK)(NdisBindingHandle))->MacBindingHandle);
  988. Miniport = Open->MiniportHandle;
  989. *NdisVcHandle = NULL;
  990. //
  991. // Allocate the memory for NDIS_VC_BLOCK
  992. //
  993. Vc = ALLOC_FROM_POOL(sizeof(NDIS_CO_VC_BLOCK), NDIS_TAG_CO);
  994. if (Vc == NULL)
  995. return NDIS_STATUS_RESOURCES;
  996. //
  997. // Initialize the VC block
  998. //
  999. NdisZeroMemory(Vc, sizeof(NDIS_CO_VC_BLOCK));
  1000. INITIALIZE_SPIN_LOCK(&Vc->Lock);
  1001. InitializeListHead(&Vc->CallMgrLinkage);
  1002. InitializeListHead(&Vc->ClientLinkage);
  1003. //
  1004. // Cache some miniport handlers
  1005. //
  1006. Vc->Miniport = Miniport;
  1007. Vc->WCoSendPacketsHandler = Miniport->DriverHandle->MiniportCharacteristics.CoSendPacketsHandler;
  1008. Vc->WCoDeleteVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoDeleteVcHandler;
  1009. Vc->WCoActivateVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoActivateVcHandler;
  1010. Vc->WCoDeactivateVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoDeactivateVcHandler;
  1011. //
  1012. // We have only one reference for vc on creation.
  1013. //
  1014. pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
  1015. Vc->AfBlock = pAf;
  1016. Vc->References = 1;
  1017. //
  1018. // First call the miniport to get its context
  1019. //
  1020. Status = (*Open->MiniportCoCreateVcHandler)(Miniport->MiniportAdapterContext,
  1021. Vc,
  1022. &Vc->MiniportContext);
  1023. if (Status != NDIS_STATUS_SUCCESS)
  1024. {
  1025. FREE_POOL(Vc);
  1026. return Status;
  1027. }
  1028. if (ARGUMENT_PRESENT(NdisAfHandle))
  1029. {
  1030. Vc->ClientOpen = pAf->ClientOpen;
  1031. Vc->CallMgrOpen = pAf->CallMgrOpen;
  1032. Vc->CoSendCompleteHandler =
  1033. pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoSendCompleteHandler;
  1034. Vc->CoReceivePacketHandler =
  1035. pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler;
  1036. Vc->ClModifyCallQoSCompleteHandler = pAf->ClientEntries.ClModifyCallQoSCompleteHandler;
  1037. Vc->ClIncomingCallQoSChangeHandler = pAf->ClientEntries.ClIncomingCallQoSChangeHandler;
  1038. Vc->ClCallConnectedHandler = pAf->ClientEntries.ClCallConnectedHandler;
  1039. Vc->CmActivateVcCompleteHandler = pAf->CallMgrEntries->CmActivateVcCompleteHandler;
  1040. Vc->CmDeactivateVcCompleteHandler = pAf->CallMgrEntries->CmDeactivateVcCompleteHandler;
  1041. Vc->CmModifyCallQoSHandler = pAf->CallMgrEntries->CmModifyCallQoSHandler;
  1042. //
  1043. // Determine who the caller is and initialize the other.
  1044. //
  1045. if (Open == pAf->ClientOpen)
  1046. {
  1047. Vc->ClientContext = ProtocolVcContext;
  1048. if (pAf->CallMgrOpen == NULL)
  1049. {
  1050. Vc->CallMgrContext = Vc->MiniportContext;
  1051. }
  1052. else
  1053. {
  1054. //
  1055. // Call-up to the call-manager now to get its context
  1056. //
  1057. Status = (*pAf->CallMgrOpen->CoCreateVcHandler)(pAf->CallMgrContext,
  1058. Vc,
  1059. &Vc->CallMgrContext);
  1060. }
  1061. }
  1062. else
  1063. {
  1064. ASSERT (pAf->CallMgrOpen == Open);
  1065. Vc->CallMgrContext = ProtocolVcContext;
  1066. //
  1067. // Call-up to the client now to get its context
  1068. //
  1069. Status = (*pAf->ClientOpen->CoCreateVcHandler)(pAf->ClientContext,
  1070. Vc,
  1071. &Vc->ClientContext);
  1072. }
  1073. if (Status == NDIS_STATUS_SUCCESS)
  1074. {
  1075. if (Open == pAf->ClientOpen)
  1076. {
  1077. //
  1078. // Link this in the open_block
  1079. //
  1080. ExInterlockedInsertHeadList(&Open->InactiveVcHead,
  1081. &Vc->ClientLinkage,
  1082. &Open->SpinLock.SpinLock);
  1083. if (pAf->CallMgrOpen != NULL)
  1084. {
  1085. Vc->DeleteVcContext = Vc->CallMgrContext;
  1086. Vc->CoDeleteVcHandler = pAf->CallMgrOpen->CoDeleteVcHandler;
  1087. ExInterlockedInsertHeadList(&pAf->CallMgrOpen->InactiveVcHead,
  1088. &Vc->CallMgrLinkage,
  1089. &pAf->CallMgrOpen->SpinLock.SpinLock);
  1090. }
  1091. else
  1092. {
  1093. Vc->DeleteVcContext = NULL;
  1094. Vc->CoDeleteVcHandler = NULL;
  1095. }
  1096. }
  1097. else
  1098. {
  1099. //
  1100. // Link this in the open_block
  1101. //
  1102. Vc->DeleteVcContext = Vc->ClientContext;
  1103. Vc->CoDeleteVcHandler = pAf->ClientOpen->CoDeleteVcHandler;
  1104. ExInterlockedInsertHeadList(&Open->InactiveVcHead,
  1105. &Vc->CallMgrLinkage,
  1106. &Open->SpinLock.SpinLock);
  1107. ExInterlockedInsertHeadList(&pAf->ClientOpen->InactiveVcHead,
  1108. &Vc->ClientLinkage,
  1109. &pAf->ClientOpen->SpinLock.SpinLock);
  1110. }
  1111. }
  1112. else
  1113. {
  1114. Status = (*Vc->WCoDeleteVcHandler)(Vc->MiniportContext);
  1115. FREE_POOL(Vc);
  1116. Vc = NULL;
  1117. }
  1118. }
  1119. else
  1120. {
  1121. //
  1122. // This is a call-manager only VC and so the call-manager is the client and there
  1123. // is no call-manager associated with it. This VC cannot be used to CoMakeCall or
  1124. // CmDispatchIncomingCall. Set the client values to the call-manager
  1125. //
  1126. // Vc->CoDeleteVcContexr = NULL;
  1127. // Vc->CoDeleteVcHandler = NULL;
  1128. Vc->ClientOpen = Open;
  1129. Vc->ClientContext = ProtocolVcContext;
  1130. Vc->CoSendCompleteHandler =
  1131. Open->ProtocolHandle->ProtocolCharacteristics.CoSendCompleteHandler;
  1132. Vc->CoReceivePacketHandler =
  1133. Open->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler;
  1134. //
  1135. // Do set the following call-manager entries since this VC will need to be
  1136. // activated. Also set the call-managers context for the same reasons.
  1137. //
  1138. Vc->CmActivateVcCompleteHandler = Open->CmActivateVcCompleteHandler;
  1139. Vc->CmDeactivateVcCompleteHandler = Open->CmDeactivateVcCompleteHandler;
  1140. Vc->CallMgrContext = ProtocolVcContext;
  1141. //
  1142. // Link this in the open_block
  1143. //
  1144. ExInterlockedInsertHeadList(&Open->InactiveVcHead,
  1145. &Vc->ClientLinkage,
  1146. &Open->SpinLock.SpinLock);
  1147. }
  1148. *NdisVcHandle = Vc;
  1149. return Status;
  1150. }
  1151. NDIS_STATUS
  1152. NdisCoDeleteVc(
  1153. IN PNDIS_HANDLE NdisVcHandle
  1154. )
  1155. /*++
  1156. Routine Description:
  1157. Synchronous call from either the call-manager or the client to delete a VC. Only inactive
  1158. VCs can be deleted. Active Vcs or partially active Vcs cannot be.
  1159. Arguments:
  1160. NdisVcHandle The Vc to delete
  1161. Return Value:
  1162. NDIS_STATUS_SUCCESS If all goes well
  1163. NDIS_STATUS_NOT_ACCEPTED If Vc is active
  1164. NDIS_STATUS_CLOSING If Vc de-activation is pending
  1165. --*/
  1166. {
  1167. PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
  1168. NDIS_STATUS Status;
  1169. KIRQL OldIrql;
  1170. ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
  1171. if (Vc->Flags & (VC_ACTIVE | VC_ACTIVATE_PENDING))
  1172. {
  1173. Status = NDIS_STATUS_NOT_ACCEPTED;
  1174. }
  1175. else if (Vc->Flags & VC_DEACTIVATE_PENDING)
  1176. {
  1177. Status = NDIS_STATUS_CLOSING;
  1178. }
  1179. else
  1180. {
  1181. Vc->Flags |= VC_CLOSING;
  1182. //
  1183. // Call the miniport to delete it first
  1184. //
  1185. Status = (*Vc->WCoDeleteVcHandler)(Vc->MiniportContext);
  1186. ASSERT (Status == NDIS_STATUS_SUCCESS);
  1187. //
  1188. // Next the non-creator, if any
  1189. //
  1190. if (Vc->CoDeleteVcHandler != NULL)
  1191. {
  1192. Status = (*Vc->CoDeleteVcHandler)(Vc->DeleteVcContext);
  1193. ASSERT (Status == NDIS_STATUS_SUCCESS);
  1194. }
  1195. //
  1196. // Now de-link the vc from the client and call-manager
  1197. //
  1198. ACQUIRE_SPIN_LOCK_DPC(&Vc->ClientOpen->SpinLock.SpinLock);
  1199. RemoveEntryList(&Vc->ClientLinkage);
  1200. RELEASE_SPIN_LOCK_DPC(&Vc->ClientOpen->SpinLock.SpinLock);
  1201. if (Vc->CallMgrOpen != NULL)
  1202. {
  1203. ACQUIRE_SPIN_LOCK_DPC(&Vc->CallMgrOpen->SpinLock.SpinLock);
  1204. RemoveEntryList(&Vc->CallMgrLinkage);
  1205. RELEASE_SPIN_LOCK_DPC(&Vc->CallMgrOpen->SpinLock.SpinLock);
  1206. }
  1207. Status = NDIS_STATUS_SUCCESS;
  1208. }
  1209. RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
  1210. if (Status == NDIS_STATUS_SUCCESS)
  1211. {
  1212. ndisDereferenceVc(Vc);
  1213. }
  1214. return Status;
  1215. }
  1216. NDIS_STATUS
  1217. NdisMCmCreateVc(
  1218. IN NDIS_HANDLE MiniportAdapterHandle,
  1219. IN NDIS_HANDLE NdisAfHandle,
  1220. IN NDIS_HANDLE MiniportVcContext,
  1221. OUT PNDIS_HANDLE NdisVcHandle
  1222. )
  1223. /*++
  1224. Routine Description:
  1225. This is a call by the miniport (with a resident CM) to create a Vc for an incoming call.
  1226. Arguments:
  1227. MiniportAdapterHandle - Miniport's adapter context
  1228. NdisAfHandle - Pointer to the AF Block.
  1229. MiniportVcContext - Miniport's context to associate with this vc.
  1230. NdisVcHandle - Where the handle to this Vc will be returned.
  1231. Return Value:
  1232. NDIS_STATUS_SUCCESS if all the components succeed.
  1233. ErrorCode to signify why the call failed.
  1234. --*/
  1235. {
  1236. PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
  1237. PNDIS_CO_VC_BLOCK Vc;
  1238. PNDIS_CO_AF_BLOCK pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
  1239. NDIS_STATUS Status;
  1240. *NdisVcHandle = NULL;
  1241. //
  1242. // Allocate the memory for NDIS_VC_BLOCK
  1243. //
  1244. Vc = ALLOC_FROM_POOL(sizeof(NDIS_CO_VC_BLOCK), NDIS_TAG_CO);
  1245. if (Vc == NULL)
  1246. return NDIS_STATUS_RESOURCES;
  1247. //
  1248. // Initialize the VC block
  1249. //
  1250. NdisZeroMemory(Vc, sizeof(NDIS_CO_VC_BLOCK));
  1251. INITIALIZE_SPIN_LOCK(&Vc->Lock);
  1252. InitializeListHead(&Vc->CallMgrLinkage);
  1253. InitializeListHead(&Vc->ClientLinkage);
  1254. //
  1255. // Cache some miniport handlers
  1256. //
  1257. Vc->Miniport = Miniport;
  1258. Vc->WCoSendPacketsHandler = Miniport->DriverHandle->MiniportCharacteristics.CoSendPacketsHandler;
  1259. Vc->WCoDeleteVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoDeleteVcHandler;
  1260. Vc->WCoActivateVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoActivateVcHandler;
  1261. Vc->WCoDeactivateVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoDeactivateVcHandler;
  1262. Vc->MiniportContext = MiniportVcContext;
  1263. //
  1264. // We have only one reference for vc on creation.
  1265. //
  1266. pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
  1267. Vc->AfBlock = pAf;
  1268. Vc->References = 1;
  1269. ASSERT (ARGUMENT_PRESENT(NdisAfHandle));
  1270. Vc->ClientOpen = pAf->ClientOpen;
  1271. Vc->CallMgrOpen = NULL;
  1272. Vc->CoSendCompleteHandler =
  1273. pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoSendCompleteHandler;
  1274. Vc->CoReceivePacketHandler =
  1275. pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler;
  1276. Vc->ClModifyCallQoSCompleteHandler = pAf->ClientEntries.ClModifyCallQoSCompleteHandler;
  1277. Vc->ClIncomingCallQoSChangeHandler = pAf->ClientEntries.ClIncomingCallQoSChangeHandler;
  1278. Vc->ClCallConnectedHandler = pAf->ClientEntries.ClCallConnectedHandler;
  1279. Vc->CmActivateVcCompleteHandler = pAf->CallMgrEntries->CmActivateVcCompleteHandler;
  1280. Vc->CmDeactivateVcCompleteHandler = pAf->CallMgrEntries->CmDeactivateVcCompleteHandler;
  1281. Vc->CmModifyCallQoSHandler = pAf->CallMgrEntries->CmModifyCallQoSHandler;
  1282. Vc->CallMgrContext = MiniportVcContext;
  1283. //
  1284. // Call-up to the client now to get its context
  1285. //
  1286. Status = (*pAf->ClientOpen->CoCreateVcHandler)(pAf->ClientContext,
  1287. Vc,
  1288. &Vc->ClientContext);
  1289. if (Status == NDIS_STATUS_SUCCESS)
  1290. {
  1291. //
  1292. // Link this in the open_block
  1293. //
  1294. Vc->DeleteVcContext = Vc->ClientContext;
  1295. Vc->CoDeleteVcHandler = pAf->ClientOpen->CoDeleteVcHandler;
  1296. ExInterlockedInsertHeadList(&pAf->ClientOpen->InactiveVcHead,
  1297. &Vc->ClientLinkage,
  1298. &pAf->ClientOpen->SpinLock.SpinLock);
  1299. }
  1300. else
  1301. {
  1302. Status = (*Vc->WCoDeleteVcHandler)(Vc->MiniportContext);
  1303. FREE_POOL(Vc);
  1304. Vc = NULL;
  1305. }
  1306. *NdisVcHandle = Vc;
  1307. return Status;
  1308. }
  1309. NDIS_STATUS
  1310. NdisMCmDeleteVc(
  1311. IN PNDIS_HANDLE NdisVcHandle
  1312. )
  1313. /*++
  1314. Routine Description:
  1315. This is a called by the miniport (with a resident CM) to delete a Vc created by it. Identical to
  1316. NdisMCoDeleteVc but a seperate api for completeness.
  1317. Arguments:
  1318. NdisVcHandle The Vc to delete
  1319. Return Value:
  1320. NDIS_STATUS_SUCCESS If all goes well
  1321. NDIS_STATUS_NOT_ACCEPTED If Vc is active
  1322. NDIS_STATUS_CLOSING If Vc de-activation is pending
  1323. --*/
  1324. {
  1325. return(NdisMCmDeleteVc(NdisVcHandle));
  1326. }
  1327. NDIS_STATUS
  1328. NdisCmActivateVc(
  1329. IN PNDIS_HANDLE NdisVcHandle,
  1330. IN OUT PCO_CALL_PARAMETERS CallParameters
  1331. )
  1332. /*++
  1333. Routine Description:
  1334. Called by the call-manager to set the Vc parameters on the Vc. The wrapper
  1335. saved the media id (e.g. Vpi/Vci for atm) in the Vc so that a p-mode protocol can
  1336. get this info as well on receives.
  1337. Arguments:
  1338. NdisVcHandle The Vc to set parameters on.
  1339. MediaParameters The parameters to set.
  1340. Return Value:
  1341. NDIS_STATUS_PENDING If the miniport pends the call.
  1342. NDIS_STATUS_CLOSING If Vc de-activation is pending
  1343. --*/
  1344. {
  1345. PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
  1346. NDIS_STATUS Status;
  1347. KIRQL OldIrql;
  1348. ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
  1349. //
  1350. // Make sure the Vc does not have an activation/de-activation pending
  1351. // Not that it is ok for the Vc to be already active - then it is a re-activation.
  1352. //
  1353. if (Vc->Flags & VC_ACTIVATE_PENDING)
  1354. {
  1355. Status = NDIS_STATUS_NOT_ACCEPTED;
  1356. }
  1357. else if (Vc->Flags & VC_DEACTIVATE_PENDING)
  1358. {
  1359. Status = NDIS_STATUS_CLOSING;
  1360. }
  1361. else
  1362. {
  1363. Vc->Flags |= VC_ACTIVATE_PENDING;
  1364. //
  1365. // Save the media id for the Vc
  1366. //
  1367. Status = NDIS_STATUS_SUCCESS;
  1368. Vc->pVcId = &CallParameters->MediaParameters->MediaSpecific;
  1369. }
  1370. RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
  1371. if (Status == NDIS_STATUS_SUCCESS)
  1372. {
  1373. //
  1374. // Now call down to the miniport to activate it
  1375. //
  1376. Status = (*Vc->WCoActivateVcHandler)(Vc->MiniportContext, CallParameters);
  1377. }
  1378. if (Status != NDIS_STATUS_PENDING)
  1379. {
  1380. NdisMCoActivateVcComplete(Status, Vc, CallParameters);
  1381. Status = NDIS_STATUS_PENDING;
  1382. }
  1383. return Status;
  1384. }
  1385. NDIS_STATUS
  1386. NdisMCmActivateVc(
  1387. IN PNDIS_HANDLE NdisVcHandle,
  1388. IN PCO_CALL_PARAMETERS CallParameters
  1389. )
  1390. /*++
  1391. Routine Description:
  1392. Called by the miniport resident call-manager to set the Vc parameters on the Vc. This is a
  1393. synchronous call.
  1394. Arguments:
  1395. NdisVcHandle The Vc to set parameters on.
  1396. MediaParameters The parameters to set.
  1397. Return Value:
  1398. NDIS_STATUS_CLOSING If Vc de-activation is pending
  1399. --*/
  1400. {
  1401. PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
  1402. NDIS_STATUS Status;
  1403. KIRQL OldIrql;
  1404. ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
  1405. //
  1406. // Make sure the Vc does not have an activation/de-activation pending
  1407. // Not that it is ok for the Vc to be already active - then it is a re-activation.
  1408. //
  1409. if (Vc->Flags & VC_ACTIVATE_PENDING)
  1410. {
  1411. Status = NDIS_STATUS_NOT_ACCEPTED;
  1412. }
  1413. else if (Vc->Flags & VC_DEACTIVATE_PENDING)
  1414. {
  1415. Status = NDIS_STATUS_CLOSING;
  1416. }
  1417. else
  1418. {
  1419. Vc->Flags |= VC_ACTIVE;
  1420. Status = NDIS_STATUS_SUCCESS;
  1421. Vc->pVcId = &CallParameters->MediaParameters->MediaSpecific;
  1422. }
  1423. RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
  1424. return Status;
  1425. }
  1426. VOID
  1427. NdisMCoActivateVcComplete(
  1428. IN NDIS_STATUS Status,
  1429. IN PNDIS_HANDLE NdisVcHandle,
  1430. IN PCO_CALL_PARAMETERS CallParameters
  1431. )
  1432. /*++
  1433. Routine Description:
  1434. Called by the mini-port to complete a pending activation call.
  1435. Arguments:
  1436. Status Status of activation.
  1437. NdisVcHandle The Vc in question.
  1438. Return Value:
  1439. NONE
  1440. The call-manager's completion routine is called.
  1441. --*/
  1442. {
  1443. PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
  1444. KIRQL OldIrql;
  1445. ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
  1446. ASSERT (Vc->Flags & VC_ACTIVATE_PENDING);
  1447. Vc->Flags &= ~VC_ACTIVATE_PENDING;
  1448. if (Status == NDIS_STATUS_SUCCESS)
  1449. {
  1450. Vc->Flags |= VC_ACTIVE;
  1451. }
  1452. RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
  1453. //
  1454. // Complete the call to the call-manager
  1455. //
  1456. (*Vc->CmActivateVcCompleteHandler)(Status, Vc->CallMgrContext, CallParameters);
  1457. }
  1458. NDIS_STATUS
  1459. NdisCmDeactivateVc(
  1460. IN PNDIS_HANDLE NdisVcHandle
  1461. )
  1462. /*++
  1463. Routine Description:
  1464. Called by the call-manager to de-activate a Vc.
  1465. Arguments:
  1466. NdisVcHandle The Vc to de-activate the Vc.
  1467. Return Value:
  1468. NDIS_STATUS_PENDING If the miniport pends the call.
  1469. NDIS_STATUS_SUCCESS If all goes well
  1470. NDIS_STATUS_CLOSING If Vc de-activation is pending
  1471. --*/
  1472. {
  1473. PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
  1474. NDIS_STATUS Status;
  1475. KIRQL OldIrql;
  1476. ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
  1477. if ((Vc->Flags & (VC_ACTIVE | VC_ACTIVATE_PENDING)) == 0)
  1478. {
  1479. Status = NDIS_STATUS_NOT_ACCEPTED;
  1480. }
  1481. else if (Vc->Flags & VC_DEACTIVATE_PENDING)
  1482. {
  1483. Status = NDIS_STATUS_CLOSING;
  1484. }
  1485. else
  1486. {
  1487. Vc->Flags |= VC_DEACTIVATE_PENDING;
  1488. }
  1489. RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
  1490. //
  1491. // Now call down to the miniport to de-activate it
  1492. //
  1493. Status = (*Vc->WCoDeactivateVcHandler)(Vc->MiniportContext);
  1494. if (Status != NDIS_STATUS_PENDING)
  1495. {
  1496. NdisMCoDeactivateVcComplete(Status, Vc);
  1497. Status = NDIS_STATUS_PENDING;
  1498. }
  1499. return Status;
  1500. }
  1501. NDIS_STATUS
  1502. NdisMCmDeactivateVc(
  1503. IN PNDIS_HANDLE NdisVcHandle
  1504. )
  1505. /*++
  1506. Routine Description:
  1507. Called by the miniport resident call-manager to de-activate the Vc. This is a
  1508. synchronous call.
  1509. Arguments:
  1510. NdisVcHandle The Vc to set parameters on.
  1511. Return Value:
  1512. NDIS_STATUS_CLOSING If Vc de-activation is pending
  1513. --*/
  1514. {
  1515. PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
  1516. NDIS_STATUS Status;
  1517. KIRQL OldIrql;
  1518. ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
  1519. if ((Vc->Flags & (VC_ACTIVE | VC_ACTIVATE_PENDING)) == 0)
  1520. {
  1521. Status = NDIS_STATUS_NOT_ACCEPTED;
  1522. }
  1523. else if (Vc->Flags & VC_DEACTIVATE_PENDING)
  1524. {
  1525. Status = NDIS_STATUS_CLOSING;
  1526. }
  1527. else
  1528. {
  1529. Status = NDIS_STATUS_SUCCESS;
  1530. Vc->Flags &= ~VC_ACTIVE;
  1531. }
  1532. RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
  1533. return Status;
  1534. }
  1535. VOID
  1536. NdisMCoDeactivateVcComplete(
  1537. IN NDIS_STATUS Status,
  1538. IN PNDIS_HANDLE NdisVcHandle
  1539. )
  1540. /*++
  1541. Routine Description:
  1542. Called by the mini-port to complete a pending de-activation of a Vc.
  1543. Arguments:
  1544. NdisVcHandle The Vc in question.
  1545. Return Value:
  1546. NONE
  1547. The call-manager's completion routine is called.
  1548. --*/
  1549. {
  1550. PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
  1551. KIRQL OldIrql;
  1552. ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
  1553. ASSERT (Vc->Flags & VC_DEACTIVATE_PENDING);
  1554. Vc->Flags &= ~VC_DEACTIVATE_PENDING;
  1555. if (Status == NDIS_STATUS_SUCCESS)
  1556. {
  1557. Vc->Flags &= ~VC_ACTIVE;
  1558. }
  1559. RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
  1560. //
  1561. // Complete the call to the call-manager
  1562. //
  1563. (*Vc->CmDeactivateVcCompleteHandler)(Status, Vc->CallMgrContext);
  1564. }
  1565. NDIS_STATUS
  1566. NdisClMakeCall(
  1567. IN NDIS_HANDLE NdisVcHandle,
  1568. IN OUT PCO_CALL_PARAMETERS CallParameters,
  1569. IN NDIS_HANDLE ProtocolPartyContext OPTIONAL,
  1570. OUT PNDIS_HANDLE NdisPartyHandle OPTIONAL
  1571. )
  1572. /*++
  1573. Routine Description:
  1574. Arguments:
  1575. Return Value:
  1576. --*/
  1577. {
  1578. PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
  1579. PNDIS_CO_AF_BLOCK pAf;
  1580. PNDIS_CO_PARTY_BLOCK pParty = NULL;
  1581. PVOID CallMgrPartyContext = NULL;
  1582. NDIS_STATUS Status;
  1583. do
  1584. {
  1585. pAf = Vc->AfBlock;
  1586. ASSERT (pAf != NULL);
  1587. if (!ndisReferenceAf(pAf))
  1588. {
  1589. Status = NDIS_STATUS_FAILURE;
  1590. break;
  1591. }
  1592. if (ARGUMENT_PRESENT(NdisPartyHandle))
  1593. {
  1594. *NdisPartyHandle = NULL;
  1595. pParty = (PNDIS_CO_PARTY_BLOCK)ALLOC_FROM_POOL(sizeof(NDIS_CO_PARTY_BLOCK),
  1596. NDIS_TAG_CO);
  1597. if (pParty == NULL)
  1598. {
  1599. Status = NDIS_STATUS_RESOURCES;
  1600. break;
  1601. }
  1602. pParty->Vc = Vc;
  1603. pParty->ClientContext = ProtocolPartyContext;
  1604. pParty->ClIncomingDropPartyHandler =
  1605. pAf->ClientEntries.ClIncomingDropPartyHandler;
  1606. pParty->ClDropPartyCompleteHandler =
  1607. pAf->ClientEntries.ClDropPartyCompleteHandler;
  1608. }
  1609. //
  1610. // Pass the request off to the call manager
  1611. //
  1612. Status = (*pAf->CallMgrEntries->CmMakeCallHandler)(Vc->CallMgrContext,
  1613. CallParameters,
  1614. pParty,
  1615. &CallMgrPartyContext);
  1616. if (Status != NDIS_STATUS_PENDING)
  1617. {
  1618. NdisCmMakeCallComplete(Status,
  1619. Vc,
  1620. pParty,
  1621. CallMgrPartyContext,
  1622. CallParameters);
  1623. Status = NDIS_STATUS_PENDING;
  1624. }
  1625. } while (FALSE);
  1626. if (!NT_SUCCESS(Status))
  1627. {
  1628. //
  1629. // These are resource failures and not a failure from call-manager
  1630. //
  1631. if (pParty != NULL)
  1632. {
  1633. FREE_POOL(pParty);
  1634. }
  1635. }
  1636. return Status;
  1637. }
  1638. VOID
  1639. NdisCmMakeCallComplete(
  1640. IN NDIS_STATUS Status,
  1641. IN NDIS_HANDLE NdisVcHandle,
  1642. IN NDIS_HANDLE NdisPartyHandle OPTIONAL,
  1643. IN NDIS_HANDLE CallMgrPartyContext OPTIONAL,
  1644. IN PCO_CALL_PARAMETERS CallParameters
  1645. )
  1646. /*++
  1647. Routine Description:
  1648. Arguments:
  1649. Return Value:
  1650. --*/
  1651. {
  1652. PNDIS_CO_AF_BLOCK pAf;
  1653. PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
  1654. PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
  1655. KIRQL OldIrql;
  1656. pAf = Vc->AfBlock;
  1657. ASSERT (Status != NDIS_STATUS_PENDING);
  1658. if (Status == NDIS_STATUS_SUCCESS)
  1659. {
  1660. //
  1661. // Call completed successfully. Complete it to the client.
  1662. //
  1663. //
  1664. // Reference the Vc for the client. This is dereferenced when
  1665. // the client calls NdisClCloseCall()
  1666. //
  1667. ndisReferenceVc(Vc);
  1668. if (ARGUMENT_PRESENT(NdisPartyHandle))
  1669. {
  1670. pParty->CallMgrContext = CallMgrPartyContext;
  1671. ndisReferenceVc(Vc);
  1672. }
  1673. ACQUIRE_SPIN_LOCK(&pAf->ClientOpen->SpinLock.SpinLock, &OldIrql);
  1674. RemoveEntryList(&Vc->ClientLinkage);
  1675. InsertHeadList(&pAf->ClientOpen->ActiveVcHead,
  1676. &Vc->ClientLinkage);
  1677. RELEASE_SPIN_LOCK(&pAf->ClientOpen->SpinLock.SpinLock, OldIrql);
  1678. }
  1679. else
  1680. {
  1681. ndisDereferenceAf(pAf);
  1682. }
  1683. (*pAf->ClientEntries.ClMakeCallCompleteHandler)(Status,
  1684. Vc->ClientContext,
  1685. pParty,
  1686. CallParameters);
  1687. }
  1688. NDIS_STATUS
  1689. NdisCmDispatchIncomingCall(
  1690. IN NDIS_HANDLE NdisSapHandle,
  1691. IN NDIS_HANDLE NdisVcHandle,
  1692. IN OUT PCO_CALL_PARAMETERS CallParameters
  1693. )
  1694. /*++
  1695. Routine Description:
  1696. Call from the call-manager to dispatch an incoming vc to the client who registered the Sap.
  1697. The client is identified by the NdisSapHandle.
  1698. Arguments:
  1699. NdisBindingHandle - Identifies the miniport on which the Vc is created
  1700. NdisSapHandle - Identifies the client
  1701. CallParameters - Self explanatory
  1702. NdisVcHandle - Pointer to the NDIS_CO_VC_BLOCK created via NdisCmCreateVc
  1703. Return Value:
  1704. Return value from the client or an processing error.
  1705. --*/
  1706. {
  1707. PNDIS_CO_SAP_BLOCK Sap;
  1708. PNDIS_CO_VC_BLOCK Vc;
  1709. PNDIS_CO_AF_BLOCK pAf;
  1710. NDIS_STATUS Status;
  1711. Sap = (PNDIS_CO_SAP_BLOCK)NdisSapHandle;
  1712. Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
  1713. pAf = Sap->AfBlock;
  1714. ASSERT(pAf == Vc->AfBlock);
  1715. //
  1716. // Make sure the SAP's not closing
  1717. //
  1718. if (!ndisReferenceSap(Sap))
  1719. {
  1720. return(NDIS_STATUS_FAILURE);
  1721. }
  1722. //
  1723. // Make sure the AF is not closing
  1724. //
  1725. if (!ndisReferenceAf(pAf))
  1726. {
  1727. ndisDereferenceSap(Sap);
  1728. return(NDIS_STATUS_FAILURE);
  1729. }
  1730. //
  1731. // Notify the client of this call
  1732. //
  1733. Status = (*pAf->ClientEntries.ClIncomingCallHandler)(Sap->ClientContext,
  1734. Vc->ClientContext,
  1735. CallParameters);
  1736. if (Status != NDIS_STATUS_PENDING)
  1737. {
  1738. NdisClIncomingCallComplete(Status, Vc, CallParameters);
  1739. Status = NDIS_STATUS_PENDING;
  1740. }
  1741. ndisDereferenceSap(Sap);
  1742. return Status;
  1743. }
  1744. VOID
  1745. NdisClIncomingCallComplete(
  1746. IN NDIS_STATUS Status,
  1747. IN NDIS_HANDLE NdisVcHandle,
  1748. IN PCO_CALL_PARAMETERS CallParameters
  1749. )
  1750. /*++
  1751. Routine Description:
  1752. Arguments:
  1753. Return Value:
  1754. --*/
  1755. {
  1756. PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
  1757. KIRQL OldIrql;
  1758. ASSERT (Status != NDIS_STATUS_PENDING);
  1759. if (Status == NDIS_STATUS_SUCCESS)
  1760. {
  1761. ACQUIRE_SPIN_LOCK(&Vc->ClientOpen->SpinLock.SpinLock, &OldIrql);
  1762. //
  1763. // Reference the Vc. This is dereferenced when NdisClCloseCall is called.
  1764. //
  1765. Vc->References ++;
  1766. RemoveEntryList(&Vc->ClientLinkage);
  1767. InsertHeadList(&Vc->ClientOpen->ActiveVcHead,
  1768. &Vc->ClientLinkage);
  1769. RELEASE_SPIN_LOCK(&Vc->ClientOpen->SpinLock.SpinLock, OldIrql);
  1770. }
  1771. //
  1772. // Call the call-manager handler to notify that client is done with this.
  1773. //
  1774. (*Vc->AfBlock->CallMgrEntries->CmIncomingCallCompleteHandler)(
  1775. Status,
  1776. Vc->CallMgrContext,
  1777. CallParameters);
  1778. }
  1779. VOID
  1780. NdisCmDispatchCallConnected(
  1781. IN NDIS_HANDLE NdisVcHandle
  1782. )
  1783. /*++
  1784. Routine Description:
  1785. Called by the call-manager to complete the final hand-shake on an incoming call.
  1786. Arguments:
  1787. NdisVcHandle - Pointer to the vc block
  1788. Return Value:
  1789. None.
  1790. --*/
  1791. {
  1792. PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
  1793. (*Vc->ClCallConnectedHandler)(Vc->ClientContext);
  1794. }
  1795. NDIS_STATUS
  1796. NdisClModifyCallQoS(
  1797. IN NDIS_HANDLE NdisVcHandle,
  1798. IN PCO_CALL_PARAMETERS CallParameters
  1799. )
  1800. /*++
  1801. Routine Description:
  1802. Initiated by the client to modify the QoS associated with the call.
  1803. Arguments:
  1804. NdisVcHandle - Pointer to the vc block
  1805. CallParameters - New call QoS
  1806. Return Value:
  1807. --*/
  1808. {
  1809. PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
  1810. NDIS_STATUS Status;
  1811. //
  1812. // Ask the call-manager to take care of this
  1813. //
  1814. Status = (*Vc->CmModifyCallQoSHandler)(Vc->CallMgrContext,
  1815. CallParameters);
  1816. return Status;
  1817. }
  1818. VOID
  1819. NdisCmModifyCallQoSComplete(
  1820. IN NDIS_STATUS Status,
  1821. IN NDIS_HANDLE NdisVcHandle,
  1822. IN PCO_CALL_PARAMETERS CallParameters
  1823. )
  1824. {
  1825. PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
  1826. //
  1827. // Simply notify the client
  1828. //
  1829. (*Vc->ClModifyCallQoSCompleteHandler)(Status,
  1830. Vc->ClientContext,
  1831. CallParameters);
  1832. }
  1833. VOID
  1834. NdisCmDispatchIncomingCallQoSChange(
  1835. IN NDIS_HANDLE NdisVcHandle,
  1836. IN PCO_CALL_PARAMETERS CallParameters
  1837. )
  1838. /*++
  1839. Routine Description:
  1840. Called by the call-manager to indicate a remote requested change in the call-qos. This is
  1841. simply an indication. A client must respond by either accepting it (do nothing) or reject
  1842. it (by either modifying the call qos or by tearing down the call).
  1843. Arguments:
  1844. NdisVcHandle - Pointer to the vc block
  1845. CallParameters - New call qos
  1846. Return Value:
  1847. None.
  1848. --*/
  1849. {
  1850. PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
  1851. //
  1852. // Simply notify the client
  1853. //
  1854. (*Vc->ClIncomingCallQoSChangeHandler)(Vc->ClientContext,
  1855. CallParameters);
  1856. }
  1857. NDIS_STATUS
  1858. NdisClCloseCall(
  1859. IN NDIS_HANDLE NdisVcHandle,
  1860. IN NDIS_HANDLE NdisPartyHandle OPTIONAL,
  1861. IN PVOID Buffer OPTIONAL,
  1862. IN UINT Size OPTIONAL
  1863. )
  1864. /*++
  1865. Routine Description:
  1866. Called by the client to close down a connection established via either NdisClMakeCall
  1867. or accepting an incoming call via NdisClIncomingCallComplete. The optional buffer can
  1868. be specified by the client to send a disconnect message. Upto the call-manager to do
  1869. something reasonable with it.
  1870. Arguments:
  1871. NdisVcHandle - Pointer to the vc block
  1872. Buffer - Optional disconnect message
  1873. Size - Size of the disconnect message
  1874. Return Value:
  1875. --*/
  1876. {
  1877. PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
  1878. PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
  1879. NDIS_STATUS Status;
  1880. //
  1881. // Simply notify the call-manager
  1882. //
  1883. Status = (*Vc->AfBlock->CallMgrEntries->CmCloseCallHandler)(Vc->CallMgrContext,
  1884. (pParty != NULL) ?
  1885. pParty->CallMgrContext :
  1886. NULL,
  1887. Buffer,
  1888. Size);
  1889. if (Status != NDIS_STATUS_PENDING)
  1890. {
  1891. NdisCmCloseCallComplete(Status, Vc, pParty);
  1892. Status = NDIS_STATUS_PENDING;
  1893. }
  1894. return Status;
  1895. }
  1896. VOID
  1897. NdisCmCloseCallComplete(
  1898. IN NDIS_STATUS Status,
  1899. IN NDIS_HANDLE NdisVcHandle,
  1900. IN NDIS_HANDLE NdisPartyHandle OPTIONAL
  1901. )
  1902. /*++
  1903. Routine Description:
  1904. Arguments:
  1905. NdisVcHandle - Pointer to the vc block
  1906. Return Value:
  1907. Nothing. Client handler called
  1908. --*/
  1909. {
  1910. PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
  1911. PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
  1912. //
  1913. // Notify the client and dereference the Vc
  1914. //
  1915. (*Vc->AfBlock->ClientEntries.ClCloseCallCompleteHandler)(Status,
  1916. Vc->ClientContext,
  1917. (pParty != NULL) ?
  1918. pParty->CallMgrContext :
  1919. NULL);
  1920. ndisDereferenceAf(Vc->AfBlock);
  1921. ndisDereferenceVc(Vc);
  1922. if (pParty != NULL)
  1923. {
  1924. ASSERT (Vc == pParty->Vc);
  1925. ndisDereferenceVc(pParty->Vc);
  1926. FREE_POOL(pParty);
  1927. }
  1928. }
  1929. VOID
  1930. NdisCmDispatchIncomingCloseCall(
  1931. IN NDIS_STATUS CloseStatus,
  1932. IN NDIS_HANDLE NdisVcHandle,
  1933. IN PVOID Buffer,
  1934. IN UINT Size
  1935. )
  1936. /*++
  1937. Routine Description:
  1938. Arguments:
  1939. Return Value:
  1940. --*/
  1941. {
  1942. PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
  1943. //
  1944. // Notify the client
  1945. //
  1946. (*Vc->AfBlock->ClientEntries.ClIncomingCloseCallHandler)(
  1947. CloseStatus,
  1948. Vc->ClientContext,
  1949. Buffer,
  1950. Size);
  1951. }
  1952. NDIS_STATUS
  1953. NdisClAddParty(
  1954. IN NDIS_HANDLE NdisVcHandle,
  1955. IN NDIS_HANDLE ProtocolPartyContext,
  1956. IN OUT PCO_CALL_PARAMETERS CallParameters,
  1957. OUT PNDIS_HANDLE NdisPartyHandle
  1958. )
  1959. /*++
  1960. Routine Description:
  1961. Call from the client to the call-manager to add a party to a point-to-multi-point call.
  1962. Arguments:
  1963. NdisVcHandle - The handle client obtained via NdisClMakeCall()
  1964. ProtocolPartyContext - Protocol's context for this leaf
  1965. Flags - Call flags
  1966. CallParameters - Call parameters
  1967. NdisPartyHandle - Place holder for the handle to identify the leaf
  1968. Return Value:
  1969. NDIS_STATUS_PENDING The call has pended and will complete via CoAddPartyCompleteHandler.
  1970. --*/
  1971. {
  1972. PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
  1973. PNDIS_CO_PARTY_BLOCK pParty;
  1974. NDIS_STATUS Status;
  1975. do
  1976. {
  1977. *NdisPartyHandle = NULL;
  1978. if (!ndisReferenceVc(Vc))
  1979. {
  1980. Status = NDIS_STATUS_FAILURE;
  1981. break;
  1982. }
  1983. pParty = ALLOC_FROM_POOL(sizeof(NDIS_CO_PARTY_BLOCK), NDIS_TAG_CO);
  1984. if (pParty == NULL)
  1985. {
  1986. Status = NDIS_STATUS_RESOURCES;
  1987. break;
  1988. }
  1989. pParty->ClientContext = ProtocolPartyContext;
  1990. pParty->Vc = Vc;
  1991. pParty->ClIncomingDropPartyHandler =
  1992. Vc->AfBlock->ClientEntries.ClIncomingDropPartyHandler;
  1993. pParty->ClDropPartyCompleteHandler =
  1994. Vc->AfBlock->ClientEntries.ClDropPartyCompleteHandler;
  1995. //
  1996. // Simply call the call-manager to do its stuff.
  1997. //
  1998. Status = (*Vc->AfBlock->CallMgrEntries->CmAddPartyHandler)(
  1999. Vc->CallMgrContext,
  2000. CallParameters,
  2001. pParty,
  2002. &pParty->CallMgrContext);
  2003. if (Status != NDIS_STATUS_PENDING)
  2004. {
  2005. NdisCmAddPartyComplete(Status,
  2006. pParty,
  2007. pParty->CallMgrContext,
  2008. CallParameters);
  2009. Status = NDIS_STATUS_PENDING;
  2010. }
  2011. } while (FALSE);
  2012. return Status;
  2013. }
  2014. VOID
  2015. NdisCmAddPartyComplete(
  2016. IN NDIS_STATUS Status,
  2017. IN NDIS_HANDLE NdisPartyHandle,
  2018. IN NDIS_HANDLE CallMgrPartyContext OPTIONAL,
  2019. IN PCO_CALL_PARAMETERS CallParameters
  2020. )
  2021. /*++
  2022. Routine Description:
  2023. Arguments:
  2024. Return Value:
  2025. --*/
  2026. {
  2027. PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
  2028. ASSERT (Status != NDIS_STATUS_PENDING);
  2029. if (Status == NDIS_STATUS_SUCCESS)
  2030. {
  2031. pParty->CallMgrContext = CallMgrPartyContext;
  2032. }
  2033. //
  2034. // Complete the call to the client
  2035. //
  2036. (*pParty->Vc->AfBlock->ClientEntries.ClAddPartyCompleteHandler)(
  2037. Status,
  2038. pParty->ClientContext,
  2039. pParty,
  2040. CallParameters);
  2041. if (Status != NDIS_STATUS_SUCCESS)
  2042. {
  2043. ndisDereferenceVc(pParty->Vc);
  2044. FREE_POOL(pParty);
  2045. }
  2046. }
  2047. NDIS_STATUS
  2048. NdisClDropParty(
  2049. IN NDIS_HANDLE NdisPartyHandle,
  2050. IN PVOID Buffer OPTIONAL,
  2051. IN UINT Size OPTIONAL
  2052. )
  2053. /*++
  2054. Routine Description:
  2055. Arguments:
  2056. Return Value:
  2057. --*/
  2058. {
  2059. PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
  2060. NDIS_STATUS Status;
  2061. //
  2062. // Pass it along to the call-manager to handle this
  2063. //
  2064. Status = (*pParty->Vc->AfBlock->CallMgrEntries->CmDropPartyHandler)(
  2065. pParty->CallMgrContext,
  2066. Buffer,
  2067. Size);
  2068. if (Status != NDIS_STATUS_PENDING)
  2069. {
  2070. NdisCmDropPartyComplete(Status, pParty);
  2071. Status = NDIS_STATUS_PENDING;
  2072. }
  2073. return Status;
  2074. }
  2075. VOID
  2076. NdisCmDropPartyComplete(
  2077. IN NDIS_STATUS Status,
  2078. IN NDIS_HANDLE NdisPartyHandle
  2079. )
  2080. /*++
  2081. Routine Description:
  2082. Arguments:
  2083. Return Value:
  2084. --*/
  2085. {
  2086. PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
  2087. ASSERT (Status != NDIS_STATUS_PENDING);
  2088. //
  2089. // Complete the call to the client
  2090. //
  2091. (*pParty->ClDropPartyCompleteHandler)(Status,
  2092. pParty->ClientContext);
  2093. ndisDereferenceVc(pParty->Vc);
  2094. FREE_POOL(pParty);
  2095. }
  2096. VOID
  2097. NdisCmDispatchIncomingDropParty(
  2098. IN NDIS_STATUS DropStatus,
  2099. IN NDIS_HANDLE NdisPartyHandle,
  2100. IN PVOID Buffer,
  2101. IN UINT Size
  2102. )
  2103. /*++
  2104. Routine Description:
  2105. Called by the call-manager to notify the client that this leaf of the multi-party
  2106. call is terminated. The client cannot use the NdisPartyHandle after completing this
  2107. call - synchronously or by calling NdisClIncomingDropPartyComplete.
  2108. Arguments:
  2109. Return Value:
  2110. --*/
  2111. {
  2112. PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
  2113. //
  2114. // Notify the client
  2115. //
  2116. (*pParty->ClIncomingDropPartyHandler)(DropStatus,
  2117. pParty->ClientContext,
  2118. Buffer,
  2119. Size);
  2120. }
  2121. BOOLEAN
  2122. ndisReferenceVc(
  2123. IN PNDIS_CO_VC_BLOCK Vc
  2124. )
  2125. /*++
  2126. Routine Description:
  2127. Arguments:
  2128. Return Value:
  2129. --*/
  2130. {
  2131. KIRQL OldIrql;
  2132. BOOLEAN rc = FALSE;
  2133. ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
  2134. if ((Vc->Flags & VC_CLOSING) == 0)
  2135. {
  2136. Vc->References ++;
  2137. rc = TRUE;
  2138. }
  2139. RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
  2140. return rc;
  2141. }
  2142. VOID
  2143. ndisDereferenceVc(
  2144. IN PNDIS_CO_VC_BLOCK Vc
  2145. )
  2146. /*++
  2147. Routine Description:
  2148. Arguments:
  2149. Return Value:
  2150. --*/
  2151. {
  2152. KIRQL OldIrql;
  2153. BOOLEAN Done = FALSE;
  2154. ACQUIRE_SPIN_LOCK(&Vc->Lock, &OldIrql);
  2155. ASSERT (Vc->References > 0);
  2156. Vc->References --;
  2157. if (Vc->References == 0)
  2158. {
  2159. ASSERT (Vc->Flags & VC_CLOSING);
  2160. Done = TRUE;
  2161. }
  2162. RELEASE_SPIN_LOCK(&Vc->Lock, OldIrql);
  2163. if (Done)
  2164. FREE_POOL(Vc);
  2165. }
  2166. VOID
  2167. ndisMCoFreeResources(
  2168. PNDIS_M_OPEN_BLOCK Open
  2169. )
  2170. /*++
  2171. Routine Description:
  2172. Cleans-up address family list for call-managers etc.
  2173. CALLED WITH MINIPORT LOCK HELD.
  2174. Arguments:
  2175. Open - Pointer to the Open block for miniports
  2176. Return Value:
  2177. None
  2178. --*/
  2179. {
  2180. PNDIS_MINIPORT_BLOCK Miniport;
  2181. PNDIS_AF_LIST *pAfList, pTmp;
  2182. Miniport = Open->MiniportHandle;
  2183. for (pAfList = &Miniport->CallMgrAfList;
  2184. (pTmp = *pAfList) != NULL;
  2185. NOTHING)
  2186. {
  2187. if (pTmp->Open == Open)
  2188. {
  2189. *pAfList = pTmp->NextOpen;
  2190. FREE_POOL(pTmp);
  2191. }
  2192. else
  2193. {
  2194. pAfList = &pTmp->NextOpen;
  2195. }
  2196. }
  2197. ASSERT (IsListEmpty(&Open->ActiveVcHead));
  2198. ASSERT (IsListEmpty(&Open->InactiveVcHead));
  2199. }
  2200. NDIS_STATUS
  2201. NdisCoRequest(
  2202. IN NDIS_HANDLE NdisBindingHandle,
  2203. IN NDIS_HANDLE NdisAfHandle OPTIONAL,
  2204. IN NDIS_HANDLE NdisVcHandle OPTIONAL,
  2205. IN NDIS_HANDLE NdisPartyHandle OPTIONAL,
  2206. IN PNDIS_REQUEST NdisRequest
  2207. )
  2208. /*++
  2209. Routine Description:
  2210. This api is used for two separate paths.
  2211. 1. A symmetric call between the client and the call-manager. This mechanism is a
  2212. two-way mechanism for the call-manager and client to communicate with each other in an
  2213. asynchronous manner.
  2214. 2. A request down to the miniport.
  2215. Arguments:
  2216. NdisBindingHandle - Specifies the binding and identifies the caller as call-manager/client
  2217. NdisAfHandle - Pointer to the AF Block and identifies the target. If absent, the
  2218. request is targeted to the miniport.
  2219. NdisVcHandle - Pointer to optional VC block. If present the request relates to the
  2220. VC
  2221. NdisPartyHandle - Pointer to the optional Party Block. If present the request relates
  2222. to the party.
  2223. NdisRequest - The request itself
  2224. Return Value:
  2225. NDIS_STATUS_PENDING if the target pends the call.
  2226. NDIS_STATUS_FAILURE if the binding or af is closing.
  2227. Anything else return code from the other end.
  2228. --*/
  2229. {
  2230. PNDIS_M_OPEN_BLOCK Open;
  2231. PNDIS_CO_AF_BLOCK pAf;
  2232. NDIS_HANDLE VcContext;
  2233. PNDIS_COREQ_RESERVED ReqRsvd;
  2234. NDIS_STATUS Status;
  2235. ReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(NdisRequest);
  2236. Open = (PNDIS_M_OPEN_BLOCK)(((PNDIS_OPEN_BLOCK)NdisBindingHandle)->MacBindingHandle);
  2237. do
  2238. {
  2239. if (ARGUMENT_PRESENT(NdisAfHandle))
  2240. {
  2241. CO_REQUEST_HANDLER CoRequestHandler;
  2242. NDIS_HANDLE AfContext, PartyContext;
  2243. pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
  2244. //
  2245. // Attempt to reference the AF
  2246. //
  2247. if (!ndisReferenceAf(pAf))
  2248. {
  2249. Status = NDIS_STATUS_FAILURE;
  2250. break;
  2251. }
  2252. VcContext = NULL;
  2253. PartyContext = NULL;
  2254. NdisZeroMemory(ReqRsvd, sizeof(NDIS_COREQ_RESERVED));
  2255. //
  2256. // Figure out who we are and call the peer
  2257. //
  2258. if (pAf->ClientOpen == Open)
  2259. {
  2260. //
  2261. // This is the client, so call the call-manager's CoRequestHandler
  2262. //
  2263. CoRequestHandler =
  2264. pAf->CallMgrOpen->ProtocolHandle->ProtocolCharacteristics.CoRequestHandler;
  2265. AfContext = pAf->CallMgrContext;
  2266. ReqRsvd->AfContext = pAf->ClientContext;
  2267. ReqRsvd->CoRequestCompleteHandler = Open->CoRequestCompleteHandler;
  2268. if (ARGUMENT_PRESENT(NdisVcHandle))
  2269. {
  2270. VcContext = ((PNDIS_CO_VC_BLOCK)NdisVcHandle)->CallMgrContext;
  2271. }
  2272. if (ARGUMENT_PRESENT(NdisPartyHandle))
  2273. {
  2274. PartyContext = ((PNDIS_CO_PARTY_BLOCK)NdisPartyHandle)->CallMgrContext;
  2275. }
  2276. }
  2277. else
  2278. {
  2279. ASSERT (pAf->CallMgrOpen == Open);
  2280. //
  2281. // This is the call-manager, so call the client's CoRequestHandler
  2282. //
  2283. CoRequestHandler =
  2284. pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoRequestHandler;
  2285. AfContext = pAf->ClientContext;
  2286. ReqRsvd->AfContext = pAf->CallMgrContext;
  2287. ReqRsvd->CoRequestCompleteHandler = Open->CoRequestCompleteHandler;
  2288. if (ARGUMENT_PRESENT(NdisVcHandle))
  2289. {
  2290. ReqRsvd->VcContext = pAf->CallMgrContext;
  2291. VcContext = ((PNDIS_CO_VC_BLOCK)NdisVcHandle)->ClientContext;
  2292. }
  2293. if (ARGUMENT_PRESENT(NdisPartyHandle))
  2294. {
  2295. ReqRsvd->PartyContext = ((PNDIS_CO_PARTY_BLOCK)NdisPartyHandle)->CallMgrContext;
  2296. PartyContext = ((PNDIS_CO_PARTY_BLOCK)NdisPartyHandle)->ClientContext;
  2297. }
  2298. }
  2299. //
  2300. // Now call the handler
  2301. //
  2302. Status = (*CoRequestHandler)(AfContext, VcContext, PartyContext, NdisRequest);
  2303. if (Status != NDIS_STATUS_PENDING)
  2304. {
  2305. NdisCoRequestComplete(Status,
  2306. NdisAfHandle,
  2307. NdisVcHandle,
  2308. NdisPartyHandle,
  2309. NdisRequest);
  2310. Status = NDIS_STATUS_PENDING;
  2311. }
  2312. }
  2313. else
  2314. {
  2315. KIRQL OldIrql;
  2316. PNDIS_MINIPORT_BLOCK Miniport;
  2317. Miniport = Open->MiniportHandle;
  2318. //
  2319. // Start off by referencing the open.
  2320. //
  2321. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  2322. if (Open->Flags & fMINIPORT_OPEN_CLOSING)
  2323. {
  2324. Status = NDIS_STATUS_CLOSING;
  2325. }
  2326. else if (Miniport->Flags & (fMINIPORT_RESET_IN_PROGRESS | fMINIPORT_RESET_REQUESTED))
  2327. {
  2328. Status = NDIS_STATUS_RESET_IN_PROGRESS;
  2329. }
  2330. else
  2331. {
  2332. Open->References ++;
  2333. }
  2334. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  2335. if (Status == NDIS_STATUS_SUCCESS)
  2336. {
  2337. ReqRsvd->Open = Open;
  2338. ReqRsvd->CoRequestCompleteHandler = Open->CoRequestCompleteHandler;
  2339. ReqRsvd->VcContext = NULL;
  2340. ReqRsvd->Flags = COREQ_DOWNLEVEL;
  2341. ReqRsvd->RealRequest = NdisRequest;
  2342. if (ARGUMENT_PRESENT(NdisVcHandle))
  2343. {
  2344. ReqRsvd->VcContext = ((PNDIS_CO_VC_BLOCK)NdisVcHandle)->ClientContext;
  2345. }
  2346. //
  2347. // Call the miniport's CoRequest Handler
  2348. //
  2349. Status = (*Open->MiniportCoRequestHandler)(Open->MiniportAdapterContext,
  2350. (NdisVcHandle != NULL) ?
  2351. ((PNDIS_CO_VC_BLOCK)NdisVcHandle)->MiniportContext :
  2352. NULL,
  2353. NdisRequest);
  2354. if (Status != NDIS_STATUS_PENDING)
  2355. {
  2356. NdisMCoRequestComplete(Status,
  2357. Open->MiniportHandle,
  2358. NdisRequest);
  2359. }
  2360. }
  2361. }
  2362. } while (FALSE);
  2363. return Status;
  2364. }
  2365. VOID
  2366. NdisCoRequestComplete(
  2367. IN NDIS_STATUS Status,
  2368. IN NDIS_HANDLE NdisAfHandle,
  2369. IN NDIS_HANDLE NdisVcHandle OPTIONAL,
  2370. IN NDIS_HANDLE NdisPartyHandle OPTIONAL,
  2371. IN PNDIS_REQUEST NdisRequest
  2372. )
  2373. /*++
  2374. Routine Description:
  2375. Arguments:
  2376. Return Value:
  2377. --*/
  2378. {
  2379. PNDIS_COREQ_RESERVED ReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(NdisRequest);
  2380. //
  2381. // Simply call the request completion handler and deref the Af block
  2382. //
  2383. (*ReqRsvd->CoRequestCompleteHandler)(Status,
  2384. ReqRsvd->AfContext,
  2385. ReqRsvd->VcContext,
  2386. ReqRsvd->PartyContext,
  2387. NdisRequest);
  2388. ndisDereferenceAf((PNDIS_CO_AF_BLOCK)NdisAfHandle);
  2389. }
  2390. VOID
  2391. NdisMCoRequestComplete(
  2392. IN NDIS_STATUS Status,
  2393. IN NDIS_HANDLE NdisBindingHandle,
  2394. IN PNDIS_REQUEST NdisRequest
  2395. )
  2396. /*++
  2397. Routine Description:
  2398. Arguments:
  2399. Return Value:
  2400. --*/
  2401. {
  2402. PNDIS_COREQ_RESERVED ReqRsvd;
  2403. PNDIS_MINIPORT_BLOCK Miniport;
  2404. PNDIS_M_OPEN_BLOCK Open;
  2405. ReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(NdisRequest);
  2406. Miniport = (PNDIS_MINIPORT_BLOCK)NdisBindingHandle;
  2407. Open = ReqRsvd->Open;
  2408. if ((NdisRequest->RequestType == NdisRequestQueryInformation) &&
  2409. (NdisRequest->DATA.QUERY_INFORMATION.Oid == OID_GEN_CURRENT_PACKET_FILTER) &&
  2410. (NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength != 0))
  2411. {
  2412. if (Open->Flags & fMINIPORT_OPEN_PMODE)
  2413. {
  2414. *(PULONG)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer) |=
  2415. NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL;
  2416. }
  2417. }
  2418. if (Open != NULL)
  2419. {
  2420. PNDIS_REQUEST RealRequest;
  2421. KIRQL OldIrql;
  2422. RealRequest = NdisRequest;
  2423. if (ReqRsvd->RealRequest != NULL)
  2424. {
  2425. RealRequest = ReqRsvd->RealRequest;
  2426. RealRequest->DATA.QUERY_INFORMATION.BytesWritten = NdisRequest->DATA.QUERY_INFORMATION.BytesWritten;
  2427. RealRequest->DATA.QUERY_INFORMATION.BytesNeeded = NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded;
  2428. }
  2429. RealRequest = (ReqRsvd->RealRequest == NULL) ? NdisRequest : ReqRsvd->RealRequest;
  2430. ASSERT ((ReqRsvd->Flags & (COREQ_GLOBAL_REQ | COREQ_QUERY_OIDS)) == 0);
  2431. if (ReqRsvd->Flags == COREQ_DOWNLEVEL)
  2432. {
  2433. ASSERT(RealRequest != NdisRequest);
  2434. //
  2435. // Complete the request to the protocol and deref the open
  2436. //
  2437. (*ReqRsvd->RequestCompleteHandler)(ReqRsvd->Open->ProtocolBindingContext,
  2438. RealRequest,
  2439. Status);
  2440. FREE_POOL(NdisRequest);
  2441. }
  2442. else
  2443. {
  2444. ASSERT(RealRequest == NdisRequest);
  2445. //
  2446. // Complete the request to the protocol and deref the open
  2447. //
  2448. (*ReqRsvd->CoRequestCompleteHandler)(Status,
  2449. ReqRsvd->Open->ProtocolBindingContext,
  2450. ReqRsvd->VcContext,
  2451. NULL,
  2452. NdisRequest);
  2453. }
  2454. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  2455. Open->References --;
  2456. if (Open->References == 0)
  2457. {
  2458. ndisMFinishClose(Miniport, Open);
  2459. }
  2460. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  2461. }
  2462. else if (ReqRsvd->Flags == COREQ_GLOBAL_REQ)
  2463. {
  2464. PIRP Irp;
  2465. PNDIS_QUERY_GLOBAL_REQUEST GlobalRequest;
  2466. GlobalRequest = CONTAINING_RECORD(NdisRequest,
  2467. NDIS_QUERY_GLOBAL_REQUEST,
  2468. Request);
  2469. ASSERT(ReqRsvd->RealRequest == NULL);
  2470. Irp = GlobalRequest->Irp;
  2471. Irp->IoStatus.Information = NdisRequest->DATA.QUERY_INFORMATION.BytesWritten;
  2472. if (Status == NDIS_STATUS_SUCCESS)
  2473. {
  2474. Irp->IoStatus.Status = STATUS_SUCCESS;
  2475. }
  2476. else if (Status == NDIS_STATUS_INVALID_LENGTH)
  2477. {
  2478. Irp->IoStatus.Status = STATUS_BUFFER_OVERFLOW;
  2479. }
  2480. else
  2481. {
  2482. Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
  2483. }
  2484. IoCompleteRequest (Irp, IO_NETWORK_INCREMENT);
  2485. FREE_POOL (GlobalRequest);
  2486. }
  2487. else if (ReqRsvd->Flags == COREQ_QUERY_OIDS)
  2488. {
  2489. PNDIS_QUERY_OPEN_REQUEST OpenReq;
  2490. ASSERT(ReqRsvd->RealRequest == NULL);
  2491. OpenReq = CONTAINING_RECORD(NdisRequest,
  2492. NDIS_QUERY_OPEN_REQUEST,
  2493. Request);
  2494. OpenReq->NdisStatus = Status;
  2495. SET_EVENT(&OpenReq->Event);
  2496. }
  2497. else if (ReqRsvd->Flags == COREQ_QUERY_STATS)
  2498. {
  2499. PNDIS_QUERY_ALL_REQUEST AllReq;
  2500. ASSERT(ReqRsvd->RealRequest == NULL);
  2501. AllReq = CONTAINING_RECORD(NdisRequest,
  2502. NDIS_QUERY_ALL_REQUEST,
  2503. Request);
  2504. AllReq->NdisStatus = Status;
  2505. SET_EVENT(&AllReq->Event);
  2506. }
  2507. else if (ReqRsvd->Flags == COREQ_QUERY_SET)
  2508. {
  2509. PNDIS_QS_REQUEST QSReq;
  2510. ASSERT(ReqRsvd->RealRequest == NULL);
  2511. QSReq = CONTAINING_RECORD(NdisRequest,
  2512. NDIS_QS_REQUEST,
  2513. Request);
  2514. QSReq->NdisStatus = Status;
  2515. SET_EVENT(&QSReq->Event);
  2516. }
  2517. else
  2518. {
  2519. ASSERT(0);
  2520. }
  2521. }
  2522. VOID
  2523. NdisMCoIndicateReceivePacket(
  2524. IN NDIS_HANDLE NdisVcHandle,
  2525. IN PPNDIS_PACKET PacketArray,
  2526. IN UINT NumberOfPackets
  2527. )
  2528. /*++
  2529. Routine Description:
  2530. This routine is called by the Miniport to indicate a set of packets to
  2531. a particular VC.
  2532. Arguments:
  2533. NdisVcHandle - The handle suppplied by Ndis when the VC on which
  2534. data is received was first reserved.
  2535. PacketArray - Array of packets.
  2536. NumberOfPackets - Number of packets being indicated.
  2537. Return Value:
  2538. None.
  2539. --*/
  2540. {
  2541. UINT i, Ref, NumPmodeOpens;
  2542. PPNDIS_PACKET pPktArray;
  2543. NDIS_STATUS Status;
  2544. PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
  2545. PNDIS_MINIPORT_BLOCK Miniport;
  2546. Miniport = Vc->Miniport;
  2547. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  2548. MINIPORT_SET_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
  2549. //
  2550. // NOTE that checking Vc Flags for Closing should not be needed since the CallMgr
  2551. // holds onto the protocol's CloseCall request until the ref count goes to zero -
  2552. // which means the miniport has to have completed its RELEASE_VC, which will
  2553. // inturn mandate that we will NOT get any further indications from it.
  2554. // The miniport must not complete a RELEASE_VC until it is no longer indicating data.
  2555. //
  2556. for (i = 0, pPktArray = PacketArray;
  2557. i < NumberOfPackets;
  2558. i++, pPktArray++)
  2559. {
  2560. PNDIS_PACKET Packet;
  2561. NDIS_STATUS SavedStatus;
  2562. Packet = *pPktArray;
  2563. ASSERT(Packet != NULL);
  2564. //
  2565. // Set context in the packet so that NdisReturnPacket can do the right thing
  2566. //
  2567. PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount = 0;
  2568. PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->Miniport = Miniport;
  2569. //
  2570. // Ensure that we force re-calculation.
  2571. //
  2572. Packet->Private.ValidCounts = FALSE;
  2573. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  2574. //
  2575. // Indicate the packet to the binding.
  2576. //
  2577. Ref = (*Vc->CoReceivePacketHandler)(Vc->ClientOpen->ProtocolBindingContext,
  2578. Vc->ClientContext,
  2579. Packet);
  2580. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  2581. if (Ref > 0)
  2582. {
  2583. ASSERT(NDIS_GET_PACKET_STATUS(Packet) != NDIS_STATUS_RESOURCES);
  2584. PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount += Ref;
  2585. if (PNDIS_REFERENCE_FROM_PNDIS_PACKET(Packet)->RefCount != 0)
  2586. {
  2587. NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_PENDING);
  2588. }
  2589. }
  2590. //
  2591. // If there are promiscuous opens on this miniport, indicate it to them as well.
  2592. // The client context will identify the VC.
  2593. //
  2594. if (Miniport->PmodeOpens > 0)
  2595. {
  2596. PNDIS_M_OPEN_BLOCK pPmodeOpen;
  2597. NumPmodeOpens = Miniport->PmodeOpens;
  2598. for (pPmodeOpen = Miniport->OpenQueue;
  2599. (NumPmodeOpens > 0);
  2600. pPmodeOpen = pPmodeOpen->MiniportNextOpen)
  2601. {
  2602. if (pPmodeOpen->Flags & fMINIPORT_OPEN_PMODE)
  2603. {
  2604. pPmodeOpen->ReceivedAPacket = TRUE;
  2605. SavedStatus = NDIS_GET_PACKET_STATUS(Packet);
  2606. NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_RESOURCES);
  2607. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  2608. //
  2609. // For Pmode opens, we pass the VcId to the indication routine
  2610. // since the protocol does not really own the VC.
  2611. //
  2612. Ref = (*pPmodeOpen->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler)(
  2613. pPmodeOpen->ProtocolBindingContext,
  2614. Vc->pVcId,
  2615. Packet);
  2616. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  2617. ASSERT(Ref == 0);
  2618. NDIS_SET_PACKET_STATUS(Packet, SavedStatus);
  2619. NumPmodeOpens --;
  2620. }
  2621. }
  2622. }
  2623. }
  2624. MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_PACKET_ARRAY_VALID);
  2625. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  2626. //
  2627. // It should be impossible to assert here
  2628. // since the pVc will not lose all of its reference counts
  2629. // until the Miniport completes the RELEASE_VC which is should not
  2630. // do UNTIL there are no outstanding indications.
  2631. //
  2632. ASSERT(Vc->References);
  2633. }
  2634. VOID
  2635. NdisMCoReceiveComplete(
  2636. IN NDIS_HANDLE MiniportAdapterHandle
  2637. )
  2638. /*++
  2639. Routine Description:
  2640. This routine is called by the Miniport to indicate that the receive
  2641. process is complete to all bindings. Only those bindings which
  2642. have received packets will be notified. The Miniport lock is held
  2643. when this is called.
  2644. Arguments:
  2645. MiniportAdapterHandle - The handle supplied by Ndis at initialization
  2646. time through miniport initialize.
  2647. Return Value:
  2648. None.
  2649. --*/
  2650. {
  2651. PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
  2652. PNDIS_M_OPEN_BLOCK Open;
  2653. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  2654. //
  2655. // check all of the bindings on this adapter
  2656. //
  2657. for (Open = Miniport->OpenQueue;
  2658. Open != NULL;
  2659. NOTHING)
  2660. {
  2661. if (((Open->Flags & fMINIPORT_OPEN_CLOSING) == 0) &&
  2662. Open->ReceivedAPacket)
  2663. {
  2664. //
  2665. // Indicate the binding.
  2666. //
  2667. Open->ReceivedAPacket = FALSE;
  2668. Open->References++;
  2669. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  2670. (*Open->ReceiveCompleteHandler)(Open->ProtocolBindingContext);
  2671. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  2672. //
  2673. // possibly the client closed the adapter in the time interval where
  2674. // the spin lock is released.
  2675. //
  2676. if ((--Open->References) == 0)
  2677. {
  2678. //
  2679. // This binding is shutting down. We have to kill it.
  2680. //
  2681. ndisMFinishClose(Miniport, Open);
  2682. //
  2683. // we have to start over in the loop through all of the
  2684. // Opens since the finishClose could have remove one or more
  2685. // opens from the list
  2686. //
  2687. Open = Miniport->OpenQueue;
  2688. }
  2689. else if (Open->Flags & fMINIPORT_OPEN_CLOSING)
  2690. {
  2691. //
  2692. // This Open has been dequeued from the miniport so start over
  2693. // at the beginning of the list
  2694. //
  2695. Open = Miniport->OpenQueue;
  2696. }
  2697. }
  2698. else
  2699. {
  2700. Open = Open->MiniportNextOpen;
  2701. }
  2702. }
  2703. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  2704. }
  2705. VOID
  2706. NdisCoSendPackets(
  2707. IN NDIS_HANDLE NdisVcHandle,
  2708. IN PPNDIS_PACKET PacketArray,
  2709. IN UINT NumberOfPackets
  2710. )
  2711. /*++
  2712. Routine Description:
  2713. Arguments:
  2714. Return Value:
  2715. --*/
  2716. {
  2717. PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
  2718. PNDIS_MINIPORT_BLOCK Miniport;
  2719. PNDIS_PACKET Packet;
  2720. ULONG PacketCount;
  2721. NDIS_STATUS s;
  2722. ULONG NumPmodeOpens;
  2723. //
  2724. // If there are promiscuous opens on this miniport, this must be indicated to them.
  2725. // Do this before it is send down to the miniport to preserve packet ordering.
  2726. //
  2727. Miniport = Vc->Miniport;
  2728. if (Miniport->PmodeOpens > 0)
  2729. {
  2730. PNDIS_M_OPEN_BLOCK pPmodeOpen;
  2731. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  2732. NumPmodeOpens = Miniport->PmodeOpens;
  2733. for (pPmodeOpen = Miniport->OpenQueue;
  2734. (NumPmodeOpens > 0);
  2735. pPmodeOpen = pPmodeOpen->MiniportNextOpen)
  2736. {
  2737. if (pPmodeOpen->Flags & fMINIPORT_OPEN_PMODE)
  2738. {
  2739. ULONG Ref;
  2740. pPmodeOpen->ReceivedAPacket = TRUE;
  2741. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  2742. PacketCount = NumberOfPackets;
  2743. Packet = *PacketArray;
  2744. while (PacketCount--)
  2745. {
  2746. //
  2747. // For Pmode opens, we pass the VcId to the indication routine
  2748. // since the protocol does not really own the VC. On lookback
  2749. // the packet cannot be held.
  2750. //
  2751. s = NDIS_GET_PACKET_STATUS(Packet);
  2752. NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_RESOURCES);
  2753. Ref = (*pPmodeOpen->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler)(
  2754. pPmodeOpen->ProtocolBindingContext,
  2755. Vc->pVcId,
  2756. Packet);
  2757. ASSERT (Ref == 0);
  2758. NDIS_SET_PACKET_STATUS(Packet, s);
  2759. Packet++;
  2760. }
  2761. NumPmodeOpens--;
  2762. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  2763. }
  2764. }
  2765. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  2766. }
  2767. //
  2768. // Simply call down to the miniport. The miniport must complete the sends for
  2769. // all cases. The send either succeeds/pends or fails. The miniport cannot
  2770. // ask the wrapper to queue it.
  2771. //
  2772. (*Vc->WCoSendPacketsHandler)(Vc->MiniportContext,
  2773. PacketArray,
  2774. NumberOfPackets);
  2775. PacketCount = NumberOfPackets;
  2776. Packet = *PacketArray;
  2777. while (PacketCount--)
  2778. {
  2779. NDIS_STATUS s;
  2780. s = NDIS_GET_PACKET_STATUS(Packet);
  2781. if (s != NDIS_STATUS_PENDING)
  2782. {
  2783. (Vc->CoSendCompleteHandler)(s,
  2784. Vc->ClientContext,
  2785. Packet);
  2786. }
  2787. }
  2788. }
  2789. VOID
  2790. NdisMCoSendComplete(
  2791. IN NDIS_STATUS Status,
  2792. IN NDIS_HANDLE NdisVcHandle,
  2793. IN PNDIS_PACKET Packet
  2794. )
  2795. /*++
  2796. Routine Description:
  2797. This function is called by the miniport when a send has completed. This
  2798. routine simply calls the protocol to pass along the indication.
  2799. Arguments:
  2800. MiniportAdapterHandle - points to the adapter block.
  2801. NdisVcHandle - the handle supplied to the adapter on the OID_RESERVE_VC
  2802. PacketArray - a ptr to an array of NDIS_PACKETS
  2803. NumberOfPackets - the number of packets in PacketArray
  2804. Status - the send status that applies to all packets in the array
  2805. Return Value:
  2806. None.
  2807. --*/
  2808. {
  2809. PNDIS_MINIPORT_BLOCK Miniport;
  2810. PNDIS_M_OPEN_BLOCK Open;
  2811. PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
  2812. //
  2813. // There should not be any reason to grab the spin lock and increment the
  2814. // ref count on Open since the open cannot close until the Vc closes and
  2815. // the Vc cannot close in the middle of an indication because the miniport
  2816. // will not complete a RELEASE_VC until is it no longer indicating
  2817. //
  2818. //
  2819. // Indicate to Protocol;
  2820. //
  2821. Open = Vc->ClientOpen;
  2822. Miniport = Vc->Miniport;
  2823. (Vc->CoSendCompleteHandler)(Status,
  2824. Vc->ClientContext,
  2825. Packet);
  2826. //
  2827. // Technically this Vc should not close since there is a send outstanding
  2828. // on it, and the client should not close a Vc with an outstanding send.
  2829. //
  2830. ASSERT(Vc->References);
  2831. ASSERT(Open->References);
  2832. }
  2833. VOID
  2834. NdisMCoIndicateStatus(
  2835. IN NDIS_HANDLE MiniportAdapterHandle,
  2836. IN NDIS_HANDLE NdisVcHandle,
  2837. IN NDIS_STATUS GeneralStatus,
  2838. IN PVOID StatusBuffer,
  2839. IN ULONG StatusBufferSize
  2840. )
  2841. /*++
  2842. Routine Description:
  2843. This routine handles passing CoStatus to the protocol. The miniport calls
  2844. this routine when it has status on a VC or a general status for all Vcs - in
  2845. this case the NdisVcHandle is null.
  2846. Arguments:
  2847. MiniportAdapterHandle - pointer to the mini-port block;
  2848. NdisVcHandle - a pointer to the Vc block
  2849. GeneralStatus - the completion status of the request.
  2850. StatusBuffer - a buffer containing medium and status specific info
  2851. StatusBufferSize - the size of the buffer.
  2852. Return Value:
  2853. none
  2854. --*/
  2855. {
  2856. PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
  2857. PNDIS_CO_VC_BLOCK Vc = (PNDIS_CO_VC_BLOCK)NdisVcHandle;
  2858. PNDIS_M_OPEN_BLOCK Open;
  2859. if (Vc != NULL)
  2860. {
  2861. Open = Vc->ClientOpen;
  2862. (Open->ProtocolHandle->ProtocolCharacteristics.CoStatusHandler)(
  2863. Open->ProtocolBindingContext,
  2864. Vc->ClientContext,
  2865. GeneralStatus,
  2866. StatusBuffer,
  2867. StatusBufferSize);
  2868. }
  2869. else
  2870. {
  2871. //
  2872. // this must be a general status for all clients of this miniport
  2873. // since the Vc handle is null, so indicate this to all protocols.
  2874. //
  2875. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  2876. for (Open = Miniport->OpenQueue;
  2877. Open != NULL;
  2878. NOTHING)
  2879. {
  2880. if ((Open->Flags & fMINIPORT_OPEN_CLOSING) == 0)
  2881. {
  2882. Open->References++;
  2883. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  2884. (Open->ProtocolHandle->ProtocolCharacteristics.CoStatusHandler)(
  2885. Open->ProtocolBindingContext,
  2886. NULL,
  2887. GeneralStatus,
  2888. StatusBuffer,
  2889. StatusBufferSize);
  2890. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  2891. //
  2892. // possibly the client closed the adapter in the time interval where
  2893. // the spin lock is released.
  2894. //
  2895. if ((--Open->References) == 0)
  2896. {
  2897. //
  2898. // This binding is shutting down. We have to kill it.
  2899. //
  2900. ndisMFinishClose(Miniport, Open);
  2901. //
  2902. // we have to start over in the loop through all of the
  2903. // Opens since the finishClose could have remove one or more
  2904. // opens from the list - this may result in status being indicated
  2905. // twice to a particular protocol....
  2906. //
  2907. Open = Miniport->OpenQueue;
  2908. continue;
  2909. }
  2910. else if (Open->Flags & fMINIPORT_OPEN_CLOSING)
  2911. {
  2912. //
  2913. // This Open has been dequeued from the miniport so start over
  2914. // at the beginning of the list
  2915. //
  2916. Open = Miniport->OpenQueue;
  2917. continue;
  2918. }
  2919. }
  2920. Open = Open->MiniportNextOpen;
  2921. }
  2922. NDIS_RELEASE_MINIPORT_SPIN_LOCK_DPC(Miniport);
  2923. }
  2924. }
  2925. NDIS_STATUS
  2926. ndisMRejectSend(
  2927. IN NDIS_HANDLE NdisBindingHandle,
  2928. IN PNDIS_PACKET Packet
  2929. )
  2930. /*++
  2931. Routine Description:
  2932. This routine handles any error cases where a protocol binds to an Atm
  2933. miniport and tries to use the normal NdisSend() call.
  2934. Arguments:
  2935. NdisBindingHandle - Handle returned by NdisOpenAdapter.
  2936. Packet - the Ndis packet to send
  2937. Return Value:
  2938. NDIS_STATUS - always fails
  2939. --*/
  2940. {
  2941. return(NDIS_STATUS_NOT_SUPPORTED);
  2942. }
  2943. VOID
  2944. ndisMRejectSendPackets(
  2945. IN PNDIS_OPEN_BLOCK OpenBlock,
  2946. IN PPNDIS_PACKET Packet,
  2947. IN UINT NumberOfPackets
  2948. )
  2949. /*++
  2950. Routine Description:
  2951. This routine handles any error cases where a protocol binds to an Atm
  2952. miniport and tries to use the normal NdisSend() call.
  2953. Arguments:
  2954. OpenBlock - Pointer to the NdisOpenBlock
  2955. Packet - Pointer to the array of packets to send
  2956. NumberOfPackets - self-explanatory
  2957. Return Value:
  2958. None - SendCompleteHandler is called for the protocol calling this.
  2959. --*/
  2960. {
  2961. PNDIS_M_OPEN_BLOCK MiniportOpen = (PNDIS_M_OPEN_BLOCK)(OpenBlock->MacBindingHandle);
  2962. UINT i;
  2963. for (i = 0; i < NumberOfPackets; i++)
  2964. {
  2965. (*MiniportOpen->SendCompleteHandler)(MiniportOpen->ProtocolBindingContext,
  2966. Packet[i],
  2967. NDIS_STATUS_NOT_SUPPORTED);
  2968. }
  2969. }
  2970. NDIS_STATUS
  2971. ndisMWrappedRequest(
  2972. IN NDIS_HANDLE NdisBindingHandle,
  2973. IN PNDIS_REQUEST NdisRequest
  2974. )
  2975. /*++
  2976. Routine Description:
  2977. This routine handles wrapping an NdisRequest to NdisCoRequest since a NDIS 4.1
  2978. miniport does not support QueryInformation and SetInformation handlers.
  2979. Arguments:
  2980. NdisBindingHandle - Points to the NDIS_OPEN_BLOCK
  2981. NdisRequest - The request
  2982. Return Value:
  2983. NDIS_STATUS_PENDING If the request pends or an appropriate code if it succeeds/fails
  2984. --*/
  2985. {
  2986. PNDIS_M_OPEN_BLOCK Open;
  2987. KIRQL OldIrql;
  2988. PNDIS_MINIPORT_BLOCK Miniport;
  2989. PNDIS_COREQ_RESERVED ReqRsvd;
  2990. PNDIS_REQUEST NewReq;
  2991. NDIS_STATUS Status;
  2992. PULONG Filter;
  2993. Open = (PNDIS_M_OPEN_BLOCK)NdisBindingHandle;
  2994. Miniport = Open->MiniportHandle;
  2995. //
  2996. // Start off by allocating a request. We do this since the original request is not
  2997. // big enough to accomodate the ReqRsvd block
  2998. //
  2999. NewReq = ALLOC_FROM_POOL(sizeof(NDIS_REQUEST), NDIS_TAG_CO);
  3000. if (NewReq == NULL)
  3001. {
  3002. return NDIS_STATUS_RESOURCES;
  3003. }
  3004. //
  3005. // Copy the original request to the new structure
  3006. //
  3007. NewReq->RequestType = NdisRequest->RequestType;
  3008. NewReq->DATA.SET_INFORMATION.Oid = NdisRequest->DATA.SET_INFORMATION.Oid;
  3009. NewReq->DATA.SET_INFORMATION.InformationBuffer = NdisRequest->DATA.SET_INFORMATION.InformationBuffer;
  3010. NewReq->DATA.SET_INFORMATION.InformationBufferLength = NdisRequest->DATA.SET_INFORMATION.InformationBufferLength;
  3011. ReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(NewReq);
  3012. ReqRsvd->RealRequest = NdisRequest;
  3013. //
  3014. // Start off by referencing the open.
  3015. //
  3016. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  3017. if (Open->Flags & fMINIPORT_OPEN_CLOSING)
  3018. {
  3019. Status = NDIS_STATUS_CLOSING;
  3020. }
  3021. else if (Miniport->Flags & (fMINIPORT_RESET_IN_PROGRESS | fMINIPORT_RESET_REQUESTED))
  3022. {
  3023. Status = NDIS_STATUS_RESET_IN_PROGRESS;
  3024. }
  3025. else
  3026. {
  3027. Open->References ++;
  3028. Status = NDIS_STATUS_SUCCESS;
  3029. Filter = (PULONG)(NdisRequest->DATA.SET_INFORMATION.InformationBuffer);
  3030. //
  3031. // If this was a request to turn p-mode/l-only on/off then mark things appropriately
  3032. //
  3033. if ((NdisRequest->RequestType == NdisRequestSetInformation) &&
  3034. (NdisRequest->DATA.SET_INFORMATION.Oid == OID_GEN_CURRENT_PACKET_FILTER))
  3035. {
  3036. if (*Filter & (NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL))
  3037. {
  3038. if ((Open->Flags & fMINIPORT_OPEN_PMODE) == 0)
  3039. {
  3040. Open->Flags |= fMINIPORT_OPEN_PMODE;
  3041. Miniport->PmodeOpens ++;
  3042. }
  3043. *Filter &= ~(NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL);
  3044. }
  3045. else
  3046. {
  3047. if (Open->Flags & fMINIPORT_OPEN_PMODE)
  3048. {
  3049. Open->Flags &= ~fMINIPORT_OPEN_PMODE;
  3050. Miniport->PmodeOpens --;
  3051. }
  3052. }
  3053. }
  3054. }
  3055. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  3056. if (Status == NDIS_STATUS_SUCCESS)
  3057. {
  3058. ReqRsvd->Open = Open;
  3059. ReqRsvd->RequestCompleteHandler = Open->ProtocolHandle->ProtocolCharacteristics.RequestCompleteHandler;
  3060. ReqRsvd->VcContext = NULL;
  3061. ReqRsvd->Flags = COREQ_DOWNLEVEL;
  3062. if ((NdisRequest->RequestType == NdisRequestSetInformation) &&
  3063. (NdisRequest->DATA.SET_INFORMATION.Oid == OID_GEN_CURRENT_PACKET_FILTER) &&
  3064. (*Filter == 0))
  3065. {
  3066. NewReq->DATA.SET_INFORMATION.BytesRead = 4;
  3067. Status = NDIS_STATUS_SUCCESS;
  3068. }
  3069. else
  3070. {
  3071. //
  3072. // Call the miniport's CoRequest Handler
  3073. //
  3074. Status = (*Open->MiniportCoRequestHandler)(Open->MiniportAdapterContext,
  3075. NULL,
  3076. NewReq);
  3077. }
  3078. if (Status != NDIS_STATUS_PENDING)
  3079. {
  3080. NdisMCoRequestComplete(Status,
  3081. Open->MiniportHandle,
  3082. NewReq);
  3083. Status = NDIS_STATUS_PENDING;
  3084. }
  3085. }
  3086. return Status;
  3087. }