Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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