Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

5260 lines
151 KiB

  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_OPEN_BLOCK CallMgrOpen;
  74. PNDIS_MINIPORT_BLOCK Miniport;
  75. PNDIS_AF_NOTIFY AfNotify = NULL;
  76. CallMgrOpen = (PNDIS_OPEN_BLOCK)NdisBindingHandle;
  77. Miniport = CallMgrOpen->MiniportHandle;
  78. Protocol = CallMgrOpen->ProtocolHandle;
  79. PnPReferencePackage();
  80. //
  81. // Make sure that the miniport is a CoNdis miniport and
  82. // there is no other module registering the same address family.
  83. //
  84. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  85. do
  86. {
  87. CallMgrOpen->Flags |= fMINIPORT_OPEN_CALL_MANAGER;
  88. //
  89. // Make sure the binding is not closing down
  90. //
  91. if (CallMgrOpen->Flags & fMINIPORT_OPEN_CLOSING)
  92. {
  93. Status = NDIS_STATUS_FAILURE;
  94. break;
  95. }
  96. //
  97. // Make sure that the miniport is a CoNdis miniport and
  98. // protocol is also a NDIS 5.0 or later protocol.
  99. //
  100. if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
  101. {
  102. //
  103. // Not a NDIS 5.0 or later miniport
  104. //
  105. Status = NDIS_STATUS_FAILURE;
  106. break;
  107. }
  108. if (Protocol->ProtocolCharacteristics.MajorNdisVersion < 5)
  109. {
  110. //
  111. // Not a NDIS 5.0 or later protocol
  112. //
  113. Status = NDIS_STATUS_FAILURE;
  114. break;
  115. }
  116. //
  117. // Make sure that the call-manager characteristics are 5.0 or later
  118. //
  119. if ((CmCharacteristics->MajorVersion < 5) ||
  120. (SizeOfCmCharacteristics < sizeof(NDIS_CALL_MANAGER_CHARACTERISTICS)))
  121. {
  122. //
  123. // Not a NDIS 5.0 or later protocol
  124. //
  125. Status = NDIS_STATUS_FAILURE;
  126. break;
  127. }
  128. //
  129. // Search registered call-managers for this miniport and make sure there is no
  130. // clash. A call-manager can only register one address family per-open. This
  131. // is due to the way we cache handlers. Can be over-come if the handlers are
  132. // identical for each address-family - but decided not to since it is un-interesting.
  133. //
  134. for (AfList = Miniport->CallMgrAfList;
  135. AfList != NULL;
  136. AfList = AfList->NextAf)
  137. {
  138. if (NdisEqualMemory(&AfList->AddressFamily, AddressFamily, sizeof(CO_ADDRESS_FAMILY)))
  139. {
  140. Status = NDIS_STATUS_FAILURE;
  141. break;
  142. }
  143. }
  144. if (AfList == NULL)
  145. {
  146. //
  147. // No other entity has claimed this address family.
  148. // Allocate an AfList and a notify structure
  149. //
  150. AfList = (PNDIS_AF_LIST)ALLOC_FROM_POOL(sizeof(NDIS_AF_LIST), NDIS_TAG_CO);
  151. if (AfList == NULL)
  152. {
  153. Status = NDIS_STATUS_RESOURCES;
  154. break;
  155. }
  156. Status = ndisCreateNotifyQueue(Miniport, NULL, AddressFamily, &AfNotify);
  157. if (Status != NDIS_STATUS_SUCCESS)
  158. {
  159. FREE_POOL(AfList);
  160. break;
  161. }
  162. AfList->AddressFamily = *AddressFamily;
  163. CopyMemory(&AfList->CmChars,
  164. CmCharacteristics,
  165. sizeof(NDIS_CALL_MANAGER_CHARACTERISTICS));
  166. //
  167. // link it in the miniport list
  168. //
  169. AfList->Open = CallMgrOpen;
  170. AfList->NextAf = Miniport->CallMgrAfList;
  171. Miniport->CallMgrAfList = AfList;
  172. //
  173. // Finally cache some handlers in the open-block
  174. //
  175. CallMgrOpen->CoCreateVcHandler = CmCharacteristics->CmCreateVcHandler;
  176. CallMgrOpen->CoDeleteVcHandler = CmCharacteristics->CmDeleteVcHandler;
  177. CallMgrOpen->CmActivateVcCompleteHandler = CmCharacteristics->CmActivateVcCompleteHandler;
  178. CallMgrOpen->CmDeactivateVcCompleteHandler = CmCharacteristics->CmDeactivateVcCompleteHandler;
  179. CallMgrOpen->CoRequestCompleteHandler = CmCharacteristics->CmRequestCompleteHandler;
  180. if (AfNotify != NULL)
  181. {
  182. //
  183. // Notify existing clients of this registration
  184. //
  185. QUEUE_WORK_ITEM(&AfNotify->WorkItem, DelayedWorkQueue);
  186. }
  187. }
  188. } while (FALSE);
  189. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  190. PnPDereferencePackage();
  191. return(Status);
  192. }
  193. NDIS_STATUS
  194. NdisMCmRegisterAddressFamily(
  195. IN NDIS_HANDLE MiniportAdapterHandle,
  196. IN PCO_ADDRESS_FAMILY AddressFamily,
  197. IN PNDIS_CALL_MANAGER_CHARACTERISTICS CmCharacteristics,
  198. IN UINT SizeOfCmCharacteristics
  199. )
  200. /*++
  201. Routine Description:
  202. This is a call from the miniport supported call-manager to register the address family
  203. supported by this call-manager.
  204. Arguments:
  205. MiniportAdapterHandle - Pointer to the miniports NDIS_MINIPORT_BLOCK.
  206. AddressFamily - The address family being registered.
  207. CmCharacteristics - Call-Manager characteristics
  208. SizeOfCmCharacteristics - Size of Call-Manager characteristics
  209. Return Value:
  210. NDIS_STATUS_SUCCESS if the address family registration is successfully.
  211. NDIS_STATUS_FAILURE if the caller is not a call-manager or this address
  212. family is already registered for this miniport.
  213. --*/
  214. {
  215. PNDIS_MINIPORT_BLOCK Miniport;
  216. NDIS_STATUS Status;
  217. PNDIS_AF_LIST AfList;
  218. KIRQL OldIrql;
  219. PnPReferencePackage();
  220. Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
  221. //
  222. // Make sure that the miniport is a CoNdis miniport and
  223. // there is no other module registering the same address family.
  224. //
  225. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  226. do
  227. {
  228. //
  229. // Make sure that the miniport is a CoNdis miniport
  230. //
  231. if (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO))
  232. {
  233. //
  234. // Not a NDIS 5.0 or later miniport
  235. //
  236. Status = NDIS_STATUS_FAILURE;
  237. break;
  238. }
  239. //
  240. // Make sure that the call-manager characteristics are 5.0 or later
  241. //
  242. if ((CmCharacteristics->MajorVersion < 5) ||
  243. (SizeOfCmCharacteristics < sizeof(NDIS_CALL_MANAGER_CHARACTERISTICS)))
  244. {
  245. //
  246. // Not a NDIS 5.0 or later protocol
  247. //
  248. Status = NDIS_STATUS_FAILURE;
  249. break;
  250. }
  251. //
  252. // Search registered call-managers for this miniport and make sure there is no
  253. // clash. A call-manager can only register one address family per-open. This
  254. // is due to the way we cache handlers. Can be over-come if the handlers are
  255. // identical for each address-family - but decided not to since it is un-interesting.
  256. //
  257. for (AfList = Miniport->CallMgrAfList;
  258. AfList != NULL;
  259. AfList = AfList->NextAf)
  260. {
  261. if (NdisEqualMemory(&AfList->AddressFamily, AddressFamily, sizeof(CO_ADDRESS_FAMILY)))
  262. {
  263. Status = NDIS_STATUS_FAILURE;
  264. break;
  265. }
  266. }
  267. if ((AfList == NULL) && MINIPORT_INCREMENT_REF(Miniport))
  268. {
  269. //
  270. // No other entity has claimed this address family.
  271. // Allocate an AfList and a notify structure
  272. //
  273. AfList = (PNDIS_AF_LIST)ALLOC_FROM_POOL(sizeof(NDIS_AF_LIST), NDIS_TAG_CO);
  274. if (AfList == NULL)
  275. {
  276. Status = NDIS_STATUS_RESOURCES;
  277. break;
  278. }
  279. AfList->AddressFamily = *AddressFamily;
  280. CopyMemory(&AfList->CmChars,
  281. CmCharacteristics,
  282. sizeof(NDIS_CALL_MANAGER_CHARACTERISTICS));
  283. //
  284. // link it in the miniport list
  285. //
  286. AfList->Open = NULL;
  287. AfList->NextAf = Miniport->CallMgrAfList;
  288. Miniport->CallMgrAfList = AfList;
  289. MINIPORT_DECREMENT_REF(Miniport);
  290. Status = NDIS_STATUS_SUCCESS;
  291. }
  292. } while (FALSE);
  293. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  294. PnPDereferencePackage();
  295. return Status;
  296. }
  297. NDIS_STATUS
  298. ndisCreateNotifyQueue(
  299. IN PNDIS_MINIPORT_BLOCK Miniport,
  300. IN PNDIS_OPEN_BLOCK Open OPTIONAL,
  301. IN PCO_ADDRESS_FAMILY AddressFamily OPTIONAL,
  302. IN PNDIS_AF_NOTIFY * AfNotify
  303. )
  304. /*++
  305. Routine Description:
  306. Collect a set of address-family notifications that can then be passed on to ndisNotifyAfRegistration.
  307. If the Open is NULL, this implies that an AddressFamily is being registered and must be notified to
  308. all protocols on this miniport. If the AddressFamily is NULL (and the Open is specified) then all
  309. registered AddressFamilies on this miniport must be indicated to the Open.
  310. Arguments:
  311. Miniport - Miniport of interest
  312. Open - Optional - see comments above
  313. AddressFamily - Optional - see comments above
  314. AfNotify - Place holder for the list of notifications
  315. Return Value:
  316. NDIS_STATUS_SUCCESS - No errors, AfNotify can be NULL
  317. NDIS_STATUS_RESOURCES - Failed to allocate memory
  318. Note: Called at DPC with Miniport lock held.
  319. --*/
  320. {
  321. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  322. PNDIS_AF_NOTIFY AfN;
  323. PNDIS_OPEN_BLOCK tOpen;
  324. PNDIS_AF_LIST AfList;
  325. ASSERT(ARGUMENT_PRESENT(Open) ^ ARGUMENT_PRESENT(AddressFamily));
  326. *AfNotify = NULL;
  327. if (ARGUMENT_PRESENT(Open))
  328. {
  329. ACQUIRE_SPIN_LOCK_DPC(&Open->SpinLock);
  330. ASSERT(Open->ProtocolHandle->ProtocolCharacteristics.CoAfRegisterNotifyHandler != NULL);
  331. for (AfList = Miniport->CallMgrAfList;
  332. AfList != NULL;
  333. AfList = AfList->NextAf)
  334. {
  335. if (MINIPORT_TEST_FLAG(Open, fMINIPORT_OPEN_UNBINDING | fMINIPORT_OPEN_CLOSING))
  336. {
  337. //
  338. // this open is going away. skip it.
  339. //
  340. break;
  341. }
  342. else
  343. {
  344. OPEN_INCREMENT_AF_NOTIFICATION(Open);
  345. // DbgPrint("ndisCreateNotifyQueue: Open %p, AFNotifyRef %lx\n", Open, Open->PendingAfNotifications);
  346. }
  347. AfN = (PNDIS_AF_NOTIFY)ALLOC_FROM_POOL(sizeof(NDIS_AF_NOTIFY), NDIS_TAG_CO);
  348. if (AfN == NULL)
  349. {
  350. Status = NDIS_STATUS_RESOURCES;
  351. break;
  352. }
  353. AfN->Miniport = Miniport;
  354. AfN->Open = Open;
  355. M_OPEN_INCREMENT_REF_INTERLOCKED(Open);
  356. AfN->AddressFamily = AfList->AddressFamily;
  357. INITIALIZE_WORK_ITEM(&AfN->WorkItem, ndisNotifyAfRegistration, AfN);
  358. AfN->Next = *AfNotify;
  359. *AfNotify = AfN;
  360. }
  361. RELEASE_SPIN_LOCK_DPC(&Open->SpinLock);
  362. }
  363. else
  364. {
  365. for (tOpen = Miniport->OpenQueue;
  366. tOpen != NULL;
  367. tOpen = tOpen->MiniportNextOpen)
  368. {
  369. if (tOpen->ProtocolHandle->ProtocolCharacteristics.CoAfRegisterNotifyHandler != NULL)
  370. {
  371. ACQUIRE_SPIN_LOCK_DPC(&tOpen->SpinLock);
  372. if (MINIPORT_TEST_FLAG(tOpen, fMINIPORT_OPEN_UNBINDING | fMINIPORT_OPEN_CLOSING))
  373. {
  374. //
  375. // this open is going away. skip it.
  376. //
  377. RELEASE_SPIN_LOCK_DPC(&tOpen->SpinLock);
  378. continue;
  379. }
  380. else
  381. {
  382. OPEN_INCREMENT_AF_NOTIFICATION(tOpen);
  383. // DbgPrint("ndisCreateNotifyQueue: tOpen %p, AFNotifyRef %lx\n", tOpen, tOpen->PendingAfNotifications);
  384. RELEASE_SPIN_LOCK_DPC(&tOpen->SpinLock);
  385. }
  386. AfN = (PNDIS_AF_NOTIFY)ALLOC_FROM_POOL(sizeof(NDIS_AF_NOTIFY), NDIS_TAG_CO);
  387. if (AfN == NULL)
  388. {
  389. Status = NDIS_STATUS_RESOURCES;
  390. ndisDereferenceAfNotification(tOpen);
  391. break;
  392. }
  393. AfN->Miniport = Miniport;
  394. AfN->Open = tOpen;
  395. M_OPEN_INCREMENT_REF_INTERLOCKED(tOpen);
  396. AfN->AddressFamily = *AddressFamily;
  397. INITIALIZE_WORK_ITEM(&AfN->WorkItem, ndisNotifyAfRegistration, AfN);
  398. AfN->Next = *AfNotify;
  399. *AfNotify = AfN;
  400. }
  401. }
  402. }
  403. return Status;
  404. }
  405. VOID
  406. ndisNotifyAfRegistration(
  407. IN PNDIS_AF_NOTIFY AfNotify
  408. )
  409. /*++
  410. Routine Description:
  411. Notify protocols that care that a new address family has been registered.
  412. Arguments:
  413. AfNotify - Structure that holds context information.
  414. Return Value:
  415. None.
  416. --*/
  417. {
  418. KIRQL OldIrql;
  419. PNDIS_MINIPORT_BLOCK Miniport;
  420. PNDIS_PROTOCOL_BLOCK Protocol;
  421. PNDIS_OPEN_BLOCK Open;
  422. PNDIS_AF_NOTIFY Af, AfNext;
  423. Miniport = AfNotify->Miniport;
  424. PnPReferencePackage();
  425. for (Af = AfNotify; Af != NULL; Af = AfNext)
  426. {
  427. AfNext = Af->Next;
  428. Open = Af->Open;
  429. Protocol = Open->ProtocolHandle;
  430. if (!MINIPORT_TEST_FLAG(Open, fMINIPORT_OPEN_UNBINDING | fMINIPORT_OPEN_CLOSING))
  431. {
  432. (*Protocol->ProtocolCharacteristics.CoAfRegisterNotifyHandler)(
  433. Open->ProtocolBindingContext,
  434. &Af->AddressFamily);
  435. }
  436. FREE_POOL(Af);
  437. ndisDereferenceAfNotification(Open);
  438. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  439. ndisMDereferenceOpen(Open);
  440. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  441. }
  442. PnPDereferencePackage();
  443. }
  444. NDIS_STATUS
  445. NdisClOpenAddressFamily(
  446. IN NDIS_HANDLE NdisBindingHandle,
  447. IN PCO_ADDRESS_FAMILY AddressFamily,
  448. IN NDIS_HANDLE ClientAfContext,
  449. IN PNDIS_CLIENT_CHARACTERISTICS ClCharacteristics,
  450. IN UINT SizeOfClCharacteristics,
  451. OUT PNDIS_HANDLE NdisAfHandle
  452. )
  453. /*++
  454. Routine Description:
  455. This is a call from a NDIS 5.0 or later protocol to open a particular
  456. address familty - in essence getting a handle to the call-manager.
  457. Arguments:
  458. NdisBindingHandle - Pointer to the protocol's NDIS_OPEN_BLOCK.
  459. PCO_ADDRESS_FAMILY - The address family being registered.
  460. ClientAfContext - Protocol context associated with this handle.
  461. NdisAfHandle - Handle returned by NDIS for this address family.
  462. Return Value:
  463. NDIS_STATUS_SUCCESS if the address family open is successfully.
  464. NDIS_STATUS_PENDING if the call-manager pends this call. The caller will get
  465. called at the completion handler when done.
  466. NDIS_STATUS_FAILURE if the caller is not a NDIS 5.0 prototcol or this address
  467. family is not registered for this miniport.
  468. --*/
  469. {
  470. PNDIS_CO_AF_BLOCK pAf;
  471. PNDIS_AF_LIST AfList;
  472. PNDIS_OPEN_BLOCK CallMgrOpen, ClientOpen;
  473. PNDIS_MINIPORT_BLOCK Miniport;
  474. PNDIS_PROTOCOL_BLOCK Protocol;
  475. KIRQL OldIrql;
  476. NTSTATUS Status;
  477. *NdisAfHandle = NULL;
  478. ClientOpen = (PNDIS_OPEN_BLOCK)NdisBindingHandle;
  479. Miniport = ClientOpen->MiniportHandle;
  480. Protocol = ClientOpen->ProtocolHandle;
  481. PnPReferencePackage();
  482. do
  483. {
  484. ClientOpen->Flags |= fMINIPORT_OPEN_CLIENT;
  485. //
  486. // Make sure the binding is not closing down
  487. //
  488. if (ClientOpen->Flags & fMINIPORT_OPEN_CLOSING)
  489. {
  490. Status = NDIS_STATUS_FAILURE;
  491. break;
  492. }
  493. //
  494. // Make sure that the miniport is a CoNdis miniport and
  495. // protocol is also a NDIS 5.0 or later protocol.
  496. //
  497. if ((Miniport->DriverHandle->MiniportCharacteristics.MajorNdisVersion < 5) ||
  498. (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_IS_CO)))
  499. {
  500. //
  501. // Not a NDIS 5.0 or later miniport
  502. //
  503. Status = NDIS_STATUS_FAILURE;
  504. break;
  505. }
  506. if (Protocol->ProtocolCharacteristics.MajorNdisVersion < 5)
  507. {
  508. //
  509. // Not a NDIS 5.0 or later protocol
  510. //
  511. Status = NDIS_STATUS_FAILURE;
  512. break;
  513. }
  514. //
  515. // Make sure that the client characteristics are 5.0 or later
  516. //
  517. if ((ClCharacteristics->MajorVersion < 5) ||
  518. (SizeOfClCharacteristics < sizeof(NDIS_CLIENT_CHARACTERISTICS)))
  519. {
  520. //
  521. // Not a NDIS 5.0 or later protocol
  522. //
  523. Status = NDIS_STATUS_FAILURE;
  524. break;
  525. }
  526. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  527. //
  528. // Search the miniport block for a registered call-manager for this address family
  529. //
  530. for (AfList = Miniport->CallMgrAfList;
  531. AfList != NULL;
  532. AfList = AfList->NextAf)
  533. {
  534. if (AfList->AddressFamily.AddressFamily == AddressFamily->AddressFamily)
  535. {
  536. CallMgrOpen = AfList->Open;
  537. break;
  538. }
  539. }
  540. //
  541. // If we found a matching call manager, make sure that the callmgr
  542. // is not currently closing.
  543. //
  544. if ((AfList == NULL) ||
  545. ((AfList != NULL) && (AfList->Open != NULL) && (AfList->Open->Flags & fMINIPORT_OPEN_CLOSING)) ||
  546. (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_PM_HALTED)))
  547. {
  548. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  549. Status = NDIS_STATUS_FAILURE;
  550. break;
  551. }
  552. //
  553. // Allocate memory for the AF block.
  554. //
  555. pAf = ALLOC_FROM_POOL(sizeof(NDIS_CO_AF_BLOCK), NDIS_TAG_CO);
  556. if (pAf == NULL)
  557. {
  558. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  559. Status = NDIS_STATUS_RESOURCES;
  560. break;
  561. }
  562. pAf->References = 1;
  563. pAf->Flags = (AfList->Open == NULL) ? AF_COMBO : 0;
  564. pAf->Miniport = Miniport;
  565. pAf->ClientOpen = ClientOpen;
  566. pAf->CallMgrOpen = CallMgrOpen = AfList->Open;
  567. pAf->ClientContext = ClientAfContext;
  568. //
  569. // Reference the call-manager's file object - we do not want to let it
  570. // duck from under the client.
  571. //
  572. //
  573. // Reference the client and the call-manager opens
  574. //
  575. M_OPEN_INCREMENT_REF_INTERLOCKED(ClientOpen);
  576. NdisInterlockedIncrement(&ClientOpen->AfReferences);
  577. if (CallMgrOpen != NULL)
  578. {
  579. M_OPEN_INCREMENT_REF_INTERLOCKED(CallMgrOpen);
  580. NdisInterlockedIncrement(&CallMgrOpen->AfReferences);
  581. }
  582. else
  583. {
  584. ObReferenceObject(Miniport->DeviceObject);
  585. Miniport->Ref.ReferenceCount ++;
  586. #ifdef TRACK_MINIPORT_REFCOUNTS
  587. M_LOG_MINIPORT_INCREMENT_REF(Miniport, __LINE__, MODULE_NUMBER);
  588. #endif
  589. }
  590. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  591. INITIALIZE_SPIN_LOCK(&pAf->Lock);
  592. //
  593. // Cache in call-manager entry points
  594. //
  595. pAf->CallMgrEntries = &AfList->CmChars;
  596. //
  597. // And also Cache in client entry points
  598. //
  599. CopyMemory(&pAf->ClientEntries,
  600. ClCharacteristics,
  601. sizeof(NDIS_CLIENT_CHARACTERISTICS));
  602. //
  603. // Cache some handlers in the open-block
  604. //
  605. ClientOpen->CoCreateVcHandler = ClCharacteristics->ClCreateVcHandler;
  606. ClientOpen->CoDeleteVcHandler = ClCharacteristics->ClDeleteVcHandler;
  607. ClientOpen->CoRequestCompleteHandler = ClCharacteristics->ClRequestCompleteHandler;
  608. //
  609. // Now call the CallMgr's OpenAfHandler
  610. //
  611. Status = (*AfList->CmChars.CmOpenAfHandler)((CallMgrOpen != NULL) ?
  612. CallMgrOpen->ProtocolBindingContext :
  613. Miniport->MiniportAdapterContext,
  614. AddressFamily,
  615. pAf,
  616. &pAf->CallMgrContext);
  617. if (Status != NDIS_STATUS_PENDING)
  618. {
  619. NdisCmOpenAddressFamilyComplete(Status,
  620. pAf,
  621. pAf->CallMgrContext);
  622. Status = NDIS_STATUS_PENDING;
  623. }
  624. } while (FALSE);
  625. PnPDereferencePackage();
  626. return Status;
  627. }
  628. VOID
  629. NdisCmOpenAddressFamilyComplete(
  630. IN NDIS_STATUS Status,
  631. IN NDIS_HANDLE NdisAfHandle,
  632. IN NDIS_HANDLE CallMgrAfContext
  633. )
  634. /*++
  635. Routine Description:
  636. Completion routine for the OpenAddressFamily call. The call manager had pended this
  637. call earlier (or will pend). If the call succeeded there is a valid CallMgrContext
  638. supplied here as well
  639. Arguments:
  640. Status - Completion status
  641. NdisAfHandle - Pointer to the AfBlock
  642. CallMgrAfContext - Call manager's context used in other calls into the call manager.
  643. Return Value:
  644. NONE. The client's completion handler is called.
  645. --*/
  646. {
  647. PNDIS_CO_AF_BLOCK pAf;
  648. PNDIS_OPEN_BLOCK ClientOpen;
  649. PNDIS_MINIPORT_BLOCK Miniport;
  650. KIRQL OldIrql;
  651. ASSERT(Status != NDIS_STATUS_PENDING);
  652. pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
  653. ClientOpen = pAf->ClientOpen;
  654. Miniport = pAf->Miniport;
  655. if (Status != NDIS_STATUS_SUCCESS)
  656. {
  657. if (pAf->CallMgrOpen == NULL)
  658. {
  659. ObDereferenceObject(Miniport->DeviceObject);
  660. }
  661. }
  662. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  663. pAf->CallMgrContext = CallMgrAfContext;
  664. if (Status != NDIS_STATUS_SUCCESS)
  665. {
  666. //
  667. // OpenAfHandler failed
  668. //
  669. if (pAf->CallMgrOpen != NULL)
  670. {
  671. NdisInterlockedDecrement(&pAf->CallMgrOpen->AfReferences);
  672. ndisMDereferenceOpen(pAf->CallMgrOpen);
  673. }
  674. else
  675. {
  676. MINIPORT_DECREMENT_REF(Miniport);
  677. }
  678. NdisInterlockedDecrement(&ClientOpen->AfReferences);
  679. ndisMDereferenceOpen(ClientOpen);
  680. }
  681. else
  682. {
  683. //
  684. // queue this CallMgr open onto the miniport open
  685. //
  686. pAf->NextAf = ClientOpen->NextAf;
  687. ClientOpen->NextAf = pAf;
  688. }
  689. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  690. //
  691. // Finally call the client's completion handler
  692. //
  693. (*pAf->ClientEntries.ClOpenAfCompleteHandler)(Status,
  694. pAf->ClientContext,
  695. (Status == NDIS_STATUS_SUCCESS) ? pAf : NULL);
  696. if (Status != NDIS_STATUS_SUCCESS)
  697. {
  698. FREE_POOL(pAf);
  699. }
  700. }
  701. NDIS_STATUS
  702. NdisClCloseAddressFamily(
  703. IN NDIS_HANDLE NdisAfHandle
  704. )
  705. /*++
  706. Routine Description:
  707. This call closes the Af object which essentially tears down the client-callmanager
  708. 'binding'. Causes all open Vcs to be closed and saps to be de-registered "by the call
  709. manager".
  710. Arguments:
  711. NdisAfHandle - Pointer to the Af.
  712. Return Value:
  713. Status from Call Manager.
  714. --*/
  715. {
  716. PNDIS_CO_AF_BLOCK pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
  717. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  718. KIRQL OldIrql;
  719. //
  720. // Mark the address family as closing and call the call-manager to process.
  721. //
  722. ACQUIRE_SPIN_LOCK(&pAf->Lock, &OldIrql);
  723. if (pAf->Flags & AF_CLOSING)
  724. {
  725. Status = NDIS_STATUS_FAILURE;
  726. }
  727. pAf->Flags |= AF_CLOSING;
  728. RELEASE_SPIN_LOCK(&pAf->Lock, OldIrql);
  729. if (Status == NDIS_STATUS_SUCCESS)
  730. {
  731. Status = (*pAf->CallMgrEntries->CmCloseAfHandler)(pAf->CallMgrContext);
  732. if (Status != NDIS_STATUS_PENDING)
  733. {
  734. NdisCmCloseAddressFamilyComplete(Status, pAf);
  735. Status = NDIS_STATUS_PENDING;
  736. }
  737. }
  738. return Status;
  739. }
  740. VOID
  741. NdisCmCloseAddressFamilyComplete(
  742. IN NDIS_STATUS Status,
  743. IN NDIS_HANDLE NdisAfHandle
  744. )
  745. /*++
  746. Routine Description:
  747. Completion routine for the CloseAddressFamily call. The call manager had pended this
  748. call earlier (or will pend). If the call succeeded there is a valid CallMgrContext
  749. supplied here as well
  750. Arguments:
  751. Status - Completion status
  752. NdisAfHandle - Pointer to the AfBlock
  753. Return Value:
  754. NONE. The client's completion handler is called.
  755. --*/
  756. {
  757. PNDIS_CO_AF_BLOCK pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
  758. PNDIS_CO_AF_BLOCK * ppAf;
  759. PNDIS_MINIPORT_BLOCK Miniport;
  760. KIRQL OldIrql;
  761. Miniport = pAf->Miniport;
  762. //
  763. // NOTE: Memphis closes the adapters synchronously. so we have to deref
  764. // the open -before- calling ClCloseAfCompleteHandler because
  765. // ClCloseAfCompleteHandler will try to close the adapter and CloseAdapter
  766. // will pend forever since the ref count never goes to zero
  767. //
  768. //
  769. // Complete the call to the client
  770. //
  771. (*pAf->ClientEntries.ClCloseAfCompleteHandler)(Status,
  772. pAf->ClientContext);
  773. if (Status == NDIS_STATUS_SUCCESS)
  774. {
  775. if (pAf->CallMgrOpen == NULL)
  776. {
  777. ObDereferenceObject(Miniport->DeviceObject);
  778. }
  779. Miniport = pAf->Miniport;
  780. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  781. if (pAf->CallMgrOpen != NULL)
  782. {
  783. NdisInterlockedDecrement(&pAf->CallMgrOpen->AfReferences);
  784. ndisMDereferenceOpen(pAf->CallMgrOpen);
  785. }
  786. else
  787. {
  788. MINIPORT_DECREMENT_REF(Miniport);
  789. }
  790. //
  791. // Unlink from list of open AFs for this client.
  792. //
  793. for (ppAf = &pAf->ClientOpen->NextAf;
  794. *ppAf != NULL;
  795. ppAf = &((*ppAf)->NextAf))
  796. {
  797. if (*ppAf == pAf)
  798. {
  799. *ppAf = pAf->NextAf;
  800. break;
  801. }
  802. }
  803. NdisInterlockedDecrement(&pAf->ClientOpen->AfReferences);
  804. ndisMDereferenceOpen(pAf->ClientOpen);
  805. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  806. }
  807. //
  808. // Finally dereference the AF Block, if the call-manager successfully closed it.
  809. //
  810. if (Status == NDIS_STATUS_SUCCESS)
  811. {
  812. ndisDereferenceAf(pAf);
  813. }
  814. }
  815. BOOLEAN
  816. FASTCALL
  817. ndisReferenceAf(
  818. IN PNDIS_CO_AF_BLOCK pAf
  819. )
  820. /*++
  821. Routine Description:
  822. Arguments:
  823. Return Value:
  824. --*/
  825. {
  826. KIRQL OldIrql;
  827. BOOLEAN rc = FALSE;
  828. ACQUIRE_SPIN_LOCK(&pAf->Lock, &OldIrql);
  829. if ((pAf->Flags & AF_CLOSING) == 0)
  830. {
  831. pAf->References ++;
  832. rc = TRUE;
  833. }
  834. RELEASE_SPIN_LOCK(&pAf->Lock, OldIrql);
  835. return rc;
  836. }
  837. VOID
  838. FASTCALL
  839. ndisDereferenceAf(
  840. IN PNDIS_CO_AF_BLOCK pAf
  841. )
  842. /*++
  843. Routine Description:
  844. Arguments:
  845. Return Value:
  846. --*/
  847. {
  848. KIRQL OldIrql;
  849. BOOLEAN Done = FALSE;
  850. ACQUIRE_SPIN_LOCK(&pAf->Lock, &OldIrql);
  851. ASSERT(pAf->References > 0);
  852. pAf->References --;
  853. if (pAf->References == 0)
  854. {
  855. ASSERT(pAf->Flags & AF_CLOSING);
  856. Done = TRUE;
  857. }
  858. RELEASE_SPIN_LOCK(&pAf->Lock, OldIrql);
  859. if (Done)
  860. FREE_POOL(pAf);
  861. }
  862. NDIS_STATUS
  863. NdisClRegisterSap(
  864. IN NDIS_HANDLE NdisAfHandle,
  865. IN NDIS_HANDLE ProtocolSapContext,
  866. IN PCO_SAP Sap,
  867. OUT PNDIS_HANDLE NdisSapHandle
  868. )
  869. /*++
  870. Routine Description:
  871. This is a call from a NDIS 5.0 or later protocol to register its SAP
  872. with the call manager.
  873. Arguments:
  874. NdisBindingHandle - Pointer to the protocol's NDIS_OPEN_BLOCK.
  875. PCO_ADDRESS_FAMILY - The address family being registered.
  876. ClientAfContext - Protocol context associated with this handle.
  877. NdisAfHandle - Handle returned by NDIS for this address family.
  878. Return Value:
  879. NDIS_STATUS_SUCCESS if the address family open is successfully.
  880. NDIS_STATUS_PENDING if the call-manager pends this call. The caller will get
  881. NDIS_STATUS_FAILURE if the caller is not a NDIS 5.0 prototcol or this address
  882. family is not registered for this miniport.
  883. --*/
  884. {
  885. NDIS_STATUS Status;
  886. PNDIS_CO_AF_BLOCK pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
  887. PNDIS_CO_SAP_BLOCK pSap;
  888. *NdisSapHandle = NULL;
  889. do
  890. {
  891. //
  892. // Reference the Af for this SAP
  893. //
  894. if (!ndisReferenceAf(pAf))
  895. {
  896. Status = NDIS_STATUS_FAILURE;
  897. break;
  898. }
  899. pSap = (PNDIS_CO_SAP_BLOCK)ALLOC_FROM_POOL(sizeof(NDIS_CO_SAP_BLOCK), NDIS_TAG_CO);
  900. if (pSap == NULL)
  901. {
  902. *NdisSapHandle = NULL;
  903. Status = NDIS_STATUS_RESOURCES;
  904. break;
  905. }
  906. pSap->Flags = 0;
  907. pSap->References = 1;
  908. INITIALIZE_SPIN_LOCK(&pSap->Lock);
  909. pSap->AfBlock = pAf;
  910. pSap->Sap = Sap;
  911. pSap->ClientContext = ProtocolSapContext;
  912. Status = (*pAf->CallMgrEntries->CmRegisterSapHandler)(pAf->CallMgrContext,
  913. Sap,
  914. pSap,
  915. &pSap->CallMgrContext);
  916. if (Status != NDIS_STATUS_PENDING)
  917. {
  918. NdisCmRegisterSapComplete(Status, pSap, pSap->CallMgrContext);
  919. Status = NDIS_STATUS_PENDING;
  920. }
  921. } while (FALSE);
  922. return Status;
  923. }
  924. VOID
  925. NdisCmRegisterSapComplete(
  926. IN NDIS_STATUS Status,
  927. IN NDIS_HANDLE NdisSapHandle,
  928. IN NDIS_HANDLE CallMgrSapContext
  929. )
  930. /*++
  931. Routine Description:
  932. Completion routine for the registerSap call. The call manager had pended this
  933. call earlier (or will pend). If the call succeeded there is a valid CallMgrContext
  934. supplied here as well
  935. Arguments:
  936. Status - Completion status
  937. NdisAfHandle - Pointer to the AfBlock
  938. CallMgrAfContext - Call manager's context used in other calls into the call manager.
  939. Return Value:
  940. NONE. The client's completion handler is called.
  941. --*/
  942. {
  943. PNDIS_CO_SAP_BLOCK pSap = (PNDIS_CO_SAP_BLOCK)NdisSapHandle;
  944. PNDIS_CO_AF_BLOCK pAf;
  945. ASSERT(Status != NDIS_STATUS_PENDING);
  946. pAf = pSap->AfBlock;
  947. pSap->CallMgrContext = CallMgrSapContext;
  948. //
  949. // Call the clients completion handler
  950. //
  951. (*pAf->ClientEntries.ClRegisterSapCompleteHandler)(Status,
  952. pSap->ClientContext,
  953. pSap->Sap,
  954. pSap);
  955. if (Status != NDIS_STATUS_SUCCESS)
  956. {
  957. ndisDereferenceAf(pSap->AfBlock);
  958. FREE_POOL(pSap);
  959. }
  960. }
  961. NDIS_STATUS
  962. NdisClDeregisterSap(
  963. IN NDIS_HANDLE NdisSapHandle
  964. )
  965. /*++
  966. Routine Description:
  967. Arguments:
  968. Return Value:
  969. --*/
  970. {
  971. PNDIS_CO_SAP_BLOCK pSap = (PNDIS_CO_SAP_BLOCK)NdisSapHandle;
  972. NDIS_STATUS Status;
  973. KIRQL OldIrql;
  974. BOOLEAN fAlreadyClosing;
  975. ACQUIRE_SPIN_LOCK(&pSap->Lock, &OldIrql);
  976. fAlreadyClosing = FALSE;
  977. if (pSap->Flags & SAP_CLOSING)
  978. {
  979. fAlreadyClosing = TRUE;
  980. }
  981. pSap->Flags |= SAP_CLOSING;
  982. RELEASE_SPIN_LOCK(&pSap->Lock, OldIrql);
  983. if (fAlreadyClosing)
  984. {
  985. return NDIS_STATUS_FAILURE;
  986. }
  987. //
  988. // Notify the call-manager that this sap is being de-registered
  989. //
  990. Status = (*pSap->AfBlock->CallMgrEntries->CmDeregisterSapHandler)(pSap->CallMgrContext);
  991. if (Status != NDIS_STATUS_PENDING)
  992. {
  993. NdisCmDeregisterSapComplete(Status, pSap);
  994. Status = NDIS_STATUS_PENDING;
  995. }
  996. return Status;
  997. }
  998. VOID
  999. NdisCmDeregisterSapComplete(
  1000. IN NDIS_STATUS Status,
  1001. IN NDIS_HANDLE NdisSapHandle
  1002. )
  1003. /*++
  1004. Routine Description:
  1005. Arguments:
  1006. Return Value:
  1007. --*/
  1008. {
  1009. PNDIS_CO_SAP_BLOCK pSap = (PNDIS_CO_SAP_BLOCK)NdisSapHandle;
  1010. ASSERT(Status != NDIS_STATUS_PENDING);
  1011. //
  1012. // Complete the call to the client and deref the sap
  1013. //
  1014. (*pSap->AfBlock->ClientEntries.ClDeregisterSapCompleteHandler)(Status,
  1015. pSap->ClientContext);
  1016. if (Status == NDIS_STATUS_SUCCESS)
  1017. {
  1018. ndisDereferenceAf(pSap->AfBlock);
  1019. ndisDereferenceSap(pSap);
  1020. }
  1021. }
  1022. BOOLEAN
  1023. FASTCALL
  1024. ndisReferenceSap(
  1025. IN PNDIS_CO_SAP_BLOCK pSap
  1026. )
  1027. /*++
  1028. Routine Description:
  1029. Arguments:
  1030. Return Value:
  1031. --*/
  1032. {
  1033. KIRQL OldIrql;
  1034. BOOLEAN rc = FALSE;
  1035. ACQUIRE_SPIN_LOCK(&pSap->Lock, &OldIrql);
  1036. if ((pSap->Flags & SAP_CLOSING) == 0)
  1037. {
  1038. pSap->References ++;
  1039. rc = TRUE;
  1040. }
  1041. RELEASE_SPIN_LOCK(&pSap->Lock, OldIrql);
  1042. return rc;
  1043. }
  1044. VOID
  1045. FASTCALL
  1046. ndisDereferenceSap(
  1047. IN PNDIS_CO_SAP_BLOCK pSap
  1048. )
  1049. /*++
  1050. Routine Description:
  1051. Arguments:
  1052. Return Value:
  1053. --*/
  1054. {
  1055. KIRQL OldIrql;
  1056. BOOLEAN Done = FALSE;
  1057. ACQUIRE_SPIN_LOCK(&pSap->Lock, &OldIrql);
  1058. ASSERT(pSap->References > 0);
  1059. pSap->References --;
  1060. if (pSap->References == 0)
  1061. {
  1062. ASSERT(pSap->Flags & SAP_CLOSING);
  1063. Done = TRUE;
  1064. }
  1065. RELEASE_SPIN_LOCK(&pSap->Lock, OldIrql);
  1066. if (Done)
  1067. FREE_POOL(pSap);
  1068. }
  1069. NDIS_STATUS
  1070. NdisCoCreateVc(
  1071. IN NDIS_HANDLE NdisBindingHandle,
  1072. IN NDIS_HANDLE NdisAfHandle OPTIONAL,
  1073. IN NDIS_HANDLE ProtocolVcContext,
  1074. IN OUT PNDIS_HANDLE NdisVcHandle
  1075. )
  1076. /*++
  1077. Routine Description:
  1078. This is a call from either the call-manager or from the client to create a vc.
  1079. The vc would then be owned by call-manager (signalling vc) or the client.
  1080. This is a synchronous call to all parties and simply creates an end-point over
  1081. which either incoming calls can be dispatched or out-going calls can be made.
  1082. Combined Miniport/Call Manager drivers call NdisMCmCreateVc instead of NdisCoCreateVc.
  1083. Arguments:
  1084. NdisBindingHandle - Pointer to the caller's NDIS_OPEN_BLOCK.
  1085. NdisAfHandle - Pointer to the AF Block. Not specified for call-manager's private vcs.
  1086. NdisVcHandle - Where the handle to this Vc will be returned. If this is non-NULL,
  1087. then we assume a valid Vc and return a new handle to it (this would be
  1088. a call from the NDIS Proxy to create a second handle to an existing Vc).
  1089. Return Value:
  1090. NDIS_STATUS_SUCCESS if all the components succeed.
  1091. ErrorCode to signify why the call failed.
  1092. --*/
  1093. {
  1094. NDIS_STATUS Status;
  1095. PNDIS_OPEN_BLOCK Open;
  1096. PNDIS_MINIPORT_BLOCK Miniport;
  1097. PNDIS_CO_AF_BLOCK pAf;
  1098. PNDIS_CO_VC_PTR_BLOCK VcPtr; // VcPtr is returned in NdisVcHandle
  1099. PNDIS_CO_VC_PTR_BLOCK ExistingVcPtr; // Passed in optionally by caller
  1100. PNDIS_CO_VC_BLOCK VcBlock; // Created if ExistingVcPtr is NULL
  1101. KIRQL OldIrql;
  1102. BOOLEAN bCallerIsProxy;
  1103. BOOLEAN bCallerIsClient;
  1104. BOOLEAN bVcToComboMiniport; // VC being created to Integrated MCM
  1105. DBGPRINT(DBG_COMP_CO, DBG_LEVEL_INFO,
  1106. ("=>NdisCoCreateVc\n"));
  1107. //
  1108. // Get the caller's open for the miniport.
  1109. //
  1110. Open = (PNDIS_OPEN_BLOCK)NdisBindingHandle;
  1111. Miniport = Open->MiniportHandle;
  1112. pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
  1113. //
  1114. // Is this VC being created to an integrated call manager + miniport driver?
  1115. //
  1116. bVcToComboMiniport = ((pAf) && ((pAf->Flags & AF_COMBO) != 0));
  1117. //
  1118. // The caller is either a Client or a Call manager.
  1119. //
  1120. bCallerIsClient = ((pAf != NULL) && (Open == pAf->ClientOpen));
  1121. //
  1122. // The caller could be a Proxy protocol.
  1123. //
  1124. bCallerIsProxy = ((Open->ProtocolHandle->ProtocolCharacteristics.Flags & NDIS_PROTOCOL_PROXY) != 0);
  1125. //
  1126. // A proxy protocol could pass in its handle to an existing VC, in order
  1127. // to "duplicate" it to another client.
  1128. //
  1129. ExistingVcPtr = *NdisVcHandle;
  1130. //
  1131. // Initialize.
  1132. //
  1133. VcPtr = NULL;
  1134. VcBlock = NULL;
  1135. Status = NDIS_STATUS_SUCCESS;
  1136. do
  1137. {
  1138. //
  1139. // Only a proxy protocol can pass in an existing VC pointer.
  1140. //
  1141. if (ExistingVcPtr && !bCallerIsProxy)
  1142. {
  1143. Status = NDIS_STATUS_FAILURE;
  1144. break;
  1145. }
  1146. //
  1147. // Allocate context for this VC creation: a VC Pointer Block.
  1148. // We return a pointer to this as the NdisVcHandle for the caller.
  1149. //
  1150. VcPtr = ALLOC_FROM_POOL(sizeof(NDIS_CO_VC_PTR_BLOCK), NDIS_TAG_CO);
  1151. if (VcPtr == NULL)
  1152. {
  1153. Status = NDIS_STATUS_RESOURCES;
  1154. break;
  1155. }
  1156. //
  1157. // Initialize the VC Ptr
  1158. //
  1159. NdisZeroMemory(VcPtr, sizeof(NDIS_CO_VC_PTR_BLOCK));
  1160. INITIALIZE_SPIN_LOCK(&VcPtr->Lock);
  1161. InitializeListHead(&VcPtr->CallMgrLink);
  1162. InitializeListHead(&VcPtr->ClientLink);
  1163. InitializeListHead(&VcPtr->VcLink);
  1164. if (ExistingVcPtr == NULL)
  1165. {
  1166. //
  1167. // New VC being created. Allocate and prepare the base VC block.
  1168. //
  1169. DBGPRINT(DBG_COMP_CO, DBG_LEVEL_INFO,
  1170. ("NdisCoCreateVc: passed in ptr == NULL\n"));
  1171. VcBlock = ALLOC_FROM_POOL(sizeof(NDIS_CO_VC_BLOCK), NDIS_TAG_CO);
  1172. if (VcBlock == NULL)
  1173. {
  1174. Status = NDIS_STATUS_RESOURCES;
  1175. FREE_POOL(VcPtr);
  1176. VcPtr = NULL;
  1177. break;
  1178. }
  1179. //
  1180. // Initialize the VC block
  1181. //
  1182. NdisZeroMemory(VcBlock, sizeof(NDIS_CO_VC_BLOCK));
  1183. INITIALIZE_SPIN_LOCK(&VcBlock->Lock);
  1184. //
  1185. // Stick the Miniport in the VC for use in NdisM functions
  1186. //
  1187. VcBlock->Miniport = Miniport;
  1188. if (!bVcToComboMiniport)
  1189. {
  1190. //
  1191. // Call the miniport to get its context for this VC.
  1192. //
  1193. Status = (*Open->MiniportCoCreateVcHandler)(Miniport->MiniportAdapterContext,
  1194. VcPtr,
  1195. &VcPtr->MiniportContext);
  1196. if (Status != NDIS_STATUS_SUCCESS)
  1197. {
  1198. FREE_POOL(VcBlock);
  1199. break;
  1200. }
  1201. }
  1202. }
  1203. else
  1204. {
  1205. //
  1206. // A VC Pointer was passed in.
  1207. //
  1208. DBGPRINT(DBG_COMP_CO, DBG_LEVEL_INFO,
  1209. ("NdisCoCreateVc: NdisVcHandle is not NULL!\n"));
  1210. //
  1211. // Get the Vc from the passed-in VcPtr.
  1212. //
  1213. VcBlock = ExistingVcPtr->VcBlock;
  1214. //
  1215. // Copy the Miniport Context into the new VC ptr.
  1216. //
  1217. VcPtr->MiniportContext = ExistingVcPtr->MiniportContext;
  1218. }
  1219. //
  1220. // Cache some miniport handlers in the new VC pointer Block
  1221. //
  1222. VcPtr->WCoSendPacketsHandler = Miniport->DriverHandle->MiniportCharacteristics.CoSendPacketsHandler;
  1223. if (!bVcToComboMiniport)
  1224. {
  1225. //
  1226. // For an MCM driver, CreateVc and DeleteVc go only to the Call Manager
  1227. // section.
  1228. //
  1229. VcPtr->WCoDeleteVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoDeleteVcHandler;
  1230. }
  1231. VcPtr->WCoActivateVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoActivateVcHandler;
  1232. VcPtr->WCoDeactivateVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoDeactivateVcHandler;
  1233. //
  1234. // Set up some reverse pointers in the new VC Pointer Block
  1235. //
  1236. VcPtr->Miniport = Miniport;
  1237. VcPtr->VcBlock = VcBlock;
  1238. VcPtr->AfBlock = pAf;
  1239. VcPtr->References = 1;
  1240. VcPtr->pVcFlags = &VcBlock->Flags;
  1241. if (ARGUMENT_PRESENT(NdisAfHandle))
  1242. {
  1243. //
  1244. // This VC is associated with an AF block, meaning that it is
  1245. // a normal Client-CM-Miniport VC.
  1246. //
  1247. VcPtr->ClientOpen = pAf->ClientOpen;
  1248. VcPtr->CallMgrOpen = pAf->CallMgrOpen;
  1249. //
  1250. // Cache non-data path client handlers in new VcPtr.
  1251. //
  1252. VcPtr->ClModifyCallQoSCompleteHandler = pAf->ClientEntries.ClModifyCallQoSCompleteHandler;
  1253. VcPtr->ClIncomingCallQoSChangeHandler = pAf->ClientEntries.ClIncomingCallQoSChangeHandler;
  1254. VcPtr->ClCallConnectedHandler = pAf->ClientEntries.ClCallConnectedHandler;
  1255. VcPtr->CmActivateVcCompleteHandler = pAf->CallMgrEntries->CmActivateVcCompleteHandler;
  1256. VcPtr->CmDeactivateVcCompleteHandler = pAf->CallMgrEntries->CmDeactivateVcCompleteHandler;
  1257. VcPtr->CmModifyCallQoSHandler = pAf->CallMgrEntries->CmModifyCallQoSHandler;
  1258. //
  1259. // Mark this VC if the proxy is handing it off to a proxied client.
  1260. //
  1261. if (ExistingVcPtr != NULL)
  1262. {
  1263. VcBlock->Flags |= VC_HANDOFF_IN_PROGRESS;
  1264. }
  1265. //
  1266. // Update data path handlers based on who is calling this, and for
  1267. // what purpose.
  1268. //
  1269. if (!bCallerIsProxy)
  1270. {
  1271. VcBlock->ClientOpen = pAf->ClientOpen;
  1272. VcBlock->CoReceivePacketHandler = pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler;
  1273. VcBlock->CoSendCompleteHandler = pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoSendCompleteHandler;
  1274. VcPtr->OwnsVcBlock = TRUE;
  1275. if (bCallerIsClient)
  1276. {
  1277. //
  1278. // Client-created VC, for an outgoing call.
  1279. //
  1280. VcBlock->pClientVcPtr = VcPtr;
  1281. }
  1282. else
  1283. {
  1284. //
  1285. // Call Manager-created VC, for an incoming call.
  1286. //
  1287. VcBlock->pProxyVcPtr = VcPtr;
  1288. }
  1289. }
  1290. else
  1291. {
  1292. //
  1293. // The caller is a proxy.
  1294. //
  1295. if (bCallerIsClient)
  1296. {
  1297. //
  1298. // CreateVc from a proxy client to a real Call manager.
  1299. //
  1300. if (ExistingVcPtr == NULL)
  1301. {
  1302. //
  1303. // Proxy client creating a new VC, e.g. for a TAPI outgoing call.
  1304. //
  1305. VcBlock->ClientOpen = pAf->ClientOpen;
  1306. VcBlock->CoReceivePacketHandler = pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler;
  1307. VcBlock->CoSendCompleteHandler = pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoSendCompleteHandler;
  1308. }
  1309. else
  1310. {
  1311. //
  1312. // Proxy client creating a VC on behalf of a CreateVc called
  1313. // by a proxied client. The data handlers belong to the
  1314. // proxied client, but deletion of this VC does not.
  1315. //
  1316. VcBlock->pClientVcPtr = ExistingVcPtr;
  1317. ExistingVcPtr->OwnsVcBlock = FALSE; // Real (Proxied) Client doesn't own it
  1318. }
  1319. VcBlock->pProxyVcPtr = VcPtr;
  1320. VcPtr->OwnsVcBlock = TRUE; // Proxy client owns it
  1321. }
  1322. else
  1323. {
  1324. //
  1325. // CreateVc from a proxy Call manager to a proxied client.
  1326. //
  1327. VcBlock->ClientOpen = pAf->ClientOpen;
  1328. VcBlock->CoReceivePacketHandler = pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler;
  1329. VcBlock->CoSendCompleteHandler = pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoSendCompleteHandler;
  1330. VcBlock->pClientVcPtr = VcPtr;
  1331. if (ExistingVcPtr != NULL)
  1332. {
  1333. //
  1334. // Proxy CM forwarding a call to a proxied client.
  1335. //
  1336. VcBlock->pProxyVcPtr = ExistingVcPtr;
  1337. ExistingVcPtr->OwnsVcBlock = TRUE;
  1338. }
  1339. else
  1340. {
  1341. //
  1342. // Proxy CM creating a fresh VC to a proxied client.
  1343. // No well-known examples of this case, here for completeness.
  1344. //
  1345. VcPtr->OwnsVcBlock = TRUE;
  1346. }
  1347. }
  1348. }
  1349. //
  1350. // Determine who the caller is and initialize the other. NOTE: As soon as the Proxy Create handler
  1351. // is called, this function can get re-entered. Lock down the VcPtr.
  1352. //
  1353. ACQUIRE_SPIN_LOCK(&VcPtr->Lock, &OldIrql);
  1354. if (Open == pAf->ClientOpen)
  1355. {
  1356. VcPtr->ClientContext = ProtocolVcContext;
  1357. //
  1358. // Call-up to the call-manager now to get its context
  1359. //
  1360. Status = (*pAf->CallMgrEntries->CmCreateVcHandler)(pAf->CallMgrContext,
  1361. VcPtr,
  1362. &VcPtr->CallMgrContext);
  1363. if (bVcToComboMiniport)
  1364. {
  1365. //
  1366. // Need the MiniportContext field filled in for NdisCoSendPackets
  1367. //
  1368. VcPtr->MiniportContext = VcPtr->CallMgrContext;
  1369. }
  1370. }
  1371. else
  1372. {
  1373. ASSERT(pAf->CallMgrOpen == Open);
  1374. VcPtr->CallMgrContext = ProtocolVcContext;
  1375. //
  1376. // Call-up to the client now to get its context
  1377. //
  1378. Status = (*pAf->ClientOpen->CoCreateVcHandler)(pAf->ClientContext,
  1379. VcPtr,
  1380. &VcPtr->ClientContext);
  1381. }
  1382. //
  1383. // Set up Client Context in VC if non-proxy, so the miniport passes the right client
  1384. // context (client's handle to the VcPtr) when indicating packets. If the passd-in handle
  1385. // is NULL, it's simple -- move the context. If it's not NULL, AND this is a Proxy call mgr,
  1386. // move it so data goes to the new client and not to the Proxy.
  1387. //
  1388. if ((Status == NDIS_STATUS_SUCCESS) &&
  1389. ((ExistingVcPtr == NULL) || (bCallerIsProxy && !bCallerIsClient)))
  1390. {
  1391. VcBlock->ClientContext = VcPtr->ClientContext;
  1392. }
  1393. if (ExistingVcPtr != NULL)
  1394. {
  1395. VcBlock->Flags &= ~VC_HANDOFF_IN_PROGRESS;
  1396. }
  1397. RELEASE_SPIN_LOCK(&VcPtr->Lock, OldIrql);
  1398. if (Status == NDIS_STATUS_SUCCESS)
  1399. {
  1400. //
  1401. // Link this VC Pointer in the client's and call manager's
  1402. // Open blocks. Also remember the DeleteVc handler of the
  1403. // non-creator of this VC pointer, to be called when this
  1404. // VC pointer is deleted.
  1405. //
  1406. if (bCallerIsClient)
  1407. {
  1408. //
  1409. // Link into Client's Open block.
  1410. //
  1411. ExInterlockedInsertHeadList(&Open->InactiveVcHead,
  1412. &VcPtr->ClientLink,
  1413. &Open->SpinLock);
  1414. VcPtr->DeleteVcContext = VcPtr->CallMgrContext;
  1415. VcPtr->CoDeleteVcHandler = pAf->CallMgrEntries->CmDeleteVcHandler;
  1416. if (!bVcToComboMiniport)
  1417. {
  1418. //
  1419. // Link into CM's Open block.
  1420. //
  1421. ExInterlockedInsertHeadList(&pAf->CallMgrOpen->InactiveVcHead,
  1422. &VcPtr->CallMgrLink,
  1423. &pAf->CallMgrOpen->SpinLock);
  1424. }
  1425. }
  1426. else
  1427. {
  1428. //
  1429. // Caller is a Call Manager.
  1430. //
  1431. VcPtr->DeleteVcContext = VcPtr->ClientContext;
  1432. VcPtr->CoDeleteVcHandler = pAf->ClientOpen->CoDeleteVcHandler;
  1433. ExInterlockedInsertHeadList(&Open->InactiveVcHead,
  1434. &VcPtr->CallMgrLink,
  1435. &Open->SpinLock);
  1436. ExInterlockedInsertHeadList(&pAf->ClientOpen->InactiveVcHead,
  1437. &VcPtr->ClientLink,
  1438. &pAf->ClientOpen->SpinLock);
  1439. }
  1440. }
  1441. else
  1442. {
  1443. //
  1444. // The target protocol (Client or CM) failed CreateVc.
  1445. // Tell the miniport about it.
  1446. //
  1447. NDIS_STATUS Sts;
  1448. if (!bVcToComboMiniport)
  1449. {
  1450. Sts = (*VcPtr->WCoDeleteVcHandler)(VcPtr->MiniportContext);
  1451. }
  1452. if (ExistingVcPtr == NULL)
  1453. {
  1454. FREE_POOL(VcBlock);
  1455. }
  1456. FREE_POOL(VcPtr);
  1457. VcPtr = NULL;
  1458. }
  1459. }
  1460. else
  1461. {
  1462. //
  1463. // No AF handle present. This is a call-manager only VC and so the call-manager
  1464. // is the client and there is no call-manager associated with it. This VC cannot
  1465. // be used with a ClMakeCall or CmDispatchIncomingCall. Set the client values to the
  1466. // call-manager
  1467. //
  1468. DBGPRINT(DBG_COMP_CO, DBG_LEVEL_INFO,
  1469. ("NdisCoCreateVc: signaling vc\n"));
  1470. VcPtr->ClientOpen = Open;
  1471. VcPtr->ClientContext = ProtocolVcContext;
  1472. VcBlock->pClientVcPtr = VcPtr;
  1473. VcPtr->OwnsVcBlock = TRUE; // CM owns the VC block
  1474. VcBlock->ClientContext = VcPtr->ClientContext;
  1475. VcBlock->ClientOpen = Open;
  1476. VcBlock->CoSendCompleteHandler = Open->ProtocolHandle->ProtocolCharacteristics.CoSendCompleteHandler;
  1477. VcBlock->CoReceivePacketHandler = Open->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler;
  1478. //
  1479. // Do set the following call-manager entries since this VC will need to be
  1480. // activated. Also set the call-managers context for the same reasons.
  1481. //
  1482. VcPtr->CmActivateVcCompleteHandler = Open->CmActivateVcCompleteHandler;
  1483. VcPtr->CmDeactivateVcCompleteHandler = Open->CmDeactivateVcCompleteHandler;
  1484. VcPtr->CallMgrContext = ProtocolVcContext;
  1485. //
  1486. // Link this in the open_block
  1487. //
  1488. ExInterlockedInsertHeadList(&Open->InactiveVcHead,
  1489. &VcPtr->ClientLink,
  1490. &Open->SpinLock);
  1491. }
  1492. break;
  1493. }
  1494. while (FALSE);
  1495. if (NDIS_STATUS_SUCCESS == Status)
  1496. {
  1497. LARGE_INTEGER Increment = {0, 1};
  1498. //
  1499. // Assign this VC an ID and update the miniports count.
  1500. //
  1501. VcPtr->VcIndex = ExInterlockedAddLargeInteger(&Miniport->VcIndex, Increment, &ndisGlobalLock);
  1502. }
  1503. *NdisVcHandle = VcPtr;
  1504. DBGPRINT(DBG_COMP_CO, DBG_LEVEL_INFO,
  1505. ("<=NdisCoCreateVc: VcPtr %x, Status %x\n", VcPtr, Status));
  1506. return Status;
  1507. }
  1508. NDIS_STATUS
  1509. NdisCoDeleteVc(
  1510. IN PNDIS_HANDLE NdisVcHandle
  1511. )
  1512. /*++
  1513. Routine Description:
  1514. Synchronous call from either the call-manager or the client to delete a VC. Only inactive
  1515. VCs can be deleted. Active Vcs or partially active Vcs cannot be.
  1516. Arguments:
  1517. NdisVcHandle The Vc to delete
  1518. Return Value:
  1519. NDIS_STATUS_SUCCESS If all goes well
  1520. NDIS_STATUS_NOT_ACCEPTED If Vc is active
  1521. NDIS_STATUS_CLOSING If Vc de-activation is pending
  1522. --*/
  1523. {
  1524. PNDIS_CO_VC_PTR_BLOCK VcPtr = (PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle;
  1525. NDIS_STATUS Status;
  1526. KIRQL OldIrql;
  1527. DBGPRINT(DBG_COMP_CO, DBG_LEVEL_INFO,
  1528. ("NdisCoDeleteVc VcPtr %x/%x, Ref %d VcBlock %x, Flags %x\n",
  1529. VcPtr, VcPtr->CallFlags, VcPtr->References, VcPtr->VcBlock, *VcPtr->pVcFlags));
  1530. ACQUIRE_SPIN_LOCK(&VcPtr->Lock, &OldIrql);
  1531. if (*VcPtr->pVcFlags & (VC_ACTIVE | VC_ACTIVATE_PENDING))
  1532. {
  1533. Status = NDIS_STATUS_NOT_ACCEPTED;
  1534. }
  1535. else if (*VcPtr->pVcFlags & (VC_DEACTIVATE_PENDING))
  1536. {
  1537. Status = NDIS_STATUS_CLOSING;
  1538. }
  1539. else
  1540. {
  1541. //
  1542. // Take this VcPtr out of the VC's list
  1543. //
  1544. // If the VC isn't already closing mark it as closing.
  1545. //
  1546. // We call the miniport's delete handler if the VC block's Proxy ptr points
  1547. // to this VC ptr. (This indicates that the VC block is owned/created by the
  1548. // CM/Proxy, not the CL).
  1549. //
  1550. // NOTE: We don't delete the VC until all these pointers
  1551. // have gone since the Proxy may wish to redirect the VC to another protocol.
  1552. // However, in general the Proxy would follow a call to DeleteVc for the Client ptr
  1553. // with one for the Proxy.
  1554. // (Note the MP context refers to the VC, not the VcPtr).
  1555. //
  1556. VcPtr->CallFlags |= VC_PTR_BLOCK_CLOSING;
  1557. if (VcPtr->OwnsVcBlock &&
  1558. (VcPtr->WCoDeleteVcHandler != NULL))
  1559. {
  1560. *VcPtr->pVcFlags |= VC_DELETE_PENDING;
  1561. }
  1562. //
  1563. // If this VC is responding to WMI then get rid of it.
  1564. //
  1565. if (NULL != VcPtr->VcInstanceName.Buffer)
  1566. {
  1567. //
  1568. // Notify the removal of this VC.
  1569. //
  1570. PWNODE_SINGLE_INSTANCE wnode;
  1571. PUCHAR ptmp;
  1572. NTSTATUS NtStatus;
  1573. ndisSetupWmiNode(VcPtr->Miniport,
  1574. &VcPtr->VcInstanceName,
  1575. 0,
  1576. (PVOID)&GUID_NDIS_NOTIFY_VC_REMOVAL,
  1577. &wnode);
  1578. if (wnode != NULL)
  1579. {
  1580. //
  1581. // Indicate the event to WMI. WMI will take care of freeing
  1582. // the WMI struct back to pool.
  1583. //
  1584. NtStatus = IoWMIWriteEvent(wnode);
  1585. if (!NT_SUCCESS(NtStatus))
  1586. {
  1587. DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
  1588. ("IoWMIWriteEvent failed %lx\n", NtStatus));
  1589. FREE_POOL(wnode);
  1590. }
  1591. }
  1592. ACQUIRE_SPIN_LOCK_DPC(&VcPtr->Miniport->VcCountLock);
  1593. //
  1594. // Remove the VC from the list of WMI enabled VCs
  1595. //
  1596. RemoveEntryList(&VcPtr->WmiLink);
  1597. //
  1598. // Decrement the number of VC's that have names assigned to them.
  1599. //
  1600. VcPtr->Miniport->VcCount--;
  1601. //
  1602. // Free the VC's name buffer.
  1603. //
  1604. FREE_POOL(VcPtr->VcInstanceName.Buffer);
  1605. VcPtr->VcInstanceName.Buffer = NULL;
  1606. VcPtr->VcInstanceName.Length = VcPtr->VcInstanceName.MaximumLength = 0;
  1607. RELEASE_SPIN_LOCK_DPC(&VcPtr->Miniport->VcCountLock);
  1608. }
  1609. //
  1610. // Next the non-creator's delete handler, if any
  1611. //
  1612. if (VcPtr->CoDeleteVcHandler != NULL)
  1613. {
  1614. Status = (*VcPtr->CoDeleteVcHandler)(VcPtr->DeleteVcContext);
  1615. ASSERT(Status == NDIS_STATUS_SUCCESS);
  1616. }
  1617. //
  1618. // Now de-link the VcPtr from the client and the call-manager
  1619. //
  1620. ACQUIRE_SPIN_LOCK_DPC(&VcPtr->ClientOpen->SpinLock);
  1621. RemoveEntryList(&VcPtr->ClientLink);
  1622. RELEASE_SPIN_LOCK_DPC(&VcPtr->ClientOpen->SpinLock);
  1623. if (VcPtr->CallMgrOpen != NULL)
  1624. {
  1625. ACQUIRE_SPIN_LOCK_DPC(&VcPtr->CallMgrOpen->SpinLock);
  1626. RemoveEntryList(&VcPtr->CallMgrLink);
  1627. RELEASE_SPIN_LOCK_DPC(&VcPtr->CallMgrOpen->SpinLock);
  1628. }
  1629. Status = NDIS_STATUS_SUCCESS;
  1630. }
  1631. RELEASE_SPIN_LOCK(&VcPtr->Lock, OldIrql);
  1632. if (Status == NDIS_STATUS_SUCCESS)
  1633. {
  1634. ndisDereferenceVcPtr(VcPtr);
  1635. }
  1636. return Status;
  1637. }
  1638. NDIS_STATUS
  1639. NdisMCmCreateVc(
  1640. IN NDIS_HANDLE MiniportAdapterHandle,
  1641. IN NDIS_HANDLE NdisAfHandle,
  1642. IN NDIS_HANDLE MiniportVcContext,
  1643. OUT PNDIS_HANDLE NdisVcHandle
  1644. )
  1645. /*++
  1646. Routine Description:
  1647. This is a call by the miniport (with a resident CM) to create a Vc for an incoming call.
  1648. Arguments:
  1649. MiniportAdapterHandle - Miniport's adapter context
  1650. NdisAfHandle - Pointer to the AF Block.
  1651. MiniportVcContext - Miniport's context to associate with this vc.
  1652. NdisVcHandle - Where the handle to this Vc will be returned.
  1653. Return Value:
  1654. NDIS_STATUS_SUCCESS if all the components succeed.
  1655. ErrorCode to signify why the call failed.
  1656. --*/
  1657. {
  1658. PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
  1659. PNDIS_CO_VC_BLOCK VcBlock;
  1660. PNDIS_CO_AF_BLOCK pAf;
  1661. PNDIS_CO_VC_PTR_BLOCK VcPtr;
  1662. NDIS_STATUS Status;
  1663. *NdisVcHandle = NULL;
  1664. //
  1665. // Allocate the memory for NDIS_VC_BLOCK
  1666. //
  1667. VcBlock = ALLOC_FROM_POOL(sizeof(NDIS_CO_VC_BLOCK), NDIS_TAG_CO);
  1668. if (VcBlock == NULL)
  1669. return NDIS_STATUS_RESOURCES;
  1670. //
  1671. // Initialize the VC block
  1672. //
  1673. NdisZeroMemory(VcBlock, sizeof(NDIS_CO_VC_BLOCK));
  1674. INITIALIZE_SPIN_LOCK(&VcBlock->Lock);
  1675. //
  1676. // Allocate the memory for NDIS_VC_PTR_BLOCK
  1677. //
  1678. VcPtr = ALLOC_FROM_POOL(sizeof(NDIS_CO_VC_PTR_BLOCK), NDIS_TAG_CO);
  1679. if (VcPtr == NULL)
  1680. {
  1681. FREE_POOL(VcBlock);
  1682. return NDIS_STATUS_RESOURCES;
  1683. }
  1684. //
  1685. // Initialize the VC Pointer block
  1686. //
  1687. NdisZeroMemory(VcPtr, sizeof(NDIS_CO_VC_PTR_BLOCK));
  1688. INITIALIZE_SPIN_LOCK(&VcPtr->Lock);
  1689. //
  1690. // Cache some miniport handlers
  1691. //
  1692. VcPtr->Miniport = Miniport;
  1693. VcPtr->WCoSendPacketsHandler = Miniport->DriverHandle->MiniportCharacteristics.CoSendPacketsHandler;
  1694. VcPtr->WCoDeleteVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoDeleteVcHandler;
  1695. VcPtr->WCoActivateVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoActivateVcHandler;
  1696. VcPtr->WCoDeactivateVcHandler = Miniport->DriverHandle->MiniportCharacteristics.CoDeactivateVcHandler;
  1697. VcBlock->Miniport = Miniport;
  1698. VcBlock->MiniportContext = MiniportVcContext;
  1699. VcPtr->MiniportContext = MiniportVcContext;
  1700. //
  1701. // Set up the VcBlock in the new VcPtr
  1702. //
  1703. VcPtr->VcBlock = VcBlock;
  1704. // VcPtrs to preempt potential for unsynched state when Protocols, Miniports and
  1705. // Miniport-exported Call Managers refer to VCs/VcPtrs as appropriate...similar
  1706. // for References, which is accessed from Vc directly in IndicateReceivePacket.
  1707. //
  1708. VcPtr->pVcFlags = &VcBlock->Flags;
  1709. //
  1710. // We have only one reference for vc on creation.
  1711. //
  1712. pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
  1713. VcPtr->AfBlock = pAf;
  1714. VcPtr->References = 1;
  1715. ASSERT(ARGUMENT_PRESENT(NdisAfHandle));
  1716. VcPtr->ClientOpen = pAf->ClientOpen;
  1717. VcPtr->CallMgrOpen = NULL;
  1718. VcBlock->ClientOpen = pAf->ClientOpen;
  1719. VcBlock->CoSendCompleteHandler = pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoSendCompleteHandler;
  1720. VcBlock->CoReceivePacketHandler = pAf->ClientOpen->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler;
  1721. VcPtr->ClModifyCallQoSCompleteHandler = pAf->ClientEntries.ClModifyCallQoSCompleteHandler;
  1722. VcPtr->ClIncomingCallQoSChangeHandler = pAf->ClientEntries.ClIncomingCallQoSChangeHandler;
  1723. VcPtr->ClCallConnectedHandler = pAf->ClientEntries.ClCallConnectedHandler;
  1724. VcPtr->CmActivateVcCompleteHandler = pAf->CallMgrEntries->CmActivateVcCompleteHandler;
  1725. VcPtr->CmDeactivateVcCompleteHandler = pAf->CallMgrEntries->CmDeactivateVcCompleteHandler;
  1726. VcPtr->CmModifyCallQoSHandler = pAf->CallMgrEntries->CmModifyCallQoSHandler;
  1727. VcPtr->CallMgrContext = MiniportVcContext;
  1728. VcBlock->CallMgrContext = MiniportVcContext;
  1729. //
  1730. // Call-up to the client now to get its context
  1731. //
  1732. Status = (*pAf->ClientOpen->CoCreateVcHandler)(pAf->ClientContext,
  1733. VcPtr,
  1734. &VcPtr->ClientContext);
  1735. if (Status == NDIS_STATUS_SUCCESS)
  1736. {
  1737. //
  1738. // Setup the client context in the VC block. This may be overwritten by the
  1739. // new client context in a subsequent call to CoCreateVc by the proxy.
  1740. // Link this in the open_block
  1741. //
  1742. VcBlock->ClientContext = VcPtr->ClientContext;
  1743. VcPtr->DeleteVcContext = VcPtr->ClientContext;
  1744. VcPtr->CoDeleteVcHandler = pAf->ClientOpen->CoDeleteVcHandler;
  1745. ExInterlockedInsertHeadList(&pAf->ClientOpen->InactiveVcHead,
  1746. &VcPtr->ClientLink,
  1747. &pAf->ClientOpen->SpinLock);
  1748. VcBlock->pClientVcPtr = VcPtr;
  1749. }
  1750. else
  1751. {
  1752. FREE_POOL(VcBlock);
  1753. FREE_POOL(VcPtr);
  1754. VcPtr = NULL;
  1755. }
  1756. *NdisVcHandle = VcPtr;
  1757. return Status;
  1758. }
  1759. NDIS_STATUS
  1760. NdisMCmDeleteVc(
  1761. IN PNDIS_HANDLE NdisVcHandle
  1762. )
  1763. /*++
  1764. Routine Description:
  1765. This is a called by the miniport (with a resident CM) to delete a Vc created by it. Identical to
  1766. NdisMCoDeleteVc but a seperate api for completeness.
  1767. Arguments:
  1768. NdisVcHandle The Vc to delete
  1769. Return Value:
  1770. NDIS_STATUS_SUCCESS If all goes well
  1771. NDIS_STATUS_NOT_ACCEPTED If Vc is active
  1772. NDIS_STATUS_CLOSING If Vc de-activation is pending
  1773. --*/
  1774. {
  1775. PNDIS_CO_VC_PTR_BLOCK VcPtr = (PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle;
  1776. PNDIS_CO_VC_BLOCK VcBlock = VcPtr->VcBlock;
  1777. if (VcBlock->pProxyVcPtr != NULL)
  1778. {
  1779. return (NdisCoDeleteVc ((PNDIS_HANDLE)VcBlock->pProxyVcPtr));
  1780. }
  1781. else
  1782. {
  1783. ASSERT(VcBlock->pClientVcPtr != NULL);
  1784. return (NdisCoDeleteVc((PNDIS_HANDLE)VcBlock->pClientVcPtr));
  1785. }
  1786. }
  1787. NDIS_STATUS
  1788. NdisCmActivateVc(
  1789. IN PNDIS_HANDLE NdisVcHandle,
  1790. IN OUT PCO_CALL_PARAMETERS CallParameters
  1791. )
  1792. /*++
  1793. Routine Description:
  1794. Called by the call-manager to set the Vc parameters on the Vc. The wrapper
  1795. saved the media id (e.g. Vpi/Vci for atm) in the Vc so that a p-mode protocol can
  1796. get this info as well on receives.
  1797. Arguments:
  1798. NdisVcHandle The Vc to set parameters on.
  1799. MediaParameters The parameters to set.
  1800. Return Value:
  1801. NDIS_STATUS_PENDING If the miniport pends the call.
  1802. NDIS_STATUS_CLOSING If Vc de-activation is pending
  1803. --*/
  1804. {
  1805. PNDIS_CO_VC_PTR_BLOCK VcPtr = (PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle;
  1806. PNDIS_CO_VC_BLOCK VcBlock = (PNDIS_CO_VC_BLOCK)VcPtr->VcBlock;
  1807. NDIS_STATUS Status;
  1808. KIRQL OldIrql;
  1809. DBGPRINT(DBG_COMP_CO, DBG_LEVEL_INFO,
  1810. ("NdisCmActivateVC: VcPtr is 0x%x; VC is 0x%x; MiniportContext is 0x%x\n", VcPtr,
  1811. VcPtr->VcBlock, VcPtr->MiniportContext));
  1812. ACQUIRE_SPIN_LOCK(&VcPtr->Lock, &OldIrql);
  1813. //
  1814. // Make sure the Vc does not have an activation/de-activation pending
  1815. // Not that it is ok for the Vc to be already active - then it is a re-activation.
  1816. //
  1817. if (*VcPtr->pVcFlags & VC_ACTIVATE_PENDING)
  1818. {
  1819. Status = NDIS_STATUS_NOT_ACCEPTED;
  1820. }
  1821. else if (*VcPtr->pVcFlags & VC_DEACTIVATE_PENDING)
  1822. {
  1823. Status = NDIS_STATUS_CLOSING;
  1824. }
  1825. else
  1826. {
  1827. *VcPtr->pVcFlags |= VC_ACTIVATE_PENDING;
  1828. //
  1829. // Save the media id for the Vc
  1830. //
  1831. Status = NDIS_STATUS_SUCCESS;
  1832. ASSERT(CallParameters->MediaParameters->MediaSpecific.Length >= sizeof(ULONGLONG));
  1833. VcBlock->VcId = *(UNALIGNED ULONGLONG *)(&CallParameters->MediaParameters->MediaSpecific.Parameters);
  1834. }
  1835. //
  1836. // Set up CM Context and ActivateComplete handler in VC before
  1837. // calling miniports activate func
  1838. //
  1839. VcBlock->CmActivateVcCompleteHandler = VcPtr->CmActivateVcCompleteHandler;
  1840. VcBlock->CallMgrContext = VcPtr->CallMgrContext;
  1841. RELEASE_SPIN_LOCK(&VcPtr->Lock, OldIrql);
  1842. if (Status == NDIS_STATUS_SUCCESS)
  1843. {
  1844. //
  1845. // Now call down to the miniport to activate it. MiniportContext contains
  1846. // Miniport's handle for underlying VC (not VcPtr).
  1847. //
  1848. Status = (*VcPtr->WCoActivateVcHandler)(VcPtr->MiniportContext, CallParameters);
  1849. }
  1850. if (Status != NDIS_STATUS_PENDING)
  1851. {
  1852. NdisMCoActivateVcComplete(Status, VcPtr, CallParameters);
  1853. Status = NDIS_STATUS_PENDING;
  1854. }
  1855. return Status;
  1856. }
  1857. NDIS_STATUS
  1858. NdisMCmActivateVc(
  1859. IN PNDIS_HANDLE NdisVcHandle,
  1860. IN PCO_CALL_PARAMETERS CallParameters
  1861. )
  1862. /*++
  1863. Routine Description:
  1864. Called by the miniport resident call-manager to set the Vc parameters on the Vc.
  1865. Arguments:
  1866. NdisVcHandle The Vc to set parameters on.
  1867. MediaParameters The parameters to set.
  1868. Return Value:
  1869. NDIS_STATUS_CLOSING If Vc de-activation is pending
  1870. --*/
  1871. {
  1872. PNDIS_CO_VC_PTR_BLOCK VcPtr = (PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle;
  1873. PNDIS_CO_VC_BLOCK VcBlock = VcPtr->VcBlock;
  1874. NDIS_STATUS Status;
  1875. KIRQL OldIrql;
  1876. ACQUIRE_SPIN_LOCK(&VcBlock->Lock, &OldIrql);
  1877. VcBlock->Flags |= VC_ACTIVE;
  1878. VcBlock->VcId = *(UNALIGNED ULONGLONG *)(&CallParameters->MediaParameters->MediaSpecific.Parameters);
  1879. RELEASE_SPIN_LOCK(&VcBlock->Lock, OldIrql);
  1880. Status = NDIS_STATUS_SUCCESS;
  1881. return Status;
  1882. }
  1883. VOID
  1884. NdisMCoActivateVcComplete(
  1885. IN NDIS_STATUS Status,
  1886. IN PNDIS_HANDLE NdisVcHandle,
  1887. IN PCO_CALL_PARAMETERS CallParameters
  1888. )
  1889. /*++
  1890. Routine Description:
  1891. Called by the mini-port to complete a pending activation call.
  1892. Also called by CmActivateVc when the miniport doesn't pend the CreateVc call.
  1893. Note that in the second case, we've copied the flags/context/CM function into the
  1894. VC from the VC Ptr.
  1895. Arguments:
  1896. Status Status of activation.
  1897. NdisVcHandle The Vc in question.
  1898. Return Value:
  1899. NONE
  1900. The call-manager's completion routine is called.
  1901. --*/
  1902. {
  1903. PNDIS_CO_VC_PTR_BLOCK VcPtr = (PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle;
  1904. PNDIS_CO_VC_BLOCK VcBlock = VcPtr->VcBlock;
  1905. KIRQL OldIrql;
  1906. ACQUIRE_SPIN_LOCK(&VcBlock->Lock, &OldIrql);
  1907. ASSERT(VcBlock->Flags & VC_ACTIVATE_PENDING);
  1908. VcBlock->Flags &= ~VC_ACTIVATE_PENDING;
  1909. if (Status == NDIS_STATUS_SUCCESS)
  1910. {
  1911. VcBlock->Flags |= VC_ACTIVE;
  1912. }
  1913. RELEASE_SPIN_LOCK(&VcBlock->Lock, OldIrql);
  1914. //
  1915. // Complete the call to the call-manager
  1916. //
  1917. (*VcBlock->CmActivateVcCompleteHandler)(Status, VcBlock->CallMgrContext, CallParameters);
  1918. }
  1919. NDIS_STATUS
  1920. NdisCmDeactivateVc(
  1921. IN PNDIS_HANDLE NdisVcHandle
  1922. )
  1923. /*++
  1924. Routine Description:
  1925. Called by the call-manager to de-activate a Vc.
  1926. Arguments:
  1927. NdisVcHandle The Vc to de-activate the Vc.
  1928. Return Value:
  1929. NDIS_STATUS_PENDING If the miniport pends the call.
  1930. NDIS_STATUS_SUCCESS If all goes well
  1931. NDIS_STATUS_CLOSING If Vc de-activation is pending
  1932. --*/
  1933. {
  1934. PNDIS_CO_VC_PTR_BLOCK VcPtr = (PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle;
  1935. PNDIS_CO_VC_BLOCK VcBlock = VcPtr->VcBlock;
  1936. NDIS_STATUS Status;
  1937. KIRQL OldIrql;
  1938. ACQUIRE_SPIN_LOCK(&VcPtr->Lock, &OldIrql);
  1939. if ((*VcPtr->pVcFlags & (VC_ACTIVE | VC_ACTIVATE_PENDING)) == 0)
  1940. {
  1941. Status = NDIS_STATUS_NOT_ACCEPTED;
  1942. }
  1943. else if (*VcPtr->pVcFlags & VC_DEACTIVATE_PENDING)
  1944. {
  1945. Status = NDIS_STATUS_CLOSING;
  1946. }
  1947. else
  1948. {
  1949. *VcPtr->pVcFlags |= VC_DEACTIVATE_PENDING;
  1950. }
  1951. RELEASE_SPIN_LOCK(&VcPtr->Lock, OldIrql);
  1952. //
  1953. // Set up flags, CM Context and DeactivateComplete handler in VC before
  1954. // calling mimiports deactivate func
  1955. //
  1956. VcBlock->CmDeactivateVcCompleteHandler = VcPtr->CmDeactivateVcCompleteHandler;
  1957. VcBlock->CallMgrContext = VcPtr->CallMgrContext;
  1958. //
  1959. // Now call down to the miniport to de-activate it
  1960. //
  1961. Status = (*VcPtr->WCoDeactivateVcHandler)(VcPtr->MiniportContext);
  1962. if (Status != NDIS_STATUS_PENDING)
  1963. {
  1964. NdisMCoDeactivateVcComplete(Status, VcPtr);
  1965. Status = NDIS_STATUS_PENDING;
  1966. }
  1967. return Status;
  1968. }
  1969. NDIS_STATUS
  1970. NdisMCmDeactivateVc(
  1971. IN PNDIS_HANDLE NdisVcHandle
  1972. )
  1973. /*++
  1974. Routine Description:
  1975. Called by the miniport resident call-manager to de-activate the Vc. This is a
  1976. synchronous call.
  1977. Arguments:
  1978. NdisVcHandle The Vc to set parameters on.
  1979. Return Value:
  1980. NDIS_STATUS_NOT_ACCEPTED If Vc is not activated
  1981. NDIS_STATUS_SUCCESS Otherwise
  1982. --*/
  1983. {
  1984. PNDIS_CO_VC_PTR_BLOCK VcPtr = (PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle;
  1985. PNDIS_CO_VC_BLOCK VcBlock = VcPtr->VcBlock;
  1986. NDIS_STATUS Status;
  1987. KIRQL OldIrql;
  1988. ACQUIRE_SPIN_LOCK(&VcBlock->Lock, &OldIrql);
  1989. if ((VcBlock->Flags & VC_ACTIVE) == 0)
  1990. {
  1991. Status = NDIS_STATUS_NOT_ACCEPTED;
  1992. }
  1993. else
  1994. {
  1995. Status = NDIS_STATUS_SUCCESS;
  1996. VcBlock->Flags &= ~VC_ACTIVE;
  1997. }
  1998. RELEASE_SPIN_LOCK(&VcBlock->Lock, OldIrql);
  1999. return Status;
  2000. }
  2001. VOID
  2002. NdisMCoDeactivateVcComplete(
  2003. IN NDIS_STATUS Status,
  2004. IN PNDIS_HANDLE NdisVcHandle
  2005. )
  2006. /*++
  2007. Routine Description:
  2008. Called by the mini-port to complete a pending de-activation of a Vc.
  2009. Arguments:
  2010. NdisVcHandle The Vc in question.
  2011. Return Value:
  2012. NONE
  2013. The call-manager's completion routine is called.
  2014. --*/
  2015. {
  2016. PNDIS_CO_VC_PTR_BLOCK VcPtr = (PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle;
  2017. PNDIS_CO_VC_BLOCK VcBlock = VcPtr->VcBlock;
  2018. KIRQL OldIrql;
  2019. ACQUIRE_SPIN_LOCK(&VcBlock->Lock, &OldIrql);
  2020. ASSERT(VcBlock->Flags & VC_DEACTIVATE_PENDING);
  2021. VcBlock->Flags &= ~VC_DEACTIVATE_PENDING;
  2022. if (Status == NDIS_STATUS_SUCCESS)
  2023. {
  2024. VcBlock->Flags &= ~VC_ACTIVE;
  2025. }
  2026. RELEASE_SPIN_LOCK(&VcBlock->Lock, OldIrql);
  2027. //
  2028. // Complete the call to the call-manager
  2029. //
  2030. (*VcBlock->CmDeactivateVcCompleteHandler)(Status, VcBlock->CallMgrContext);
  2031. }
  2032. NDIS_STATUS
  2033. NdisClMakeCall(
  2034. IN NDIS_HANDLE NdisVcHandle,
  2035. IN OUT PCO_CALL_PARAMETERS CallParameters,
  2036. IN NDIS_HANDLE ProtocolPartyContext OPTIONAL,
  2037. OUT PNDIS_HANDLE NdisPartyHandle OPTIONAL
  2038. )
  2039. /*++
  2040. Routine Description:
  2041. Arguments:
  2042. Return Value:
  2043. --*/
  2044. {
  2045. PNDIS_CO_VC_PTR_BLOCK VcPtr = (PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle;
  2046. PNDIS_CO_AF_BLOCK pAf;
  2047. PNDIS_CO_PARTY_BLOCK pParty = NULL;
  2048. PVOID CallMgrPartyContext = NULL;
  2049. NDIS_STATUS Status;
  2050. KIRQL OldIrql;
  2051. do
  2052. {
  2053. pAf = VcPtr->AfBlock;
  2054. ASSERT(pAf != NULL);
  2055. if (!ndisReferenceAf(pAf))
  2056. {
  2057. Status = NDIS_STATUS_FAILURE;
  2058. break;
  2059. }
  2060. //
  2061. // Ref the VC for the life of the active vc.
  2062. // This is Deref'd is in MakeCallComplete If the call fails and CloseCallComplete
  2063. // when it succeeds
  2064. //
  2065. if (!ndisReferenceVcPtr(VcPtr))
  2066. {
  2067. ndisDereferenceAf(pAf);
  2068. Status = NDIS_STATUS_FAILURE;
  2069. break;
  2070. }
  2071. if (ARGUMENT_PRESENT(NdisPartyHandle))
  2072. {
  2073. *NdisPartyHandle = NULL;
  2074. pParty = (PNDIS_CO_PARTY_BLOCK)ALLOC_FROM_POOL(sizeof(NDIS_CO_PARTY_BLOCK),
  2075. NDIS_TAG_CO);
  2076. if (pParty == NULL)
  2077. {
  2078. ndisDereferenceAf(pAf);
  2079. ndisDereferenceVcPtr(VcPtr);
  2080. Status = NDIS_STATUS_RESOURCES;
  2081. break;
  2082. }
  2083. pParty->VcPtr = VcPtr;
  2084. pParty->ClientContext = ProtocolPartyContext;
  2085. pParty->ClIncomingDropPartyHandler = pAf->ClientEntries.ClIncomingDropPartyHandler;
  2086. pParty->ClDropPartyCompleteHandler = pAf->ClientEntries.ClDropPartyCompleteHandler;
  2087. }
  2088. ACQUIRE_SPIN_LOCK(&VcPtr->Lock, &OldIrql);
  2089. ASSERT((VcPtr->CallFlags & (VC_CALL_ACTIVE |
  2090. VC_CALL_PENDING |
  2091. VC_CALL_ABORTED |
  2092. VC_CALL_CLOSE_PENDING)) == 0);
  2093. VcPtr->CallFlags |= VC_CALL_PENDING;
  2094. RELEASE_SPIN_LOCK(&VcPtr->Lock, OldIrql);
  2095. //
  2096. // Pass the request off to the call manager
  2097. //
  2098. Status = (*pAf->CallMgrEntries->CmMakeCallHandler)(VcPtr->CallMgrContext,
  2099. CallParameters,
  2100. pParty,
  2101. &CallMgrPartyContext);
  2102. if (Status != NDIS_STATUS_PENDING)
  2103. {
  2104. NdisCmMakeCallComplete(Status,
  2105. VcPtr,
  2106. pParty,
  2107. CallMgrPartyContext,
  2108. CallParameters);
  2109. Status = NDIS_STATUS_PENDING;
  2110. }
  2111. } while (FALSE);
  2112. return Status;
  2113. }
  2114. VOID
  2115. NdisCmMakeCallComplete(
  2116. IN NDIS_STATUS Status,
  2117. IN NDIS_HANDLE NdisVcHandle,
  2118. IN NDIS_HANDLE NdisPartyHandle OPTIONAL,
  2119. IN NDIS_HANDLE CallMgrPartyContext OPTIONAL,
  2120. IN PCO_CALL_PARAMETERS CallParameters
  2121. )
  2122. /*++
  2123. Routine Description:
  2124. Arguments:
  2125. Return Value:
  2126. --*/
  2127. {
  2128. PNDIS_CO_AF_BLOCK pAf;
  2129. PNDIS_CO_VC_PTR_BLOCK VcPtr = (PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle;
  2130. PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
  2131. KIRQL OldIrql;
  2132. BOOLEAN fAborted;
  2133. DBGPRINT(DBG_COMP_CO, DBG_LEVEL_INFO,
  2134. ("NdisCmMakeCallComplete(%x): VcPtr %x/%x, Ref %d, VCBlock %x/%x\n",
  2135. Status, VcPtr, VcPtr->CallFlags, VcPtr->References,
  2136. VcPtr->VcBlock, VcPtr->VcBlock->Flags));
  2137. pAf = VcPtr->AfBlock;
  2138. ASSERT(Status != NDIS_STATUS_PENDING);
  2139. ACQUIRE_SPIN_LOCK(&VcPtr->Lock, &OldIrql);
  2140. VcPtr->CallFlags &= ~VC_CALL_PENDING;
  2141. if (Status == NDIS_STATUS_SUCCESS)
  2142. {
  2143. VcPtr->CallFlags |= VC_CALL_ACTIVE;
  2144. }
  2145. else
  2146. {
  2147. fAborted = ((VcPtr->CallFlags & VC_CALL_ABORTED) != 0);
  2148. }
  2149. RELEASE_SPIN_LOCK(&VcPtr->Lock, OldIrql);
  2150. if (Status == NDIS_STATUS_SUCCESS)
  2151. {
  2152. //
  2153. // Call completed successfully. Complete it to the client.
  2154. //
  2155. if (ARGUMENT_PRESENT(NdisPartyHandle))
  2156. {
  2157. pParty->CallMgrContext = CallMgrPartyContext;
  2158. ndisReferenceVcPtr(VcPtr);
  2159. }
  2160. ACQUIRE_SPIN_LOCK(&pAf->ClientOpen->SpinLock, &OldIrql);
  2161. RemoveEntryList(&VcPtr->ClientLink);
  2162. InsertHeadList(&pAf->ClientOpen->ActiveVcHead,
  2163. &VcPtr->ClientLink);
  2164. RELEASE_SPIN_LOCK(&pAf->ClientOpen->SpinLock, OldIrql);
  2165. }
  2166. else
  2167. {
  2168. //
  2169. // Deref the VC and Af (was ref'd in MakeCall) - but only if the call was
  2170. // not aborted. In this case CloseCall will do the right thing.
  2171. //
  2172. if (!fAborted)
  2173. {
  2174. ndisDereferenceVcPtr(VcPtr);
  2175. ndisDereferenceAf(pAf);
  2176. if (pParty)
  2177. {
  2178. FREE_POOL(pParty);
  2179. }
  2180. }
  2181. DBGPRINT(DBG_COMP_CO, DBG_LEVEL_INFO,
  2182. ("NdisCmMakeCallComplete: Failed %lx\n", Status));
  2183. }
  2184. (*pAf->ClientEntries.ClMakeCallCompleteHandler)(Status,
  2185. VcPtr->ClientContext,
  2186. pParty,
  2187. CallParameters);
  2188. }
  2189. NDIS_STATUS
  2190. NdisCmDispatchIncomingCall(
  2191. IN NDIS_HANDLE NdisSapHandle,
  2192. IN NDIS_HANDLE NdisVcHandle,
  2193. IN OUT PCO_CALL_PARAMETERS CallParameters
  2194. )
  2195. /*++
  2196. Routine Description:
  2197. Call from the call-manager to dispatch an incoming vc to the client who registered the Sap.
  2198. The client is identified by the NdisSapHandle.
  2199. Arguments:
  2200. NdisBindingHandle - Identifies the miniport on which the Vc is created
  2201. NdisSapHandle - Identifies the client
  2202. CallParameters - Self explanatory
  2203. NdisVcHandle - Pointer to the NDIS_CO_VC_BLOCK created via NdisCmCreateVc
  2204. Return Value:
  2205. Return value from the client or an processing error.
  2206. --*/
  2207. {
  2208. PNDIS_CO_SAP_BLOCK Sap;
  2209. PNDIS_CO_VC_PTR_BLOCK VcPtr;
  2210. PNDIS_CO_AF_BLOCK pAf;
  2211. NDIS_STATUS Status;
  2212. Sap = (PNDIS_CO_SAP_BLOCK)NdisSapHandle;
  2213. VcPtr = (PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle;
  2214. pAf = Sap->AfBlock;
  2215. ASSERT(pAf == VcPtr->AfBlock);
  2216. //
  2217. // Make sure the SAP's not closing
  2218. //
  2219. if (!ndisReferenceSap(Sap))
  2220. {
  2221. return(NDIS_STATUS_FAILURE);
  2222. }
  2223. //
  2224. // Make sure the AF is not closing
  2225. //
  2226. if (!ndisReferenceAf(pAf))
  2227. {
  2228. ndisDereferenceSap(Sap);
  2229. return(NDIS_STATUS_FAILURE);
  2230. }
  2231. //
  2232. // Notify the client of this call
  2233. //
  2234. Status = (*pAf->ClientEntries.ClIncomingCallHandler)(Sap->ClientContext,
  2235. VcPtr->ClientContext,
  2236. CallParameters);
  2237. if (Status != NDIS_STATUS_PENDING)
  2238. {
  2239. NdisClIncomingCallComplete(Status, VcPtr, CallParameters);
  2240. Status = NDIS_STATUS_PENDING;
  2241. }
  2242. ndisDereferenceSap(Sap);
  2243. return Status;
  2244. }
  2245. VOID
  2246. NdisClIncomingCallComplete(
  2247. IN NDIS_STATUS Status,
  2248. IN NDIS_HANDLE NdisVcHandle,
  2249. IN PCO_CALL_PARAMETERS CallParameters
  2250. )
  2251. /*++
  2252. Routine Description:
  2253. Arguments:
  2254. Return Value:
  2255. --*/
  2256. {
  2257. PNDIS_CO_VC_PTR_BLOCK VcPtr = (PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle;
  2258. KIRQL OldIrql;
  2259. ASSERT(Status != NDIS_STATUS_PENDING);
  2260. if (Status == NDIS_STATUS_SUCCESS)
  2261. {
  2262. ACQUIRE_SPIN_LOCK(&VcPtr->ClientOpen->SpinLock, &OldIrql);
  2263. //
  2264. // Reference the VcPtr. This is dereferenced when NdisClCloseCall is called.
  2265. //
  2266. VcPtr->References ++;
  2267. RemoveEntryList(&VcPtr->ClientLink);
  2268. InsertHeadList(&VcPtr->ClientOpen->ActiveVcHead,
  2269. &VcPtr->ClientLink);
  2270. RELEASE_SPIN_LOCK(&VcPtr->ClientOpen->SpinLock, OldIrql);
  2271. ACQUIRE_SPIN_LOCK(&VcPtr->Lock, &OldIrql);
  2272. ASSERT((VcPtr->CallFlags & (VC_CALL_ABORTED | VC_CALL_PENDING)) == 0);
  2273. VcPtr->CallFlags |= VC_CALL_ACTIVE;
  2274. RELEASE_SPIN_LOCK(&VcPtr->Lock, OldIrql);
  2275. }
  2276. //
  2277. // Call the call-manager handler to notify that client is done with this.
  2278. //
  2279. (*VcPtr->AfBlock->CallMgrEntries->CmIncomingCallCompleteHandler)(
  2280. Status,
  2281. VcPtr->CallMgrContext,
  2282. CallParameters);
  2283. }
  2284. VOID
  2285. NdisCmDispatchCallConnected(
  2286. IN NDIS_HANDLE NdisVcHandle
  2287. )
  2288. /*++
  2289. Routine Description:
  2290. Called by the call-manager to complete the final hand-shake on an incoming call.
  2291. Arguments:
  2292. NdisVcHandle - Pointer to the vc block
  2293. Return Value:
  2294. None.
  2295. --*/
  2296. {
  2297. PNDIS_CO_VC_PTR_BLOCK VcPtr = (PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle;
  2298. (*VcPtr->ClCallConnectedHandler)(VcPtr->ClientContext);
  2299. }
  2300. NDIS_STATUS
  2301. NdisClModifyCallQoS(
  2302. IN NDIS_HANDLE NdisVcHandle,
  2303. IN PCO_CALL_PARAMETERS CallParameters
  2304. )
  2305. /*++
  2306. Routine Description:
  2307. Initiated by the client to modify the QoS associated with the call.
  2308. Arguments:
  2309. NdisVcHandle - Pointer to the vc block
  2310. CallParameters - New call QoS
  2311. Return Value:
  2312. --*/
  2313. {
  2314. PNDIS_CO_VC_PTR_BLOCK VcPtr = (PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle;
  2315. NDIS_STATUS Status;
  2316. //
  2317. // Ask the call-manager to take care of this
  2318. //
  2319. Status = (*VcPtr->CmModifyCallQoSHandler)(VcPtr->CallMgrContext,
  2320. CallParameters);
  2321. return Status;
  2322. }
  2323. VOID
  2324. NdisCmModifyCallQoSComplete(
  2325. IN NDIS_STATUS Status,
  2326. IN NDIS_HANDLE NdisVcHandle,
  2327. IN PCO_CALL_PARAMETERS CallParameters
  2328. )
  2329. {
  2330. PNDIS_CO_VC_PTR_BLOCK VcPtr = (PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle;
  2331. //
  2332. // Simply notify the client
  2333. //
  2334. (*VcPtr->ClModifyCallQoSCompleteHandler)(Status,
  2335. VcPtr->ClientContext,
  2336. CallParameters);
  2337. }
  2338. VOID
  2339. NdisCmDispatchIncomingCallQoSChange(
  2340. IN NDIS_HANDLE NdisVcHandle,
  2341. IN PCO_CALL_PARAMETERS CallParameters
  2342. )
  2343. /*++
  2344. Routine Description:
  2345. Called by the call-manager to indicate a remote requested change in the call-qos. This is
  2346. simply an indication. A client must respond by either accepting it (do nothing) or reject
  2347. it (by either modifying the call qos or by tearing down the call).
  2348. Arguments:
  2349. NdisVcHandle - Pointer to the vc block
  2350. CallParameters - New call qos
  2351. Return Value:
  2352. None.
  2353. --*/
  2354. {
  2355. PNDIS_CO_VC_PTR_BLOCK VcPtr = (PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle;
  2356. //
  2357. // Simply notify the client
  2358. //
  2359. (*VcPtr->ClIncomingCallQoSChangeHandler)(VcPtr->ClientContext,
  2360. CallParameters);
  2361. }
  2362. NDIS_STATUS
  2363. NdisClCloseCall(
  2364. IN NDIS_HANDLE NdisVcHandle,
  2365. IN NDIS_HANDLE NdisPartyHandle OPTIONAL,
  2366. IN PVOID Buffer OPTIONAL,
  2367. IN UINT Size OPTIONAL
  2368. )
  2369. /*++
  2370. Routine Description:
  2371. Called by the client to close down a connection established via either NdisClMakeCall
  2372. or accepting an incoming call via NdisClIncomingCallComplete. The optional buffer can
  2373. be specified by the client to send a disconnect message. Upto the call-manager to do
  2374. something reasonable with it.
  2375. Arguments:
  2376. NdisVcHandle - Pointer to the vc block
  2377. Buffer - Optional disconnect message
  2378. Size - Size of the disconnect message
  2379. Return Value:
  2380. --*/
  2381. {
  2382. PNDIS_CO_VC_PTR_BLOCK VcPtr = (PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle;
  2383. PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
  2384. NDIS_STATUS Status;
  2385. KIRQL OldIrql;
  2386. DBGPRINT(DBG_COMP_CO, DBG_LEVEL_INFO,
  2387. ("NdisClCloseCall: VcPtr %x/%x, Ref %d, VCBlock %x/%x\n",
  2388. VcPtr, VcPtr->CallFlags, VcPtr->References,
  2389. VcPtr->VcBlock, VcPtr->VcBlock->Flags));
  2390. //
  2391. // Ref the VC. (Gets DeRef'd in CloseCallComplete)
  2392. //
  2393. if (!ndisReferenceVcPtr(VcPtr))
  2394. {
  2395. return (NDIS_STATUS_FAILURE);
  2396. }
  2397. ACQUIRE_SPIN_LOCK(&VcPtr->Lock, &OldIrql);
  2398. VcPtr->CallFlags |= VC_CALL_CLOSE_PENDING;
  2399. if (VcPtr->CallFlags & VC_CALL_PENDING)
  2400. VcPtr->CallFlags |= VC_CALL_ABORTED;
  2401. RELEASE_SPIN_LOCK(&VcPtr->Lock, OldIrql);
  2402. //
  2403. // Simply notify the call-manager
  2404. //
  2405. Status = (*VcPtr->AfBlock->CallMgrEntries->CmCloseCallHandler)(VcPtr->CallMgrContext,
  2406. (pParty != NULL) ?
  2407. pParty->CallMgrContext :
  2408. NULL,
  2409. Buffer,
  2410. Size);
  2411. if (Status != NDIS_STATUS_PENDING)
  2412. {
  2413. NdisCmCloseCallComplete(Status, VcPtr, pParty);
  2414. Status = NDIS_STATUS_PENDING;
  2415. }
  2416. return Status;
  2417. }
  2418. VOID
  2419. NdisCmCloseCallComplete(
  2420. IN NDIS_STATUS Status,
  2421. IN NDIS_HANDLE NdisVcHandle,
  2422. IN NDIS_HANDLE NdisPartyHandle OPTIONAL
  2423. )
  2424. /*++
  2425. Routine Description:
  2426. Arguments:
  2427. NdisVcHandle - Pointer to the vc block
  2428. Return Value:
  2429. Nothing. Client handler called
  2430. --*/
  2431. {
  2432. PNDIS_CO_VC_PTR_BLOCK VcPtr = (PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle;
  2433. PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
  2434. NDIS_HANDLE ClientVcContext;
  2435. NDIS_HANDLE ClientPartyContext;
  2436. CL_CLOSE_CALL_COMPLETE_HANDLER CloseCallCompleteHandler;
  2437. KIRQL OldIrql;
  2438. ULONG VcFlags;
  2439. DBGPRINT(DBG_COMP_CO, DBG_LEVEL_INFO,
  2440. ("NdisCmCloseCallComplete(%x): VcPtr %x/%x, Ref %d, VCBlock %x/%x\n",
  2441. Status, VcPtr, VcPtr->CallFlags, VcPtr->References,
  2442. VcPtr->VcBlock, VcPtr->VcBlock->Flags));
  2443. ACQUIRE_SPIN_LOCK(&VcPtr->Lock, &OldIrql);
  2444. VcPtr->CallFlags &= ~(VC_CALL_CLOSE_PENDING | VC_CALL_ABORTED);
  2445. ClientVcContext = VcPtr->ClientContext;
  2446. ClientPartyContext = (pParty != NULL)? pParty->ClientContext: NULL;
  2447. CloseCallCompleteHandler = VcPtr->AfBlock->ClientEntries.ClCloseCallCompleteHandler;
  2448. if (Status == NDIS_STATUS_SUCCESS)
  2449. {
  2450. VcFlags = VcPtr->CallFlags;
  2451. VcPtr->CallFlags &= ~(VC_CALL_ACTIVE);
  2452. RELEASE_SPIN_LOCK(&VcPtr->Lock, OldIrql);
  2453. if (pParty != NULL)
  2454. {
  2455. ASSERT(VcPtr == pParty->VcPtr);
  2456. ndisDereferenceVcPtr(pParty->VcPtr);
  2457. FREE_POOL(pParty);
  2458. }
  2459. //
  2460. // Deref the Vc and Af for refs taken in MakeCall/IncomingCallComplete
  2461. //
  2462. ndisDereferenceAf(VcPtr->AfBlock);
  2463. if (VcFlags & VC_CALL_ACTIVE)
  2464. {
  2465. ndisDereferenceVcPtr(VcPtr);
  2466. }
  2467. }
  2468. else
  2469. {
  2470. //
  2471. // Leave the VC and VC Ptr in their original states (before this
  2472. // failed CloseCall happened)
  2473. //
  2474. RELEASE_SPIN_LOCK(&VcPtr->Lock, OldIrql);
  2475. }
  2476. //
  2477. // Deref the VC (Refs were taken in CloseCall)
  2478. //
  2479. ndisDereferenceVcPtr(VcPtr);
  2480. //
  2481. // Now inform the client of CloseCall completion.
  2482. //
  2483. (*CloseCallCompleteHandler)(Status,
  2484. ClientVcContext,
  2485. ClientPartyContext);
  2486. }
  2487. VOID
  2488. NdisCmDispatchIncomingCloseCall(
  2489. IN NDIS_STATUS CloseStatus,
  2490. IN NDIS_HANDLE NdisVcHandle,
  2491. IN PVOID Buffer,
  2492. IN UINT Size
  2493. )
  2494. /*++
  2495. Routine Description:
  2496. Arguments:
  2497. Return Value:
  2498. --*/
  2499. {
  2500. PNDIS_CO_VC_PTR_BLOCK VcPtr = (PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle;
  2501. //
  2502. // Notify the client
  2503. //
  2504. (*VcPtr->AfBlock->ClientEntries.ClIncomingCloseCallHandler)(
  2505. CloseStatus,
  2506. VcPtr->ClientContext,
  2507. Buffer,
  2508. Size);
  2509. }
  2510. NDIS_STATUS
  2511. NdisClAddParty(
  2512. IN NDIS_HANDLE NdisVcHandle,
  2513. IN NDIS_HANDLE ProtocolPartyContext,
  2514. IN OUT PCO_CALL_PARAMETERS CallParameters,
  2515. OUT PNDIS_HANDLE NdisPartyHandle
  2516. )
  2517. /*++
  2518. Routine Description:
  2519. Call from the client to the call-manager to add a party to a point-to-multi-point call.
  2520. Arguments:
  2521. NdisVcHandle - The handle client obtained via NdisClMakeCall()
  2522. ProtocolPartyContext - Protocol's context for this leaf
  2523. Flags - Call flags
  2524. CallParameters - Call parameters
  2525. NdisPartyHandle - Place holder for the handle to identify the leaf
  2526. Return Value:
  2527. NDIS_STATUS_PENDING The call has pended and will complete via CoAddPartyCompleteHandler.
  2528. --*/
  2529. {
  2530. PNDIS_CO_VC_PTR_BLOCK VcPtr = (PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle;
  2531. PNDIS_CO_PARTY_BLOCK pParty;
  2532. NDIS_STATUS Status;
  2533. do
  2534. {
  2535. *NdisPartyHandle = NULL;
  2536. if (!ndisReferenceVcPtr(VcPtr))
  2537. {
  2538. Status = NDIS_STATUS_FAILURE;
  2539. break;
  2540. }
  2541. pParty = ALLOC_FROM_POOL(sizeof(NDIS_CO_PARTY_BLOCK), NDIS_TAG_CO);
  2542. if (pParty == NULL)
  2543. {
  2544. Status = NDIS_STATUS_RESOURCES;
  2545. break;
  2546. }
  2547. pParty->ClientContext = ProtocolPartyContext;
  2548. pParty->VcPtr = VcPtr;
  2549. pParty->ClIncomingDropPartyHandler = VcPtr->AfBlock->ClientEntries.ClIncomingDropPartyHandler;
  2550. pParty->ClDropPartyCompleteHandler = VcPtr->AfBlock->ClientEntries.ClDropPartyCompleteHandler;
  2551. //
  2552. // Simply call the call-manager to do its stuff.
  2553. //
  2554. Status = (*VcPtr->AfBlock->CallMgrEntries->CmAddPartyHandler)(
  2555. VcPtr->CallMgrContext,
  2556. CallParameters,
  2557. pParty,
  2558. &pParty->CallMgrContext);
  2559. if (Status != NDIS_STATUS_PENDING)
  2560. {
  2561. NdisCmAddPartyComplete(Status,
  2562. pParty,
  2563. pParty->CallMgrContext,
  2564. CallParameters);
  2565. Status = NDIS_STATUS_PENDING;
  2566. }
  2567. } while (FALSE);
  2568. return Status;
  2569. }
  2570. VOID
  2571. NdisCmAddPartyComplete(
  2572. IN NDIS_STATUS Status,
  2573. IN NDIS_HANDLE NdisPartyHandle,
  2574. IN NDIS_HANDLE CallMgrPartyContext OPTIONAL,
  2575. IN PCO_CALL_PARAMETERS CallParameters
  2576. )
  2577. /*++
  2578. Routine Description:
  2579. Arguments:
  2580. Return Value:
  2581. --*/
  2582. {
  2583. PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
  2584. ASSERT(Status != NDIS_STATUS_PENDING);
  2585. if (Status == NDIS_STATUS_SUCCESS)
  2586. {
  2587. pParty->CallMgrContext = CallMgrPartyContext;
  2588. }
  2589. //
  2590. // Complete the call to the client
  2591. //
  2592. (*pParty->VcPtr->AfBlock->ClientEntries.ClAddPartyCompleteHandler)(
  2593. Status,
  2594. pParty->ClientContext,
  2595. pParty,
  2596. CallParameters);
  2597. if (Status != NDIS_STATUS_SUCCESS)
  2598. {
  2599. ndisDereferenceVcPtr(pParty->VcPtr);
  2600. FREE_POOL(pParty);
  2601. }
  2602. }
  2603. NDIS_STATUS
  2604. NdisClDropParty(
  2605. IN NDIS_HANDLE NdisPartyHandle,
  2606. IN PVOID Buffer OPTIONAL,
  2607. IN UINT Size OPTIONAL
  2608. )
  2609. /*++
  2610. Routine Description:
  2611. Arguments:
  2612. Return Value:
  2613. --*/
  2614. {
  2615. PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
  2616. NDIS_STATUS Status;
  2617. //
  2618. // Pass it along to the call-manager to handle this
  2619. //
  2620. Status = (*pParty->VcPtr->AfBlock->CallMgrEntries->CmDropPartyHandler)(
  2621. pParty->CallMgrContext,
  2622. Buffer,
  2623. Size);
  2624. if (Status != NDIS_STATUS_PENDING)
  2625. {
  2626. NdisCmDropPartyComplete(Status, pParty);
  2627. Status = NDIS_STATUS_PENDING;
  2628. }
  2629. return Status;
  2630. }
  2631. NTSTATUS
  2632. ndisUnicodeStringToPointer(
  2633. IN PUNICODE_STRING String,
  2634. IN ULONG Base OPTIONAL,
  2635. OUT PVOID * Value
  2636. )
  2637. /*++
  2638. Routine Description:
  2639. Converts an address represented as a unicode string into a pointer.
  2640. (stolen from RtlUnicodeStringToInteger() in ntos\rtl\cnvint.c)
  2641. Arguments:
  2642. String - The Unicode String holding the address
  2643. Base - Radix of the address represented in the string (2, 8, 10, or 16)
  2644. Value - Address of the pointer in which to store the address.
  2645. Return Value:
  2646. STATUS_SUCCESS - for successful conversion
  2647. STATUS_INVALID_ARG - if the base supplied is invalid
  2648. Other exception code - if another exception occurs
  2649. --*/
  2650. {
  2651. PCWSTR s;
  2652. WCHAR c, Sign;
  2653. ULONG nChars, Digit, Shift;
  2654. #if defined(_WIN64)
  2655. ULONGLONG Result;
  2656. #else
  2657. ULONG Result;
  2658. #endif
  2659. s = String->Buffer;
  2660. nChars = String->Length / sizeof( WCHAR );
  2661. while (nChars-- && (Sign = *s++) <= ' ')
  2662. {
  2663. if (!nChars)
  2664. {
  2665. Sign = UNICODE_NULL;
  2666. break;
  2667. }
  2668. }
  2669. c = Sign;
  2670. if ((c == L'-') || (c == L'+'))
  2671. {
  2672. if (nChars)
  2673. {
  2674. nChars--;
  2675. c = *s++;
  2676. }
  2677. else
  2678. {
  2679. c = UNICODE_NULL;
  2680. }
  2681. }
  2682. if (Base == 0)
  2683. {
  2684. Base = 10;
  2685. Shift = 0;
  2686. if (c == L'0')
  2687. {
  2688. if (nChars)
  2689. {
  2690. nChars--;
  2691. c = *s++;
  2692. if (c == L'x')
  2693. {
  2694. Base = 16;
  2695. Shift = 4;
  2696. }
  2697. else
  2698. if (c == L'o')
  2699. {
  2700. Base = 8;
  2701. Shift = 3;
  2702. }
  2703. else
  2704. if (c == L'b')
  2705. {
  2706. Base = 2;
  2707. Shift = 1;
  2708. }
  2709. else
  2710. {
  2711. nChars++;
  2712. s--;
  2713. }
  2714. }
  2715. if (nChars)
  2716. {
  2717. nChars--;
  2718. c = *s++;
  2719. }
  2720. else
  2721. {
  2722. c = UNICODE_NULL;
  2723. }
  2724. }
  2725. }
  2726. else
  2727. {
  2728. switch(Base)
  2729. {
  2730. case 16:
  2731. Shift = 4;
  2732. break;
  2733. case 8:
  2734. Shift = 3;
  2735. break;
  2736. case 2:
  2737. Shift = 1;
  2738. break;
  2739. case 10:
  2740. Shift = 0;
  2741. break;
  2742. default:
  2743. return(STATUS_INVALID_PARAMETER);
  2744. }
  2745. }
  2746. Result = 0;
  2747. while (c != UNICODE_NULL)
  2748. {
  2749. if (c >= L'0' && c <= L'9')
  2750. {
  2751. Digit = c - L'0';
  2752. }
  2753. else if (c >= L'A' && c <= L'F')
  2754. {
  2755. Digit = c - L'A' + 10;
  2756. }
  2757. else if (c >= L'a' && c <= L'f')
  2758. {
  2759. Digit = c - L'a' + 10;
  2760. }
  2761. else
  2762. {
  2763. break;
  2764. }
  2765. if (Digit >= Base)
  2766. {
  2767. break;
  2768. }
  2769. if (Shift == 0)
  2770. {
  2771. Result = (Base * Result) + Digit;
  2772. }
  2773. else
  2774. {
  2775. Result = (Result << Shift) | Digit;
  2776. }
  2777. if (!nChars)
  2778. {
  2779. break;
  2780. }
  2781. nChars--;
  2782. c = *s++;
  2783. }
  2784. if (Sign == L'-')
  2785. {
  2786. #if defined(_WIN64)
  2787. Result = (ULONGLONG)(-(LONGLONG)Result);
  2788. #else
  2789. Result = (ULONG)(-(LONG)Result);
  2790. #endif
  2791. }
  2792. try
  2793. {
  2794. *Value = (PVOID)Result;
  2795. }
  2796. except(EXCEPTION_EXECUTE_HANDLER)
  2797. {
  2798. return (GetExceptionCode());
  2799. }
  2800. return( STATUS_SUCCESS );
  2801. }
  2802. NDIS_STATUS
  2803. NdisClGetProtocolVcContextFromTapiCallId(
  2804. IN UNICODE_STRING TapiCallId,
  2805. OUT PNDIS_HANDLE ProtocolVcContext
  2806. )
  2807. /*++
  2808. Routine Description:
  2809. Retrieves the protocol VC context for a VC identified by a TAPI Call ID string
  2810. (this string is the UNICODE representation of the identifier returned by
  2811. NdisCoGetTapiCallId).
  2812. Arguments:
  2813. TapiCallId - A TAPI Call Id String
  2814. ProtocolVcContext - Pointer to a NDIS_HANDLE variable in which to store the
  2815. Protocol VC Context
  2816. Return Value:
  2817. NDIS_STATUS_FAILURE if the VC context could not be obtained, NDIS_STATUS_SUCCESS
  2818. otherwise.
  2819. --*/
  2820. {
  2821. NTSTATUS Status = ndisUnicodeStringToPointer(&TapiCallId,
  2822. 16,
  2823. (PVOID *)ProtocolVcContext);
  2824. return (NT_SUCCESS(Status) ? NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE);
  2825. }
  2826. VOID
  2827. NdisCmDropPartyComplete(
  2828. IN NDIS_STATUS Status,
  2829. IN NDIS_HANDLE NdisPartyHandle
  2830. )
  2831. /*++
  2832. Routine Description:
  2833. Arguments:
  2834. Return Value:
  2835. --*/
  2836. {
  2837. PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
  2838. ASSERT(Status != NDIS_STATUS_PENDING);
  2839. //
  2840. // Complete the call to the client
  2841. //
  2842. (*pParty->ClDropPartyCompleteHandler)(Status,
  2843. pParty->ClientContext);
  2844. if (Status == NDIS_STATUS_SUCCESS)
  2845. {
  2846. ndisDereferenceVcPtr(pParty->VcPtr);
  2847. FREE_POOL(pParty);
  2848. }
  2849. }
  2850. VOID
  2851. NdisCmDispatchIncomingDropParty(
  2852. IN NDIS_STATUS DropStatus,
  2853. IN NDIS_HANDLE NdisPartyHandle,
  2854. IN PVOID Buffer,
  2855. IN UINT Size
  2856. )
  2857. /*++
  2858. Routine Description:
  2859. Called by the call-manager to notify the client that this leaf of the multi-party
  2860. call is terminated. The client cannot use the NdisPartyHandle after completing this
  2861. call - synchronously or by calling NdisClIncomingDropPartyComplete.
  2862. Arguments:
  2863. Return Value:
  2864. --*/
  2865. {
  2866. PNDIS_CO_PARTY_BLOCK pParty = (PNDIS_CO_PARTY_BLOCK)NdisPartyHandle;
  2867. //
  2868. // Notify the client
  2869. //
  2870. (*pParty->ClIncomingDropPartyHandler)(DropStatus,
  2871. pParty->ClientContext,
  2872. Buffer,
  2873. Size);
  2874. }
  2875. BOOLEAN
  2876. FASTCALL
  2877. ndisReferenceVcPtr(
  2878. IN PNDIS_CO_VC_PTR_BLOCK VcPtr
  2879. )
  2880. /*++
  2881. Routine Description:
  2882. Arguments:
  2883. Return Value:
  2884. --*/
  2885. {
  2886. KIRQL OldIrql;
  2887. BOOLEAN rc = FALSE;
  2888. DBGPRINT(DBG_COMP_CO, DBG_LEVEL_INFO,
  2889. ("ndisReferenceVcPtr: VcPtr %x/%x, Flags %x, Ref %d, VcBlock %x\n",
  2890. VcPtr, VcPtr->CallFlags, *VcPtr->pVcFlags, VcPtr->References, VcPtr->VcBlock));
  2891. ACQUIRE_SPIN_LOCK(&VcPtr->Lock, &OldIrql);
  2892. if ((VcPtr->CallFlags & VC_PTR_BLOCK_CLOSING) == 0)
  2893. {
  2894. VcPtr->References ++;
  2895. rc = TRUE;
  2896. }
  2897. RELEASE_SPIN_LOCK(&VcPtr->Lock, OldIrql);
  2898. return rc;
  2899. }
  2900. VOID
  2901. FASTCALL
  2902. ndisDereferenceVcPtr(
  2903. IN PNDIS_CO_VC_PTR_BLOCK VcPtr
  2904. )
  2905. /*++
  2906. Routine Description:
  2907. Arguments:
  2908. Return Value:
  2909. --*/
  2910. {
  2911. KIRQL OldIrql;
  2912. BOOLEAN Done = FALSE;
  2913. BOOLEAN IsProxyVc;
  2914. PNDIS_CO_VC_BLOCK VcBlock;
  2915. DBGPRINT(DBG_COMP_CO, DBG_LEVEL_INFO,
  2916. ("ndisDereferenceVcPtr: VcPtr %x/%x, Flags %x, Ref %d, VcBlock %x\n",
  2917. VcPtr, VcPtr->CallFlags, *VcPtr->pVcFlags, VcPtr->References, VcPtr->VcBlock));
  2918. ACQUIRE_SPIN_LOCK(&VcPtr->Lock, &OldIrql);
  2919. //
  2920. // Take this VcPtr out of the VC's list
  2921. //
  2922. VcBlock = VcPtr->VcBlock;
  2923. ASSERT(VcBlock != NULL);
  2924. ASSERT(VcPtr->References > 0);
  2925. VcPtr->References --;
  2926. if (VcPtr->References == 0)
  2927. {
  2928. ASSERT(VcPtr->CallFlags & VC_PTR_BLOCK_CLOSING);
  2929. if (*VcPtr->pVcFlags & VC_DELETE_PENDING)
  2930. {
  2931. NDIS_STATUS Status;
  2932. DBGPRINT(DBG_COMP_CO, DBG_LEVEL_INFO,
  2933. ("ndisDereferenceVcPtr: Calling minport\n"));
  2934. *VcPtr->pVcFlags &= ~VC_DELETE_PENDING; // don't call DeleteVc > once
  2935. RELEASE_SPIN_LOCK_DPC(&VcPtr->Lock);
  2936. Status = (*VcPtr->WCoDeleteVcHandler)(VcPtr->MiniportContext);
  2937. ACQUIRE_SPIN_LOCK_DPC(&VcPtr->Lock);
  2938. ASSERT(Status == NDIS_STATUS_SUCCESS);
  2939. }
  2940. if (VcPtr == VcBlock->pClientVcPtr)
  2941. {
  2942. IsProxyVc = FALSE;
  2943. }
  2944. else
  2945. {
  2946. DBGPRINT(DBG_COMP_CO, DBG_LEVEL_INFO,
  2947. ("ndisDereferenceVcPtr: VC ptr is Proxy\n"));
  2948. ASSERT(VcPtr == VcBlock->pProxyVcPtr);
  2949. IsProxyVc = TRUE;
  2950. }
  2951. RELEASE_SPIN_LOCK(&VcPtr->Lock, OldIrql);
  2952. DBGPRINT(DBG_COMP_CO, DBG_LEVEL_INFO,
  2953. ("ndisDereferenceVcPtr: freeing VcPtr %x (VcBlock %x)\n", VcPtr, VcPtr->VcBlock));
  2954. FREE_POOL(VcPtr);
  2955. Done = TRUE;
  2956. }
  2957. else
  2958. {
  2959. RELEASE_SPIN_LOCK(&VcPtr->Lock, OldIrql);
  2960. }
  2961. if (Done)
  2962. {
  2963. //
  2964. // Any more VC ptrs q'd off this VC? If not,
  2965. // free the VC too. Note both pointers need to be empty, since
  2966. // a VC with no proxy can only ever be a normal
  2967. // non- (or pre-) proxied VC (so we leave it alone).
  2968. //
  2969. // Note that you can have a VC with no Proxy pointer, and a VC
  2970. // with no non-Proxy pointer. [REVIEWERS: Maybe we should assert that a VC
  2971. // that's been proxied should never be left without a proxy pointer when the
  2972. // non-proxy ptr is not null! (This would be a 'dangling' VC with no owner). This
  2973. // would require a 'proxied' flag in the VC].
  2974. //
  2975. ACQUIRE_SPIN_LOCK(&VcBlock->Lock, &OldIrql);
  2976. if (IsProxyVc)
  2977. {
  2978. VcBlock->pProxyVcPtr = NULL;
  2979. }
  2980. else
  2981. {
  2982. VcBlock->pClientVcPtr = NULL;
  2983. }
  2984. if ((VcBlock->pProxyVcPtr == NULL) &&
  2985. (VcBlock->pClientVcPtr == NULL))
  2986. {
  2987. RELEASE_SPIN_LOCK(&VcBlock->Lock, OldIrql);
  2988. DBGPRINT(DBG_COMP_CO, DBG_LEVEL_INFO,
  2989. ("ndisDereferenceVcPtr: refs are 0; VcPtrs are both NULL; freeing VCBlock %x\n", VcBlock));
  2990. FREE_POOL(VcBlock);
  2991. }
  2992. else
  2993. {
  2994. RELEASE_SPIN_LOCK(&VcBlock->Lock, OldIrql);
  2995. }
  2996. }
  2997. }
  2998. VOID
  2999. FASTCALL
  3000. ndisMCoFreeResources(
  3001. PNDIS_OPEN_BLOCK Open
  3002. )
  3003. /*++
  3004. Routine Description:
  3005. Cleans-up address family list for call-managers etc.
  3006. CALLED WITH MINIPORT LOCK HELD.
  3007. Arguments:
  3008. Open - Pointer to the Open block for miniports
  3009. Return Value:
  3010. None
  3011. --*/
  3012. {
  3013. PNDIS_MINIPORT_BLOCK Miniport;
  3014. PNDIS_AF_LIST *pAfList, pTmp;
  3015. Miniport = Open->MiniportHandle;
  3016. for (pAfList = &Miniport->CallMgrAfList;
  3017. (pTmp = *pAfList) != NULL;
  3018. NOTHING)
  3019. {
  3020. if (pTmp->Open == Open)
  3021. {
  3022. *pAfList = pTmp->NextAf;
  3023. FREE_POOL(pTmp);
  3024. }
  3025. else
  3026. {
  3027. pAfList = &pTmp->NextAf;
  3028. }
  3029. }
  3030. ASSERT(IsListEmpty(&Open->ActiveVcHead));
  3031. }
  3032. NDIS_STATUS
  3033. NdisCoAssignInstanceName(
  3034. IN NDIS_HANDLE NdisVcHandle,
  3035. IN PNDIS_STRING BaseInstanceName,
  3036. OUT PNDIS_STRING pVcInstanceName OPTIONAL
  3037. )
  3038. {
  3039. NDIS_STATUS Status;
  3040. PNDIS_CO_VC_PTR_BLOCK VcBlock = (PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle;
  3041. PNDIS_MINIPORT_BLOCK Miniport = VcBlock->Miniport;
  3042. USHORT cbSize;
  3043. PWSTR pwBuffer;
  3044. INT c;
  3045. UINT Value;
  3046. UNICODE_STRING VcInstance;
  3047. ULONGLONG VcIndex;
  3048. KIRQL OldIrql;
  3049. do
  3050. {
  3051. //
  3052. // Is there already a name associated with this VC?
  3053. //
  3054. cbSize = VcBlock->VcInstanceName.Length;
  3055. if (NULL == VcBlock->VcInstanceName.Buffer)
  3056. {
  3057. //
  3058. // The VC instance name will be of the format:
  3059. // [XXXX:YYYYYYYYYYYYYYYY] Base Name
  3060. // Where XXXX is the adapter instance number and YY..YY is the zero extended VC index.
  3061. //
  3062. cbSize = VC_INSTANCE_ID_SIZE;
  3063. if (NULL != BaseInstanceName)
  3064. {
  3065. cbSize += BaseInstanceName->Length;
  3066. }
  3067. pwBuffer = ALLOC_FROM_POOL(cbSize, NDIS_TAG_NAME_BUF);
  3068. if (NULL == pwBuffer)
  3069. {
  3070. Status = NDIS_STATUS_RESOURCES;
  3071. break;
  3072. }
  3073. NdisZeroMemory(pwBuffer, cbSize);
  3074. //
  3075. // Setup the prolog and the seperator and fill in the adapter instance #
  3076. //
  3077. pwBuffer[0] = L'[';
  3078. pwBuffer[VC_ID_INDEX] = VC_IDENTIFIER;
  3079. //
  3080. // Add the adapter instance number.
  3081. //
  3082. Value = Miniport->InstanceNumber;
  3083. for (c = 4; c > 0; c--)
  3084. {
  3085. pwBuffer[c] = ndisHexLookUp[Value & NIBBLE_MASK];
  3086. Value >>= 4;
  3087. }
  3088. //
  3089. // Add the VC index.
  3090. //
  3091. VcIndex = VcBlock->VcIndex.QuadPart;
  3092. for (c = 15; c >= 0; c--)
  3093. {
  3094. //
  3095. // Get the nibble to convert.
  3096. //
  3097. Value = (UINT)(VcIndex & NIBBLE_MASK);
  3098. pwBuffer[5+c] = ndisHexLookUp[Value];
  3099. //
  3100. // Shift the VcIndex by a nibble.
  3101. //
  3102. VcIndex >>= 4;
  3103. }
  3104. //
  3105. // Add closing bracket and a space
  3106. //
  3107. pwBuffer[21] = L']';;
  3108. pwBuffer[22] = L' ';;
  3109. //
  3110. // Initialize a temporary UNICODE_STRING to build the name.
  3111. //
  3112. VcInstance.Buffer = pwBuffer;
  3113. VcInstance.Length = VC_INSTANCE_ID_SIZE;
  3114. VcInstance.MaximumLength = cbSize;
  3115. if (NULL != BaseInstanceName)
  3116. {
  3117. //
  3118. // Append the base instance name passed into us to the end.
  3119. //
  3120. RtlAppendUnicodeStringToString(&VcInstance, BaseInstanceName);
  3121. }
  3122. ACQUIRE_SPIN_LOCK(&Miniport->VcCountLock, &OldIrql);
  3123. Miniport->VcCount++;
  3124. VcBlock->VcInstanceName = VcInstance;
  3125. //
  3126. // Add the VC to the list of WMI enabled VCs
  3127. //
  3128. InsertTailList(&Miniport->WmiEnabledVcs, &VcBlock->WmiLink);
  3129. RELEASE_SPIN_LOCK(&Miniport->VcCountLock, OldIrql);
  3130. //
  3131. // Notify the arrival of this VC.
  3132. //
  3133. {
  3134. PWNODE_SINGLE_INSTANCE wnode;
  3135. PUCHAR ptmp;
  3136. NTSTATUS NtStatus;
  3137. ndisSetupWmiNode(Miniport,
  3138. &VcInstance,
  3139. 0,
  3140. (PVOID)&GUID_NDIS_NOTIFY_VC_ARRIVAL,
  3141. &wnode);
  3142. if (wnode != NULL)
  3143. {
  3144. //
  3145. // Indicate the event to WMI. WMI will take care of freeing
  3146. // the WMI struct back to pool.
  3147. //
  3148. NtStatus = IoWMIWriteEvent(wnode);
  3149. if (!NT_SUCCESS(NtStatus))
  3150. {
  3151. DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
  3152. ("IoWMIWriteEvent failed %lx\n", NtStatus));
  3153. FREE_POOL(wnode);
  3154. }
  3155. }
  3156. }
  3157. }
  3158. //
  3159. // Copy the instance name string into callers NDIS_STRING.
  3160. //
  3161. if (ARGUMENT_PRESENT(pVcInstanceName))
  3162. {
  3163. pVcInstanceName->Buffer = ALLOC_FROM_POOL(cbSize, NDIS_TAG_NAME_BUF);
  3164. if (NULL == pVcInstanceName->Buffer)
  3165. {
  3166. Status = NDIS_STATUS_RESOURCES;
  3167. break;
  3168. }
  3169. NdisMoveMemory(pVcInstanceName->Buffer, VcBlock->VcInstanceName.Buffer, cbSize);
  3170. pVcInstanceName->Length = VcBlock->VcInstanceName.Length;
  3171. pVcInstanceName->MaximumLength = cbSize;
  3172. }
  3173. Status = NDIS_STATUS_SUCCESS;
  3174. } while (FALSE);
  3175. return(Status);
  3176. }
  3177. NDIS_STATUS
  3178. NdisCoRequest(
  3179. IN NDIS_HANDLE NdisBindingHandle,
  3180. IN NDIS_HANDLE NdisAfHandle OPTIONAL,
  3181. IN NDIS_HANDLE NdisVcHandle OPTIONAL,
  3182. IN NDIS_HANDLE NdisPartyHandle OPTIONAL,
  3183. IN PNDIS_REQUEST NdisRequest
  3184. )
  3185. /*++
  3186. Routine Description:
  3187. This api is used for two separate paths.
  3188. 1. A symmetric call between the client and the call-manager. This mechanism is a
  3189. two-way mechanism for the call-manager and client to communicate with each other in an
  3190. asynchronous manner.
  3191. 2. A request down to the miniport.
  3192. Arguments:
  3193. NdisBindingHandle - Specifies the binding and identifies the caller as call-manager/client
  3194. NdisAfHandle - Pointer to the AF Block and identifies the target. If absent, the
  3195. request is targeted to the miniport.
  3196. NdisVcHandle - Pointer to optional VC PTR block. If present the request relates to the
  3197. VC
  3198. NdisPartyHandle - Pointer to the optional Party Block. If present the request relates
  3199. to the party.
  3200. NdisRequest - The request itself
  3201. Return Value:
  3202. NDIS_STATUS_PENDING if the target pends the call.
  3203. NDIS_STATUS_FAILURE if the binding or af is closing.
  3204. Anything else return code from the other end.
  3205. --*/
  3206. {
  3207. PNDIS_OPEN_BLOCK Open;
  3208. PNDIS_CO_AF_BLOCK pAf;
  3209. NDIS_HANDLE VcContext;
  3210. PNDIS_COREQ_RESERVED CoReqRsvd;
  3211. PNDIS_CO_VC_PTR_BLOCK VcPtr = (PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle;
  3212. NDIS_STATUS Status;
  3213. KIRQL OldIrql;
  3214. CoReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(NdisRequest);
  3215. Open = (PNDIS_OPEN_BLOCK)NdisBindingHandle;
  3216. do
  3217. {
  3218. if (ARGUMENT_PRESENT(NdisAfHandle))
  3219. {
  3220. CO_REQUEST_HANDLER CoRequestHandler;
  3221. NDIS_HANDLE AfContext, PartyContext;
  3222. pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
  3223. //
  3224. // Attempt to reference the AF
  3225. //
  3226. if (!ndisReferenceAf(pAf))
  3227. {
  3228. Status = NDIS_STATUS_FAILURE;
  3229. break;
  3230. }
  3231. VcContext = NULL;
  3232. PartyContext = NULL;
  3233. NdisZeroMemory(CoReqRsvd, sizeof(NDIS_COREQ_RESERVED));
  3234. INITIALIZE_EVENT(&CoReqRsvd->Event);
  3235. PNDIS_RESERVED_FROM_PNDIS_REQUEST(NdisRequest)->Flags = REQST_SIGNAL_EVENT;
  3236. //
  3237. // Figure out who we are and call the peer
  3238. //
  3239. if (pAf->ClientOpen == Open)
  3240. {
  3241. //
  3242. // This is the client, so call the call-manager's CoRequestHandler
  3243. //
  3244. CoRequestHandler = pAf->CallMgrEntries->CmRequestHandler;
  3245. AfContext = pAf->CallMgrContext;
  3246. CoReqRsvd->AfContext = pAf->ClientContext;
  3247. CoReqRsvd->CoRequestCompleteHandler = pAf->ClientEntries.ClRequestCompleteHandler;
  3248. if (ARGUMENT_PRESENT(NdisVcHandle))
  3249. {
  3250. CoReqRsvd->VcContext = VcPtr->ClientContext;
  3251. VcContext = VcPtr->CallMgrContext;
  3252. }
  3253. if (ARGUMENT_PRESENT(NdisPartyHandle))
  3254. {
  3255. CoReqRsvd->PartyContext = ((PNDIS_CO_PARTY_BLOCK)NdisPartyHandle)->ClientContext;
  3256. PartyContext = ((PNDIS_CO_PARTY_BLOCK)NdisPartyHandle)->CallMgrContext;
  3257. }
  3258. }
  3259. else
  3260. {
  3261. ASSERT(pAf->CallMgrOpen == Open);
  3262. //
  3263. // This is the call-manager, so call the client's CoRequestHandler
  3264. //
  3265. CoRequestHandler = pAf->ClientEntries.ClRequestHandler;
  3266. AfContext = pAf->ClientContext;
  3267. CoReqRsvd->AfContext = pAf->CallMgrContext;
  3268. CoReqRsvd->CoRequestCompleteHandler = pAf->CallMgrEntries->CmRequestCompleteHandler;
  3269. if (ARGUMENT_PRESENT(NdisVcHandle))
  3270. {
  3271. CoReqRsvd->VcContext = VcPtr->CallMgrContext;
  3272. VcContext = VcPtr->ClientContext;
  3273. }
  3274. if (ARGUMENT_PRESENT(NdisPartyHandle))
  3275. {
  3276. CoReqRsvd->PartyContext = ((PNDIS_CO_PARTY_BLOCK)NdisPartyHandle)->CallMgrContext;
  3277. PartyContext = ((PNDIS_CO_PARTY_BLOCK)NdisPartyHandle)->ClientContext;
  3278. }
  3279. }
  3280. if (CoRequestHandler == NULL)
  3281. {
  3282. Status = NDIS_STATUS_NOT_SUPPORTED;
  3283. break;
  3284. }
  3285. if (MINIPORT_PNP_TEST_FLAG(Open->MiniportHandle, fMINIPORT_DEVICE_FAILED))
  3286. {
  3287. Status = (NdisRequest->RequestType == NdisRequestSetInformation) ?
  3288. NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE;
  3289. }
  3290. else
  3291. {
  3292. //
  3293. // Now call the handler
  3294. //
  3295. Status = (*CoRequestHandler)(AfContext, VcContext, PartyContext, NdisRequest);
  3296. }
  3297. if (Status != NDIS_STATUS_PENDING)
  3298. {
  3299. NdisCoRequestComplete(Status,
  3300. NdisAfHandle,
  3301. NdisVcHandle,
  3302. NdisPartyHandle,
  3303. NdisRequest);
  3304. Status = NDIS_STATUS_PENDING;
  3305. }
  3306. }
  3307. else
  3308. {
  3309. PNDIS_MINIPORT_BLOCK Miniport;
  3310. Miniport = Open->MiniportHandle;
  3311. //
  3312. // Start off by referencing the open.
  3313. //
  3314. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  3315. if (Open->Flags & fMINIPORT_OPEN_CLOSING)
  3316. {
  3317. Status = NDIS_STATUS_CLOSING;
  3318. }
  3319. else if (MINIPORT_TEST_FLAG(Miniport, (fMINIPORT_RESET_IN_PROGRESS | fMINIPORT_RESET_REQUESTED)))
  3320. {
  3321. Status = NDIS_STATUS_RESET_IN_PROGRESS;
  3322. }
  3323. else
  3324. {
  3325. Status = NDIS_STATUS_SUCCESS;
  3326. M_OPEN_INCREMENT_REF_INTERLOCKED(Open);
  3327. }
  3328. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  3329. if (Status == NDIS_STATUS_SUCCESS)
  3330. {
  3331. PNDIS_RESERVED_FROM_PNDIS_REQUEST(NdisRequest)->Open = Open;
  3332. PNDIS_RESERVED_FROM_PNDIS_REQUEST(NdisRequest)->Flags = 0;
  3333. CoReqRsvd->CoRequestCompleteHandler = Open->CoRequestCompleteHandler;
  3334. CoReqRsvd->VcContext = NULL;
  3335. if (ARGUMENT_PRESENT(NdisVcHandle))
  3336. {
  3337. if (VcPtr->ClientOpen == Open)
  3338. {
  3339. CoReqRsvd->VcContext = VcPtr->ClientContext;
  3340. }
  3341. else
  3342. {
  3343. CoReqRsvd->VcContext = VcPtr->CallMgrContext;
  3344. }
  3345. }
  3346. if (MINIPORT_PNP_TEST_FLAG(Open->MiniportHandle, fMINIPORT_DEVICE_FAILED))
  3347. {
  3348. Status = (NdisRequest->RequestType == NdisRequestSetInformation) ?
  3349. NDIS_STATUS_SUCCESS : NDIS_STATUS_FAILURE;
  3350. }
  3351. else
  3352. {
  3353. //
  3354. // Call the miniport's CoRequest Handler
  3355. //
  3356. Status = (*Open->MiniportCoRequestHandler)(Open->MiniportAdapterContext,
  3357. (NdisVcHandle != NULL) ?
  3358. VcPtr->MiniportContext : NULL,
  3359. NdisRequest);
  3360. }
  3361. if (Status != NDIS_STATUS_PENDING)
  3362. {
  3363. NdisMCoRequestComplete(Status,
  3364. Open->MiniportHandle,
  3365. NdisRequest);
  3366. Status = NDIS_STATUS_PENDING;
  3367. }
  3368. }
  3369. }
  3370. } while (FALSE);
  3371. return Status;
  3372. }
  3373. NDIS_STATUS
  3374. NdisMCmRequest(
  3375. IN NDIS_HANDLE NdisAfHandle,
  3376. IN NDIS_HANDLE NdisVcHandle OPTIONAL,
  3377. IN NDIS_HANDLE NdisPartyHandle OPTIONAL,
  3378. IN OUT PNDIS_REQUEST NdisRequest
  3379. )
  3380. /*++
  3381. Routine Description:
  3382. This api is a symmetric call between the client and an integrated call-manager.
  3383. This mechanism is a two-way mechanism for the call-manager and client to communicate
  3384. with each other in an asynchronous manner.
  3385. Arguments:
  3386. NdisAfHandle - Pointer to the AF Block and identifies the target. If absent, the
  3387. request is targeted to the miniport.
  3388. NdisVcHandle - Pointer to optional VC PTR block. If present the request relates to the
  3389. VC
  3390. NdisPartyHandle - Pointer to the optional Party Block. If present the request relates
  3391. to the party.
  3392. NdisRequest - The request itself
  3393. Return Value:
  3394. NDIS_STATUS_PENDING if the target pends the call.
  3395. NDIS_STATUS_FAILURE if the binding or af is closing.
  3396. Anything else return code from the other end.
  3397. --*/
  3398. {
  3399. PNDIS_CO_AF_BLOCK pAf;
  3400. NDIS_HANDLE VcContext, PartyContext;
  3401. PNDIS_COREQ_RESERVED CoReqRsvd;
  3402. NDIS_STATUS Status;
  3403. CoReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(NdisRequest);
  3404. pAf = (PNDIS_CO_AF_BLOCK)NdisAfHandle;
  3405. do
  3406. {
  3407. //
  3408. // Attempt to reference the AF
  3409. //
  3410. if (!ndisReferenceAf(pAf))
  3411. {
  3412. Status = NDIS_STATUS_FAILURE;
  3413. break;
  3414. }
  3415. VcContext = NULL;
  3416. PartyContext = NULL;
  3417. NdisZeroMemory(CoReqRsvd, sizeof(NDIS_COREQ_RESERVED));
  3418. INITIALIZE_EVENT(&CoReqRsvd->Event);
  3419. PNDIS_RESERVED_FROM_PNDIS_REQUEST(NdisRequest)->Flags = REQST_SIGNAL_EVENT;
  3420. CoReqRsvd->AfContext = pAf->CallMgrContext;
  3421. CoReqRsvd->CoRequestCompleteHandler = pAf->CallMgrEntries->CmRequestCompleteHandler;
  3422. if (ARGUMENT_PRESENT(NdisVcHandle))
  3423. {
  3424. CoReqRsvd->VcContext = pAf->CallMgrContext;
  3425. VcContext = ((PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle)->ClientContext;
  3426. }
  3427. if (ARGUMENT_PRESENT(NdisPartyHandle))
  3428. {
  3429. CoReqRsvd->PartyContext = ((PNDIS_CO_PARTY_BLOCK)NdisPartyHandle)->CallMgrContext;
  3430. PartyContext = ((PNDIS_CO_PARTY_BLOCK)NdisPartyHandle)->ClientContext;
  3431. }
  3432. //
  3433. // Now call the handler
  3434. //
  3435. Status = (*pAf->ClientEntries.ClRequestHandler)(pAf->ClientContext,
  3436. VcContext,
  3437. PartyContext,
  3438. NdisRequest);
  3439. if (Status != NDIS_STATUS_PENDING)
  3440. {
  3441. NdisCoRequestComplete(Status,
  3442. NdisAfHandle,
  3443. NdisVcHandle,
  3444. NdisPartyHandle,
  3445. NdisRequest);
  3446. Status = NDIS_STATUS_PENDING;
  3447. }
  3448. } while (FALSE);
  3449. return Status;
  3450. }
  3451. VOID
  3452. NdisCoRequestComplete(
  3453. IN NDIS_STATUS Status,
  3454. IN NDIS_HANDLE NdisAfHandle,
  3455. IN NDIS_HANDLE NdisVcHandle OPTIONAL,
  3456. IN NDIS_HANDLE NdisPartyHandle OPTIONAL,
  3457. IN PNDIS_REQUEST NdisRequest
  3458. )
  3459. /*++
  3460. Routine Description:
  3461. Arguments:
  3462. Return Value:
  3463. --*/
  3464. {
  3465. PNDIS_COREQ_RESERVED ReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(NdisRequest);
  3466. //
  3467. // Simply call the request completion handler and deref the Af block
  3468. //
  3469. (*ReqRsvd->CoRequestCompleteHandler)(Status,
  3470. ReqRsvd->AfContext,
  3471. ReqRsvd->VcContext,
  3472. ReqRsvd->PartyContext,
  3473. NdisRequest);
  3474. ndisDereferenceAf((PNDIS_CO_AF_BLOCK)NdisAfHandle);
  3475. }
  3476. NDIS_STATUS
  3477. NdisCoGetTapiCallId(
  3478. IN NDIS_HANDLE NdisVcHandle,
  3479. IN OUT PVAR_STRING TapiCallId
  3480. )
  3481. /*++
  3482. Routine Description:
  3483. Returns a string that can be used by a TAPI application to identify a particular VC.
  3484. Arguments:
  3485. NdisVcHandle - The NDIS handle to the VC to identify
  3486. TapiCallId - Pointer to a VAR_STRING structure in which to return
  3487. the identifier
  3488. Return Value:
  3489. NDIS_STATUS_BUFFER_TOO_SHORT if the VAR_STRING structure's ulTotalSize field indicates
  3490. that it does not contain enough space to hold the VC's identifier. The ulNeededSize
  3491. field will be set to the size needed.
  3492. NDIS_STATUS_INVALID_DATA if the NdisVcHandle passed in is not valid.
  3493. NDIS_STATUS_SUCCESS otherwise.
  3494. --*/
  3495. {
  3496. NDIS_HANDLE ClientContext;
  3497. TapiCallId->ulUsedSize = 0;
  3498. if (NdisVcHandle)
  3499. ClientContext = ((PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle)->ClientContext;
  3500. else
  3501. return NDIS_STATUS_INVALID_DATA;
  3502. //
  3503. // Determine the size we will need.
  3504. //
  3505. TapiCallId->ulNeededSize = sizeof(VAR_STRING) + sizeof(ClientContext);
  3506. //
  3507. // Check that there is enough space to copy the call ID. If not,
  3508. // we bail.
  3509. //
  3510. if (TapiCallId->ulTotalSize < TapiCallId->ulNeededSize)
  3511. return NDIS_STATUS_BUFFER_TOO_SHORT;
  3512. //
  3513. // Set fields, do the copy.
  3514. //
  3515. TapiCallId->ulStringFormat = STRINGFORMAT_BINARY;
  3516. TapiCallId->ulStringSize = sizeof(ClientContext);
  3517. TapiCallId->ulStringOffset = sizeof(VAR_STRING);
  3518. NdisMoveMemory(((PUCHAR)TapiCallId) + TapiCallId->ulStringOffset,
  3519. &ClientContext,
  3520. sizeof(ClientContext));
  3521. TapiCallId->ulUsedSize = sizeof(VAR_STRING) + sizeof(ClientContext);
  3522. return NDIS_STATUS_SUCCESS;
  3523. }
  3524. VOID
  3525. NdisMCoRequestComplete(
  3526. IN NDIS_STATUS Status,
  3527. IN NDIS_HANDLE NdisBindingHandle,
  3528. IN PNDIS_REQUEST NdisRequest
  3529. )
  3530. /*++
  3531. Routine Description:
  3532. Arguments:
  3533. Return Value:
  3534. --*/
  3535. {
  3536. PNDIS_REQUEST_RESERVED ReqRsvd;
  3537. PNDIS_COREQ_RESERVED CoReqRsvd;
  3538. PNDIS_MINIPORT_BLOCK Miniport;
  3539. PNDIS_OPEN_BLOCK Open;
  3540. ReqRsvd = PNDIS_RESERVED_FROM_PNDIS_REQUEST(NdisRequest);
  3541. CoReqRsvd = PNDIS_COREQ_RESERVED_FROM_REQUEST(NdisRequest);
  3542. Miniport = (PNDIS_MINIPORT_BLOCK)NdisBindingHandle;
  3543. Open = ReqRsvd->Open;
  3544. if ((NdisRequest->RequestType == NdisRequestQueryInformation) &&
  3545. (NdisRequest->DATA.QUERY_INFORMATION.Oid == OID_GEN_CURRENT_PACKET_FILTER) &&
  3546. (NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength != 0))
  3547. {
  3548. if ((Open != NULL) && (Open->Flags & fMINIPORT_OPEN_PMODE))
  3549. {
  3550. *(PULONG)(NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer) |=
  3551. NDIS_PACKET_TYPE_PROMISCUOUS | NDIS_PACKET_TYPE_ALL_LOCAL;
  3552. }
  3553. }
  3554. if (Open != NULL)
  3555. {
  3556. KIRQL OldIrql;
  3557. if (ReqRsvd->Flags & REQST_DOWNLEVEL)
  3558. {
  3559. //
  3560. // Complete the request to the protocol and deref the open
  3561. //
  3562. if (NdisRequest->RequestType == NdisRequestSetInformation)
  3563. {
  3564. NdisMSetInformationComplete(Miniport, Status);
  3565. }
  3566. else
  3567. {
  3568. NdisMQueryInformationComplete(Miniport, Status);
  3569. }
  3570. }
  3571. else
  3572. {
  3573. //
  3574. // Complete the request to the protocol and deref the open
  3575. //
  3576. ReqRsvd->Flags |= REQST_COMPLETED;
  3577. (*CoReqRsvd->CoRequestCompleteHandler)(Status,
  3578. ReqRsvd->Open->ProtocolBindingContext,
  3579. CoReqRsvd->VcContext,
  3580. NULL,
  3581. NdisRequest);
  3582. NDIS_ACQUIRE_MINIPORT_SPIN_LOCK(Miniport, &OldIrql);
  3583. ndisMDereferenceOpen(Open);
  3584. NDIS_RELEASE_MINIPORT_SPIN_LOCK(Miniport, OldIrql);
  3585. }
  3586. }
  3587. else
  3588. {
  3589. //
  3590. // Just set status and signal
  3591. //
  3592. CoReqRsvd->Status = Status;
  3593. SET_EVENT(&CoReqRsvd->Event);
  3594. }
  3595. }
  3596. VOID
  3597. NdisMCoIndicateReceivePacket(
  3598. IN NDIS_HANDLE NdisVcHandle,
  3599. IN PPNDIS_PACKET PacketArray,
  3600. IN UINT NumberOfPackets
  3601. )
  3602. /*++
  3603. Routine Description:
  3604. This routine is called by the Miniport to indicate a set of packets to
  3605. a particular VC.
  3606. Arguments:
  3607. NdisVcHandle - The handle suppplied by Ndis when the VC on which
  3608. data is received was first reserved.
  3609. PacketArray - Array of packets.
  3610. NumberOfPackets - Number of packets being indicated.
  3611. Return Value:
  3612. None.
  3613. --*/
  3614. {
  3615. PNULL_FILTER Filter;
  3616. UINT i, NumPmodeOpens;
  3617. PNDIS_STACK_RESERVED NSR;
  3618. PNDIS_PACKET_OOB_DATA pOob;
  3619. PPNDIS_PACKET pPktArray;
  3620. PNDIS_PACKET Packet;
  3621. PNDIS_CO_VC_PTR_BLOCK VcPtr = (PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle;
  3622. PNDIS_CO_VC_BLOCK VcBlock = VcPtr->VcBlock;
  3623. PNDIS_MINIPORT_BLOCK Miniport;
  3624. LOCK_STATE LockState;
  3625. #ifdef TRACK_RECEIVED_PACKETS
  3626. ULONG OrgPacketStackLocation;
  3627. PETHREAD CurThread = PsGetCurrentThread();
  3628. // ULONG CurThread = KeGetCurrentProcessorNumber();
  3629. #endif
  3630. Miniport = VcBlock->Miniport;
  3631. Filter = Miniport->NullDB;
  3632. READ_LOCK_FILTER(Miniport, Filter, &LockState);
  3633. VcBlock->ClientOpen->Flags |= fMINIPORT_PACKET_RECEIVED;
  3634. //
  3635. // NOTE that checking Vc Flags for Closing should not be needed since the CallMgr
  3636. // holds onto the protocol's CloseCall request until the ref count goes to zero -
  3637. // which means the miniport has to have completed its RELEASE_VC, which will
  3638. // inturn mandate that we will NOT get any further indications from it.
  3639. // The miniport must not complete a RELEASE_VC until it is no longer indicating data.
  3640. //
  3641. for (i = 0, pPktArray = PacketArray;
  3642. i < NumberOfPackets;
  3643. i++, pPktArray++)
  3644. {
  3645. Packet = *pPktArray;
  3646. ASSERT(Packet != NULL);
  3647. #ifdef TRACK_RECEIVED_PACKETS
  3648. OrgPacketStackLocation = CURR_STACK_LOCATION(Packet);
  3649. #endif
  3650. pOob = NDIS_OOB_DATA_FROM_PACKET(Packet);
  3651. PUSH_PACKET_STACK(Packet);
  3652. NDIS_STACK_RESERVED_FROM_PACKET(Packet, &NSR)
  3653. DIRECTED_PACKETS_IN(Miniport);
  3654. DIRECTED_BYTES_IN_PACKET(Miniport, Packet);
  3655. //
  3656. // Set context in the packet so that NdisReturnPacket can do the right thing
  3657. //
  3658. NDIS_INITIALIZE_RCVD_PACKET(Packet, NSR, Miniport);
  3659. if (pOob->Status != NDIS_STATUS_RESOURCES)
  3660. {
  3661. pOob->Status = NDIS_STATUS_SUCCESS;
  3662. }
  3663. //
  3664. // Indicate the packet to the binding.
  3665. //
  3666. if ((VcBlock->Flags & VC_HANDOFF_IN_PROGRESS) == 0)
  3667. {
  3668. NSR->XRefCount = (SHORT)(*VcBlock->CoReceivePacketHandler)(VcBlock->ClientOpen->ProtocolBindingContext,
  3669. VcBlock->ClientContext,
  3670. Packet);
  3671. }
  3672. else
  3673. {
  3674. //
  3675. // This VC is being transitioned from the NDIS proxy to
  3676. // a proxied client. Since the proxy client may not be fully
  3677. // set up, don't indicate this packet.
  3678. //
  3679. NSR->XRefCount = 0;
  3680. }
  3681. //
  3682. // If there are promiscuous opens on this miniport, indicate it to them as well.
  3683. // The client context will identify the VC.
  3684. //
  3685. if ((NumPmodeOpens = Miniport->PmodeOpens) > 0)
  3686. {
  3687. PNULL_BINDING_INFO Open, NextOpen;
  3688. PNDIS_OPEN_BLOCK pPmodeOpen;
  3689. for (Open = Filter->OpenList;
  3690. Open && (NumPmodeOpens > 0);
  3691. Open = NextOpen)
  3692. {
  3693. NextOpen = Open->NextOpen;
  3694. pPmodeOpen = (PNDIS_OPEN_BLOCK)(Open->NdisBindingHandle);
  3695. if (pPmodeOpen->Flags & fMINIPORT_OPEN_PMODE)
  3696. {
  3697. NDIS_STATUS SavedStatus;
  3698. UINT Ref;
  3699. if (pPmodeOpen->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler != NULL)
  3700. {
  3701. pPmodeOpen->Flags |= fMINIPORT_PACKET_RECEIVED;
  3702. SavedStatus = NDIS_GET_PACKET_STATUS(Packet);
  3703. NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_RESOURCES);
  3704. //
  3705. // For Pmode opens, we pass the VcId to the indication routine
  3706. // since the protocol does not really own the VC.
  3707. //
  3708. Ref = (*pPmodeOpen->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler)(
  3709. pPmodeOpen->ProtocolBindingContext,
  3710. &VcBlock->VcId,
  3711. Packet);
  3712. ASSERT(Ref == 0);
  3713. NDIS_SET_PACKET_STATUS(Packet, SavedStatus);
  3714. }
  3715. NumPmodeOpens --;
  3716. }
  3717. }
  3718. }
  3719. //
  3720. // Tackle refcounts now
  3721. //
  3722. TACKLE_REF_COUNT(Miniport, Packet, NSR, pOob);
  3723. }
  3724. READ_UNLOCK_FILTER(Miniport, Filter, &LockState);
  3725. }
  3726. VOID
  3727. NdisMCoReceiveComplete(
  3728. IN NDIS_HANDLE MiniportAdapterHandle
  3729. )
  3730. /*++
  3731. Routine Description:
  3732. This routine is called by the Miniport to indicate that the receive
  3733. process is complete to all bindings. Only those bindings which
  3734. have received packets will be notified. The Miniport lock is held
  3735. when this is called.
  3736. Arguments:
  3737. MiniportAdapterHandle - The handle supplied by Ndis at initialization
  3738. time through miniport initialize.
  3739. Return Value:
  3740. None.
  3741. --*/
  3742. {
  3743. PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
  3744. PNULL_FILTER Filter;
  3745. PNDIS_OPEN_BLOCK Open;
  3746. LOCK_STATE LockState;
  3747. Filter = Miniport->NullDB;
  3748. READ_LOCK_FILTER(Miniport, Filter, &LockState);
  3749. //
  3750. // check all of the bindings on this adapter
  3751. //
  3752. for (Open = Miniport->OpenQueue;
  3753. Open != NULL;
  3754. Open = Open->MiniportNextOpen)
  3755. {
  3756. if (Open->Flags & fMINIPORT_PACKET_RECEIVED)
  3757. {
  3758. //
  3759. // Indicate the binding.
  3760. //
  3761. Open->Flags &= ~fMINIPORT_PACKET_RECEIVED;
  3762. (*Open->ReceiveCompleteHandler)(Open->ProtocolBindingContext);
  3763. }
  3764. }
  3765. READ_UNLOCK_FILTER(Miniport, Filter, &LockState);
  3766. }
  3767. VOID
  3768. NdisCoSendPackets(
  3769. IN NDIS_HANDLE NdisVcHandle,
  3770. IN PPNDIS_PACKET PacketArray,
  3771. IN UINT NumberOfPackets
  3772. )
  3773. /*++
  3774. Routine Description:
  3775. Arguments:
  3776. Return Value:
  3777. --*/
  3778. {
  3779. PNDIS_CO_VC_PTR_BLOCK VcPtr = (PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle;
  3780. PNULL_FILTER Filter;
  3781. LOCK_STATE LockState;
  3782. PNDIS_CO_VC_BLOCK VcBlock = VcPtr->VcBlock;
  3783. PNDIS_STACK_RESERVED NSR;
  3784. PNDIS_MINIPORT_BLOCK Miniport = VcPtr->Miniport;
  3785. PNDIS_PACKET Packet;
  3786. UINT PacketCount, Index, NumToSend;
  3787. NDIS_STATUS Status;
  3788. ULONG NumPmodeOpens;
  3789. DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
  3790. ("NdisCoSendPackets: VcPtr %x, FirstPkt %x, NumPkts %d\n",
  3791. VcPtr, *PacketArray, NumberOfPackets));
  3792. Filter = Miniport->NullDB;
  3793. READ_LOCK_FILTER(Miniport, Filter, &LockState);
  3794. //
  3795. // If there are promiscuous opens on this miniport, this must be indicated to them.
  3796. // Do this before it is send down to the miniport to preserve packet ordering.
  3797. //
  3798. if ((NumPmodeOpens = Miniport->PmodeOpens) > 0)
  3799. {
  3800. PNDIS_OPEN_BLOCK pPmodeOpen;
  3801. for (pPmodeOpen = Miniport->OpenQueue;
  3802. pPmodeOpen && (NumPmodeOpens > 0);
  3803. pPmodeOpen = pPmodeOpen->MiniportNextOpen)
  3804. {
  3805. if (pPmodeOpen->Flags & fMINIPORT_OPEN_PMODE)
  3806. {
  3807. ULONG Ref;
  3808. pPmodeOpen->Flags |= fMINIPORT_PACKET_RECEIVED;
  3809. for (PacketCount = 0; PacketCount < NumberOfPackets; PacketCount++)
  3810. {
  3811. Packet = PacketArray[PacketCount];
  3812. //
  3813. // For Pmode opens, we pass the VcId to the indication routine
  3814. // since the protocol does not really own the VC. On lookback
  3815. // the packet cannot be held.
  3816. //
  3817. Status = NDIS_GET_PACKET_STATUS(Packet);
  3818. NDIS_SET_PACKET_STATUS(Packet, NDIS_STATUS_RESOURCES);
  3819. Packet->Private.Flags |= NDIS_FLAGS_IS_LOOPBACK_PACKET;
  3820. Ref = (*pPmodeOpen->ProtocolHandle->ProtocolCharacteristics.CoReceivePacketHandler)(
  3821. pPmodeOpen->ProtocolBindingContext,
  3822. &VcBlock->VcId,
  3823. Packet);
  3824. ASSERT(Ref == 0);
  3825. NDIS_SET_PACKET_STATUS(Packet, Status);
  3826. Packet->Private.Flags &= ~NDIS_FLAGS_IS_LOOPBACK_PACKET;
  3827. }
  3828. NumPmodeOpens--;
  3829. }
  3830. }
  3831. }
  3832. Status = NDIS_STATUS_SUCCESS;
  3833. for (PacketCount = 0, Index = 0, NumToSend = 0;
  3834. PacketCount < NumberOfPackets;
  3835. PacketCount++)
  3836. {
  3837. Packet = PacketArray[PacketCount];
  3838. PUSH_PACKET_STACK(Packet);
  3839. NDIS_STACK_RESERVED_FROM_PACKET(Packet, &NSR)
  3840. if (MINIPORT_TEST_SEND_FLAG(Miniport, fMINIPORT_SEND_DO_NOT_MAP_MDLS))
  3841. {
  3842. ndisMCheckPacketAndGetStatsOutAlreadyMapped(Miniport, Packet);
  3843. }
  3844. else
  3845. {
  3846. ndisMCheckPacketAndGetStatsOut(Miniport, Packet, &Status);
  3847. }
  3848. if (Status == NDIS_STATUS_SUCCESS)
  3849. {
  3850. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_SG_LIST))
  3851. {
  3852. NSR->Open = VcPtr->ClientOpen;
  3853. NSR->VcPtr = VcPtr;
  3854. ndisMAllocSGList(Miniport, Packet);
  3855. }
  3856. else
  3857. {
  3858. NumToSend ++;
  3859. }
  3860. }
  3861. else
  3862. {
  3863. NdisMCoSendComplete(NDIS_STATUS_RESOURCES, NdisVcHandle, Packet);
  3864. if (NumToSend != 0)
  3865. {
  3866. ASSERT (!MINIPORT_TEST_FLAG(Miniport, fMINIPORT_SG_LIST));
  3867. //
  3868. // Call down to the miniport to send this batch
  3869. // The miniport must complete the sends for all cases.
  3870. // The send either succeeds/pends or fails.
  3871. //
  3872. (*VcPtr->WCoSendPacketsHandler)(VcPtr->MiniportContext,
  3873. &PacketArray[Index],
  3874. NumToSend);
  3875. NumToSend = 0;
  3876. }
  3877. Index = PacketCount + 1;
  3878. }
  3879. }
  3880. if (NumToSend != 0)
  3881. {
  3882. //
  3883. // Send down the remaining packets
  3884. //
  3885. (*VcPtr->WCoSendPacketsHandler)(VcPtr->MiniportContext,
  3886. &PacketArray[Index],
  3887. NumToSend);
  3888. }
  3889. READ_UNLOCK_FILTER(Miniport, Filter, &LockState);
  3890. }
  3891. VOID
  3892. NdisMCoSendComplete(
  3893. IN NDIS_STATUS Status,
  3894. IN NDIS_HANDLE NdisVcHandle,
  3895. IN PNDIS_PACKET Packet
  3896. )
  3897. /*++
  3898. Routine Description:
  3899. This function is called by the miniport when a send has completed. This
  3900. routine simply calls the protocol to pass along the indication.
  3901. Arguments:
  3902. MiniportAdapterHandle - points to the adapter block.
  3903. NdisVcHandle - the handle supplied to the adapter on the OID_RESERVE_VC
  3904. PacketArray - a ptr to an array of NDIS_PACKETS
  3905. NumberOfPackets - the number of packets in PacketArray
  3906. Status - the send status that applies to all packets in the array
  3907. Return Value:
  3908. None.
  3909. --*/
  3910. {
  3911. PNDIS_MINIPORT_BLOCK Miniport;
  3912. PNDIS_OPEN_BLOCK Open;
  3913. PNDIS_CO_VC_PTR_BLOCK VcPtr = (PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle;
  3914. PNDIS_CO_VC_BLOCK VcBlock = VcPtr->VcBlock;
  3915. PNDIS_STACK_RESERVED NSR;
  3916. DBGPRINT(DBG_COMP_SEND, DBG_LEVEL_INFO,
  3917. ("NdisMCoSendComplete: Status %x, VcPtr %x, Pkt %x\n",
  3918. Status, VcPtr, Packet));
  3919. //
  3920. // There should not be any reason to grab the spin lock and increment the
  3921. // ref count on Open since the open cannot close until the Vc closes and
  3922. // the Vc cannot close in the middle of an indication because the miniport
  3923. // will not complete a RELEASE_VC until is it no longer indicating
  3924. //
  3925. //
  3926. // Indicate to Protocol;
  3927. //
  3928. Open = VcBlock->ClientOpen;
  3929. Miniport = VcBlock->Miniport;
  3930. if (MINIPORT_TEST_FLAG(Miniport, fMINIPORT_SG_LIST) &&
  3931. (NDIS_PER_PACKET_INFO_FROM_PACKET(Packet, ScatterGatherListPacketInfo) != NULL))
  3932. {
  3933. ndisMFreeSGList(Miniport, Packet);
  3934. }
  3935. NDIS_STACK_RESERVED_FROM_PACKET(Packet, &NSR)
  3936. MINIPORT_CLEAR_PACKET_FLAG(Packet, fPACKET_CLEAR_ITEMS);
  3937. CLEAR_WRAPPER_RESERVED(NSR);
  3938. POP_PACKET_STACK(Packet);
  3939. (VcBlock->CoSendCompleteHandler)(Status,
  3940. VcBlock->ClientContext,
  3941. Packet);
  3942. //
  3943. // Technically this Vc should not close since there is a send outstanding
  3944. // on it, and the client should not close a Vc with an outstanding send.
  3945. //
  3946. // Took out the VcBlock->References assertion since refs are now kept in VcPtr.
  3947. // NOTE: We could keep the Client ref count (i.e. the VcPtr of the protocol
  3948. // that receives the data indications) in the VC, and use a pointer in the VcPtr,
  3949. // in which case we would assert on *VcPtr->pReferences.
  3950. //
  3951. ASSERT(Open->References > 0);
  3952. }
  3953. VOID
  3954. NdisMCoIndicateStatus(
  3955. IN NDIS_HANDLE MiniportAdapterHandle,
  3956. IN NDIS_HANDLE NdisVcHandle,
  3957. IN NDIS_STATUS GeneralStatus,
  3958. IN PVOID StatusBuffer,
  3959. IN ULONG StatusBufferSize
  3960. )
  3961. /*++
  3962. Routine Description:
  3963. This routine handles passing CoStatus to the protocol. The miniport calls
  3964. this routine when it has status on a VC or a general status for all Vcs - in
  3965. this case the NdisVcHandle is null.
  3966. Arguments:
  3967. MiniportAdapterHandle - pointer to the mini-port block;
  3968. NdisVcHandle - a pointer to the Vc block
  3969. GeneralStatus - the completion status of the request.
  3970. StatusBuffer - a buffer containing medium and status specific info
  3971. StatusBufferSize - the size of the buffer.
  3972. Return Value:
  3973. none
  3974. --*/
  3975. {
  3976. PNDIS_MINIPORT_BLOCK Miniport = (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
  3977. PNDIS_CO_VC_PTR_BLOCK VcPtr = (PNDIS_CO_VC_PTR_BLOCK)NdisVcHandle;
  3978. PNDIS_CO_VC_BLOCK VcBlock;
  3979. PNDIS_OPEN_BLOCK Open;
  3980. BOOLEAN fMediaConnectStateIndication = FALSE;
  3981. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  3982. ("==>NdisMCoIndicateStatus\n"));
  3983. if ((GeneralStatus == NDIS_STATUS_MEDIA_CONNECT) || (GeneralStatus == NDIS_STATUS_MEDIA_DISCONNECT))
  3984. {
  3985. fMediaConnectStateIndication = TRUE;
  3986. }
  3987. do
  3988. {
  3989. NTSTATUS NtStatus;
  3990. PUNICODE_STRING InstanceName;
  3991. PWNODE_SINGLE_INSTANCE wnode;
  3992. ULONG DataBlockSize = 0;
  3993. ULONG BufSize;
  3994. PUCHAR ptmp;
  3995. PNDIS_GUID pNdisGuid;
  3996. //
  3997. // Get nice pointers to the instance names.
  3998. //
  3999. if (NULL != NdisVcHandle)
  4000. {
  4001. InstanceName = &VcPtr->VcInstanceName;
  4002. }
  4003. else
  4004. {
  4005. InstanceName = Miniport->pAdapterInstanceName;
  4006. }
  4007. //
  4008. // If there is no instance name then we can't indicate an event.
  4009. //
  4010. if (NULL == InstanceName)
  4011. {
  4012. break;
  4013. }
  4014. //
  4015. // Check to see if the status is enabled for WMI event indication.
  4016. //
  4017. NtStatus = ndisWmiGetGuid(&pNdisGuid, Miniport, NULL, GeneralStatus);
  4018. if ((!NT_SUCCESS(NtStatus)) ||
  4019. !NDIS_GUID_TEST_FLAG(pNdisGuid, fNDIS_GUID_EVENT_ENABLED))
  4020. {
  4021. break;
  4022. }
  4023. //
  4024. // If the data item is an array then we need to add in the number of
  4025. // elements.
  4026. //
  4027. if (NDIS_GUID_TEST_FLAG(pNdisGuid, fNDIS_GUID_ARRAY))
  4028. {
  4029. DataBlockSize = StatusBufferSize + sizeof(ULONG);
  4030. }
  4031. else
  4032. {
  4033. DataBlockSize = pNdisGuid->Size;
  4034. }
  4035. //
  4036. // in case of media connect/disconnect status indication, include the
  4037. // NIC's name in the WMI event
  4038. //
  4039. if (fMediaConnectStateIndication && (NULL == NdisVcHandle))
  4040. {
  4041. DataBlockSize += Miniport->MiniportName.Length + sizeof(WCHAR);
  4042. }
  4043. ndisSetupWmiNode(Miniport,
  4044. InstanceName,
  4045. DataBlockSize,
  4046. (PVOID)&pNdisGuid->Guid,
  4047. &wnode);
  4048. if (wnode != NULL)
  4049. {
  4050. //
  4051. // Save the number of elements in the first ULONG.
  4052. //
  4053. ptmp = (PUCHAR)wnode + wnode->DataBlockOffset;
  4054. //
  4055. // Copy in the data.
  4056. //
  4057. if (NDIS_GUID_TEST_FLAG(pNdisGuid, fNDIS_GUID_ARRAY))
  4058. {
  4059. //
  4060. // If the status is an array but there is no data then complete it with no
  4061. // data and a 0 length
  4062. //
  4063. if ((NULL == StatusBuffer) || (0 == StatusBufferSize))
  4064. {
  4065. *((PULONG)ptmp) = 0;
  4066. ptmp += sizeof(ULONG);
  4067. }
  4068. else
  4069. {
  4070. //
  4071. // Save the number of elements in the first ULONG.
  4072. //
  4073. *((PULONG)ptmp) = StatusBufferSize / pNdisGuid->Size;
  4074. //
  4075. // Copy the data after the number of elements.
  4076. //
  4077. NdisMoveMemory(ptmp + sizeof(ULONG), StatusBuffer, StatusBufferSize);
  4078. ptmp += sizeof(ULONG) + StatusBufferSize;
  4079. }
  4080. }
  4081. else
  4082. {
  4083. //
  4084. // Do we indicate any data up?
  4085. //
  4086. if (0 != pNdisGuid->Size)
  4087. {
  4088. //
  4089. // Copy the data into the buffer.
  4090. //
  4091. NdisMoveMemory(ptmp, StatusBuffer, pNdisGuid->Size);
  4092. ptmp += pNdisGuid->Size;
  4093. }
  4094. }
  4095. if (fMediaConnectStateIndication && (NULL == NdisVcHandle))
  4096. {
  4097. //
  4098. // for media connect/disconnect status,
  4099. // add the name of the adapter
  4100. //
  4101. RtlCopyMemory(ptmp,
  4102. Miniport->MiniportName.Buffer,
  4103. Miniport->MiniportName.Length);
  4104. }
  4105. //
  4106. // Indicate the event to WMI. WMI will take care of freeing
  4107. // the WMI struct back to pool.
  4108. //
  4109. NtStatus = IoWMIWriteEvent(wnode);
  4110. if (!NT_SUCCESS(NtStatus))
  4111. {
  4112. DBGPRINT(DBG_COMP_WMI, DBG_LEVEL_ERR,
  4113. (" ndisMCoIndicateStatus: Unable to indicate the WMI event.\n"));
  4114. FREE_POOL(wnode);
  4115. }
  4116. }
  4117. } while (FALSE);
  4118. switch (GeneralStatus)
  4119. {
  4120. case NDIS_STATUS_MEDIA_DISCONNECT:
  4121. MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_MEDIA_CONNECTED);
  4122. //
  4123. // miniport can do media sense and indicate that status to Ndis
  4124. //
  4125. MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_REQUIRES_MEDIA_POLLING);
  4126. MINIPORT_SET_FLAG(Miniport, fMINIPORT_SUPPORTS_MEDIA_SENSE);
  4127. //
  4128. // Is this a PM enabled miniport? And is dynamic power policy
  4129. // enabled for the miniport?
  4130. //
  4131. if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_DEVICE_POWER_ENABLE) &&
  4132. (Miniport->WakeUpEnable & NDIS_PNP_WAKE_UP_LINK_CHANGE) &&
  4133. (Miniport->MediaDisconnectTimeOut != (USHORT)(-1)))
  4134. {
  4135. //
  4136. // Are we already waiting for the disconnect timer to fire?
  4137. //
  4138. if (!MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_WAIT))
  4139. {
  4140. //
  4141. // Mark the miniport as disconnecting and fire off the
  4142. // timer.
  4143. //
  4144. MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_CANCELLED);
  4145. MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_WAIT);
  4146. NdisSetTimer(&Miniport->MediaDisconnectTimer, Miniport->MediaDisconnectTimeOut * 1000);
  4147. }
  4148. }
  4149. break;
  4150. case NDIS_STATUS_MEDIA_CONNECT:
  4151. MINIPORT_SET_FLAG(Miniport, fMINIPORT_MEDIA_CONNECTED);
  4152. //
  4153. // miniport can do media sense and can indicate that status to Ndis. Do not poll
  4154. //
  4155. MINIPORT_CLEAR_FLAG(Miniport, fMINIPORT_REQUIRES_MEDIA_POLLING);
  4156. MINIPORT_SET_FLAG(Miniport, fMINIPORT_SUPPORTS_MEDIA_SENSE);
  4157. //
  4158. // if media disconnect timer was set, cancel the timer
  4159. //
  4160. if (MINIPORT_PNP_TEST_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_WAIT))
  4161. {
  4162. BOOLEAN fTimerCancelled;
  4163. //
  4164. // Clear the disconnect wait bit and cancel the timer.
  4165. // IF the timer routine hasn't grabed the lock then we are ok.
  4166. //
  4167. MINIPORT_PNP_CLEAR_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_WAIT);
  4168. MINIPORT_PNP_SET_FLAG(Miniport, fMINIPORT_MEDIA_DISCONNECT_CANCELLED);
  4169. NdisCancelTimer(&Miniport->MediaDisconnectTimer, &fTimerCancelled);
  4170. }
  4171. break;
  4172. }
  4173. if (VcPtr != NULL)
  4174. {
  4175. VcBlock = VcPtr->VcBlock;
  4176. //
  4177. // If this is a proxied VC, indicate to the proxy.
  4178. //
  4179. if (VcBlock->pProxyVcPtr)
  4180. {
  4181. Open = VcBlock->pProxyVcPtr->ClientOpen;
  4182. (Open->ProtocolHandle->ProtocolCharacteristics.CoStatusHandler)(Open->ProtocolBindingContext,
  4183. VcPtr->ClientContext,
  4184. GeneralStatus,
  4185. StatusBuffer,
  4186. StatusBufferSize);
  4187. }
  4188. //
  4189. // Indicate to the client.
  4190. //
  4191. if (VcBlock->pClientVcPtr)
  4192. {
  4193. Open = VcBlock->pClientVcPtr->ClientOpen;
  4194. (Open->ProtocolHandle->ProtocolCharacteristics.CoStatusHandler)(Open->ProtocolBindingContext,
  4195. VcPtr->ClientContext,
  4196. GeneralStatus,
  4197. StatusBuffer,
  4198. StatusBufferSize);
  4199. }
  4200. }
  4201. else if (Miniport->NullDB != NULL)
  4202. {
  4203. LOCK_STATE LockState;
  4204. //
  4205. // this must be a general status for all clients of this miniport
  4206. // since the Vc handle is null, so indicate this to all protocols.
  4207. //
  4208. READ_LOCK_FILTER(Miniport, Miniport->NullDB, &LockState);
  4209. for (Open = Miniport->OpenQueue;
  4210. Open != NULL;
  4211. Open = Open->MiniportNextOpen)
  4212. {
  4213. if (((Open->Flags & fMINIPORT_OPEN_CLOSING) == 0) &&
  4214. (Open->ProtocolHandle->ProtocolCharacteristics.CoStatusHandler != NULL))
  4215. {
  4216. (Open->ProtocolHandle->ProtocolCharacteristics.CoStatusHandler)(
  4217. Open->ProtocolBindingContext,
  4218. NULL,
  4219. GeneralStatus,
  4220. StatusBuffer,
  4221. StatusBufferSize);
  4222. }
  4223. }
  4224. READ_UNLOCK_FILTER(Miniport, Miniport->NullDB, &LockState);
  4225. }
  4226. DBGPRINT(DBG_COMP_CO, DBG_LEVEL_INFO,
  4227. ("<==NdisMCoIndicateStatus\n"));
  4228. }
  4229. VOID
  4230. ndisDereferenceAfNotification(
  4231. IN PNDIS_OPEN_BLOCK Open
  4232. )
  4233. {
  4234. ULONG Ref;
  4235. KIRQL OldIrql;
  4236. // DbgPrint("==>ndisDereferenceAfNotification Open: %p\n", Open);
  4237. ACQUIRE_SPIN_LOCK(&Open->SpinLock, &OldIrql);
  4238. OPEN_DECREMENT_AF_NOTIFICATION(Open, Ref);
  4239. if ((Ref == 0) &&
  4240. (Open->AfNotifyCompleteEvent != NULL))
  4241. {
  4242. SET_EVENT(Open->AfNotifyCompleteEvent);
  4243. }
  4244. RELEASE_SPIN_LOCK(&Open->SpinLock, OldIrql);
  4245. // DbgPrint("<==ndisDereferenceAfNotification Open: %p, Ref %lx\n", Open, Ref);
  4246. }