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

3099 lines
63 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. D:\nt\private\ntos\tdi\rawwan\core\tdiconn.c
  5. Abstract:
  6. TDI Entry points and support routines for Connection Objects.
  7. Revision History:
  8. Who When What
  9. -------- -------- ----------------------------------------------
  10. arvindm 04-30-97 Created
  11. Notes:
  12. --*/
  13. #include <precomp.h>
  14. #define _FILENUMBER 'NCDT'
  15. //
  16. // Private macros and definitions for the Connection Table. Copied from TCP.
  17. //
  18. #define RWAN_GET_SLOT_FROM_CONN_ID(_Id) ((_Id) & 0xffffff)
  19. #define RWAN_GET_INSTANCE_FROM_CONN_ID(_Id) ((UCHAR)((_Id) >> 24))
  20. #define RWAN_MAKE_CONN_ID(_Inst, _Slot) ((((RWAN_CONN_ID)(_Inst)) << 24) | ((RWAN_CONN_ID)(_Slot)))
  21. #define RWAN_INVALID_CONN_ID RWAN_MAKE_CONN_ID(0xff, 0xffffff)
  22. #define CONN_TABLE_GROW_DELTA 16
  23. TDI_STATUS
  24. RWanTdiOpenConnection(
  25. IN OUT PTDI_REQUEST pTdiRequest,
  26. IN PVOID ConnectionHandle
  27. )
  28. /*++
  29. Routine Description:
  30. This is the TDI entry point for opening (creating) a Connection Object.
  31. We allocate a new Connection object and return an index to it in the
  32. request itself.
  33. Arguments:
  34. pTdiRequest - Pointer to the TDI Request
  35. ConnectionHandle- This is how we refer to this connection in up-calls
  36. Return Value:
  37. TDI_SUCCESS if a connection object was successfully created, TDI_XXX
  38. failure code otherwise.
  39. --*/
  40. {
  41. TDI_STATUS Status;
  42. PRWAN_TDI_CONNECTION pConnObject;
  43. RWAN_CONN_ID ConnId;
  44. //
  45. // Initialize.
  46. //
  47. pConnObject = NULL_PRWAN_TDI_CONNECTION;
  48. do
  49. {
  50. pConnObject = RWanAllocateConnObject();
  51. if (pConnObject == NULL_PRWAN_TDI_CONNECTION)
  52. {
  53. Status = TDI_NO_RESOURCES;
  54. break;
  55. }
  56. RWAN_ACQUIRE_CONN_TABLE_LOCK();
  57. //
  58. // Prepare a context to be returned. We don't return a pointer
  59. // to our Connection object as our context, because, seemingly,
  60. // there is a chance that we might get invalid connection
  61. // contexts in other TDI requests. So we need a way to validate
  62. // a received connection context. This indirection (of using a
  63. // Connection Index) helps us do so.
  64. //
  65. ConnId = RWanGetConnId(pConnObject);
  66. RWAN_RELEASE_CONN_TABLE_LOCK();
  67. if (ConnId == RWAN_INVALID_CONN_ID)
  68. {
  69. Status = TDI_NO_RESOURCES;
  70. break;
  71. }
  72. RWanReferenceConnObject(pConnObject); // TdiOpenConnection ref
  73. pConnObject->ConnectionHandle = ConnectionHandle;
  74. //
  75. // Return our context for this connection object.
  76. //
  77. pTdiRequest->Handle.ConnectionContext = (CONNECTION_CONTEXT)UlongToPtr(ConnId);
  78. Status = TDI_SUCCESS;
  79. break;
  80. }
  81. while (FALSE);
  82. RWANDEBUGP(DL_EXTRA_LOUD, DC_CONNECT,
  83. ("RWanTdiOpenConnection: pConnObj x%x, Handle x%x, Status x%x\n",
  84. pConnObject,
  85. ConnectionHandle,
  86. Status));
  87. if (Status != TDI_SUCCESS)
  88. {
  89. //
  90. // Clean up before returning.
  91. //
  92. if (pConnObject != NULL_PRWAN_TDI_CONNECTION)
  93. {
  94. RWAN_FREE_MEM(pConnObject);
  95. }
  96. }
  97. return (Status);
  98. }
  99. #if DBG
  100. PVOID
  101. RWanTdiDbgGetConnObject(
  102. IN HANDLE ConnectionContext
  103. )
  104. /*++
  105. Routine Description:
  106. DEBUGGING ONLY: Return our internal context for a connection
  107. Arguments:
  108. ConnectionContext - TDI context
  109. Return Value:
  110. Pointer to our Connection structure if found, else NULL.
  111. --*/
  112. {
  113. PRWAN_TDI_CONNECTION pConnObject;
  114. RWAN_ACQUIRE_CONN_TABLE_LOCK();
  115. pConnObject = RWanGetConnFromId((RWAN_CONN_ID)PtrToUlong(ConnectionContext));
  116. RWAN_RELEASE_CONN_TABLE_LOCK();
  117. return ((PVOID)pConnObject);
  118. }
  119. #endif
  120. TDI_STATUS
  121. RWanTdiCloseConnection(
  122. IN PTDI_REQUEST pTdiRequest
  123. )
  124. /*++
  125. Routine Description:
  126. This is the TDI entry point to close a Connection Object.
  127. If the connection object is participating in a connection, we
  128. initiate teardown. If it is associated with an address object, we
  129. handle disassociation.
  130. Arguments:
  131. pTdiRequest - Pointer to the TDI Request
  132. Return Value:
  133. TDI_STATUS - this is TDI_PENDING if we started off CloseConnection
  134. successfully, TDI_SUCCESS if we are done with CloseConnection in here,
  135. TDI_INVALID_CONNECTION if the connection context is invalid.
  136. --*/
  137. {
  138. PRWAN_TDI_CONNECTION pConnObject;
  139. PRWAN_TDI_ADDRESS pAddrObject;
  140. PRWAN_NDIS_VC pVc;
  141. TDI_STATUS Status;
  142. RWAN_CONN_ID ConnId;
  143. PRWAN_CONN_REQUEST pConnReq;
  144. NDIS_HANDLE NdisVcHandle;
  145. INT rc;
  146. BOOLEAN bIsLockAcquired;
  147. #if DBG
  148. RWAN_IRQL EntryIrq, ExitIrq;
  149. #endif // DBG
  150. RWAN_GET_ENTRY_IRQL(EntryIrq);
  151. ConnId = (RWAN_CONN_ID) PtrToUlong(pTdiRequest->Handle.ConnectionContext);
  152. Status = TDI_PENDING;
  153. bIsLockAcquired = FALSE; // Do we hold the Conn Object locked?
  154. do
  155. {
  156. RWAN_ACQUIRE_CONN_TABLE_LOCK();
  157. pConnObject = RWanGetConnFromId(ConnId);
  158. if (pConnObject == NULL_PRWAN_TDI_CONNECTION)
  159. {
  160. RWAN_RELEASE_CONN_TABLE_LOCK();
  161. Status = TDI_INVALID_CONNECTION;
  162. break;
  163. }
  164. //
  165. // Remove this Connection Object from the Conn Table.
  166. // This effectively invalidates this ConnId.
  167. //
  168. RWanFreeConnId(ConnId);
  169. RWAN_RELEASE_CONN_TABLE_LOCK();
  170. RWANDEBUGP(DL_LOUD, DC_DISCON,
  171. ("TdiCloseConnection: pConnObj x%x, State/Flags/Ref x%x/x%x/%d, pAddrObj x%x\n",
  172. pConnObject,
  173. pConnObject->State,
  174. pConnObject->Flags,
  175. pConnObject->RefCount,
  176. pConnObject->pAddrObject));
  177. RWAN_ACQUIRE_CONN_LOCK(pConnObject);
  178. #if DBG
  179. pConnObject->OldState = pConnObject->State;
  180. pConnObject->OldFlags = pConnObject->Flags;
  181. #endif
  182. //
  183. // Mark this Connection Object as closing, and set Delete
  184. // Notification info: this will be called when the Connection
  185. // is dereferenced to death.
  186. //
  187. RWAN_SET_BIT(pConnObject->Flags, RWANF_CO_CLOSING);
  188. pConnObject->DeleteNotify.pDeleteRtn = pTdiRequest->RequestNotifyObject;
  189. pConnObject->DeleteNotify.DeleteContext = pTdiRequest->RequestContext;
  190. //
  191. // Discard any pending operation.
  192. //
  193. pConnReq = pConnObject->pConnReq;
  194. if (pConnReq != NULL)
  195. {
  196. RWanFreeConnReq(pConnReq);
  197. pConnObject->pConnReq = NULL;
  198. }
  199. //
  200. // Remove the TdiOpenConnection reference.
  201. //
  202. rc = RWanDereferenceConnObject(pConnObject); // deref: TdiCloseConn
  203. if (rc == 0)
  204. {
  205. //
  206. // The Connection object is gone. CloseConnection completion
  207. // would have been called.
  208. //
  209. break;
  210. }
  211. pAddrObject = pConnObject->pAddrObject;
  212. //
  213. // Force Disassociate Address if associated.
  214. //
  215. if (pAddrObject != NULL_PRWAN_TDI_ADDRESS)
  216. {
  217. //
  218. // Add a temp reference to keep this Conn Object alive while we
  219. // reacquire locks in the right order.
  220. //
  221. RWanReferenceConnObject(pConnObject); // temp ref: CloseConn
  222. RWAN_RELEASE_CONN_LOCK(pConnObject);
  223. RWAN_ACQUIRE_ADDRESS_LOCK(pAddrObject);
  224. RWAN_ACQUIRE_CONN_LOCK_DPC(pConnObject);
  225. //
  226. // Remove from list on Address Object.
  227. //
  228. RWAN_DELETE_FROM_LIST(&(pConnObject->ConnLink));
  229. pConnObject->pAddrObject = NULL_PRWAN_TDI_ADDRESS;
  230. rc = RWanDereferenceConnObject(pConnObject); // Force disassoc deref: CloseConn
  231. RWAN_ASSERT(rc != 0);
  232. RWAN_RELEASE_CONN_LOCK_DPC(pConnObject);
  233. rc = RWanDereferenceAddressObject(pAddrObject); // Force Disassoc: CloseConn
  234. if (rc != 0)
  235. {
  236. RWAN_RELEASE_ADDRESS_LOCK(pAddrObject);
  237. }
  238. //
  239. // Reacquire ConnObject lock: we still have the temp reference on it.
  240. //
  241. RWAN_ACQUIRE_CONN_LOCK(pConnObject);
  242. rc = RWanDereferenceConnObject(pConnObject); // remove temp ref: CloseConn
  243. if (rc == 0)
  244. {
  245. RWAN_ASSERT(Status == TDI_PENDING);
  246. break;
  247. }
  248. }
  249. bIsLockAcquired = TRUE;
  250. //
  251. // If this is a root connection object, abort the connection.
  252. //
  253. if (RWAN_IS_BIT_SET(pConnObject->Flags, RWANF_CO_ROOT))
  254. {
  255. RWANDEBUGP(DL_FATAL, DC_DISCON,
  256. ("TdiCloseConn: found root Conn Obj x%x\n", pConnObject));
  257. RWanReferenceConnObject(pConnObject); // temp ref: CloseConn (root)
  258. RWAN_RELEASE_CONN_LOCK(pConnObject);
  259. RWanDoAbortConnection(pConnObject);
  260. RWAN_ACQUIRE_CONN_LOCK(pConnObject);
  261. rc = RWanDereferenceConnObject(pConnObject); // temp ref: CloseConn (root)
  262. if (rc == 0)
  263. {
  264. bIsLockAcquired = FALSE;
  265. }
  266. break;
  267. }
  268. //
  269. // If the connection is active, tear it down.
  270. //
  271. switch (pConnObject->State)
  272. {
  273. case RWANS_CO_OUT_CALL_INITIATED:
  274. case RWANS_CO_DISCON_REQUESTED:
  275. case RWANS_CO_IN_CALL_ACCEPTING:
  276. //
  277. // An NDIS operation is in progress. When it completes,
  278. // the flag (CLOSING) we set earlier will cause the
  279. // CloseConnection to continue.
  280. //
  281. break;
  282. case RWANS_CO_CONNECTED:
  283. RWanDoTdiDisconnect(
  284. pConnObject,
  285. NULL, // pTdiRequest
  286. NULL, // pTimeout
  287. 0, // Flags
  288. NULL, // pDisconnInfo
  289. NULL // pReturnInfo
  290. );
  291. //
  292. // ConnObject Lock is released within the above.
  293. //
  294. bIsLockAcquired = FALSE;
  295. break;
  296. case RWANS_CO_DISCON_INDICATED:
  297. case RWANS_CO_DISCON_HELD:
  298. case RWANS_CO_ABORTING:
  299. //
  300. // We would have started off an NDIS CloseCall/DropParty
  301. // operation.
  302. //
  303. break;
  304. case RWANS_CO_IN_CALL_INDICATED:
  305. //
  306. // Reject the incoming call.
  307. //
  308. RWanNdisRejectIncomingCall(pConnObject, NDIS_STATUS_FAILURE);
  309. //
  310. // ConnObject Lock is released within the above.
  311. //
  312. bIsLockAcquired = FALSE;
  313. break;
  314. case RWANS_CO_CREATED:
  315. case RWANS_CO_ASSOCIATED:
  316. case RWANS_CO_LISTENING:
  317. default:
  318. //
  319. // We should have broken out of the outer do..while
  320. // earlier.
  321. //
  322. RWANDEBUGP(DL_FATAL, DC_WILDCARD,
  323. ("TdiCloseConn: pConnObj x%x/x%x, bad state %d\n",
  324. pConnObject, pConnObject->Flags, pConnObject->State));
  325. RWAN_ASSERT(FALSE);
  326. break;
  327. }
  328. break;
  329. }
  330. while (FALSE);
  331. if (bIsLockAcquired)
  332. {
  333. RWAN_RELEASE_CONN_LOCK(pConnObject);
  334. }
  335. RWAN_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
  336. RWANDEBUGP(DL_VERY_LOUD, DC_DISCON,
  337. ("TdiCloseConn: pConnObject x%x, returning x%x\n", pConnObject, Status));
  338. return (Status);
  339. }
  340. TDI_STATUS
  341. RWanTdiAssociateAddress(
  342. IN PTDI_REQUEST pTdiRequest,
  343. IN PVOID AddressContext
  344. )
  345. /*++
  346. Routine Description:
  347. This is the TDI entry point to associate a connection object
  348. with an address object. The connection object is identified
  349. by its context buried in the TDI Request, and AddressContext
  350. is our context for an address object.
  351. Arguments:
  352. pTdiRequest - Pointer to the TDI Request
  353. AddressContext - Actually a pointer to our TDI Address object.
  354. Return Value:
  355. TDI_SUCCESS if the association was successful, TDI_ALREADY_ASSOCIATED
  356. if the connection object is already associated with an address object,
  357. TDI_INVALID_CONNECTION if the specified connection context is invalid.
  358. --*/
  359. {
  360. PRWAN_TDI_ADDRESS pAddrObject;
  361. PRWAN_TDI_CONNECTION pConnObject;
  362. RWAN_CONN_ID ConnId;
  363. TDI_STATUS Status;
  364. RWAN_STATUS RWanStatus;
  365. pAddrObject = (PRWAN_TDI_ADDRESS)AddressContext;
  366. RWAN_STRUCT_ASSERT(pAddrObject, nta);
  367. ConnId = (RWAN_CONN_ID) PtrToUlong(pTdiRequest->Handle.ConnectionContext);
  368. do
  369. {
  370. RWAN_ACQUIRE_CONN_TABLE_LOCK();
  371. pConnObject = RWanGetConnFromId(ConnId);
  372. RWAN_RELEASE_CONN_TABLE_LOCK();
  373. if (pConnObject == NULL_PRWAN_TDI_CONNECTION)
  374. {
  375. Status = TDI_INVALID_CONNECTION;
  376. break;
  377. }
  378. if (pConnObject->pAddrObject != NULL_PRWAN_TDI_ADDRESS)
  379. {
  380. Status = TDI_ALREADY_ASSOCIATED;
  381. break;
  382. }
  383. //
  384. // Get a context for this associated connection object
  385. // from the media-specific module.
  386. //
  387. if (pAddrObject->pProtocol->pAfInfo->AfChars.pAfSpAssociateConnection)
  388. {
  389. RWanStatus = (*pAddrObject->pProtocol->pAfInfo->AfChars.pAfSpAssociateConnection)(
  390. pAddrObject->AfSpAddrContext,
  391. (RWAN_HANDLE)pConnObject,
  392. &(pConnObject->AfSpConnContext));
  393. if (RWanStatus != RWAN_STATUS_SUCCESS)
  394. {
  395. Status = RWanToTdiStatus(RWanStatus);
  396. break;
  397. }
  398. RWAN_SET_BIT(pConnObject->Flags, RWANF_CO_AFSP_CONTEXT_VALID);
  399. RWANDEBUGP(DL_LOUD, DC_WILDCARD,
  400. ("Associate: AddrObj %x, ConnObj %x, AfSpAddrCont %x, AfSpConnCont %x\n",
  401. pAddrObject,
  402. pConnObject,
  403. pAddrObject->AfSpAddrContext,
  404. pConnObject->AfSpConnContext));
  405. }
  406. //
  407. // Acquire locks in the right order.
  408. //
  409. RWAN_ACQUIRE_ADDRESS_LOCK(pAddrObject);
  410. RWAN_ACQUIRE_CONN_LOCK_DPC(pConnObject);
  411. RWAN_ASSERT(pConnObject->State == RWANS_CO_CREATED);
  412. pConnObject->State = RWANS_CO_ASSOCIATED;
  413. //
  414. // Attach this Connection Object to this Address Object.
  415. //
  416. pConnObject->pAddrObject = pAddrObject;
  417. RWAN_INSERT_TAIL_LIST(&(pAddrObject->IdleConnList),
  418. &(pConnObject->ConnLink));
  419. RWanReferenceConnObject(pConnObject); // Associate ref
  420. //
  421. // Check if this is a Leaf connection object.
  422. //
  423. if (RWAN_IS_BIT_SET(pAddrObject->Flags, RWANF_AO_PMP_ROOT))
  424. {
  425. RWAN_ASSERT(pAddrObject->pRootConnObject != NULL);
  426. RWAN_SET_BIT(pConnObject->Flags, RWANF_CO_LEAF);
  427. pConnObject->pRootConnObject = pAddrObject->pRootConnObject;
  428. }
  429. RWAN_RELEASE_CONN_LOCK_DPC(pConnObject);
  430. RWanReferenceAddressObject(pAddrObject); // New Connection object associated
  431. RWAN_RELEASE_ADDRESS_LOCK(pAddrObject);
  432. Status = TDI_SUCCESS;
  433. break;
  434. }
  435. while (FALSE);
  436. RWANDEBUGP(DL_EXTRA_LOUD, DC_CONNECT,
  437. ("RWanTdiAssociate: pAddrObject x%x, ConnId x%x, pConnObj x%x, Status x%x\n",
  438. pAddrObject, ConnId, pConnObject, Status));
  439. return (Status);
  440. }
  441. TDI_STATUS
  442. RWanTdiDisassociateAddress(
  443. IN PTDI_REQUEST pTdiRequest
  444. )
  445. /*++
  446. Routine Description:
  447. This is the TDI entry point for disassociating a connection object
  448. from the address object it is currently associated with. The connection
  449. object is identified by its handle buried within the TDI request.
  450. Arguments:
  451. pTdiRequest - Pointer to the TDI Request
  452. Return Value:
  453. TDI_SUCCESS if successful, TDI_NOT_ASSOCIATED if the connection object
  454. isn't associated with an address object, TDI_INVALID_CONNECTION if the
  455. given connection context is invalid, TDI_CONNECTION_ACTIVE if the
  456. connection is active.
  457. --*/
  458. {
  459. PRWAN_TDI_CONNECTION pConnObject;
  460. RWAN_CONN_ID ConnId;
  461. PRWAN_TDI_ADDRESS pAddrObject;
  462. TDI_STATUS Status;
  463. INT rc;
  464. ConnId = (RWAN_CONN_ID) PtrToUlong(pTdiRequest->Handle.ConnectionContext);
  465. do
  466. {
  467. RWAN_ACQUIRE_CONN_TABLE_LOCK();
  468. pConnObject = RWanGetConnFromId(ConnId);
  469. RWAN_RELEASE_CONN_TABLE_LOCK();
  470. if (pConnObject == NULL_PRWAN_TDI_CONNECTION)
  471. {
  472. Status = TDI_INVALID_CONNECTION;
  473. break;
  474. }
  475. //
  476. // See if the connection is associated.
  477. //
  478. pAddrObject = pConnObject->pAddrObject;
  479. if (pAddrObject == NULL_PRWAN_TDI_ADDRESS)
  480. {
  481. Status = TDI_NOT_ASSOCIATED;
  482. break;
  483. }
  484. //
  485. // Tell the media-specific module about this disassociation.
  486. // This invalidates the module's context for this connection
  487. // object.
  488. //
  489. if (RWAN_IS_BIT_SET(pConnObject->Flags, RWANF_CO_AFSP_CONTEXT_VALID) &&
  490. pAddrObject->pProtocol->pAfInfo->AfChars.pAfSpDisassociateConnection)
  491. {
  492. (*pAddrObject->pProtocol->pAfInfo->AfChars.pAfSpDisassociateConnection)(
  493. pConnObject->AfSpConnContext);
  494. RWAN_RESET_BIT(pConnObject->Flags, RWANF_CO_AFSP_CONTEXT_VALID);
  495. }
  496. //
  497. // Unlink this from the address object.
  498. //
  499. RWAN_ACQUIRE_ADDRESS_LOCK(pAddrObject);
  500. RWAN_DELETE_FROM_LIST(&(pConnObject->ConnLink));
  501. rc = RWanDereferenceAddressObject(pAddrObject); // Disassoc conn
  502. if (rc != 0)
  503. {
  504. RWAN_RELEASE_ADDRESS_LOCK(pAddrObject);
  505. }
  506. RWAN_ACQUIRE_CONN_LOCK(pConnObject);
  507. pConnObject->pAddrObject = NULL_PRWAN_TDI_ADDRESS;
  508. rc = RWanDereferenceConnObject(pConnObject); // Disassoc deref
  509. if (rc != 0)
  510. {
  511. RWAN_RELEASE_CONN_LOCK(pConnObject);
  512. }
  513. Status = TDI_SUCCESS;
  514. break;
  515. }
  516. while (FALSE);
  517. RWANDEBUGP(DL_LOUD, DC_DISCON,
  518. ("RWanTdiDisassociate: pAddrObject x%x, pConnObj x%x, Status x%x\n",
  519. pAddrObject, pConnObject, Status));
  520. return (Status);
  521. }
  522. TDI_STATUS
  523. RWanTdiConnect(
  524. IN PTDI_REQUEST pTdiRequest,
  525. IN PVOID pTimeout OPTIONAL,
  526. IN PTDI_CONNECTION_INFORMATION pRequestInfo,
  527. IN PTDI_CONNECTION_INFORMATION pReturnInfo
  528. )
  529. /*++
  530. Routine Description:
  531. This is the TDI Entry point for setting up a connection.
  532. The connection object is identified by its handle buried within
  533. the TDI request.
  534. Arguments:
  535. pTdiRequest - Pointer to the TDI Request
  536. pTimeout - Optional connect timeout
  537. pRequestInfo - Points to information for making the connection
  538. pReturnInfo - Place where we return final connection information
  539. Return Value:
  540. TDI_STATUS - this is TDI_PENDING if we successfully fired off
  541. a Connect Request, TDI_NO_RESOURCES if we failed because of some
  542. allocation problem, TDI_BAD_ADDR if the destination address isn't
  543. valid, TDI_INVALID_CONNECTION if the specified Connection Object
  544. isn't valid, TDI_NOT_ASSOCIATED if the connection object isn't
  545. associated with an Address Object.
  546. --*/
  547. {
  548. PRWAN_TDI_CONNECTION pConnObject;
  549. RWAN_CONN_ID ConnId;
  550. PRWAN_TDI_ADDRESS pAddrObject;
  551. PRWAN_NDIS_AF_CHARS pAfChars;
  552. PRWAN_NDIS_AF_INFO pAfInfo;
  553. PRWAN_NDIS_AF pAf;
  554. PRWAN_NDIS_VC pVc;
  555. PRWAN_CONN_REQUEST pConnReq;
  556. TDI_STATUS Status;
  557. RWAN_STATUS RWanStatus;
  558. ULONG CallFlags;
  559. PCO_CALL_PARAMETERS pCallParameters;
  560. NDIS_HANDLE NdisVcHandle;
  561. NDIS_STATUS NdisStatus;
  562. BOOLEAN bIsLockAcquired;
  563. #if DBG
  564. RWAN_IRQL EntryIrq, ExitIrq;
  565. #endif // DBG
  566. RWAN_GET_ENTRY_IRQL(EntryIrq);
  567. //
  568. // Initialize
  569. //
  570. pConnReq = NULL;
  571. pCallParameters = NULL;
  572. bIsLockAcquired = FALSE;
  573. pVc = NULL;
  574. #if DBG
  575. pConnObject = NULL;
  576. pAddrObject = NULL;
  577. #endif
  578. do
  579. {
  580. //
  581. // See if the destination address is present.
  582. //
  583. if ((pRequestInfo == NULL) ||
  584. (pRequestInfo->RemoteAddress == NULL))
  585. {
  586. Status = TDI_BAD_ADDR;
  587. break;
  588. }
  589. //
  590. // Allocate a Connection Request structure to keep track
  591. // of this request.
  592. //
  593. pConnReq = RWanAllocateConnReq();
  594. if (pConnReq == NULL)
  595. {
  596. Status = TDI_NO_RESOURCES;
  597. break;
  598. }
  599. pConnReq->Request.pReqComplete = pTdiRequest->RequestNotifyObject;
  600. pConnReq->Request.ReqContext = pTdiRequest->RequestContext;
  601. pConnReq->pConnInfo = pReturnInfo;
  602. //
  603. // Get the Connection Object.
  604. //
  605. ConnId = (RWAN_CONN_ID) PtrToUlong(pTdiRequest->Handle.ConnectionContext);
  606. RWAN_ACQUIRE_CONN_TABLE_LOCK();
  607. pConnObject = RWanGetConnFromId(ConnId);
  608. RWAN_RELEASE_CONN_TABLE_LOCK();
  609. if (pConnObject == NULL_PRWAN_TDI_CONNECTION)
  610. {
  611. Status = TDI_INVALID_CONNECTION;
  612. break;
  613. }
  614. bIsLockAcquired = TRUE;
  615. RWAN_ACQUIRE_CONN_LOCK(pConnObject);
  616. //
  617. // See if it is associated.
  618. //
  619. pAddrObject = pConnObject->pAddrObject;
  620. if (pAddrObject == NULL_PRWAN_TDI_ADDRESS)
  621. {
  622. Status = TDI_NOT_ASSOCIATED;
  623. break;
  624. }
  625. //
  626. // Check its state.
  627. //
  628. if (pConnObject->State != RWANS_CO_ASSOCIATED)
  629. {
  630. Status = TDI_INVALID_STATE;
  631. break;
  632. }
  633. //
  634. // Do we have atleast one NDIS AF for this protocol?
  635. //
  636. pAfInfo = pAddrObject->pProtocol->pAfInfo;
  637. if (RWAN_IS_LIST_EMPTY(&(pAfInfo->NdisAfList)))
  638. {
  639. Status = TDI_BAD_ADDR;
  640. break;
  641. }
  642. pAfChars = &(pAfInfo->AfChars);
  643. CallFlags = RWAN_CALLF_OUTGOING_CALL;
  644. if (RWAN_IS_BIT_SET(pAddrObject->Flags, RWANF_AO_PMP_ROOT))
  645. {
  646. CallFlags |= RWAN_CALLF_POINT_TO_MULTIPOINT;
  647. pConnObject->pRootConnObject = pAddrObject->pRootConnObject;
  648. if (pAddrObject->pRootConnObject->NdisConnection.pNdisVc == NULL)
  649. {
  650. CallFlags |= RWAN_CALLF_PMP_FIRST_LEAF;
  651. RWANDEBUGP(DL_INFO, DC_CONNECT,
  652. ("TdiConnect PMP: First Leaf: ConnObj %x, RootConn %x, AddrObj %x\n",
  653. pConnObject,
  654. pConnObject->pRootConnObject,
  655. pAddrObject));
  656. }
  657. else
  658. {
  659. CallFlags |= RWAN_CALLF_PMP_ADDNL_LEAF;
  660. RWANDEBUGP(DL_INFO, DC_CONNECT,
  661. ("TdiConnect PMP: Subseq Leaf: ConnObj %x, RootConn %x, AddrObj %x, Vc %x\n",
  662. pConnObject,
  663. pConnObject->pRootConnObject,
  664. pAddrObject,
  665. pConnObject->pRootConnObject->NdisConnection.pNdisVc
  666. ));
  667. }
  668. }
  669. else
  670. {
  671. CallFlags |= RWAN_CALLF_POINT_TO_POINT;
  672. }
  673. //
  674. // We get the AF from the media specific module.
  675. //
  676. pAf = NULL;
  677. //
  678. // Validate and convert call parameters. Also get the AF (aka port) on
  679. // which the call should be made.
  680. //
  681. RWanStatus = (*pAfChars->pAfSpTdi2NdisOptions)(
  682. pConnObject->AfSpConnContext,
  683. CallFlags,
  684. pRequestInfo,
  685. pRequestInfo->Options,
  686. pRequestInfo->OptionsLength,
  687. &pAf,
  688. &pCallParameters
  689. );
  690. if (RWanStatus != RWAN_STATUS_SUCCESS)
  691. {
  692. RWANDEBUGP(DL_WARN, DC_CONNECT,
  693. ("TdiConnect: pConnObj x%x, Tdi2NdisOptions ret x%x\n", pConnObject, RWanStatus));
  694. Status = RWanToTdiStatus(RWanStatus);
  695. break;
  696. }
  697. if (pAf == NULL)
  698. {
  699. //
  700. // Get at the first NDIS AF block for this TDI protocol.
  701. //
  702. pAf = CONTAINING_RECORD(pAfInfo->NdisAfList.Flink, RWAN_NDIS_AF, AfInfoLink);
  703. }
  704. RWAN_ASSERT(pAf != NULL);
  705. RWAN_STRUCT_ASSERT(pAf, naf);
  706. RWAN_ASSERT(pCallParameters != NULL);
  707. if (CallFlags & RWAN_CALLF_POINT_TO_MULTIPOINT)
  708. {
  709. RWAN_RELEASE_CONN_LOCK(pConnObject);
  710. bIsLockAcquired = FALSE;
  711. Status = RWanTdiPMPConnect(
  712. pAfInfo,
  713. pAddrObject,
  714. pConnObject,
  715. pCallParameters,
  716. CallFlags,
  717. pConnReq
  718. );
  719. break;
  720. }
  721. //
  722. // Allocate an NDIS VC. To avoid deadlocks, we must relinquish
  723. // the Conn Object lock temporarily.
  724. //
  725. RWAN_RELEASE_CONN_LOCK(pConnObject);
  726. pVc = RWanAllocateVc(pAf, TRUE);
  727. if (pVc == NULL)
  728. {
  729. Status = TDI_NO_RESOURCES;
  730. bIsLockAcquired = FALSE;
  731. break;
  732. }
  733. RWAN_SET_VC_CALL_PARAMS(pVc, pCallParameters);
  734. RWAN_ACQUIRE_CONN_LOCK(pConnObject);
  735. RWAN_SET_BIT(pVc->Flags, RWANF_VC_OUTGOING);
  736. //
  737. // We have completed all "immediate failure" checks.
  738. //
  739. //
  740. // Link the VC to this Connection Object.
  741. //
  742. RWAN_LINK_CONNECTION_TO_VC(pConnObject, pVc);
  743. RWanReferenceConnObject(pConnObject); // VC ref
  744. //
  745. // Save the Connection Request
  746. //
  747. pConnObject->pConnReq = pConnReq;
  748. //
  749. // Save the NDIS Call Parameters
  750. //
  751. pVc->pCallParameters = pCallParameters;
  752. pConnObject->State = RWANS_CO_OUT_CALL_INITIATED;
  753. RWAN_RELEASE_CONN_LOCK(pConnObject);
  754. bIsLockAcquired = FALSE;
  755. //
  756. // Move this connection object from the Idle list to the
  757. // Active list on the address object.
  758. //
  759. RWAN_ACQUIRE_ADDRESS_LOCK(pAddrObject);
  760. RWAN_DELETE_FROM_LIST(&(pConnObject->ConnLink));
  761. RWAN_INSERT_TAIL_LIST(&(pAddrObject->ActiveConnList),
  762. &(pConnObject->ConnLink));
  763. pAddrObject->pRootConnObject = pConnObject;
  764. RWAN_RELEASE_ADDRESS_LOCK(pAddrObject);
  765. NdisVcHandle = pVc->NdisVcHandle;
  766. //
  767. // Place the call.
  768. //
  769. NdisStatus = NdisClMakeCall(
  770. NdisVcHandle,
  771. pCallParameters,
  772. NULL, // ProtocolPartyContext
  773. NULL // pNdisPartyHandle
  774. );
  775. RWAN_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
  776. if (NdisStatus != NDIS_STATUS_PENDING)
  777. {
  778. RWanNdisMakeCallComplete(
  779. NdisStatus,
  780. (NDIS_HANDLE)pVc,
  781. NULL, // NdisPartyHandle
  782. pCallParameters
  783. );
  784. }
  785. RWAN_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
  786. Status = TDI_PENDING;
  787. break;
  788. }
  789. while (FALSE);
  790. if (Status != TDI_PENDING)
  791. {
  792. //
  793. // Clean up.
  794. //
  795. if (bIsLockAcquired)
  796. {
  797. RWAN_RELEASE_CONN_LOCK(pConnObject);
  798. }
  799. if (pConnReq != NULL)
  800. {
  801. RWanFreeConnReq(pConnReq);
  802. }
  803. if (pCallParameters != NULL)
  804. {
  805. (*pAfChars->pAfSpReturnNdisOptions)(
  806. pAf->AfSpAFContext,
  807. pCallParameters
  808. );
  809. }
  810. if (pVc != NULL)
  811. {
  812. RWanFreeVc(pVc);
  813. }
  814. }
  815. RWAN_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
  816. RWANDEBUGP(DL_LOUD, DC_CONNECT,
  817. ("TdiConnect: pTdiReq x%x, pConnObj x%x, pAddrObj x%x, Status x%x\n",
  818. pTdiRequest, pConnObject, pAddrObject, Status));
  819. return (Status);
  820. }
  821. TDI_STATUS
  822. RWanTdiPMPConnect(
  823. IN PRWAN_NDIS_AF_INFO pAfInfo,
  824. IN PRWAN_TDI_ADDRESS pAddrObject,
  825. IN PRWAN_TDI_CONNECTION pConnObject,
  826. IN PCO_CALL_PARAMETERS pCallParameters,
  827. IN ULONG CallFlags,
  828. IN PRWAN_CONN_REQUEST pConnReq
  829. )
  830. /*++
  831. Routine Description:
  832. Handle a TDI Connect for a point-to-multipoint call.
  833. Arguments:
  834. pAfInfo - Pointer to AF Info structure
  835. pAddrObject - Address Object on which this PMP call is made
  836. pConnObject - Connection object representing a node of the PMP call
  837. pCallParameters - NDIS call parameters
  838. CallFlags - Flags indicating type of call
  839. pConnReq - Information about the TDI request
  840. Return Value:
  841. TDI_PENDING if a PMP call was launched successfully, TDI_XXX error code
  842. otherwise.
  843. --*/
  844. {
  845. PRWAN_TDI_CONNECTION pRootConnObject;
  846. PRWAN_NDIS_AF pAf;
  847. PRWAN_NDIS_VC pVc;
  848. PRWAN_NDIS_PARTY pParty;
  849. NDIS_HANDLE NdisVcHandle;
  850. NDIS_STATUS NdisStatus;
  851. TDI_STATUS Status;
  852. BOOLEAN bIsFirstLeaf;
  853. #if DBG
  854. RWAN_IRQL EntryIrq, ExitIrq;
  855. #endif // DBG
  856. RWAN_GET_ENTRY_IRQL(EntryIrq);
  857. bIsFirstLeaf = ((CallFlags & RWAN_CALLF_PMP_LEAF_TYPE_MASK) == RWAN_CALLF_PMP_FIRST_LEAF);
  858. Status = TDI_PENDING;
  859. pParty = NULL;
  860. pVc = NULL;
  861. pRootConnObject = NULL;
  862. RWANDEBUGP(DL_LOUD, DC_CONNECT,
  863. ("TdiPMPConnect: pAddrObj x%x/x%x, pConnObj x%x/x%x, CallFlags x%x\n",
  864. pAddrObject, pAddrObject->Flags,
  865. pConnObject, pConnObject->Flags,
  866. CallFlags));
  867. do
  868. {
  869. //
  870. // Allocate party object.
  871. //
  872. RWAN_ALLOC_MEM(pParty, RWAN_NDIS_PARTY, sizeof(RWAN_NDIS_PARTY));
  873. if (pParty == NULL)
  874. {
  875. Status = TDI_NO_RESOURCES;
  876. break;
  877. }
  878. RWAN_ZERO_MEM(pParty, sizeof(RWAN_NDIS_PARTY));
  879. RWAN_SET_SIGNATURE(pParty, npy);
  880. //
  881. // Get at the root Connection object.
  882. //
  883. pRootConnObject = pAddrObject->pRootConnObject;
  884. RWAN_ASSERT(pRootConnObject != NULL);
  885. if (bIsFirstLeaf)
  886. {
  887. //
  888. // Get at the first NDIS AF block for this TDI protocol.
  889. //
  890. pAf = CONTAINING_RECORD(pAfInfo->NdisAfList.Flink, RWAN_NDIS_AF, AfInfoLink);
  891. pVc = RWanAllocateVc(pAf, TRUE);
  892. if (pVc == NULL)
  893. {
  894. Status = TDI_NO_RESOURCES;
  895. break;
  896. }
  897. RWAN_SET_BIT(pVc->Flags, RWANF_VC_OUTGOING);
  898. RWAN_SET_BIT(pVc->Flags, RWANF_VC_PMP);
  899. RWAN_SET_VC_CALL_PARAMS(pVc, pCallParameters);
  900. //
  901. // Link the VC to the Root Connection Object.
  902. //
  903. RWAN_ACQUIRE_CONN_LOCK(pRootConnObject);
  904. RWAN_LINK_CONNECTION_TO_VC(pRootConnObject, pVc);
  905. //
  906. // Save pointer to this first party, for use in MakeCallComplete.
  907. //
  908. pVc->pPartyMakeCall = pParty;
  909. RWanReferenceConnObject(pRootConnObject); // VC ref: TDI Conn PMP
  910. RWAN_RELEASE_CONN_LOCK(pRootConnObject);
  911. }
  912. else
  913. {
  914. pVc = pRootConnObject->NdisConnection.pNdisVc;
  915. }
  916. //
  917. // We have finished all local checks. Fill in more of the Party structure.
  918. //
  919. pParty->pVc = pVc;
  920. pParty->pConnObject = pConnObject;
  921. pParty->pCallParameters = pCallParameters;
  922. RWAN_ACQUIRE_CONN_LOCK(pConnObject);
  923. RWanReferenceConnObject(pConnObject); // Party ref
  924. pConnObject->State = RWANS_CO_OUT_CALL_INITIATED;
  925. //
  926. // Save the Connection Request
  927. //
  928. pConnObject->pConnReq = pConnReq;
  929. //
  930. // Link the Party to this Connection Object.
  931. //
  932. RWAN_ASSERT(pConnObject->NdisConnection.pNdisParty == NULL);
  933. pConnObject->NdisConnection.pNdisParty = pParty;
  934. RWAN_RELEASE_CONN_LOCK(pConnObject);
  935. //
  936. // Link the Party and VC structures.
  937. //
  938. RWAN_ACQUIRE_CONN_LOCK(pRootConnObject);
  939. RWAN_INSERT_TAIL_LIST(&(pVc->NdisPartyList), &(pParty->PartyLink));
  940. pVc->AddingPartyCount ++;
  941. NdisVcHandle = pVc->NdisVcHandle;
  942. RWAN_RELEASE_CONN_LOCK(pRootConnObject);
  943. //
  944. // Move this connection object from the Idle list to the
  945. // Active list on the address object.
  946. //
  947. RWAN_ACQUIRE_ADDRESS_LOCK(pAddrObject);
  948. RWAN_DELETE_FROM_LIST(&(pConnObject->ConnLink));
  949. RWAN_INSERT_TAIL_LIST(&(pAddrObject->ActiveConnList),
  950. &(pConnObject->ConnLink));
  951. RWAN_RELEASE_ADDRESS_LOCK(pAddrObject);
  952. RWANDEBUGP(DL_LOUD, DC_CONNECT,
  953. ("RWanTdiPMPConnect: AddrObj x%x, ConnObj x%x, RootConn x%x, VC %x, Pty %x, FirstLeaf %d\n",
  954. pAddrObject, pConnObject, pRootConnObject, pVc, pParty, bIsFirstLeaf));
  955. if (bIsFirstLeaf)
  956. {
  957. //
  958. // Place the call.
  959. //
  960. NdisStatus = NdisClMakeCall(
  961. NdisVcHandle,
  962. pCallParameters,
  963. (NDIS_HANDLE)pParty, // ProtocolPartyContext
  964. &pParty->NdisPartyHandle // pNdisPartyHandle
  965. );
  966. RWAN_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
  967. if (NdisStatus != NDIS_STATUS_PENDING)
  968. {
  969. RWanNdisMakeCallComplete(
  970. NdisStatus,
  971. (NDIS_HANDLE)pVc,
  972. pParty->NdisPartyHandle, // NdisPartyHandle
  973. pCallParameters
  974. );
  975. }
  976. }
  977. else
  978. {
  979. //
  980. // Add the new party.
  981. //
  982. NdisStatus = NdisClAddParty(
  983. NdisVcHandle,
  984. (NDIS_HANDLE)pParty,
  985. pCallParameters,
  986. &pParty->NdisPartyHandle
  987. );
  988. if (NdisStatus != NDIS_STATUS_PENDING)
  989. {
  990. RWanNdisAddPartyComplete(
  991. NdisStatus,
  992. (NDIS_HANDLE)pParty,
  993. pParty->NdisPartyHandle,
  994. pCallParameters
  995. );
  996. }
  997. }
  998. RWAN_ASSERT(Status == TDI_PENDING);
  999. break;
  1000. }
  1001. while (FALSE);
  1002. if (Status != TDI_PENDING)
  1003. {
  1004. //
  1005. // Failure - clean up.
  1006. //
  1007. RWAN_ASSERT(Status == TDI_NO_RESOURCES);
  1008. if (pParty != NULL)
  1009. {
  1010. RWAN_FREE_MEM(pParty);
  1011. }
  1012. if (pVc != NULL)
  1013. {
  1014. RWanFreeVc(pVc);
  1015. }
  1016. }
  1017. RWAN_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
  1018. return (Status);
  1019. }
  1020. TDI_STATUS
  1021. RWanTdiListen(
  1022. IN PTDI_REQUEST pTdiRequest,
  1023. IN USHORT Flags,
  1024. IN PTDI_CONNECTION_INFORMATION pAcceptableAddr,
  1025. IN PTDI_CONNECTION_INFORMATION pConnectedAddr
  1026. )
  1027. /*++
  1028. Routine Description:
  1029. This is the TDI Entry point for posting a Listen. The Connection
  1030. Object is identified by its context buried within the TDI request.
  1031. We save off information about this request, and move the connection
  1032. from the idle list to the listen list.
  1033. For now, we ignore any given remote address information.
  1034. TBD: Support remote address information in TdiListen().
  1035. Arguments:
  1036. pTdiRequest - Pointer to the TDI Request
  1037. Flags - Listen flags
  1038. pAcceptableAddr - List of acceptable remote addresses
  1039. pConnectedAddr - Place to return connected remote address
  1040. Return Value:
  1041. TDI_STATUS - this is TDI_PENDING if we successfully queued a Listen,
  1042. TDI_NO_RESOURCES if we ran into a resource failure, TDI_NOT_ASSOCIATED
  1043. if the given Connection object isn't associated with an address,
  1044. TDI_INVALID_CONNECTION if the specified connection object is invalid.
  1045. --*/
  1046. {
  1047. PRWAN_TDI_CONNECTION pConnObject;
  1048. RWAN_CONN_ID ConnId;
  1049. PRWAN_TDI_ADDRESS pAddrObject;
  1050. PRWAN_CONN_REQUEST pConnReq;
  1051. TDI_STATUS Status;
  1052. #if DBG
  1053. RWAN_IRQL EntryIrq, ExitIrq;
  1054. #endif // DBG
  1055. RWAN_GET_ENTRY_IRQL(EntryIrq);
  1056. //
  1057. // Initialize
  1058. //
  1059. pConnReq = NULL;
  1060. do
  1061. {
  1062. //
  1063. // XXX: Ignore Acceptable address(es) for now.
  1064. //
  1065. //
  1066. // Allocate a Connection Request structure to keep track
  1067. // of this request.
  1068. //
  1069. pConnReq = RWanAllocateConnReq();
  1070. if (pConnReq == NULL)
  1071. {
  1072. Status = TDI_NO_RESOURCES;
  1073. break;
  1074. }
  1075. pConnReq->Request.pReqComplete = pTdiRequest->RequestNotifyObject;
  1076. pConnReq->Request.ReqContext = pTdiRequest->RequestContext;
  1077. pConnReq->pConnInfo = pConnectedAddr;
  1078. pConnReq->Flags = Flags;
  1079. //
  1080. // Get the Connection Object.
  1081. //
  1082. ConnId = (RWAN_CONN_ID) PtrToUlong(pTdiRequest->Handle.ConnectionContext);
  1083. RWAN_ACQUIRE_CONN_TABLE_LOCK();
  1084. pConnObject = RWanGetConnFromId(ConnId);
  1085. RWAN_RELEASE_CONN_TABLE_LOCK();
  1086. if (pConnObject == NULL_PRWAN_TDI_CONNECTION)
  1087. {
  1088. Status = TDI_INVALID_CONNECTION;
  1089. break;
  1090. }
  1091. RWAN_ACQUIRE_CONN_LOCK(pConnObject);
  1092. //
  1093. // See if it is associated.
  1094. //
  1095. pAddrObject = pConnObject->pAddrObject;
  1096. if (pAddrObject == NULL)
  1097. {
  1098. RWAN_RELEASE_CONN_LOCK(pConnObject);
  1099. Status = TDI_NOT_ASSOCIATED;
  1100. break;
  1101. }
  1102. //
  1103. // We can move this Connection Object to the listen list
  1104. // only if there isn't any active connection on this.
  1105. //
  1106. if (pConnObject->State != RWANS_CO_ASSOCIATED)
  1107. {
  1108. RWAN_RELEASE_CONN_LOCK(pConnObject);
  1109. Status = TDI_INVALID_STATE;
  1110. break;
  1111. }
  1112. pConnObject->State = RWANS_CO_LISTENING;
  1113. //
  1114. // Save the Connection Request
  1115. //
  1116. pConnObject->pConnReq = pConnReq;
  1117. RWAN_RELEASE_CONN_LOCK(pConnObject);
  1118. RWANDEBUGP(DL_VERY_LOUD, DC_BIND,
  1119. ("Listen: pConnObject x%x, pAddrObject x%x\n", pConnObject, pAddrObject));
  1120. //
  1121. // Move this connection object from the Idle list to the
  1122. // Listen list.
  1123. //
  1124. RWAN_ACQUIRE_ADDRESS_LOCK(pAddrObject);
  1125. RWAN_DELETE_FROM_LIST(&(pConnObject->ConnLink));
  1126. RWAN_INSERT_TAIL_LIST(&(pAddrObject->ListenConnList),
  1127. &(pConnObject->ConnLink));
  1128. RWAN_RELEASE_ADDRESS_LOCK(pAddrObject);
  1129. Status = TDI_PENDING;
  1130. break;
  1131. }
  1132. while (FALSE);
  1133. RWAN_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
  1134. if (Status != TDI_PENDING)
  1135. {
  1136. //
  1137. // Cleanup
  1138. //
  1139. if (pConnReq != NULL)
  1140. {
  1141. RWanFreeConnReq(pConnReq);
  1142. }
  1143. }
  1144. return (Status);
  1145. }
  1146. TDI_STATUS
  1147. RWanTdiUnListen(
  1148. IN PTDI_REQUEST pTdiRequest
  1149. )
  1150. /*++
  1151. Routine Description:
  1152. This is the TDI Entry point for terminating a Listen. The Connection
  1153. Object is identified by its context buried within the TDI request.
  1154. We move the connection from the listen list to the idle list.
  1155. Arguments:
  1156. pTdiRequest - Pointer to the TDI Request
  1157. Return Value:
  1158. TDI_SUCCESS if successful.
  1159. --*/
  1160. {
  1161. PRWAN_TDI_CONNECTION pConnObject;
  1162. PRWAN_CONN_REQUEST pConnReq;
  1163. RWAN_CONN_ID ConnId;
  1164. PRWAN_TDI_ADDRESS pAddrObject;
  1165. TDI_STATUS Status;
  1166. #if DBG
  1167. RWAN_IRQL EntryIrq, ExitIrq;
  1168. #endif // DBG
  1169. RWAN_GET_ENTRY_IRQL(EntryIrq);
  1170. do
  1171. {
  1172. //
  1173. // Get the Connection Object.
  1174. //
  1175. ConnId = (RWAN_CONN_ID) PtrToUlong(pTdiRequest->Handle.ConnectionContext);
  1176. RWAN_ACQUIRE_CONN_TABLE_LOCK();
  1177. pConnObject = RWanGetConnFromId(ConnId);
  1178. RWAN_RELEASE_CONN_TABLE_LOCK();
  1179. if (pConnObject == NULL_PRWAN_TDI_CONNECTION)
  1180. {
  1181. Status = TDI_INVALID_CONNECTION;
  1182. break;
  1183. }
  1184. RWAN_ACQUIRE_CONN_LOCK(pConnObject);
  1185. //
  1186. // See if it is associated.
  1187. //
  1188. pAddrObject = pConnObject->pAddrObject;
  1189. if (pAddrObject == NULL)
  1190. {
  1191. RWAN_RELEASE_CONN_LOCK(pConnObject);
  1192. Status = TDI_NOT_ASSOCIATED;
  1193. break;
  1194. }
  1195. //
  1196. // We can move this Connection Object to the idle list
  1197. // only if there isn't any active connection on this.
  1198. //
  1199. if (pConnObject->State != RWANS_CO_LISTENING)
  1200. {
  1201. RWAN_RELEASE_CONN_LOCK(pConnObject);
  1202. Status = TDI_INVALID_STATE;
  1203. break;
  1204. }
  1205. pConnObject->State = RWANS_CO_ASSOCIATED;
  1206. pConnReq = pConnObject->pConnReq;
  1207. pConnObject->pConnReq = NULL;
  1208. RWAN_RELEASE_CONN_LOCK(pConnObject);
  1209. RWANDEBUGP(DL_VERY_LOUD, DC_BIND,
  1210. ("UnListen: pConnObject x%x, pAddrObject x%x\n", pConnObject, pAddrObject));
  1211. //
  1212. // Move this connection object from the Listen list to the
  1213. // Idle list.
  1214. //
  1215. RWAN_ACQUIRE_ADDRESS_LOCK(pAddrObject);
  1216. RWAN_DELETE_FROM_LIST(&(pConnObject->ConnLink));
  1217. RWAN_INSERT_TAIL_LIST(&(pAddrObject->IdleConnList),
  1218. &(pConnObject->ConnLink));
  1219. RWAN_RELEASE_ADDRESS_LOCK(pAddrObject);
  1220. RWanCompleteConnReq( // InCall: Listen OK
  1221. NULL,
  1222. pConnReq,
  1223. FALSE,
  1224. NULL,
  1225. NULL,
  1226. TDI_CANCELLED
  1227. );
  1228. Status = TDI_SUCCESS;
  1229. break;
  1230. }
  1231. while (FALSE);
  1232. return (Status);
  1233. }
  1234. TDI_STATUS
  1235. RWanTdiAccept(
  1236. IN PTDI_REQUEST pTdiRequest,
  1237. IN PTDI_CONNECTION_INFORMATION pAcceptInfo,
  1238. IN PTDI_CONNECTION_INFORMATION pConnectInfo
  1239. )
  1240. /*++
  1241. Routine Description:
  1242. This is the TDI entry point for accepting an incoming connection.
  1243. The Connection Object is identified by its context buried within
  1244. the TDI request.
  1245. We translate this to a call to NdisClIncomingCallComplete, and
  1246. pend this request. If all goes well, this request is completed
  1247. when we receive a CallConnected primitive from NDIS.
  1248. Arguments:
  1249. pTdiRequest - Pointer to the TDI Request
  1250. pAcceptInfo - Contains options for the connection accept
  1251. pConnectInfo - Place to return final connection information
  1252. Return Value:
  1253. TDI_STATUS - this is TDI_PENDING if we successfully processed
  1254. the Accept, TDI_INVALID_CONNECTION if the given Connection Object
  1255. isn't valid, TDI_NOT_ASSOCIATED if the connection object isn't
  1256. associated with an address object.
  1257. --*/
  1258. {
  1259. PRWAN_TDI_CONNECTION pConnObject;
  1260. PRWAN_NDIS_VC pVc;
  1261. RWAN_CONN_ID ConnId;
  1262. PRWAN_TDI_ADDRESS pAddrObject;
  1263. PRWAN_CONN_REQUEST pConnReq;
  1264. PRWAN_NDIS_AF_CHARS pAfChars;
  1265. TDI_STATUS Status;
  1266. NDIS_HANDLE NdisVcHandle;
  1267. PCO_CALL_PARAMETERS pCallParameters;
  1268. BOOLEAN bIsLockAcquired; // Have we locked the Conn Object?
  1269. //
  1270. // Initialize
  1271. //
  1272. pConnReq = NULL;
  1273. bIsLockAcquired = FALSE;
  1274. do
  1275. {
  1276. //
  1277. // XXX: Ignore Acceptable address(es) for now.
  1278. //
  1279. //
  1280. // Allocate a Connection Request structure to keep track
  1281. // of this request.
  1282. //
  1283. pConnReq = RWanAllocateConnReq();
  1284. if (pConnReq == NULL)
  1285. {
  1286. Status = TDI_NO_RESOURCES;
  1287. break;
  1288. }
  1289. pConnReq->Request.pReqComplete = pTdiRequest->RequestNotifyObject;
  1290. pConnReq->Request.ReqContext = pTdiRequest->RequestContext;
  1291. pConnReq->pConnInfo = pConnectInfo;
  1292. //
  1293. // Copy from Accept Info to Connect Info.
  1294. //
  1295. if ((pAcceptInfo != NULL) &&
  1296. (pAcceptInfo->Options != NULL) &&
  1297. (pConnectInfo != NULL) &&
  1298. (pConnectInfo->Options != NULL) &&
  1299. (pConnectInfo->OptionsLength >= pAcceptInfo->OptionsLength))
  1300. {
  1301. RWAN_COPY_MEM(pConnectInfo->Options,
  1302. pAcceptInfo->Options,
  1303. pAcceptInfo->OptionsLength);
  1304. }
  1305. //
  1306. // Get the Connection Object.
  1307. //
  1308. ConnId = (RWAN_CONN_ID) PtrToUlong(pTdiRequest->Handle.ConnectionContext);
  1309. RWAN_ACQUIRE_CONN_TABLE_LOCK();
  1310. pConnObject = RWanGetConnFromId(ConnId);
  1311. RWAN_RELEASE_CONN_TABLE_LOCK();
  1312. if (pConnObject == NULL_PRWAN_TDI_CONNECTION)
  1313. {
  1314. Status = TDI_INVALID_CONNECTION;
  1315. break;
  1316. }
  1317. bIsLockAcquired = TRUE;
  1318. RWAN_ACQUIRE_CONN_LOCK(pConnObject);
  1319. //
  1320. // Make sure that the Connection is in the right state.
  1321. //
  1322. if (pConnObject->State != RWANS_CO_IN_CALL_INDICATED)
  1323. {
  1324. Status = TDI_INVALID_STATE;
  1325. break;
  1326. }
  1327. pVc = pConnObject->NdisConnection.pNdisVc;
  1328. if (pVc == NULL)
  1329. {
  1330. Status = TDI_INVALID_CONNECTION;
  1331. break;
  1332. }
  1333. pCallParameters = pVc->pCallParameters;
  1334. pVc->pCallParameters = NULL;
  1335. //
  1336. // Update NDIS Call Parameters if Accept Options are present.
  1337. //
  1338. pAfChars = &(pVc->pNdisAf->pAfInfo->AfChars);
  1339. if (pAfChars->pAfSpUpdateNdisOptions)
  1340. {
  1341. RWAN_STATUS RWanStatus;
  1342. ULONG CallFlags = RWAN_CALLF_INCOMING_CALL|RWAN_CALLF_POINT_TO_POINT;
  1343. PVOID pTdiQoS;
  1344. ULONG TdiQoSLength;
  1345. if (pAcceptInfo)
  1346. {
  1347. pTdiQoS = pAcceptInfo->Options;
  1348. TdiQoSLength = pAcceptInfo->OptionsLength;
  1349. }
  1350. else
  1351. {
  1352. pTdiQoS = NULL;
  1353. TdiQoSLength = 0;
  1354. }
  1355. RWanStatus = (*pAfChars->pAfSpUpdateNdisOptions)(
  1356. pVc->pNdisAf->AfSpAFContext,
  1357. pConnObject->AfSpConnContext,
  1358. CallFlags,
  1359. pAcceptInfo,
  1360. pTdiQoS,
  1361. TdiQoSLength,
  1362. &pCallParameters
  1363. );
  1364. if (RWanStatus != RWAN_STATUS_SUCCESS)
  1365. {
  1366. Status = RWanToTdiStatus(RWanStatus);
  1367. break;
  1368. }
  1369. }
  1370. NdisVcHandle = pVc->NdisVcHandle;
  1371. //
  1372. // Update Connection Object state.
  1373. //
  1374. pConnObject->State = RWANS_CO_IN_CALL_ACCEPTING;
  1375. //
  1376. // Save the Connection Request
  1377. //
  1378. pConnObject->pConnReq = pConnReq;
  1379. RWAN_RELEASE_CONN_LOCK(pConnObject);
  1380. //
  1381. // Accept the call now.
  1382. //
  1383. NdisClIncomingCallComplete(
  1384. NDIS_STATUS_SUCCESS,
  1385. NdisVcHandle,
  1386. pCallParameters
  1387. );
  1388. Status = TDI_PENDING;
  1389. break;
  1390. }
  1391. while (FALSE);
  1392. if (Status != TDI_PENDING)
  1393. {
  1394. //
  1395. // Cleanup
  1396. //
  1397. if (bIsLockAcquired)
  1398. {
  1399. RWAN_RELEASE_CONN_LOCK(pConnObject);
  1400. }
  1401. if (pConnReq != NULL)
  1402. {
  1403. RWanFreeConnReq(pConnReq);
  1404. }
  1405. }
  1406. return (Status);
  1407. }
  1408. TDI_STATUS
  1409. RWanTdiDisconnect(
  1410. IN PTDI_REQUEST pTdiRequest,
  1411. IN PVOID pTimeout,
  1412. IN USHORT Flags,
  1413. IN PTDI_CONNECTION_INFORMATION pDisconnInfo,
  1414. OUT PTDI_CONNECTION_INFORMATION pReturnInfo
  1415. )
  1416. /*++
  1417. Routine Description:
  1418. This is the TDI Disconnect entry point. If this is an incoming
  1419. call waiting to be accepted, we call NdisClIncomingCallComplete
  1420. with a rejection status. Otherwise, we call NdisClCloseCall.
  1421. The Connection Object is identified by its context buried within
  1422. the TDI request.
  1423. Note that this is never called for point-to-multipoint calls.
  1424. Those are disconnected within TdiCloseConnection.
  1425. Arguments:
  1426. pTdiRequest - Pointer to the TDI Request
  1427. pTimeout - Points to timeout. Ignored.
  1428. Flags - Type of disconnect. Only Abortive is supported for now.
  1429. pDisconnInfo - Information for the disconnect. Ignored for now.
  1430. pReturnInfo - Return information about the disconnect. Ignored for now.
  1431. Return Value:
  1432. TDI_STATUS - this is TDI_SUCCESS if we just rejected an incoming
  1433. call, TDI_PENDING if we initiated NDIS CloseCall, TDI_INVALID_CONNECTION
  1434. if the Connection Object context is invalid,
  1435. --*/
  1436. {
  1437. PRWAN_TDI_CONNECTION pConnObject;
  1438. RWAN_CONN_ID ConnId;
  1439. TDI_STATUS Status;
  1440. do
  1441. {
  1442. //
  1443. // Get the Connection Object.
  1444. //
  1445. RWAN_ACQUIRE_CONN_TABLE_LOCK();
  1446. ConnId = (RWAN_CONN_ID) PtrToUlong(pTdiRequest->Handle.ConnectionContext);
  1447. pConnObject = RWanGetConnFromId(ConnId);
  1448. RWAN_RELEASE_CONN_TABLE_LOCK();
  1449. if (pConnObject == NULL_PRWAN_TDI_CONNECTION)
  1450. {
  1451. Status = TDI_INVALID_CONNECTION;
  1452. break;
  1453. }
  1454. RWANDEBUGP(DL_LOUD, DC_DISCON,
  1455. ("RWanTdiDiscon: pConnObj x%x, State/Flags x%x/x%x, pAddrObj x%x\n",
  1456. pConnObject,
  1457. pConnObject->State,
  1458. pConnObject->Flags,
  1459. pConnObject->pAddrObject));
  1460. RWAN_ACQUIRE_CONN_LOCK(pConnObject);
  1461. //
  1462. // Make sure that the Connection is in the right state for TdiDisconnect.
  1463. //
  1464. if ((pConnObject->State != RWANS_CO_CONNECTED) &&
  1465. (pConnObject->State != RWANS_CO_DISCON_INDICATED) &&
  1466. (pConnObject->State != RWANS_CO_IN_CALL_INDICATED) &&
  1467. (pConnObject->State != RWANS_CO_IN_CALL_ACCEPTING) &&
  1468. (pConnObject->State != RWANS_CO_OUT_CALL_INITIATED) &&
  1469. (pConnObject->State != RWANS_CO_DISCON_HELD))
  1470. {
  1471. RWAN_RELEASE_CONN_LOCK(pConnObject);
  1472. RWANDEBUGP(DL_INFO, DC_DISCON,
  1473. ("RWanTdiDiscon: pConnObj x%x/x%x, bad state x%x for TdiDiscon\n",
  1474. pConnObject,
  1475. pConnObject->Flags,
  1476. pConnObject->State));
  1477. Status = TDI_INVALID_STATE;
  1478. break;
  1479. }
  1480. if ((pConnObject->State == RWANS_CO_DISCON_INDICATED) ||
  1481. (pConnObject->State == RWANS_CO_DISCON_HELD))
  1482. {
  1483. //
  1484. // We would have initiated an NDIS CloseCall/DropParty already.
  1485. // Simply succeed this TDI Disconnect.
  1486. //
  1487. RWAN_RELEASE_CONN_LOCK(pConnObject);
  1488. RWANDEBUGP(DL_INFO, DC_DISCON,
  1489. ("RWanTdiDiscon: pConnObj x%x/x%x, Discon recvd state %d\n",
  1490. pConnObject,
  1491. pConnObject->Flags,
  1492. pConnObject->State));
  1493. Status = TDI_SUCCESS;
  1494. break;
  1495. }
  1496. Status = RWanDoTdiDisconnect(
  1497. pConnObject,
  1498. pTdiRequest,
  1499. pTimeout,
  1500. Flags,
  1501. pDisconnInfo,
  1502. pReturnInfo);
  1503. //
  1504. // Conn Object lock is released within the above.
  1505. //
  1506. break;
  1507. }
  1508. while (FALSE);
  1509. return (Status);
  1510. }
  1511. TDI_STATUS
  1512. RWanDoTdiDisconnect(
  1513. IN PRWAN_TDI_CONNECTION pConnObject,
  1514. IN PTDI_REQUEST pTdiRequest OPTIONAL,
  1515. IN PVOID pTimeout OPTIONAL,
  1516. IN USHORT Flags,
  1517. IN PTDI_CONNECTION_INFORMATION pDisconnInfo OPTIONAL,
  1518. OUT PTDI_CONNECTION_INFORMATION pReturnInfo OPTIONAL
  1519. )
  1520. /*++
  1521. Routine Description:
  1522. Perform a TDI Disconnect on the connection endpoint.
  1523. Separated out from the main TdiDisconnect routine
  1524. so that it can be reused by TdiCloseConnection.
  1525. NOTE: This is called with the connection object lock held. This
  1526. lock is released here.
  1527. Arguments:
  1528. pConnObject - Represents the TDI Connection being disconnected.
  1529. pTdiRequest - Pointer to the TDI Request.
  1530. pTimeout - Points to timeout. Ignored.
  1531. Flags - Type of disconnect. Only Abortive is supported for now.
  1532. pDisconnInfo - Information for the disconnect. Ignored for now.
  1533. pReturnInfo - Return information about the disconnect. Ignored for now.
  1534. Return Value:
  1535. TDI_STATUS - this is TDI_SUCCESS if we just rejected an incoming
  1536. call, TDI_PENDING if we initiated NDIS CloseCall or DropParty.
  1537. --*/
  1538. {
  1539. TDI_STATUS Status;
  1540. INT rc;
  1541. PRWAN_NDIS_VC pVc;
  1542. PRWAN_NDIS_PARTY pParty;
  1543. PRWAN_CONN_REQUEST pConnReq;
  1544. PCO_CALL_PARAMETERS pCallParameters;
  1545. NDIS_STATUS NdisStatus;
  1546. NDIS_HANDLE NdisPartyHandle;
  1547. BOOLEAN bIncomingCall;
  1548. BOOLEAN bIsPMPRoot;
  1549. BOOLEAN bIsLastLeaf;
  1550. RWAN_HANDLE AfSpConnContext;
  1551. UNREFERENCED_PARAMETER(pTimeout);
  1552. UNREFERENCED_PARAMETER(Flags);
  1553. UNREFERENCED_PARAMETER(pDisconnInfo);
  1554. UNREFERENCED_PARAMETER(pReturnInfo);
  1555. //
  1556. // Initialize
  1557. //
  1558. pConnReq = NULL;
  1559. Status = TDI_SUCCESS;
  1560. do
  1561. {
  1562. bIsPMPRoot = (pConnObject->pRootConnObject != NULL);
  1563. if (bIsPMPRoot)
  1564. {
  1565. pVc = pConnObject->pRootConnObject->NdisConnection.pNdisVc;
  1566. if (pVc == NULL)
  1567. {
  1568. //
  1569. // Can happen if DoAbort has run on this connection.
  1570. // Bail out.
  1571. //
  1572. RWANDEBUGP(DL_INFO, DC_WILDCARD,
  1573. ("DoTdiDiscon(Root): pConnObj %p/%x: VC is null, bailing out\n",
  1574. pConnObject, pConnObject->Flags));
  1575. RWAN_RELEASE_CONN_LOCK(pConnObject);
  1576. break;
  1577. }
  1578. RWAN_STRUCT_ASSERT(pVc, nvc);
  1579. RWAN_ASSERT(pVc->AddingPartyCount + pVc->ActivePartyCount > 0);
  1580. bIsLastLeaf = ((pVc->AddingPartyCount + pVc->ActivePartyCount) == 1);
  1581. pParty = pConnObject->NdisConnection.pNdisParty;
  1582. RWAN_ASSERT(pParty != NULL);
  1583. RWAN_STRUCT_ASSERT(pParty, npy);
  1584. if (RWAN_IS_BIT_SET(pParty->Flags, RWANF_PARTY_DROPPING))
  1585. {
  1586. RWANDEBUGP(DL_FATAL, DC_DISCON,
  1587. ("DoTdiDiscon (Root): pConnObj x%x, Party x%x already dropping\n",
  1588. pConnObject, pParty));
  1589. RWAN_RELEASE_CONN_LOCK(pConnObject);
  1590. break;
  1591. }
  1592. NdisPartyHandle = pParty->NdisPartyHandle;
  1593. RWANDEBUGP(DL_VERY_LOUD, DC_DISCON,
  1594. ("DoTdiDiscon (Root): pConnObj x%x, pVc x%x, pParty x%x, Adding %d, Active %d\n",
  1595. pConnObject,
  1596. pVc,
  1597. pParty,
  1598. pVc->AddingPartyCount,
  1599. pVc->ActivePartyCount));
  1600. }
  1601. else
  1602. {
  1603. pVc = pConnObject->NdisConnection.pNdisVc;
  1604. if (pVc == NULL)
  1605. {
  1606. //
  1607. // Can happen if DoAbort has run on this connection.
  1608. // Bail out.
  1609. //
  1610. RWANDEBUGP(DL_INFO, DC_WILDCARD,
  1611. ("DoTdiDiscon: pConnObj %p/%x: VC is null, bailing out\n",
  1612. pConnObject, pConnObject->Flags));
  1613. RWAN_RELEASE_CONN_LOCK(pConnObject);
  1614. break;
  1615. }
  1616. RWAN_STRUCT_ASSERT(pVc, nvc);
  1617. //
  1618. // Set last-leaf to TRUE to simplify processing later.
  1619. //
  1620. bIsLastLeaf = TRUE;
  1621. }
  1622. RWAN_ASSERT(pVc != NULL);
  1623. //
  1624. // If an outgoing call is in progress, we complete the
  1625. // pended TDI_CONNECT with a cancel status, mark this
  1626. // Connection Object as Disconnecting and exit. When the
  1627. // outgoing call completes, we will clear it if it was
  1628. // successful.
  1629. //
  1630. if (pConnObject->State == RWANS_CO_OUT_CALL_INITIATED)
  1631. {
  1632. pConnObject->State = RWANS_CO_DISCON_REQUESTED;
  1633. //
  1634. // Take out the pending TDI_CONNECT.
  1635. //
  1636. pConnReq = pConnObject->pConnReq;
  1637. RWAN_ASSERT(pConnReq != NULL);
  1638. pConnObject->pConnReq = NULL;
  1639. AfSpConnContext = pConnObject->AfSpConnContext;
  1640. RWAN_RELEASE_CONN_LOCK(pConnObject);
  1641. //
  1642. // Complete the TDI_CONNECT with a cancelled status.
  1643. //
  1644. RWanCompleteConnReq(
  1645. pVc->pNdisAf,
  1646. pConnReq,
  1647. TRUE, // Is an outgoing call
  1648. NULL, // No call params
  1649. AfSpConnContext,
  1650. TDI_CANCELLED
  1651. );
  1652. //
  1653. // We will succeed this TDI_DISCONNECT.
  1654. //
  1655. pConnReq = NULL;
  1656. Status = TDI_SUCCESS;
  1657. break;
  1658. }
  1659. //
  1660. // If this connection is in the process of being accepted,
  1661. // then complete the pending TDI_ACCEPT with a cancel
  1662. // status and reject the incoming call.
  1663. //
  1664. if (pConnObject->State == RWANS_CO_IN_CALL_ACCEPTING)
  1665. {
  1666. RWANDEBUGP(DL_FATAL, DC_DISCON,
  1667. ("DoTdiDiscon: ConnObj %x/%x, in call accepting, VC %x\n",
  1668. pConnObject,
  1669. pConnObject->Flags,
  1670. pVc));
  1671. //
  1672. // Take out the pending TDI_CONNECT.
  1673. //
  1674. pConnReq = pConnObject->pConnReq;
  1675. RWAN_ASSERT(pConnReq != NULL);
  1676. pConnObject->pConnReq = NULL;
  1677. AfSpConnContext = pConnObject->AfSpConnContext;
  1678. RWAN_RELEASE_CONN_LOCK(pConnObject);
  1679. //
  1680. // Complete the TDI_ACCEPT with a cancelled status.
  1681. //
  1682. RWanCompleteConnReq(
  1683. pVc->pNdisAf,
  1684. pConnReq,
  1685. FALSE, // Is an incoming call
  1686. NULL, // No call params
  1687. AfSpConnContext,
  1688. TDI_CANCELLED
  1689. );
  1690. //
  1691. // We will succeed this TDI_DISCONNECT.
  1692. //
  1693. pConnReq = NULL;
  1694. Status = TDI_SUCCESS;
  1695. break;
  1696. }
  1697. #if DBG
  1698. if (pConnObject->pConnReq != NULL)
  1699. {
  1700. RWANDEBUGP(DL_FATAL, DC_WILDCARD,
  1701. ("DoTdiDiscon: pConnObj %x/%x, State %x, non-NULL ConnReq %x\n",
  1702. pConnObject, pConnObject->Flags, pConnObject->State,
  1703. pConnObject->pConnReq));
  1704. }
  1705. #endif // DBG
  1706. RWAN_ASSERT(pConnObject->pConnReq == NULL);
  1707. if (pTdiRequest != NULL)
  1708. {
  1709. //
  1710. // Allocate a Connection Request structure to keep track
  1711. // of this Disconnect request.
  1712. //
  1713. pConnReq = RWanAllocateConnReq();
  1714. if (pConnReq == NULL)
  1715. {
  1716. RWAN_RELEASE_CONN_LOCK(pConnObject);
  1717. Status = TDI_NO_RESOURCES;
  1718. break;
  1719. }
  1720. pConnReq->Request.pReqComplete = pTdiRequest->RequestNotifyObject;
  1721. pConnReq->Request.ReqContext = pTdiRequest->RequestContext;
  1722. pConnReq->pConnInfo = NULL;
  1723. pConnReq->Flags = 0;
  1724. //
  1725. // Save info about the TDI Disconnect request.
  1726. //
  1727. pConnObject->pConnReq = pConnReq;
  1728. }
  1729. else
  1730. {
  1731. pConnReq = NULL;
  1732. }
  1733. bIncomingCall = (pConnObject->State == RWANS_CO_IN_CALL_INDICATED);
  1734. if (bIncomingCall)
  1735. {
  1736. pCallParameters = pVc->pCallParameters;
  1737. pVc->pCallParameters = NULL;
  1738. }
  1739. pConnObject->State = RWANS_CO_DISCON_REQUESTED;
  1740. if (bIncomingCall)
  1741. {
  1742. //
  1743. // Reject the incoming call.
  1744. //
  1745. RWanNdisRejectIncomingCall(pConnObject, NDIS_STATUS_FAILURE);
  1746. }
  1747. else
  1748. {
  1749. //
  1750. // Closing an existing call.
  1751. // TBD: we don't support Close data yet.
  1752. //
  1753. if (bIsLastLeaf)
  1754. {
  1755. RWanStartCloseCall(pConnObject, pVc);
  1756. //
  1757. // ConnObject lock is released within the above.
  1758. //
  1759. }
  1760. else
  1761. {
  1762. pVc->DroppingPartyCount ++; // DoTdiDiscon: not last leaf (DropParty)
  1763. pVc->ActivePartyCount --; // DoTdiDiscon: will DropParty
  1764. RWAN_ASSERT(pParty != NULL);
  1765. RWAN_STRUCT_ASSERT(pParty, npy);
  1766. RWAN_SET_BIT(pParty->Flags, RWANF_PARTY_DROPPING);
  1767. RWAN_RELEASE_CONN_LOCK(pConnObject);
  1768. //
  1769. // Dropping a leaf of a PMP call.
  1770. //
  1771. NdisStatus = NdisClDropParty(
  1772. NdisPartyHandle,
  1773. NULL, // No Drop data
  1774. 0 // Length of drop data
  1775. );
  1776. if (NdisStatus != NDIS_STATUS_PENDING)
  1777. {
  1778. RWanNdisDropPartyComplete(
  1779. NdisStatus,
  1780. (NDIS_HANDLE)pParty
  1781. );
  1782. }
  1783. }
  1784. }
  1785. Status = TDI_PENDING;
  1786. break;
  1787. }
  1788. while (FALSE);
  1789. if (Status != TDI_PENDING)
  1790. {
  1791. //
  1792. // Cleanup.
  1793. //
  1794. if (pConnReq)
  1795. {
  1796. RWanFreeConnReq(pConnReq);
  1797. }
  1798. }
  1799. return (Status);
  1800. }
  1801. RWAN_CONN_ID
  1802. RWanGetConnId(
  1803. IN PRWAN_TDI_CONNECTION pConnObject
  1804. )
  1805. /*++
  1806. Routine Description:
  1807. Get a free Connection ID to assign to the Connection Object.
  1808. This Connection ID is used as our context for the Connection
  1809. object.
  1810. It is assumed that the caller holds a lock to the Connection Table.
  1811. Validation scheme courtesy TCP source.
  1812. Arguments:
  1813. pConnObject - Pointer to the TDI Connection Object
  1814. Return Value:
  1815. RWAN_CONN_ID: this is RWAN_INVALID_CONN_ID iff we cannot allocate
  1816. a Connection Id.
  1817. --*/
  1818. {
  1819. ULONG Slot;
  1820. ULONG i;
  1821. BOOLEAN bFound;
  1822. RWAN_CONN_ID ConnId;
  1823. for (;;)
  1824. {
  1825. //
  1826. // Look for a free slot in the Connection Index table.
  1827. // Start from where we left off the last time we were called.
  1828. //
  1829. Slot = pRWanGlobal->NextConnIndex;
  1830. for (i = 0; i < pRWanGlobal->ConnTableSize; i++)
  1831. {
  1832. if (Slot == pRWanGlobal->ConnTableSize)
  1833. {
  1834. Slot = 0; // wrap around
  1835. }
  1836. if (pRWanGlobal->pConnTable[Slot] == NULL)
  1837. {
  1838. // Found free slot
  1839. break;
  1840. }
  1841. ++Slot;
  1842. }
  1843. if (i < pRWanGlobal->ConnTableSize)
  1844. {
  1845. bFound = TRUE;
  1846. break;
  1847. }
  1848. //
  1849. // Grow the Connection Index table, if we can.
  1850. //
  1851. if (pRWanGlobal->ConnTableSize != pRWanGlobal->MaxConnections)
  1852. {
  1853. ULONG NewTableSize;
  1854. PRWAN_TDI_CONNECTION * pNewConnTable;
  1855. PRWAN_TDI_CONNECTION * pOldConnTable;
  1856. NewTableSize = MIN(pRWanGlobal->ConnTableSize + CONN_TABLE_GROW_DELTA,
  1857. pRWanGlobal->MaxConnections);
  1858. RWAN_ALLOC_MEM(pNewConnTable,
  1859. PRWAN_TDI_CONNECTION,
  1860. NewTableSize * sizeof(PRWAN_TDI_CONNECTION));
  1861. if (pNewConnTable != NULL)
  1862. {
  1863. RWAN_ZERO_MEM(pNewConnTable, NewTableSize * sizeof(PRWAN_TDI_CONNECTION));
  1864. pOldConnTable = pRWanGlobal->pConnTable;
  1865. pRWanGlobal->pConnTable = pNewConnTable;
  1866. if (pOldConnTable != NULL)
  1867. {
  1868. //
  1869. // Copy in the contents of the old table.
  1870. //
  1871. RWAN_COPY_MEM(pNewConnTable,
  1872. pOldConnTable,
  1873. pRWanGlobal->ConnTableSize * sizeof(PRWAN_TDI_CONNECTION));
  1874. RWAN_FREE_MEM(pOldConnTable);
  1875. }
  1876. pRWanGlobal->ConnTableSize = NewTableSize;
  1877. //
  1878. // Continue search.
  1879. //
  1880. }
  1881. else
  1882. {
  1883. //
  1884. // Resource failure.
  1885. //
  1886. bFound = FALSE;
  1887. break;
  1888. }
  1889. }
  1890. else
  1891. {
  1892. //
  1893. // ConnTable is full, and we aren't permitted to grow it any further.
  1894. //
  1895. bFound = FALSE;
  1896. break;
  1897. }
  1898. }
  1899. if (bFound)
  1900. {
  1901. //
  1902. // Use the slot that we found.
  1903. //
  1904. pRWanGlobal->pConnTable[Slot] = pConnObject;
  1905. pRWanGlobal->NextConnIndex = Slot + 1;
  1906. //
  1907. // Assign an instance value for this. This is used to validate
  1908. // a given ConnId.
  1909. //
  1910. pRWanGlobal->ConnInstance++;
  1911. pConnObject->ConnInstance = pRWanGlobal->ConnInstance;
  1912. ConnId = RWAN_MAKE_CONN_ID(pConnObject->ConnInstance, Slot);
  1913. }
  1914. else
  1915. {
  1916. ConnId = RWAN_INVALID_CONN_ID;
  1917. }
  1918. return (ConnId);
  1919. }
  1920. PRWAN_TDI_CONNECTION
  1921. RWanGetConnFromId(
  1922. IN RWAN_CONN_ID ConnId
  1923. )
  1924. /*++
  1925. Routine Description:
  1926. Given a Connection ID, validate it. If found OK, return a pointer
  1927. to the TDI Connection that it represents.
  1928. It is assumed that the caller holds a lock to the Connection Table.
  1929. Validation scheme courtesy TCP source.
  1930. Arguments:
  1931. ConnId - Connection Id.
  1932. Return Value:
  1933. PRWAN_TDI_CONNECTION - pointer to a TDI Connection structure that
  1934. matches the given ConnId, if valid. Otherwise, NULL.
  1935. --*/
  1936. {
  1937. ULONG Slot;
  1938. RWAN_CONN_INSTANCE ConnInstance;
  1939. PRWAN_TDI_CONNECTION pConnObject;
  1940. Slot = RWAN_GET_SLOT_FROM_CONN_ID(ConnId);
  1941. if (Slot < pRWanGlobal->ConnTableSize)
  1942. {
  1943. pConnObject = pRWanGlobal->pConnTable[Slot];
  1944. if (pConnObject != NULL_PRWAN_TDI_CONNECTION)
  1945. {
  1946. RWAN_STRUCT_ASSERT(pConnObject, ntc);
  1947. ConnInstance = RWAN_GET_INSTANCE_FROM_CONN_ID(ConnId);
  1948. if (pConnObject->ConnInstance != ConnInstance)
  1949. {
  1950. pConnObject = NULL_PRWAN_TDI_CONNECTION;
  1951. }
  1952. }
  1953. }
  1954. else
  1955. {
  1956. pConnObject = NULL_PRWAN_TDI_CONNECTION;
  1957. }
  1958. return (pConnObject);
  1959. }
  1960. VOID
  1961. RWanFreeConnId(
  1962. IN RWAN_CONN_ID ConnId
  1963. )
  1964. /*++
  1965. Routine Description:
  1966. Free a Connection ID.
  1967. Arguments:
  1968. ConnId - ID to be freed.
  1969. Return Value:
  1970. None
  1971. --*/
  1972. {
  1973. ULONG Slot;
  1974. Slot = RWAN_GET_SLOT_FROM_CONN_ID(ConnId);
  1975. RWAN_ASSERT(Slot < pRWanGlobal->ConnTableSize);
  1976. pRWanGlobal->pConnTable[Slot] = NULL;
  1977. return;
  1978. }
  1979. TDI_STATUS
  1980. RWanToTdiStatus(
  1981. IN RWAN_STATUS RWanStatus
  1982. )
  1983. /*++
  1984. Routine Description:
  1985. Map the given local status code to an equivalent TDI status code.
  1986. Arguments:
  1987. RWanStatus - Local status code
  1988. Return Value:
  1989. TDI Status code.
  1990. --*/
  1991. {
  1992. TDI_STATUS TdiStatus;
  1993. switch (RWanStatus)
  1994. {
  1995. case RWAN_STATUS_SUCCESS:
  1996. TdiStatus = TDI_SUCCESS;
  1997. break;
  1998. case RWAN_STATUS_BAD_ADDRESS:
  1999. TdiStatus = TDI_BAD_ADDR;
  2000. break;
  2001. case RWAN_STATUS_BAD_PARAMETER:
  2002. TdiStatus = TDI_INVALID_PARAMETER;
  2003. break;
  2004. case RWAN_STATUS_MISSING_PARAMETER:
  2005. TdiStatus = TDI_INVALID_PARAMETER;
  2006. break;
  2007. case RWAN_STATUS_FAILURE:
  2008. default:
  2009. TdiStatus = TDI_INVALID_STATE; // XXX: find a better one?
  2010. break;
  2011. }
  2012. return (TdiStatus);
  2013. }
  2014. PRWAN_CONN_REQUEST
  2015. RWanAllocateConnReq(
  2016. VOID
  2017. )
  2018. /*++
  2019. Routine Description:
  2020. Allocate a structure to hold context about a TDI Connection Request.
  2021. This includes TDI_CONNECT, TDI_DISCONNECT, TDI_LISTEN and TDI_ACCEPT.
  2022. Arguments:
  2023. None
  2024. Return Value:
  2025. Pointer to allocate structure if successful, else NULL.
  2026. --*/
  2027. {
  2028. PRWAN_CONN_REQUEST pConnReq;
  2029. RWAN_ALLOC_MEM(pConnReq, RWAN_CONN_REQUEST, sizeof(RWAN_CONN_REQUEST));
  2030. if (pConnReq != NULL)
  2031. {
  2032. RWAN_SET_SIGNATURE(pConnReq, nrc);
  2033. }
  2034. return (pConnReq);
  2035. }
  2036. VOID
  2037. RWanFreeConnReq(
  2038. IN PRWAN_CONN_REQUEST pConnReq
  2039. )
  2040. /*++
  2041. Routine Description:
  2042. Free a connect request context structure.
  2043. Arguments:
  2044. pConnReq - Points to structure to be freed.
  2045. Return Value:
  2046. None
  2047. --*/
  2048. {
  2049. RWAN_STRUCT_ASSERT(pConnReq, nrc);
  2050. RWAN_FREE_MEM(pConnReq);
  2051. }
  2052. VOID
  2053. RWanAbortConnection(
  2054. IN CONNECTION_CONTEXT ConnectionContext
  2055. )
  2056. /*++
  2057. Routine Description:
  2058. Abortively closes a connection and issues a Disconnect Indication
  2059. to the user. This is called when a send or receive is cancelled,
  2060. implying that an NDIS connection is in place.
  2061. Arguments:
  2062. ConnectionContext- Our context for a TDI Connection object.
  2063. Return Value:
  2064. None
  2065. --*/
  2066. {
  2067. RWAN_CONN_ID ConnId;
  2068. PRWAN_TDI_CONNECTION pConnObject;
  2069. ConnId = (RWAN_CONN_ID)PtrToUlong(ConnectionContext);
  2070. RWAN_ACQUIRE_CONN_TABLE_LOCK();
  2071. pConnObject = RWanGetConnFromId(ConnId);
  2072. RWAN_RELEASE_CONN_TABLE_LOCK();
  2073. RWanDoAbortConnection(pConnObject);
  2074. }
  2075. VOID
  2076. RWanDoAbortConnection(
  2077. IN PRWAN_TDI_CONNECTION pConnObject
  2078. )
  2079. /*++
  2080. Routine Description:
  2081. Does the actual connection abort. Split out from RWanAbortConnection
  2082. just so that this can be called from elsewhere.
  2083. See comments under RWanAbortConnection.
  2084. Arguments:
  2085. pConnObject - Points to TDI Connection to be aborted.
  2086. Return Value:
  2087. None
  2088. --*/
  2089. {
  2090. PRWAN_NDIS_VC pVc;
  2091. PRWAN_NDIS_PARTY pParty;
  2092. PRWAN_TDI_CONNECTION pLeafConnObject;
  2093. INT rc;
  2094. BOOLEAN bIsLockReleased = TRUE;
  2095. ULONG OldState;
  2096. ULONG OldLeafState;
  2097. PLIST_ENTRY pPartyEntry;
  2098. PLIST_ENTRY pNextPartyEntry;
  2099. RWANDEBUGP(DL_INFO, DC_DISCON,
  2100. ("DoAbortConnection: pConnObject x%x/%x, pAddrObject x%x\n",
  2101. pConnObject, (pConnObject? pConnObject->Flags: 0), (pConnObject? pConnObject->pAddrObject: 0)));
  2102. do
  2103. {
  2104. if (pConnObject == NULL_PRWAN_TDI_CONNECTION)
  2105. {
  2106. break;
  2107. }
  2108. RWAN_ACQUIRE_CONN_LOCK(pConnObject);
  2109. //
  2110. // Make sure we don't do this more than once on a Connection.
  2111. //
  2112. if (pConnObject->State == RWANS_CO_ABORTING)
  2113. {
  2114. RWAN_RELEASE_CONN_LOCK(pConnObject);
  2115. break;
  2116. }
  2117. //
  2118. // Make sure the Conn Object doesn't go away during the time we
  2119. // need it.
  2120. //
  2121. RWanReferenceConnObject(pConnObject); // temp ref: RWanAbortConnection
  2122. OldState = pConnObject->State;
  2123. pConnObject->State = RWANS_CO_ABORTING;
  2124. if (RWAN_IS_BIT_SET(pConnObject->Flags, RWANF_CO_ROOT))
  2125. {
  2126. bIsLockReleased = FALSE;
  2127. //
  2128. // This is a Root Connection object.
  2129. // Indicate disconnect and schedule Closing each leaf.
  2130. //
  2131. pVc = pConnObject->NdisConnection.pNdisVc;
  2132. if (pVc != NULL)
  2133. {
  2134. for (pPartyEntry = pVc->NdisPartyList.Flink;
  2135. pPartyEntry != &(pVc->NdisPartyList);
  2136. pPartyEntry = pNextPartyEntry)
  2137. {
  2138. pParty = CONTAINING_RECORD(pPartyEntry, RWAN_NDIS_PARTY, PartyLink);
  2139. pNextPartyEntry = pParty->PartyLink.Flink;
  2140. pLeafConnObject = pParty->pConnObject;
  2141. RWAN_ASSERT(pLeafConnObject);
  2142. RWAN_STRUCT_ASSERT(pLeafConnObject, ntc);
  2143. RWAN_ACQUIRE_CONN_LOCK(pLeafConnObject);
  2144. if (pLeafConnObject->State == RWANS_CO_ABORTING)
  2145. {
  2146. RWAN_RELEASE_CONN_LOCK(pLeafConnObject);
  2147. continue;
  2148. }
  2149. #if DBG
  2150. pLeafConnObject->OldState = pLeafConnObject->State;
  2151. pLeafConnObject->OldFlags = pLeafConnObject->Flags;
  2152. #endif // DBG
  2153. OldLeafState = pLeafConnObject->State;
  2154. pLeafConnObject->State = RWANS_CO_ABORTING;
  2155. if ((OldLeafState == RWANS_CO_CONNECTED) &&
  2156. (pLeafConnObject->pAddrObject != NULL_PRWAN_TDI_ADDRESS))
  2157. {
  2158. PDisconnectEvent pDisconInd;
  2159. PVOID IndContext;
  2160. PVOID ConnectionHandle;
  2161. pDisconInd = pLeafConnObject->pAddrObject->pDisconInd;
  2162. IndContext = pLeafConnObject->pAddrObject->DisconIndContext;
  2163. if (pDisconInd != NULL)
  2164. {
  2165. pLeafConnObject->State = RWANS_CO_DISCON_INDICATED;
  2166. ConnectionHandle = pLeafConnObject->ConnectionHandle;
  2167. RWAN_RELEASE_CONN_LOCK(pLeafConnObject);
  2168. RWAN_RELEASE_CONN_LOCK(pConnObject);
  2169. RWANDEBUGP(DL_FATAL, DC_DISCON,
  2170. ("DoAbort[Leaf]: will indicate Discon, pConnObj x%x, pAddrObj x%x\n",
  2171. pLeafConnObject, pLeafConnObject->pAddrObject));
  2172. (*pDisconInd)(
  2173. IndContext,
  2174. ConnectionHandle,
  2175. 0, // Disconnect Data Length
  2176. NULL, // Disconnect Data
  2177. 0, // Disconnect Info Length
  2178. NULL, // Disconnect Info
  2179. TDI_DISCONNECT_ABORT
  2180. );
  2181. RWAN_ACQUIRE_CONN_LOCK(pConnObject);
  2182. RWAN_ACQUIRE_CONN_LOCK(pLeafConnObject);
  2183. }
  2184. }
  2185. RWanScheduleDisconnect(pLeafConnObject);
  2186. //
  2187. // Leaf Conn Object lock is freed within the above.
  2188. //
  2189. }
  2190. //
  2191. // end For all parties
  2192. //
  2193. }
  2194. //
  2195. // else Root Conn object has no associated VC.
  2196. //
  2197. rc = RWanDereferenceConnObject(pConnObject); // temp ref: RWanAbortConnection
  2198. if (rc == 0)
  2199. {
  2200. bIsLockReleased = TRUE;
  2201. break; // The Conn Object has been deref'ed away.
  2202. }
  2203. }
  2204. else
  2205. {
  2206. //
  2207. // Not PMP connection.
  2208. //
  2209. pVc = pConnObject->NdisConnection.pNdisVc;
  2210. // 157217: this prevents CoSendComplete for pended packets from
  2211. // continuing on to do StartCloseCall.
  2212. // RWAN_UNLINK_CONNECTION_AND_VC(pConnObject, pVc);
  2213. //
  2214. // First, initiate a network call close.
  2215. //
  2216. RWanStartCloseCall(pConnObject, pVc);
  2217. //
  2218. // The lock is freed within the above. Reacquire it.
  2219. //
  2220. bIsLockReleased = FALSE;
  2221. RWAN_ACQUIRE_CONN_LOCK(pConnObject);
  2222. rc = RWanDereferenceConnObject(pConnObject); // temp ref: RWanAbortConnection
  2223. if (rc == 0)
  2224. {
  2225. bIsLockReleased = TRUE;
  2226. break; // The Conn Object has been deref'ed away.
  2227. }
  2228. //
  2229. // Now, indicate a disconnect to the user, if required & possible.
  2230. //
  2231. if ((OldState == RWANS_CO_CONNECTED) &&
  2232. (pConnObject->pAddrObject != NULL_PRWAN_TDI_ADDRESS))
  2233. {
  2234. PDisconnectEvent pDisconInd;
  2235. PVOID IndContext;
  2236. PVOID ConnectionHandle;
  2237. pDisconInd = pConnObject->pAddrObject->pDisconInd;
  2238. IndContext = pConnObject->pAddrObject->DisconIndContext;
  2239. if (pDisconInd != NULL)
  2240. {
  2241. ConnectionHandle = pConnObject->ConnectionHandle;
  2242. RWAN_RELEASE_CONN_LOCK(pConnObject);
  2243. (*pDisconInd)(
  2244. IndContext,
  2245. ConnectionHandle,
  2246. 0, // Disconnect Data Length
  2247. NULL, // Disconnect Data
  2248. 0, // Disconnect Info Length
  2249. NULL, // Disconnect Info
  2250. TDI_DISCONNECT_ABORT
  2251. );
  2252. bIsLockReleased = TRUE;
  2253. }
  2254. }
  2255. }
  2256. if (!bIsLockReleased)
  2257. {
  2258. RWAN_RELEASE_CONN_LOCK(pConnObject);
  2259. }
  2260. break;
  2261. }
  2262. while (FALSE);
  2263. return;
  2264. }
  2265. VOID
  2266. RWanScheduleDisconnect(
  2267. IN PRWAN_TDI_CONNECTION pConnObject
  2268. )
  2269. /*++
  2270. Routine Description:
  2271. Schedule a call to RWanDoTdiDisconnect on the specified connection
  2272. object, as a work item.
  2273. NOTE: The Connection object is locked by the caller.
  2274. Arguments:
  2275. pConnObject - Points to TDI Connection to be aborted.
  2276. Return Value:
  2277. None
  2278. --*/
  2279. {
  2280. NDIS_STATUS Status;
  2281. RWANDEBUGP(DL_LOUD, DC_DISCON,
  2282. ("ScheduleDiscon: pConnObj x%x/x%x, state %d\n",
  2283. pConnObject, pConnObject->Flags, pConnObject->State));
  2284. do
  2285. {
  2286. //
  2287. // Check if we've already done this.
  2288. //
  2289. if (RWAN_IS_BIT_SET(pConnObject->Flags, RWANF_CO_CLOSE_SCHEDULED))
  2290. {
  2291. break;
  2292. }
  2293. RWAN_SET_BIT(pConnObject->Flags, RWANF_CO_CLOSE_SCHEDULED);
  2294. //
  2295. // Make sure the connection doesn't go away till the
  2296. // work item is handled.
  2297. //
  2298. RWanReferenceConnObject(pConnObject); // Schedule Discon ref
  2299. NdisInitializeWorkItem(
  2300. &pConnObject->CloseWorkItem,
  2301. RWanDelayedDisconnectHandler,
  2302. (PVOID)pConnObject);
  2303. Status = NdisScheduleWorkItem(&pConnObject->CloseWorkItem);
  2304. RWAN_ASSERT(Status == NDIS_STATUS_SUCCESS);
  2305. }
  2306. while (FALSE);
  2307. RWAN_RELEASE_CONN_LOCK(pConnObject);
  2308. return;
  2309. }
  2310. VOID
  2311. RWanDelayedDisconnectHandler(
  2312. IN PNDIS_WORK_ITEM pCloseWorkItem,
  2313. IN PVOID Context
  2314. )
  2315. /*++
  2316. Routine Description:
  2317. Work item routine to initiate a connection teardown.
  2318. Arguments:
  2319. pCloseWorkItem - Points to work item structure embedded in the
  2320. Connection object.
  2321. Context - Actually a pointer to the Connection object.
  2322. Return Value:
  2323. None
  2324. --*/
  2325. {
  2326. PRWAN_TDI_CONNECTION pConnObject;
  2327. ULONG rc;
  2328. pConnObject = (PRWAN_TDI_CONNECTION)Context;
  2329. RWAN_STRUCT_ASSERT(pConnObject, ntc);
  2330. RWANDEBUGP(DL_LOUD, DC_DISCON,
  2331. ("DelayedDiscon handler: pConnObj x%x/x%x, state %d\n",
  2332. pConnObject, pConnObject->Flags, pConnObject->State));
  2333. do
  2334. {
  2335. RWAN_ACQUIRE_CONN_LOCK(pConnObject);
  2336. rc = RWanDereferenceConnObject(pConnObject); // Delayed (scheduled) Discon deref
  2337. if (rc == 0)
  2338. {
  2339. //
  2340. // The Conn Object is gone.
  2341. //
  2342. break;
  2343. }
  2344. //
  2345. // Do the Disconnect now.
  2346. //
  2347. RWanDoTdiDisconnect(
  2348. pConnObject,
  2349. NULL, // pTdiRequest
  2350. NULL, // pTimeout
  2351. 0, // Flags
  2352. NULL, // pDisconnInfo
  2353. NULL // pReturnInfo
  2354. );
  2355. //
  2356. // Conn object lock is released within the above.
  2357. //
  2358. break;
  2359. }
  2360. while (FALSE);
  2361. return;
  2362. }