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.

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