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.

3678 lines
95 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. connect.c
  5. Abstract:
  6. This routine contains the code to handle connect requests
  7. for the Netbios module of the ISN transport.
  8. Author:
  9. Adam Barr (adamba) 22-November-1993
  10. Environment:
  11. Kernel mode
  12. Revision History:
  13. --*/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. #ifdef RASAUTODIAL
  17. #include <acd.h>
  18. #include <acdapi.h>
  19. BOOLEAN
  20. NbiCancelTdiConnect(
  21. IN PDEVICE pDevice,
  22. IN PREQUEST pRequest,
  23. IN PCONNECTION pConnection
  24. );
  25. #endif // RASAUTODIAL
  26. extern POBJECT_TYPE *IoFileObjectType;
  27. VOID
  28. NbiFindRouteComplete(
  29. IN PIPX_FIND_ROUTE_REQUEST FindRouteRequest,
  30. IN BOOLEAN FoundRoute
  31. )
  32. /*++
  33. Routine Description:
  34. This routine is called when a find route request
  35. previously issued to IPX completes.
  36. Arguments:
  37. FindRouteRequest - The find route request that was issued.
  38. FoundRoute - TRUE if the route was found.
  39. Return Value:
  40. None.
  41. --*/
  42. {
  43. PCONNECTION Connection;
  44. PDEVICE Device = NbiDevice;
  45. UINT i;
  46. BOOLEAN LocalRoute;
  47. USHORT TickCount;
  48. PREQUEST RequestToComplete;
  49. PUSHORT Counts;
  50. CTELockHandle LockHandle1, LockHandle2;
  51. CTELockHandle CancelLH;
  52. Connection = CONTAINING_RECORD (FindRouteRequest, CONNECTION, FindRouteRequest);
  53. NB_GET_CANCEL_LOCK(&CancelLH);
  54. NB_GET_LOCK (&Connection->Lock, &LockHandle1);
  55. NB_GET_LOCK (&Device->Lock, &LockHandle2);
  56. Connection->FindRouteInProgress = FALSE;
  57. if (FoundRoute) {
  58. //
  59. // See if the route is local or not (for local routes
  60. // we use the real MAC address in the local target, but
  61. // the NIC ID may not be what we expect.
  62. //
  63. LocalRoute = TRUE;
  64. for (i = 0; i < 6; i++) {
  65. if (FindRouteRequest->LocalTarget.MacAddress[i] != 0x00) {
  66. LocalRoute = FALSE;
  67. }
  68. }
  69. if (LocalRoute) {
  70. #if defined(_PNP_POWER)
  71. Connection->LocalTarget.NicHandle = FindRouteRequest->LocalTarget.NicHandle;
  72. #else
  73. Connection->LocalTarget.NicId = FindRouteRequest->LocalTarget.NicId;
  74. #endif _PNP_POWER
  75. } else {
  76. Connection->LocalTarget = FindRouteRequest->LocalTarget;
  77. }
  78. Counts = (PUSHORT)(&FindRouteRequest->Reserved2);
  79. TickCount = Counts[0];
  80. if (TickCount > 1) {
  81. //
  82. // Each tick is 55 ms, and for our timeout we use 10 ticks
  83. // worth (this makes tick count of 1 be about 500 ms, the
  84. // default).
  85. //
  86. // We get 55 milliseconds from
  87. //
  88. // 1 second * 1000 milliseconds 55 ms
  89. // -------- ----------------- = -----
  90. // 18.21 ticks 1 second tick
  91. //
  92. Connection->TickCount = TickCount;
  93. Connection->BaseRetransmitTimeout = (TickCount * 550) / SHORT_TIMER_DELTA;
  94. if (Connection->State != CONNECTION_STATE_ACTIVE) {
  95. Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
  96. }
  97. }
  98. Connection->HopCount = Counts[1];
  99. }
  100. //
  101. // If the call failed we just use whatever route we had before
  102. // (on a connect it will be from the name query response, on
  103. // a listen from whatever the incoming connect frame had).
  104. //
  105. if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
  106. (Connection->SubState == CONNECTION_SUBSTATE_C_W_ROUTE)) {
  107. // we dont need to hold CancelSpinLock so release it,
  108. // since we are releasing the locks out of order, we must
  109. // swap the irql to get the priorities right.
  110. NB_SWAP_IRQL( CancelLH, LockHandle1);
  111. NB_FREE_CANCEL_LOCK( CancelLH );
  112. //
  113. // Continue on with the session init frame.
  114. //
  115. (VOID)(*Device->Bind.QueryHandler)( // We should check return code
  116. IPX_QUERY_LINE_INFO,
  117. #if defined(_PNP_POWER)
  118. &Connection->LocalTarget.NicHandle,
  119. #else
  120. Connection->LocalTarget.NicId,
  121. #endif _PNP_POWER
  122. &Connection->LineInfo,
  123. sizeof(IPX_LINE_INFO),
  124. NULL);
  125. // Maximum packet size is the lower of RouterMtu and MaximumSendSize.
  126. Connection->MaximumPacketSize = NB_MIN( Device->RouterMtu - sizeof(IPX_HEADER) , Connection->LineInfo.MaximumSendSize ) - sizeof(NB_CONNECTION) ;
  127. Connection->ReceiveWindowSize = 6;
  128. Connection->SendWindowSize = 2;
  129. Connection->MaxSendWindowSize = 6; // Base on what he sent ?
  130. //
  131. // Don't set RcvSequenceMax yet because we don't know
  132. // if the connection is old or new netbios.
  133. //
  134. Connection->SubState = CONNECTION_SUBSTATE_C_W_ACK;
  135. //
  136. // We found a route, we need to start the connect
  137. // process by sending out the session initialize
  138. // frame. We start the timer to handle retries.
  139. //
  140. // CTEStartTimer doesn't deal with changing the
  141. // expiration time of a running timer, so we have
  142. // to stop it first. If we succeed in stopping the
  143. // timer, then the CREF_TIMER reference from the
  144. // previous starting of the timer remains, so we
  145. // don't need to reference the connection again.
  146. //
  147. if (!CTEStopTimer (&Connection->Timer)) {
  148. NbiReferenceConnectionLock (Connection, CREF_TIMER);
  149. }
  150. NB_FREE_LOCK (&Device->Lock, LockHandle2);
  151. CTEStartTimer(
  152. &Connection->Timer,
  153. Device->ConnectionTimeout,
  154. NbiConnectionTimeout,
  155. (PVOID)Connection);
  156. NB_FREE_LOCK (&Connection->Lock, LockHandle1);
  157. NbiSendSessionInitialize (Connection);
  158. } else if ((Connection->State == CONNECTION_STATE_LISTENING) &&
  159. (Connection->SubState == CONNECTION_SUBSTATE_L_W_ROUTE)) {
  160. if (Connection->ListenRequest != NULL) {
  161. NbiTransferReferenceConnection (Connection, CREF_LISTEN, CREF_ACTIVE);
  162. RequestToComplete = Connection->ListenRequest;
  163. Connection->ListenRequest = NULL;
  164. IoSetCancelRoutine (RequestToComplete, (PDRIVER_CANCEL)NULL);
  165. } else if (Connection->AcceptRequest != NULL) {
  166. NbiTransferReferenceConnection (Connection, CREF_ACCEPT, CREF_ACTIVE);
  167. RequestToComplete = Connection->AcceptRequest;
  168. Connection->AcceptRequest = NULL;
  169. } else {
  170. CTEAssert (FALSE);
  171. RequestToComplete = NULL;
  172. }
  173. // we dont need to hold CancelSpinLock so release it,
  174. // since we are releasing the locks out of order, we must
  175. // swap the irql to get the priorities right.
  176. NB_SWAP_IRQL( CancelLH, LockHandle1);
  177. NB_FREE_CANCEL_LOCK( CancelLH );
  178. (VOID)(*Device->Bind.QueryHandler)( // We should check return code
  179. IPX_QUERY_LINE_INFO,
  180. #if defined(_PNP_POWER)
  181. &Connection->LocalTarget.NicHandle,
  182. #else
  183. Connection->LocalTarget.NicId,
  184. #endif _PNP_POWER
  185. &Connection->LineInfo,
  186. sizeof(IPX_LINE_INFO),
  187. NULL);
  188. // Take the lowest of MaximumPacketSize ( set from the sessionInit
  189. // frame ), MaximumSendSize and RouterMtu.
  190. if (Connection->MaximumPacketSize > Connection->LineInfo.MaximumSendSize - sizeof(NB_CONNECTION)) {
  191. Connection->MaximumPacketSize = NB_MIN( Device->RouterMtu - sizeof(IPX_HEADER), Connection->LineInfo.MaximumSendSize ) - sizeof(NB_CONNECTION);
  192. } else {
  193. // Connection->MaximumPacketSize is what was set by the sender so already
  194. // accounts for the header.
  195. Connection->MaximumPacketSize = NB_MIN( Device->RouterMtu - sizeof(NB_CONNECTION) - sizeof(IPX_HEADER), Connection->MaximumPacketSize ) ;
  196. }
  197. Connection->ReceiveWindowSize = 6;
  198. Connection->SendWindowSize = 2;
  199. Connection->MaxSendWindowSize = 6; // Base on what he sent ?
  200. if (Connection->NewNetbios) {
  201. CTEAssert (Connection->LocalRcvSequenceMax == 4); // should have been set
  202. Connection->LocalRcvSequenceMax = Connection->ReceiveWindowSize;
  203. }
  204. Connection->State = CONNECTION_STATE_ACTIVE;
  205. Connection->SubState = CONNECTION_SUBSTATE_A_IDLE;
  206. Connection->ReceiveState = CONNECTION_RECEIVE_IDLE;
  207. ++Device->Statistics.OpenConnections;
  208. NB_FREE_LOCK (&Device->Lock, LockHandle2);
  209. //
  210. // StartWatchdog acquires TimerLock, so we have to
  211. // free Lock first.
  212. //
  213. NbiStartWatchdog (Connection);
  214. //
  215. // This releases the connection lock, so that SessionInitAckData
  216. // can't be freed before it is copied.
  217. //
  218. NbiSendSessionInitAck(
  219. Connection,
  220. Connection->SessionInitAckData,
  221. Connection->SessionInitAckDataLength,
  222. &LockHandle1);
  223. if (RequestToComplete != NULL) {
  224. REQUEST_STATUS(RequestToComplete) = STATUS_SUCCESS;
  225. NbiCompleteRequest (RequestToComplete);
  226. NbiFreeRequest (Device, RequestToComplete);
  227. }
  228. } else {
  229. NB_FREE_LOCK (&Device->Lock, LockHandle2);
  230. NB_FREE_LOCK (&Connection->Lock, LockHandle1);
  231. NB_FREE_CANCEL_LOCK( CancelLH );
  232. }
  233. NbiDereferenceConnection (Connection, CREF_FIND_ROUTE);
  234. } /* NbiFindRouteComplete */
  235. NTSTATUS
  236. NbiOpenConnection(
  237. IN PDEVICE Device,
  238. IN PREQUEST Request
  239. )
  240. /*++
  241. Routine Description:
  242. This routine is called to open a connection. Note that the connection that
  243. is open is of little use until associated with an address; until then,
  244. the only thing that can be done with it is close it.
  245. Arguments:
  246. Device - Pointer to the device for this driver.
  247. Request - Pointer to the request representing the open.
  248. Return Value:
  249. The function value is the status of the operation.
  250. --*/
  251. {
  252. PCONNECTION Connection;
  253. PFILE_FULL_EA_INFORMATION ea;
  254. #ifdef ISN_NT
  255. PIRP Irp = (PIRP)Request;
  256. PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
  257. #endif
  258. //
  259. // Verify Minimum Buffer length!
  260. // Bug#: 203814
  261. //
  262. ea = (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
  263. if (ea->EaValueLength < sizeof(PVOID))
  264. {
  265. NbiPrint2("NbiOpenConnection: ERROR -- (EaValueLength=%d < Min=%d)\n",
  266. ea->EaValueLength, sizeof(PVOID));
  267. CTEAssert(FALSE);
  268. return (STATUS_INVALID_ADDRESS_COMPONENT);
  269. }
  270. //
  271. // First, try to make a connection object to represent this pending
  272. // connection. Then fill in the relevant fields.
  273. // In addition to the creation, if successful NbfCreateConnection
  274. // will create a second reference which is removed once the request
  275. // references the connection, or if the function exits before that.
  276. if (!(Connection = NbiCreateConnection (Device))) {
  277. return STATUS_INSUFFICIENT_RESOURCES;
  278. }
  279. //
  280. // set the connection context so we can connect the user to this data
  281. // structure
  282. //
  283. RtlCopyMemory ( &Connection->Context, &ea->EaName[ea->EaNameLength+1], sizeof (PVOID));
  284. //
  285. // let file object point at connection and connection at file object
  286. //
  287. REQUEST_OPEN_CONTEXT(Request) = (PVOID)Connection;
  288. REQUEST_OPEN_TYPE(Request) = (PVOID)TDI_CONNECTION_FILE;
  289. #ifdef ISN_NT
  290. Connection->FileObject = IrpSp->FileObject;
  291. #endif
  292. return STATUS_SUCCESS;
  293. } /* NbiOpenConnection */
  294. VOID
  295. NbiStopConnection(
  296. IN PCONNECTION Connection,
  297. IN NTSTATUS DisconnectStatus
  298. IN NB_LOCK_HANDLE_PARAM(LockHandle)
  299. )
  300. /*++
  301. Routine Description:
  302. This routine is called to stop an active connection.
  303. THIS ROUTINE IS CALLED WITH THE CONNECTION LOCK HELD
  304. AND RETURNS WITH IT RELEASED.
  305. Arguments:
  306. Connection - The connection to be stopped.
  307. DisconnectStatus - The reason for the disconnect. One of:
  308. STATUS_LINK_FAILED: We timed out trying to probe the remote.
  309. STATUS_REMOTE_DISCONNECT: The remote sent a session end.
  310. STATUS_LOCAL_DISCONNECT: The local side disconnected.
  311. STATUS_CANCELLED: A send or receive on this connection was cancelled.
  312. STATUS_INVALID_CONNECTION: The local side closed the connection.
  313. STATUS_INVALID_ADDRESS: The local side closed the address.
  314. LockHandle - The handle which the connection lock was acquired with.
  315. Return Value:
  316. None.
  317. --*/
  318. {
  319. PREQUEST ListenRequest, AcceptRequest, SendRequest, ReceiveRequest,
  320. DisconnectWaitRequest, ConnectRequest;
  321. PREQUEST Request, TmpRequest;
  322. BOOLEAN DerefForPacketize;
  323. BOOLEAN DerefForWaitPacket;
  324. BOOLEAN DerefForActive;
  325. BOOLEAN DerefForWaitCache;
  326. BOOLEAN SendSessionEnd;
  327. BOOLEAN ActiveReceive;
  328. BOOLEAN IndicateToClient;
  329. BOOLEAN ConnectionWasActive;
  330. PDEVICE Device = NbiDevice;
  331. PADDRESS_FILE AddressFile;
  332. NB_DEFINE_LOCK_HANDLE (LockHandle2)
  333. NB_DEFINE_LOCK_HANDLE (LockHandle3)
  334. CTELockHandle CancelLH;
  335. NB_DEBUG2 (CONNECTION, ("Stop connection %lx (%lx)\n", Connection, DisconnectStatus));
  336. //
  337. // These flags control our actions after we set the state to
  338. // DISCONNECT.
  339. //
  340. DerefForPacketize = FALSE;
  341. DerefForWaitPacket = FALSE;
  342. DerefForActive = FALSE;
  343. DerefForWaitCache = FALSE;
  344. SendSessionEnd = FALSE;
  345. ActiveReceive = FALSE;
  346. IndicateToClient = FALSE;
  347. ConnectionWasActive = FALSE;
  348. //
  349. // These contain requests or queues of request to complete.
  350. //
  351. ListenRequest = NULL;
  352. AcceptRequest = NULL;
  353. SendRequest = NULL;
  354. ReceiveRequest = NULL;
  355. DisconnectWaitRequest = NULL;
  356. ConnectRequest = NULL;
  357. NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle2);
  358. if (Connection->State == CONNECTION_STATE_ACTIVE) {
  359. --Device->Statistics.OpenConnections;
  360. ConnectionWasActive = TRUE;
  361. Connection->Status = DisconnectStatus;
  362. if ((DisconnectStatus == STATUS_LINK_FAILED) ||
  363. (DisconnectStatus == STATUS_LOCAL_DISCONNECT)) {
  364. //
  365. // Send out session end frames, but fewer if
  366. // we timed out.
  367. //
  368. // What about STATUS_CANCELLED?
  369. //
  370. Connection->Retries = (DisconnectStatus == STATUS_LOCAL_DISCONNECT) ?
  371. Device->ConnectionCount :
  372. (Device->ConnectionCount / 2);
  373. SendSessionEnd = TRUE;
  374. Connection->SubState = CONNECTION_SUBSTATE_D_W_ACK;
  375. //
  376. // CTEStartTimer doesn't deal with changing the
  377. // expiration time of a running timer, so we have
  378. // to stop it first. If we succeed in stopping the
  379. // timer, then the CREF_TIMER reference from the
  380. // previous starting of the timer remains, so we
  381. // don't need to reference the connection again.
  382. //
  383. if (!CTEStopTimer (&Connection->Timer)) {
  384. NbiReferenceConnectionLock (Connection, CREF_TIMER);
  385. }
  386. CTEStartTimer(
  387. &Connection->Timer,
  388. Device->ConnectionTimeout,
  389. NbiConnectionTimeout,
  390. (PVOID)Connection);
  391. }
  392. if (Connection->ReceiveState == CONNECTION_RECEIVE_TRANSFER) {
  393. ActiveReceive = TRUE;
  394. }
  395. Connection->State = CONNECTION_STATE_DISCONNECT;
  396. DerefForActive = TRUE;
  397. if (Connection->DisconnectWaitRequest != NULL) {
  398. DisconnectWaitRequest = Connection->DisconnectWaitRequest;
  399. Connection->DisconnectWaitRequest = NULL;
  400. }
  401. if ((DisconnectStatus == STATUS_LINK_FAILED) ||
  402. (DisconnectStatus == STATUS_REMOTE_DISCONNECT) ||
  403. (DisconnectStatus == STATUS_CANCELLED)) {
  404. IndicateToClient = TRUE;
  405. }
  406. //
  407. // If we are inside NbiAssignSequenceAndSend, add
  408. // a reference so the connection won't go away during it.
  409. //
  410. if (Connection->NdisSendsInProgress > 0) {
  411. *(Connection->NdisSendReference) = TRUE;
  412. NB_DEBUG2 (SEND, ("Adding CREF_NDIS_SEND to %lx\n", Connection));
  413. NbiReferenceConnectionLock (Connection, CREF_NDIS_SEND);
  414. }
  415. //
  416. // Clean up some other stuff.
  417. //
  418. Connection->ReceiveUnaccepted = 0;
  419. Connection->CurrentIndicateOffset = 0;
  420. //
  421. // Update our counters. Some of these we never use.
  422. //
  423. switch (DisconnectStatus) {
  424. case STATUS_LOCAL_DISCONNECT:
  425. ++Device->Statistics.LocalDisconnects;
  426. break;
  427. case STATUS_REMOTE_DISCONNECT:
  428. ++Device->Statistics.RemoteDisconnects;
  429. break;
  430. case STATUS_LINK_FAILED:
  431. ++Device->Statistics.LinkFailures;
  432. break;
  433. case STATUS_IO_TIMEOUT:
  434. ++Device->Statistics.SessionTimeouts;
  435. break;
  436. case STATUS_CANCELLED:
  437. ++Device->Statistics.CancelledConnections;
  438. break;
  439. case STATUS_REMOTE_RESOURCES:
  440. ++Device->Statistics.RemoteResourceFailures;
  441. break;
  442. case STATUS_INVALID_CONNECTION:
  443. case STATUS_INVALID_ADDRESS:
  444. case STATUS_INSUFFICIENT_RESOURCES:
  445. ++Device->Statistics.LocalResourceFailures;
  446. break;
  447. case STATUS_BAD_NETWORK_PATH:
  448. case STATUS_REMOTE_NOT_LISTENING:
  449. ++Device->Statistics.NotFoundFailures;
  450. break;
  451. default:
  452. CTEAssert(FALSE);
  453. break;
  454. }
  455. } else if (Connection->State == CONNECTION_STATE_CONNECTING) {
  456. //
  457. // There is a connect in progress. We have to find ourselves
  458. // in the pending connect queue if we are there.
  459. //
  460. if (Connection->SubState == CONNECTION_SUBSTATE_C_FIND_NAME) {
  461. RemoveEntryList (REQUEST_LINKAGE(Connection->ConnectRequest));
  462. DerefForWaitCache = TRUE;
  463. }
  464. if (Connection->SubState != CONNECTION_SUBSTATE_C_DISCONN) {
  465. ConnectRequest = Connection->ConnectRequest;
  466. Connection->ConnectRequest = NULL;
  467. Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
  468. }
  469. }
  470. //
  471. // If we allocated this memory, free it.
  472. //
  473. if (Connection->SessionInitAckDataLength > 0) {
  474. NbiFreeMemory(
  475. Connection->SessionInitAckData,
  476. Connection->SessionInitAckDataLength,
  477. MEMORY_CONNECTION,
  478. "SessionInitAckData");
  479. Connection->SessionInitAckData = NULL;
  480. Connection->SessionInitAckDataLength = 0;
  481. }
  482. if (Connection->ListenRequest != NULL) {
  483. ListenRequest = Connection->ListenRequest;
  484. Connection->ListenRequest = NULL;
  485. RemoveEntryList (REQUEST_LINKAGE(ListenRequest)); // take out of Device->ListenQueue
  486. }
  487. if (Connection->AcceptRequest != NULL) {
  488. AcceptRequest = Connection->AcceptRequest;
  489. Connection->AcceptRequest = NULL;
  490. }
  491. //
  492. // Do we need to stop the connection timer?
  493. // I don't think so.
  494. //
  495. //
  496. // A lot of this we only have to tear down if we were
  497. // active before this, because once we are stopping nothing
  498. // new will get started. Some of the other stuff
  499. // can be put inside this if also.
  500. //
  501. if (ConnectionWasActive) {
  502. //
  503. // Stop any receives. If there is one that is actively
  504. // transferring we leave it and just run down the rest
  505. // of the queue. If not, we queue the rest of the
  506. // queue on the back of the current one and run
  507. // down them all.
  508. //
  509. if (ActiveReceive) {
  510. ReceiveRequest = Connection->ReceiveQueue.Head;
  511. //
  512. // Connection->ReceiveRequest will get set to NULL
  513. // when the transfer completes.
  514. //
  515. } else {
  516. ReceiveRequest = Connection->ReceiveRequest;
  517. if (ReceiveRequest) {
  518. REQUEST_SINGLE_LINKAGE (ReceiveRequest) = Connection->ReceiveQueue.Head;
  519. } else {
  520. ReceiveRequest = Connection->ReceiveQueue.Head;
  521. }
  522. Connection->ReceiveRequest = NULL;
  523. }
  524. Connection->ReceiveQueue.Head = NULL;
  525. if ((Request = Connection->FirstMessageRequest) != NULL) {
  526. //
  527. // If the current request has some sends outstanding, then
  528. // we dequeue it from the queue to let it complete when
  529. // the sends complete. In that case we set SendRequest
  530. // to be the rest of the queue, which will be aborted.
  531. // If the current request has no sends, then we put
  532. // queue everything to SendRequest to be aborted below.
  533. //
  534. #if DBG
  535. if (REQUEST_REFCOUNT(Request) > 100) {
  536. DbgPrint ("Request %lx (%lx) has high refcount\n",
  537. Connection, Request);
  538. DbgBreakPoint();
  539. }
  540. #endif
  541. if (--REQUEST_REFCOUNT(Request) == 0) {
  542. //
  543. // NOTE: If this is a multi-request message, then
  544. // the linkage of Request will already point to the
  545. // send queue head, but we don't bother checking.
  546. //
  547. SendRequest = Request;
  548. REQUEST_SINGLE_LINKAGE (Request) = Connection->SendQueue.Head;
  549. } else {
  550. if (Connection->FirstMessageRequest == Connection->LastMessageRequest) {
  551. REQUEST_SINGLE_LINKAGE (Request) = NULL;
  552. } else {
  553. Connection->SendQueue.Head = REQUEST_SINGLE_LINKAGE (Connection->LastMessageRequest);
  554. REQUEST_SINGLE_LINKAGE (Connection->LastMessageRequest) = NULL;
  555. }
  556. SendRequest = Connection->SendQueue.Head;
  557. }
  558. Connection->FirstMessageRequest = NULL;
  559. } else {
  560. //
  561. // This may happen if we were sending a probe when a
  562. // send was submitted, and the probe timed out.
  563. //
  564. SendRequest = Connection->SendQueue.Head;
  565. }
  566. Connection->SendQueue.Head = NULL;
  567. }
  568. if (Connection->OnWaitPacketQueue) {
  569. Connection->OnWaitPacketQueue = FALSE;
  570. RemoveEntryList (&Connection->WaitPacketLinkage);
  571. DerefForWaitPacket = TRUE;
  572. }
  573. if (Connection->OnPacketizeQueue) {
  574. Connection->OnPacketizeQueue = FALSE;
  575. RemoveEntryList (&Connection->PacketizeLinkage);
  576. DerefForPacketize = TRUE;
  577. }
  578. //
  579. // Should we check if DataAckPending is TRUE and send an ack??
  580. //
  581. Connection->DataAckPending = FALSE;
  582. Connection->PiggybackAckTimeout = FALSE;
  583. Connection->ReceivesWithoutAck = 0;
  584. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
  585. //
  586. // We can't acquire TimerLock with Lock held, since
  587. // we sometimes call ReferenceConnection (which does an
  588. // interlocked add using Lock) with TimerLock held.
  589. //
  590. NB_SYNC_GET_LOCK (&Device->TimerLock, &LockHandle3);
  591. if (Connection->OnShortList) {
  592. Connection->OnShortList = FALSE;
  593. RemoveEntryList (&Connection->ShortList);
  594. }
  595. if (Connection->OnLongList) {
  596. Connection->OnLongList = FALSE;
  597. RemoveEntryList (&Connection->LongList);
  598. }
  599. if (Connection->OnDataAckQueue) {
  600. Connection->OnDataAckQueue = FALSE;
  601. RemoveEntryList (&Connection->DataAckLinkage);
  602. Device->DataAckQueueChanged = TRUE;
  603. }
  604. NB_SYNC_FREE_LOCK (&Device->TimerLock, LockHandle3);
  605. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  606. if (IndicateToClient) {
  607. AddressFile = Connection->AddressFile;
  608. if (AddressFile->RegisteredHandler[TDI_EVENT_DISCONNECT]) {
  609. NB_DEBUG2 (CONNECTION, ("Session end indicated on connection %lx\n", Connection));
  610. (*AddressFile->DisconnectHandler)(
  611. AddressFile->HandlerContexts[TDI_EVENT_DISCONNECT],
  612. Connection->Context,
  613. 0, // DisconnectData
  614. NULL,
  615. 0, // DisconnectInformation
  616. NULL,
  617. TDI_DISCONNECT_RELEASE); // DisconnectReason.
  618. }
  619. }
  620. if (DisconnectWaitRequest != NULL) {
  621. //
  622. // Make the TDI tester happy by returning CONNECTION_RESET
  623. // here.
  624. //
  625. if (DisconnectStatus == STATUS_REMOTE_DISCONNECT) {
  626. REQUEST_STATUS(DisconnectWaitRequest) = STATUS_CONNECTION_RESET;
  627. } else {
  628. REQUEST_STATUS(DisconnectWaitRequest) = DisconnectStatus;
  629. }
  630. NB_GET_CANCEL_LOCK( &CancelLH );
  631. IoSetCancelRoutine (DisconnectWaitRequest, (PDRIVER_CANCEL)NULL);
  632. NB_FREE_CANCEL_LOCK ( CancelLH );
  633. NbiCompleteRequest (DisconnectWaitRequest);
  634. NbiFreeRequest (Device, DisconnectWaitRequest);
  635. }
  636. if (ConnectRequest != NULL) {
  637. REQUEST_STATUS (ConnectRequest) = STATUS_LOCAL_DISCONNECT;
  638. NB_GET_CANCEL_LOCK( &CancelLH );
  639. IoSetCancelRoutine (ConnectRequest, (PDRIVER_CANCEL)NULL);
  640. NB_FREE_CANCEL_LOCK ( CancelLH );
  641. NbiCompleteRequest(ConnectRequest);
  642. NbiFreeRequest (Device, ConnectRequest);
  643. NbiDereferenceConnection (Connection, CREF_CONNECT);
  644. }
  645. if (ListenRequest != NULL) {
  646. REQUEST_INFORMATION(ListenRequest) = 0;
  647. REQUEST_STATUS(ListenRequest) = STATUS_LOCAL_DISCONNECT;
  648. NB_GET_CANCEL_LOCK( &CancelLH );
  649. IoSetCancelRoutine (ListenRequest, (PDRIVER_CANCEL)NULL);
  650. NB_FREE_CANCEL_LOCK ( CancelLH );
  651. NbiCompleteRequest (ListenRequest);
  652. NbiFreeRequest(Device, ListenRequest);
  653. NbiDereferenceConnection (Connection, CREF_LISTEN);
  654. }
  655. if (AcceptRequest != NULL) {
  656. REQUEST_INFORMATION(AcceptRequest) = 0;
  657. REQUEST_STATUS(AcceptRequest) = STATUS_LOCAL_DISCONNECT;
  658. NbiCompleteRequest (AcceptRequest);
  659. NbiFreeRequest(Device, AcceptRequest);
  660. NbiDereferenceConnection (Connection, CREF_ACCEPT);
  661. }
  662. while (ReceiveRequest != NULL) {
  663. TmpRequest = REQUEST_SINGLE_LINKAGE (ReceiveRequest);
  664. REQUEST_STATUS (ReceiveRequest) = DisconnectStatus;
  665. REQUEST_INFORMATION (ReceiveRequest) = 0;
  666. NB_DEBUG2 (RECEIVE, ("StopConnection aborting receive %lx\n", ReceiveRequest));
  667. NB_GET_CANCEL_LOCK( &CancelLH );
  668. IoSetCancelRoutine (ReceiveRequest, (PDRIVER_CANCEL)NULL);
  669. NB_FREE_CANCEL_LOCK ( CancelLH );
  670. NbiCompleteRequest (ReceiveRequest);
  671. NbiFreeRequest (Device, ReceiveRequest);
  672. ++Connection->ConnectionInfo.ReceiveErrors;
  673. ReceiveRequest = TmpRequest;
  674. NbiDereferenceConnection (Connection, CREF_RECEIVE);
  675. }
  676. while (SendRequest != NULL) {
  677. TmpRequest = REQUEST_SINGLE_LINKAGE (SendRequest);
  678. REQUEST_STATUS (SendRequest) = DisconnectStatus;
  679. REQUEST_INFORMATION (SendRequest) = 0;
  680. NB_DEBUG2 (SEND, ("StopConnection aborting send %lx\n", SendRequest));
  681. NB_GET_CANCEL_LOCK( &CancelLH );
  682. IoSetCancelRoutine (SendRequest, (PDRIVER_CANCEL)NULL);
  683. NB_FREE_CANCEL_LOCK ( CancelLH );
  684. NbiCompleteRequest (SendRequest);
  685. NbiFreeRequest (Device, SendRequest);
  686. ++Connection->ConnectionInfo.TransmissionErrors;
  687. SendRequest = TmpRequest;
  688. NbiDereferenceConnection (Connection, CREF_SEND);
  689. }
  690. if (SendSessionEnd) {
  691. NbiSendSessionEnd (Connection);
  692. }
  693. if (DerefForWaitCache) {
  694. NbiDereferenceConnection (Connection, CREF_WAIT_CACHE);
  695. }
  696. if (DerefForPacketize) {
  697. NbiDereferenceConnection (Connection, CREF_PACKETIZE);
  698. }
  699. if (DerefForWaitPacket) {
  700. NbiDereferenceConnection (Connection, CREF_W_PACKET);
  701. }
  702. if (DerefForActive) {
  703. NbiDereferenceConnection (Connection, CREF_ACTIVE);
  704. }
  705. } /* NbiStopConnection */
  706. NTSTATUS
  707. NbiCloseConnection(
  708. IN PDEVICE Device,
  709. IN PREQUEST Request
  710. )
  711. /*++
  712. Routine Description:
  713. This routine is called to close a connection.
  714. Arguments:
  715. Device - Pointer to the device for this driver.
  716. Request - Pointer to the request representing the open.
  717. Return Value:
  718. None.
  719. --*/
  720. {
  721. NTSTATUS Status;
  722. PCONNECTION Connection;
  723. PADDRESS_FILE AddressFile;
  724. PADDRESS Address;
  725. CTELockHandle LockHandle;
  726. Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
  727. NB_DEBUG2 (CONNECTION, ("Close connection %lx\n", Connection));
  728. NB_GET_LOCK (&Device->Lock, &LockHandle);
  729. if (Connection->ReferenceCount == 0) {
  730. //
  731. // If we are associated with an address, we need
  732. // to simulate a disassociate at this point.
  733. //
  734. if ((Connection->AddressFile != NULL) &&
  735. (Connection->AddressFile != (PVOID)-1)) {
  736. AddressFile = Connection->AddressFile;
  737. Connection->AddressFile = (PVOID)-1;
  738. NB_FREE_LOCK (&Device->Lock, LockHandle);
  739. //
  740. // Take this connection out of the address file's list.
  741. //
  742. Address = AddressFile->Address;
  743. NB_GET_LOCK (&Address->Lock, &LockHandle);
  744. if (Connection->AddressFileLinked) {
  745. Connection->AddressFileLinked = FALSE;
  746. RemoveEntryList (&Connection->AddressFileLinkage);
  747. }
  748. //
  749. // We are done.
  750. //
  751. NB_FREE_LOCK (&Address->Lock, LockHandle);
  752. Connection->AddressFile = NULL;
  753. //
  754. // Clean up the reference counts and complete any
  755. // disassociate requests that pended.
  756. //
  757. NbiDereferenceAddressFile (AddressFile, AFREF_CONNECTION);
  758. NB_GET_LOCK (&Device->Lock, &LockHandle);
  759. }
  760. //
  761. // Even if the ref count is zero and some thread has already done cleanup,
  762. // we can not destroy the connection bcoz some other thread might still be
  763. // in HandleConnectionZero routine. This could happen when 2 threads call into
  764. // HandleConnectionZero, one thread runs thru completion, close comes along
  765. // and the other thread is still in HandleConnectionZero routine.
  766. //
  767. if ( Connection->CanBeDestroyed && ( Connection->ThreadsInHandleConnectionZero == 0 ) ) {
  768. NB_FREE_LOCK (&Device->Lock, LockHandle);
  769. NbiDestroyConnection(Connection);
  770. Status = STATUS_SUCCESS;
  771. } else {
  772. Connection->ClosePending = Request;
  773. NB_FREE_LOCK (&Device->Lock, LockHandle);
  774. Status = STATUS_PENDING;
  775. }
  776. } else {
  777. Connection->ClosePending = Request;
  778. NB_FREE_LOCK (&Device->Lock, LockHandle);
  779. Status = STATUS_PENDING;
  780. }
  781. return Status;
  782. } /* NbiCloseConnection */
  783. NTSTATUS
  784. NbiTdiAssociateAddress(
  785. IN PDEVICE Device,
  786. IN PREQUEST Request
  787. )
  788. /*++
  789. Routine Description:
  790. This routine performs the association of the connection and
  791. the address for the user.
  792. Arguments:
  793. Device - The netbios device.
  794. Request - The request describing the associate.
  795. Return Value:
  796. NTSTATUS - status of operation.
  797. --*/
  798. {
  799. NTSTATUS Status;
  800. PCONNECTION Connection;
  801. #ifdef ISN_NT
  802. PFILE_OBJECT FileObject;
  803. #endif
  804. PADDRESS_FILE AddressFile;
  805. PADDRESS Address;
  806. PTDI_REQUEST_KERNEL_ASSOCIATE Parameters;
  807. CTELockHandle LockHandle;
  808. //
  809. // Check that the file type is valid (Bug# 203827)
  810. //
  811. if (REQUEST_OPEN_TYPE(Request) != (PVOID)TDI_CONNECTION_FILE)
  812. {
  813. CTEAssert(FALSE);
  814. return (STATUS_INVALID_ADDRESS_COMPONENT);
  815. }
  816. //
  817. // This references the connection.
  818. //
  819. Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
  820. Status = NbiVerifyConnection (Connection);
  821. if (!NT_SUCCESS (Status))
  822. {
  823. return Status;
  824. }
  825. //
  826. // The request request parameters hold
  827. // get a pointer to the address FileObject, which points us to the
  828. // transport's address object, which is where we want to put the
  829. // connection.
  830. //
  831. Parameters = (PTDI_REQUEST_KERNEL_ASSOCIATE)REQUEST_PARAMETERS(Request);
  832. Status = ObReferenceObjectByHandle (
  833. Parameters->AddressHandle,
  834. FILE_READ_DATA,
  835. *IoFileObjectType,
  836. Request->RequestorMode,
  837. (PVOID *)&FileObject,
  838. NULL);
  839. if ((!NT_SUCCESS(Status)) ||
  840. (FileObject->DeviceObject != &(NbiDevice->DeviceObject)) || // Bug# 171836
  841. (PtrToUlong(FileObject->FsContext2) != TDI_TRANSPORT_ADDRESS_FILE))
  842. {
  843. NbiDereferenceConnection (Connection, CREF_VERIFY);
  844. return STATUS_INVALID_HANDLE;
  845. }
  846. AddressFile = (PADDRESS_FILE)(FileObject->FsContext);
  847. //
  848. // Make sure the address file is valid, and reference it.
  849. //
  850. #if defined(_PNP_POWER)
  851. Status = NbiVerifyAddressFile (AddressFile, CONFLICT_IS_NOT_OK);
  852. #else
  853. Status = NbiVerifyAddressFile (AddressFile);
  854. #endif _PNP_POWER
  855. if (!NT_SUCCESS(Status)) {
  856. #ifdef ISN_NT
  857. ObDereferenceObject (FileObject);
  858. #endif
  859. NbiDereferenceConnection (Connection, CREF_VERIFY);
  860. return Status;
  861. }
  862. NB_DEBUG2 (CONNECTION, ("Associate connection %lx with address file %lx\n",
  863. Connection, AddressFile));
  864. //
  865. // Now insert the connection into the database of the address.
  866. //
  867. Address = AddressFile->Address;
  868. NB_GET_LOCK (&Address->Lock, &LockHandle);
  869. if (Connection->AddressFile != NULL) {
  870. //
  871. // The connection is already associated with
  872. // an address file.
  873. //
  874. NB_FREE_LOCK (&Address->Lock, LockHandle);
  875. NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
  876. Status = STATUS_INVALID_CONNECTION;
  877. } else {
  878. if (AddressFile->State == ADDRESSFILE_STATE_OPEN) {
  879. Connection->AddressFile = AddressFile;
  880. Connection->AddressFileLinked = TRUE;
  881. InsertHeadList (&AddressFile->ConnectionDatabase, &Connection->AddressFileLinkage);
  882. NB_FREE_LOCK (&Address->Lock, LockHandle);
  883. NbiTransferReferenceAddressFile (AddressFile, AFREF_VERIFY, AFREF_CONNECTION);
  884. Status = STATUS_SUCCESS;
  885. } else {
  886. NB_FREE_LOCK (&Address->Lock, LockHandle);
  887. NbiDereferenceAddressFile (AddressFile, AFREF_VERIFY);
  888. Status = STATUS_INVALID_ADDRESS;
  889. }
  890. }
  891. #ifdef ISN_NT
  892. //
  893. // We don't need the reference to the file object, we just
  894. // used it to get from the handle to the object.
  895. //
  896. ObDereferenceObject (FileObject);
  897. #endif
  898. NbiDereferenceConnection (Connection, CREF_VERIFY);
  899. return Status;
  900. } /* NbiTdiAssociateAddress */
  901. NTSTATUS
  902. NbiTdiDisassociateAddress(
  903. IN PDEVICE Device,
  904. IN PREQUEST Request
  905. )
  906. /*++
  907. Routine Description:
  908. This routine performs the disassociation of the connection
  909. and the address for the user.
  910. Arguments:
  911. Device - The netbios device.
  912. Request - The request describing the associate.
  913. Return Value:
  914. NTSTATUS - status of operation.
  915. --*/
  916. {
  917. PCONNECTION Connection;
  918. NTSTATUS Status;
  919. PADDRESS_FILE AddressFile;
  920. PADDRESS Address;
  921. CTELockHandle LockHandle;
  922. NB_DEFINE_LOCK_HANDLE (LockHandle1)
  923. NB_DEFINE_SYNC_CONTEXT (SyncContext)
  924. //
  925. // Check that the file type is valid
  926. //
  927. if (REQUEST_OPEN_TYPE(Request) != (PVOID)TDI_CONNECTION_FILE)
  928. {
  929. CTEAssert(FALSE);
  930. return (STATUS_INVALID_ADDRESS_COMPONENT);
  931. }
  932. //
  933. // Check that the connection is valid. This references
  934. // the connection.
  935. //
  936. Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
  937. Status = NbiVerifyConnection (Connection);
  938. if (!NT_SUCCESS (Status)) {
  939. return Status;
  940. }
  941. NB_DEBUG2 (CONNECTION, ("Disassociate connection %lx\n", Connection));
  942. //
  943. // First check if the connection is still active.
  944. //
  945. NB_BEGIN_SYNC (&SyncContext);
  946. NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
  947. if (Connection->State != CONNECTION_STATE_INACTIVE) {
  948. //
  949. // This releases the lock.
  950. //
  951. NbiStopConnection(
  952. Connection,
  953. STATUS_INVALID_ADDRESS
  954. NB_LOCK_HANDLE_ARG (LockHandle1));
  955. } else {
  956. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
  957. }
  958. //
  959. // Keep the sync through the function??
  960. //
  961. NB_END_SYNC (&SyncContext);
  962. NB_GET_LOCK (&Device->Lock, &LockHandle);
  963. //
  964. // Make sure the connection is associated and is not in the
  965. // middle of disassociating.
  966. //
  967. if ((Connection->AddressFile != NULL) &&
  968. (Connection->AddressFile != (PVOID)-1) &&
  969. (Connection->DisassociatePending == NULL)) {
  970. if (Connection->ReferenceCount == 0) {
  971. //
  972. // Because the connection still has a reference to
  973. // the address file, we know it is still valid. We
  974. // set the connection address file to the temporary
  975. // value of -1, which prevents somebody else from
  976. // disassociating it and also prevents a new association.
  977. //
  978. AddressFile = Connection->AddressFile;
  979. Connection->AddressFile = (PVOID)-1;
  980. NB_FREE_LOCK (&Device->Lock, LockHandle);
  981. Address = AddressFile->Address;
  982. NB_GET_LOCK (&Address->Lock, &LockHandle);
  983. if (Connection->AddressFileLinked) {
  984. Connection->AddressFileLinked = FALSE;
  985. RemoveEntryList (&Connection->AddressFileLinkage);
  986. }
  987. NB_FREE_LOCK (&Address->Lock, LockHandle);
  988. Connection->AddressFile = NULL;
  989. NbiDereferenceAddressFile (AddressFile, AFREF_CONNECTION);
  990. Status = STATUS_SUCCESS;
  991. } else {
  992. //
  993. // Set this so when the count goes to 0 it will
  994. // be disassociated and the request completed.
  995. //
  996. Connection->DisassociatePending = Request;
  997. NB_FREE_LOCK (&Device->Lock, LockHandle);
  998. Status = STATUS_PENDING;
  999. }
  1000. } else {
  1001. NB_FREE_LOCK (&Device->Lock, LockHandle);
  1002. Status = STATUS_INVALID_CONNECTION;
  1003. }
  1004. NbiDereferenceConnection (Connection, CREF_VERIFY);
  1005. return Status;
  1006. } /* NbiTdiDisassociateAddress */
  1007. NTSTATUS
  1008. NbiTdiListen(
  1009. IN PDEVICE Device,
  1010. IN PREQUEST Request
  1011. )
  1012. /*++
  1013. Routine Description:
  1014. This routine posts a listen on a connection.
  1015. Arguments:
  1016. Device - The netbios device.
  1017. Request - The request describing the listen.
  1018. Return Value:
  1019. NTSTATUS - status of operation.
  1020. --*/
  1021. {
  1022. NTSTATUS Status;
  1023. PCONNECTION Connection;
  1024. CTELockHandle LockHandle1, LockHandle2;
  1025. CTELockHandle CancelLH;
  1026. //
  1027. // Check that the file type is valid
  1028. //
  1029. if (REQUEST_OPEN_TYPE(Request) != (PVOID)TDI_CONNECTION_FILE)
  1030. {
  1031. CTEAssert(FALSE);
  1032. return (STATUS_INVALID_ADDRESS_COMPONENT);
  1033. }
  1034. //
  1035. // Check that the connection is valid. This references
  1036. // the connection.
  1037. //
  1038. Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
  1039. Status = NbiVerifyConnection (Connection);
  1040. if (!NT_SUCCESS (Status)) {
  1041. return Status;
  1042. }
  1043. NB_GET_CANCEL_LOCK( &CancelLH );
  1044. NB_GET_LOCK (&Connection->Lock, &LockHandle1);
  1045. NB_GET_LOCK (&Device->Lock, &LockHandle2);
  1046. //
  1047. // The connection must be inactive, but associated and
  1048. // with no disassociate or close pending.
  1049. //
  1050. if ((Connection->State == CONNECTION_STATE_INACTIVE) &&
  1051. (Connection->AddressFile != NULL) &&
  1052. (Connection->AddressFile != (PVOID)-1) &&
  1053. (Connection->DisassociatePending == NULL) &&
  1054. (Connection->ClosePending == NULL)) {
  1055. Connection->State = CONNECTION_STATE_LISTENING;
  1056. Connection->SubState = CONNECTION_SUBSTATE_L_WAITING;
  1057. (VOID)NbiAssignConnectionId (Device, Connection); // Check return code.
  1058. if (!Request->Cancel) {
  1059. NB_DEBUG2 (CONNECTION, ("Queued listen %lx on %lx\n", Request, Connection));
  1060. InsertTailList (&Device->ListenQueue, REQUEST_LINKAGE(Request));
  1061. IoSetCancelRoutine (Request, NbiCancelListen);
  1062. Connection->ListenRequest = Request;
  1063. NbiReferenceConnectionLock (Connection, CREF_LISTEN);
  1064. Status = STATUS_PENDING;
  1065. } else {
  1066. NB_DEBUG2 (CONNECTION, ("Cancelled listen %lx on %lx\n", Request, Connection));
  1067. Connection->State = CONNECTION_STATE_INACTIVE;
  1068. Status = STATUS_CANCELLED;
  1069. }
  1070. NB_FREE_LOCK (&Device->Lock, LockHandle2);
  1071. } else {
  1072. NB_FREE_LOCK (&Device->Lock, LockHandle2);
  1073. Status = STATUS_INVALID_CONNECTION;
  1074. }
  1075. NB_FREE_LOCK (&Connection->Lock, LockHandle1);
  1076. NB_FREE_CANCEL_LOCK( CancelLH );
  1077. NbiDereferenceConnection (Connection, CREF_VERIFY);
  1078. return Status;
  1079. } /* NbiTdiListen */
  1080. NTSTATUS
  1081. NbiTdiAccept(
  1082. IN PDEVICE Device,
  1083. IN PREQUEST Request
  1084. )
  1085. /*++
  1086. Routine Description:
  1087. This routine accepts a connection to a remote machine. The
  1088. connection must previously have completed a listen with
  1089. the TDI_QUERY_ACCEPT flag on.
  1090. Arguments:
  1091. Device - The netbios device.
  1092. Request - The request describing the accept.
  1093. Return Value:
  1094. NTSTATUS - status of operation.
  1095. --*/
  1096. {
  1097. NTSTATUS Status;
  1098. PCONNECTION Connection;
  1099. CTELockHandle LockHandle1, LockHandle2;
  1100. //
  1101. // Check that the file type is valid
  1102. //
  1103. if (REQUEST_OPEN_TYPE(Request) != (PVOID)TDI_CONNECTION_FILE)
  1104. {
  1105. CTEAssert(FALSE);
  1106. return (STATUS_INVALID_ADDRESS_COMPONENT);
  1107. }
  1108. //
  1109. // Check that the connection is valid. This references
  1110. // the connection.
  1111. //
  1112. Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
  1113. Status = NbiVerifyConnection (Connection);
  1114. if (!NT_SUCCESS (Status)) {
  1115. return Status;
  1116. }
  1117. NB_GET_LOCK (&Connection->Lock, &LockHandle1);
  1118. NB_GET_LOCK (&Device->Lock, &LockHandle2);
  1119. if ((Connection->State == CONNECTION_STATE_LISTENING) &&
  1120. (Connection->SubState == CONNECTION_SUBSTATE_L_W_ACCEPT)) {
  1121. Connection->SubState = CONNECTION_SUBSTATE_L_W_ROUTE;
  1122. NbiTransferReferenceConnection (Connection, CREF_W_ACCEPT, CREF_ACCEPT);
  1123. Connection->AcceptRequest = Request;
  1124. NbiReferenceConnectionLock (Connection, CREF_FIND_ROUTE);
  1125. NB_FREE_LOCK (&Device->Lock, LockHandle2);
  1126. Connection->Retries = NbiDevice->KeepAliveCount;
  1127. NB_FREE_LOCK (&Connection->Lock, LockHandle1);
  1128. *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network =
  1129. *(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork;
  1130. RtlCopyMemory(Connection->FindRouteRequest.Node,Connection->RemoteHeader.DestinationNode,6);
  1131. Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
  1132. Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_NO_RIP;
  1133. //
  1134. // When this completes, we will send the session init
  1135. // ack. We don't call it if the client is for network 0,
  1136. // instead just fake as if no route could be found
  1137. // and we will use the local target we got here.
  1138. // The accept is completed when this completes.
  1139. //
  1140. if (*(UNALIGNED ULONG *)Connection->RemoteHeader.DestinationNetwork != 0) {
  1141. (*Device->Bind.FindRouteHandler)(
  1142. &Connection->FindRouteRequest);
  1143. } else {
  1144. NbiFindRouteComplete(
  1145. &Connection->FindRouteRequest,
  1146. FALSE);
  1147. }
  1148. NB_DEBUG2 (CONNECTION, ("Accept received on %lx\n", Connection));
  1149. Status = STATUS_PENDING;
  1150. } else {
  1151. NB_DEBUG (CONNECTION, ("Accept received on invalid connection %lx\n", Connection));
  1152. NB_FREE_LOCK (&Device->Lock, LockHandle2);
  1153. NB_FREE_LOCK (&Connection->Lock, LockHandle1);
  1154. Status = STATUS_INVALID_CONNECTION;
  1155. }
  1156. NbiDereferenceConnection (Connection, CREF_VERIFY);
  1157. return Status;
  1158. } /* NbiTdiAccept */
  1159. NTSTATUS
  1160. NbiTdiConnect(
  1161. IN PDEVICE Device,
  1162. IN PREQUEST Request
  1163. )
  1164. /*++
  1165. Routine Description:
  1166. This routine connects to a remote machine.
  1167. Arguments:
  1168. Device - The netbios device.
  1169. Request - The request describing the connect.
  1170. Return Value:
  1171. NTSTATUS - status of operation.
  1172. --*/
  1173. {
  1174. NTSTATUS Status;
  1175. PCONNECTION Connection;
  1176. TDI_ADDRESS_NETBIOS * RemoteName;
  1177. PTDI_REQUEST_KERNEL_CONNECT Parameters;
  1178. #if 0
  1179. PLARGE_INTEGER RequestedTimeout;
  1180. LARGE_INTEGER RealTimeout;
  1181. #endif
  1182. PNETBIOS_CACHE CacheName;
  1183. CTELockHandle LockHandle1, LockHandle2;
  1184. CTELockHandle CancelLH;
  1185. BOOLEAN bLockFreed = FALSE;
  1186. //
  1187. // Check that the file type is valid
  1188. //
  1189. if (REQUEST_OPEN_TYPE(Request) != (PVOID)TDI_CONNECTION_FILE)
  1190. {
  1191. CTEAssert(FALSE);
  1192. return (STATUS_INVALID_ADDRESS_COMPONENT);
  1193. }
  1194. //
  1195. // Check that the connection is valid. This references
  1196. // the connection.
  1197. //
  1198. Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
  1199. Status = NbiVerifyConnection (Connection);
  1200. if (!NT_SUCCESS (Status)) {
  1201. return Status;
  1202. }
  1203. NB_GET_CANCEL_LOCK( &CancelLH );
  1204. NB_GET_LOCK (&Connection->Lock, &LockHandle1);
  1205. NB_GET_LOCK (&Device->Lock, &LockHandle2);
  1206. //
  1207. // The connection must be inactive, but associated and
  1208. // with no disassociate or close pending.
  1209. //
  1210. if ((Connection->State == CONNECTION_STATE_INACTIVE) &&
  1211. (Connection->AddressFile != NULL) &&
  1212. (Connection->AddressFile != (PVOID)-1) &&
  1213. (Connection->DisassociatePending == NULL) &&
  1214. (Connection->ClosePending == NULL)) {
  1215. try
  1216. {
  1217. Parameters = (PTDI_REQUEST_KERNEL_CONNECT)REQUEST_PARAMETERS(Request);
  1218. RemoteName = NbiParseTdiAddress(
  1219. (PTRANSPORT_ADDRESS)(Parameters->RequestConnectionInformation->RemoteAddress),
  1220. Parameters->RequestConnectionInformation->RemoteAddressLength,
  1221. FALSE);
  1222. }
  1223. except(EXCEPTION_EXECUTE_HANDLER)
  1224. {
  1225. NbiPrint1("NbiTdiConnect: Exception <0x%x> accessing connect info\n", GetExceptionCode());
  1226. RemoteName = NULL;
  1227. }
  1228. if (RemoteName == NULL) {
  1229. //
  1230. // There is no netbios remote address specified.
  1231. //
  1232. NB_FREE_LOCK (&Device->Lock, LockHandle2);
  1233. Status = STATUS_BAD_NETWORK_PATH;
  1234. } else {
  1235. NbiReferenceConnectionLock (Connection, CREF_CONNECT);
  1236. Connection->State = CONNECTION_STATE_CONNECTING;
  1237. RtlCopyMemory (Connection->RemoteName, RemoteName->NetbiosName, 16);
  1238. Connection->Retries = Device->ConnectionCount;
  1239. (VOID)NbiAssignConnectionId (Device, Connection); // Check return code.
  1240. Status = NbiTdiConnectFindName(
  1241. Device,
  1242. Request,
  1243. Connection,
  1244. CancelLH,
  1245. LockHandle1,
  1246. LockHandle2,
  1247. &bLockFreed);
  1248. }
  1249. } else {
  1250. NB_DEBUG (CONNECTION, ("Connect on invalid connection %lx\n", Connection));
  1251. NB_FREE_LOCK (&Device->Lock, LockHandle2);
  1252. Status = STATUS_INVALID_CONNECTION;
  1253. }
  1254. if (!bLockFreed) {
  1255. NB_FREE_LOCK (&Connection->Lock, LockHandle1);
  1256. NB_FREE_CANCEL_LOCK( CancelLH );
  1257. }
  1258. NbiDereferenceConnection (Connection, CREF_VERIFY);
  1259. return Status;
  1260. } /* NbiTdiConnect */
  1261. NTSTATUS
  1262. NbiTdiConnectFindName(
  1263. IN PDEVICE Device,
  1264. IN PREQUEST Request,
  1265. IN PCONNECTION Connection,
  1266. IN CTELockHandle CancelLH,
  1267. IN CTELockHandle ConnectionLH,
  1268. IN CTELockHandle DeviceLH,
  1269. IN PBOOLEAN pbLockFreed
  1270. )
  1271. {
  1272. NTSTATUS Status;
  1273. PNETBIOS_CACHE CacheName;
  1274. //
  1275. // See what is up with this Netbios name.
  1276. //
  1277. Status = CacheFindName(
  1278. Device,
  1279. FindNameConnect,
  1280. Connection->RemoteName,
  1281. &CacheName);
  1282. if (Status == STATUS_PENDING) {
  1283. //
  1284. // A request for routes to this name has been
  1285. // sent out on the net, we queue up this connect
  1286. // request and processing will be resumed when
  1287. // we get a response.
  1288. //
  1289. Connection->SubState = CONNECTION_SUBSTATE_C_FIND_NAME;
  1290. if (!Request->Cancel) {
  1291. InsertTailList( &Device->WaitingConnects, REQUEST_LINKAGE(Request));
  1292. IoSetCancelRoutine (Request, NbiCancelConnectFindName);
  1293. Connection->ConnectRequest = Request;
  1294. NbiReferenceConnectionLock (Connection, CREF_WAIT_CACHE);
  1295. NB_DEBUG2 (CONNECTION, ("Queueing up connect %lx on %lx\n",
  1296. Request, Connection));
  1297. NB_FREE_LOCK (&Device->Lock, DeviceLH);
  1298. } else {
  1299. NB_DEBUG2 (CONNECTION, ("Cancelled connect %lx on %lx\n", Request, Connection));
  1300. Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
  1301. NB_FREE_LOCK (&Device->Lock, DeviceLH);
  1302. NbiDereferenceConnection (Connection, CREF_CONNECT);
  1303. Status = STATUS_CANCELLED;
  1304. }
  1305. } else if (Status == STATUS_SUCCESS) {
  1306. //
  1307. // We don't need to worry about referencing CacheName
  1308. // because we stop using it before we release the lock.
  1309. //
  1310. Connection->SubState = CONNECTION_SUBSTATE_C_W_ROUTE;
  1311. if (!Request->Cancel) {
  1312. IoSetCancelRoutine (Request, NbiCancelConnectWaitResponse);
  1313. // we dont need to hold CancelSpinLock so release it,
  1314. // since we are releasing the locks out of order, we must
  1315. // swap the irql to get the priorities right.
  1316. NB_SWAP_IRQL( CancelLH, ConnectionLH);
  1317. NB_FREE_CANCEL_LOCK( CancelLH );
  1318. Connection->LocalTarget = CacheName->Networks[0].LocalTarget;
  1319. RtlCopyMemory(&Connection->RemoteHeader.DestinationNetwork, &CacheName->FirstResponse, 12);
  1320. Connection->ConnectRequest = Request;
  1321. NbiReferenceConnectionLock (Connection, CREF_FIND_ROUTE);
  1322. NB_DEBUG2 (CONNECTION, ("Found connect cached %lx on %lx\n",
  1323. Request, Connection));
  1324. NB_FREE_LOCK (&Device->Lock, DeviceLH);
  1325. NB_FREE_LOCK (&Connection->Lock, ConnectionLH);
  1326. *(UNALIGNED ULONG *)Connection->FindRouteRequest.Network = CacheName->FirstResponse.NetworkAddress;
  1327. RtlCopyMemory(Connection->FindRouteRequest.Node,CacheName->FirstResponse.NodeAddress,6);
  1328. Connection->FindRouteRequest.Identifier = IDENTIFIER_NB;
  1329. Connection->FindRouteRequest.Type = IPX_FIND_ROUTE_RIP_IF_NEEDED;
  1330. //
  1331. // When this completes, we will send the session init.
  1332. // We don't call it if the client is for network 0,
  1333. // instead just fake as if no route could be found
  1334. // and we will use the local target we got here.
  1335. //
  1336. if (CacheName->FirstResponse.NetworkAddress != 0) {
  1337. (*Device->Bind.FindRouteHandler)(
  1338. &Connection->FindRouteRequest);
  1339. } else {
  1340. NbiFindRouteComplete(
  1341. &Connection->FindRouteRequest,
  1342. FALSE);
  1343. }
  1344. Status = STATUS_PENDING;
  1345. //
  1346. // This jump is like falling out of the if, except
  1347. // it skips over freeing the connection lock since
  1348. // we just did that.
  1349. //
  1350. *pbLockFreed = TRUE;
  1351. } else {
  1352. NB_DEBUG2 (CONNECTION, ("Cancelled connect %lx on %lx\n", Request, Connection));
  1353. Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
  1354. NB_FREE_LOCK (&Device->Lock, DeviceLH);
  1355. NbiDereferenceConnection (Connection, CREF_CONNECT);
  1356. Status = STATUS_CANCELLED;
  1357. }
  1358. } else {
  1359. //
  1360. // We could not find or queue a request for
  1361. // this remote, fail it. When the refcount
  1362. // drops the state will go to INACTIVE and
  1363. // the connection ID will be deassigned.
  1364. //
  1365. if (Status == STATUS_DEVICE_DOES_NOT_EXIST) {
  1366. Status = STATUS_BAD_NETWORK_PATH;
  1367. }
  1368. NB_FREE_LOCK (&Device->Lock, DeviceLH);
  1369. NbiDereferenceConnection (Connection, CREF_CONNECT);
  1370. }
  1371. return Status;
  1372. } /* NbiTdiConnectFindName */
  1373. NTSTATUS
  1374. NbiTdiDisconnect(
  1375. IN PDEVICE Device,
  1376. IN PREQUEST Request
  1377. )
  1378. /*++
  1379. Routine Description:
  1380. This routine connects to a remote machine.
  1381. Arguments:
  1382. Device - The netbios device.
  1383. Request - The request describing the connect.
  1384. Return Value:
  1385. NTSTATUS - status of operation.
  1386. --*/
  1387. {
  1388. NTSTATUS Status;
  1389. PCONNECTION Connection;
  1390. BOOLEAN DisconnectWait;
  1391. NB_DEFINE_LOCK_HANDLE (LockHandle1)
  1392. NB_DEFINE_LOCK_HANDLE (LockHandle2)
  1393. NB_DEFINE_SYNC_CONTEXT (SyncContext)
  1394. CTELockHandle CancelLH;
  1395. //
  1396. // Check that the file type is valid
  1397. //
  1398. if (REQUEST_OPEN_TYPE(Request) != (PVOID)TDI_CONNECTION_FILE)
  1399. {
  1400. CTEAssert(FALSE);
  1401. return (STATUS_INVALID_ADDRESS_COMPONENT);
  1402. }
  1403. //
  1404. // Check that the connection is valid. This references
  1405. // the connection.
  1406. //
  1407. Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
  1408. Status = NbiVerifyConnection (Connection);
  1409. if (!NT_SUCCESS (Status)) {
  1410. return Status;
  1411. }
  1412. DisconnectWait = (BOOLEAN)
  1413. ((((PTDI_REQUEST_KERNEL_DISCONNECT)(REQUEST_PARAMETERS(Request)))->RequestFlags &
  1414. TDI_DISCONNECT_WAIT) != 0);
  1415. NB_GET_CANCEL_LOCK( &CancelLH );
  1416. //
  1417. // We need to be inside a sync because NbiStopConnection
  1418. // expects that.
  1419. //
  1420. NB_BEGIN_SYNC (&SyncContext);
  1421. NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle1);
  1422. NB_SYNC_GET_LOCK (&Device->Lock, &LockHandle2);
  1423. if (DisconnectWait) {
  1424. if (Connection->State == CONNECTION_STATE_ACTIVE) {
  1425. //
  1426. // This disconnect wait will get completed by
  1427. // NbiStopConnection.
  1428. //
  1429. if (Connection->DisconnectWaitRequest == NULL) {
  1430. if (!Request->Cancel) {
  1431. IoSetCancelRoutine (Request, NbiCancelDisconnectWait);
  1432. NB_DEBUG2 (CONNECTION, ("Disconnect wait queued on connection %lx\n", Connection));
  1433. Connection->DisconnectWaitRequest = Request;
  1434. Status = STATUS_PENDING;
  1435. } else {
  1436. NB_DEBUG2 (CONNECTION, ("Cancelled disconnect wait on connection %lx\n", Connection));
  1437. Status = STATUS_CANCELLED;
  1438. }
  1439. } else {
  1440. //
  1441. // We got a second disconnect request and we already
  1442. // have one pending.
  1443. //
  1444. NB_DEBUG (CONNECTION, ("Disconnect wait failed, already queued on connection %lx\n", Connection));
  1445. Status = STATUS_INVALID_CONNECTION;
  1446. }
  1447. } else if (Connection->State == CONNECTION_STATE_DISCONNECT) {
  1448. NB_DEBUG (CONNECTION, ("Disconnect wait submitted on disconnected connection %lx\n", Connection));
  1449. Status = Connection->Status;
  1450. } else {
  1451. NB_DEBUG (CONNECTION, ("Disconnect wait failed, bad state on connection %lx\n", Connection));
  1452. Status = STATUS_INVALID_CONNECTION;
  1453. }
  1454. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
  1455. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
  1456. NB_FREE_CANCEL_LOCK( CancelLH );
  1457. } else {
  1458. if (Connection->State == CONNECTION_STATE_ACTIVE) {
  1459. // we dont need to hold CancelSpinLock so release it,
  1460. // since we are releasing the locks out of order, we must
  1461. // swap the irql to get the priorities right.
  1462. NB_SYNC_SWAP_IRQL( CancelLH, LockHandle1);
  1463. NB_FREE_CANCEL_LOCK( CancelLH );
  1464. Connection->DisconnectRequest = Request;
  1465. Status = STATUS_PENDING;
  1466. NB_DEBUG2 (CONNECTION, ("Disconnect of active connection %lx\n", Connection));
  1467. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
  1468. //
  1469. // This call releases the connection lock, sets
  1470. // the state to DISCONNECTING, and sends out
  1471. // the first session end.
  1472. //
  1473. NbiStopConnection(
  1474. Connection,
  1475. STATUS_LOCAL_DISCONNECT
  1476. NB_LOCK_HANDLE_ARG (LockHandle1));
  1477. } else if (Connection->State == CONNECTION_STATE_DISCONNECT) {
  1478. //
  1479. // There is already a disconnect pending. Queue
  1480. // this one up so it completes when the refcount
  1481. // goes to zero.
  1482. //
  1483. NB_DEBUG2 (CONNECTION, ("Disconnect of disconnecting connection %lx\n", Connection));
  1484. if (Connection->DisconnectRequest == NULL) {
  1485. Connection->DisconnectRequest = Request;
  1486. Status = STATUS_PENDING;
  1487. } else {
  1488. Status = STATUS_SUCCESS;
  1489. }
  1490. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
  1491. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
  1492. NB_FREE_CANCEL_LOCK ( CancelLH );
  1493. } else if ((Connection->State == CONNECTION_STATE_LISTENING) &&
  1494. (Connection->SubState == CONNECTION_SUBSTATE_L_W_ACCEPT)) {
  1495. //
  1496. // We were waiting for an accept, but instead we got
  1497. // a disconnect. Remove the reference and the teardown
  1498. // will proceed. The disconnect will complete when the
  1499. // refcount goes to zero.
  1500. //
  1501. NB_DEBUG2 (CONNECTION, ("Disconnect of accept pending connection %lx\n", Connection));
  1502. if (Connection->DisconnectRequest == NULL) {
  1503. Connection->DisconnectRequest = Request;
  1504. Status = STATUS_PENDING;
  1505. } else {
  1506. Status = STATUS_SUCCESS;
  1507. }
  1508. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
  1509. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
  1510. NB_FREE_CANCEL_LOCK ( CancelLH );
  1511. NbiDereferenceConnection (Connection, CREF_W_ACCEPT);
  1512. } else if (Connection->State == CONNECTION_STATE_CONNECTING) {
  1513. // we dont need to hold CancelSpinLock so release it,
  1514. // since we are releasing the locks out of order, we must
  1515. // swap the irql to get the priorities right.
  1516. NB_SYNC_SWAP_IRQL( CancelLH, LockHandle1);
  1517. NB_FREE_CANCEL_LOCK( CancelLH );
  1518. //
  1519. // We are connecting, and got a disconnect. We call
  1520. // NbiStopConnection which will handle this case
  1521. // and abort the connect.
  1522. //
  1523. NB_DEBUG2 (CONNECTION, ("Disconnect of connecting connection %lx\n", Connection));
  1524. if (Connection->DisconnectRequest == NULL) {
  1525. Connection->DisconnectRequest = Request;
  1526. Status = STATUS_PENDING;
  1527. } else {
  1528. Status = STATUS_SUCCESS;
  1529. }
  1530. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
  1531. //
  1532. // This call releases the connection lock and
  1533. // aborts the connect request.
  1534. //
  1535. NbiStopConnection(
  1536. Connection,
  1537. STATUS_LOCAL_DISCONNECT
  1538. NB_LOCK_HANDLE_ARG (LockHandle1));
  1539. } else {
  1540. NB_DEBUG2 (CONNECTION, ("Disconnect of invalid connection (%d) %lx\n",
  1541. Connection->State, Connection));
  1542. NB_SYNC_FREE_LOCK (&Device->Lock, LockHandle2);
  1543. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle1);
  1544. NB_FREE_CANCEL_LOCK( CancelLH );
  1545. Status = STATUS_INVALID_CONNECTION;
  1546. }
  1547. }
  1548. NB_END_SYNC (&SyncContext);
  1549. NbiDereferenceConnection (Connection, CREF_VERIFY);
  1550. return Status;
  1551. } /* NbiTdiDisconnect */
  1552. BOOLEAN
  1553. NbiAssignConnectionId(
  1554. IN PDEVICE Device,
  1555. IN PCONNECTION Connection
  1556. )
  1557. /*++
  1558. Routine Description:
  1559. This routine is called to assign a connection ID. It picks
  1560. one whose hash table has the fewest entries.
  1561. THIS ROUTINE IS CALLED WITH THE LOCK HELD AND RETURNS WITH
  1562. IT HELD. THE CONNECTION IS INSERTED INTO THE CORRECT HASH
  1563. ENTRY BY THIS CALL.
  1564. Arguments:
  1565. Device - The netbios device.
  1566. Connection - The connection that needs an ID assigned.
  1567. Return Value:
  1568. TRUE if it could be successfully assigned.
  1569. --*/
  1570. {
  1571. UINT Hash;
  1572. UINT i;
  1573. USHORT ConnectionId, HashId;
  1574. PCONNECTION CurConnection;
  1575. CTEAssert (Connection->LocalConnectionId == 0xffff);
  1576. //
  1577. // Find the hash bucket with the fewest entries.
  1578. //
  1579. Hash = 0;
  1580. for (i = 1; i < CONNECTION_HASH_COUNT; i++) {
  1581. if (Device->ConnectionHash[i].ConnectionCount < Device->ConnectionHash[Hash].ConnectionCount) {
  1582. Hash = i;
  1583. }
  1584. }
  1585. //
  1586. // Now find a valid connection ID within that bucket.
  1587. //
  1588. ConnectionId = Device->ConnectionHash[Hash].NextConnectionId;
  1589. while (TRUE) {
  1590. //
  1591. // Scan through the list to see if this ID is in use.
  1592. //
  1593. HashId = (USHORT)(ConnectionId | (Hash << CONNECTION_HASH_SHIFT));
  1594. CurConnection = Device->ConnectionHash[Hash].Connections;
  1595. while (CurConnection != NULL) {
  1596. if (CurConnection->LocalConnectionId != HashId) {
  1597. CurConnection = CurConnection->NextConnection;
  1598. } else {
  1599. break;
  1600. }
  1601. }
  1602. if (CurConnection == NULL) {
  1603. break;
  1604. }
  1605. if (ConnectionId >= CONNECTION_MAXIMUM_ID) {
  1606. ConnectionId = 1;
  1607. } else {
  1608. ++ConnectionId;
  1609. }
  1610. //
  1611. // What if we have 64K-1 sessions and loop forever?
  1612. //
  1613. }
  1614. if (Device->ConnectionHash[Hash].NextConnectionId >= CONNECTION_MAXIMUM_ID) {
  1615. Device->ConnectionHash[Hash].NextConnectionId = 1;
  1616. } else {
  1617. ++Device->ConnectionHash[Hash].NextConnectionId;
  1618. }
  1619. Connection->LocalConnectionId = HashId;
  1620. Connection->RemoteConnectionId = 0xffff;
  1621. NB_DEBUG2 (CONNECTION, ("Assigned ID %lx to %x\n", Connection->LocalConnectionId, Connection));
  1622. Connection->NextConnection = Device->ConnectionHash[Hash].Connections;
  1623. Device->ConnectionHash[Hash].Connections = Connection;
  1624. ++Device->ConnectionHash[Hash].ConnectionCount;
  1625. return TRUE;
  1626. } /* NbiAssignConnectionId */
  1627. VOID
  1628. NbiDeassignConnectionId(
  1629. IN PDEVICE Device,
  1630. IN PCONNECTION Connection
  1631. )
  1632. /*++
  1633. Routine Description:
  1634. This routine is called to deassign a connection ID. It removes
  1635. the connection from the hash bucket for its ID.
  1636. THIS ROUTINE IS CALLED WITH THE LOCK HELD AND RETURNS WITH
  1637. IT HELD.
  1638. Arguments:
  1639. Device - The netbios device.
  1640. Connection - The connection that needs an ID assigned.
  1641. Return Value:
  1642. None.
  1643. --*/
  1644. {
  1645. UINT Hash;
  1646. PCONNECTION CurConnection;
  1647. PCONNECTION * PrevConnection;
  1648. //
  1649. // Make sure the connection has a valid ID.
  1650. //
  1651. CTEAssert (Connection->LocalConnectionId != 0xffff);
  1652. Hash = (Connection->LocalConnectionId & CONNECTION_HASH_MASK) >> CONNECTION_HASH_SHIFT;
  1653. CurConnection = Device->ConnectionHash[Hash].Connections;
  1654. PrevConnection = &Device->ConnectionHash[Hash].Connections;
  1655. while (TRUE) {
  1656. CTEAssert (CurConnection != NULL);
  1657. //
  1658. // We can loop until we find it because it should be
  1659. // on here.
  1660. //
  1661. if (CurConnection == Connection) {
  1662. *PrevConnection = Connection->NextConnection;
  1663. --Device->ConnectionHash[Hash].ConnectionCount;
  1664. break;
  1665. }
  1666. PrevConnection = &CurConnection->NextConnection;
  1667. CurConnection = CurConnection->NextConnection;
  1668. }
  1669. Connection->LocalConnectionId = 0xffff;
  1670. } /* NbiDeassignConnectionId */
  1671. VOID
  1672. NbiConnectionTimeout(
  1673. IN CTEEvent * Event,
  1674. IN PVOID Context
  1675. )
  1676. /*++
  1677. Routine Description:
  1678. This routine is called when the connection timer expires.
  1679. This is either because we need to send the next session
  1680. initialize, or because our listen has timed out.
  1681. Arguments:
  1682. Event - The event used to queue the timer.
  1683. Context - The context, which is the connection.
  1684. Return Value:
  1685. None.
  1686. --*/
  1687. {
  1688. PCONNECTION Connection = (PCONNECTION)Context;
  1689. PDEVICE Device = NbiDevice;
  1690. PREQUEST Request;
  1691. NB_DEFINE_LOCK_HANDLE (LockHandle)
  1692. NB_DEFINE_LOCK_HANDLE (CancelLH)
  1693. //
  1694. // Take the lock and see what we need to do.
  1695. //
  1696. NB_SYNC_GET_LOCK (&Connection->Lock, &LockHandle);
  1697. if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
  1698. (Connection->SubState != CONNECTION_SUBSTATE_C_DISCONN)) {
  1699. if (--Connection->Retries == 0) {
  1700. NB_DEBUG2 (CONNECTION, ("Timing out session initializes on %lx\n", Connection));
  1701. //
  1702. // We have just timed out this connect, we fail the
  1703. // request. When the reference count goes to 0 we
  1704. // will set the state to INACTIVE and deassign
  1705. // the connection ID.
  1706. //
  1707. Request = Connection->ConnectRequest;
  1708. Connection->ConnectRequest = NULL;
  1709. Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
  1710. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  1711. NB_GET_CANCEL_LOCK( &CancelLH );
  1712. IoSetCancelRoutine (Request, (PDRIVER_CANCEL)NULL);
  1713. NB_FREE_CANCEL_LOCK( CancelLH );
  1714. REQUEST_STATUS (Request) = STATUS_REMOTE_NOT_LISTENING;
  1715. NbiCompleteRequest (Request);
  1716. NbiFreeRequest (Device, Request);
  1717. NbiDereferenceConnection (Connection, CREF_CONNECT);
  1718. NbiDereferenceConnection (Connection, CREF_TIMER);
  1719. } else {
  1720. //
  1721. // Send the next session initialize.
  1722. //
  1723. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  1724. NbiSendSessionInitialize (Connection);
  1725. CTEStartTimer(
  1726. &Connection->Timer,
  1727. Device->ConnectionTimeout,
  1728. NbiConnectionTimeout,
  1729. (PVOID)Connection);
  1730. }
  1731. } else if (Connection->State == CONNECTION_STATE_DISCONNECT) {
  1732. if ((Connection->SubState != CONNECTION_SUBSTATE_D_W_ACK) ||
  1733. (--Connection->Retries == 0)) {
  1734. NB_DEBUG2 (CONNECTION, ("Timing out disconnect of %lx\n", Connection));
  1735. //
  1736. // Just dereference the connection, that will cause the
  1737. // disconnect to be completed, the state to be set
  1738. // to INACTIVE, and our connection ID deassigned.
  1739. //
  1740. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  1741. NbiDereferenceConnection (Connection, CREF_TIMER);
  1742. } else {
  1743. //
  1744. // Send the next session end.
  1745. //
  1746. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  1747. NbiSendSessionEnd(Connection);
  1748. CTEStartTimer(
  1749. &Connection->Timer,
  1750. Device->ConnectionTimeout,
  1751. NbiConnectionTimeout,
  1752. (PVOID)Connection);
  1753. }
  1754. } else {
  1755. NB_SYNC_FREE_LOCK (&Connection->Lock, LockHandle);
  1756. NbiDereferenceConnection (Connection, CREF_TIMER);
  1757. }
  1758. } /* NbiConnectionTimeout */
  1759. VOID
  1760. NbiCancelListen(
  1761. IN PDEVICE_OBJECT DeviceObject,
  1762. IN PIRP Irp
  1763. )
  1764. /*++
  1765. Routine Description:
  1766. This routine is called by the I/O system to cancel a posted
  1767. listen.
  1768. NOTE: This routine is called with the CancelSpinLock held and
  1769. is responsible for releasing it.
  1770. Arguments:
  1771. DeviceObject - Pointer to the device object for this driver.
  1772. Irp - Pointer to the request packet representing the I/O request.
  1773. Return Value:
  1774. none.
  1775. --*/
  1776. {
  1777. PCONNECTION Connection;
  1778. CTELockHandle LockHandle1, LockHandle2;
  1779. PDEVICE Device = (PDEVICE)DeviceObject;
  1780. PREQUEST Request = (PREQUEST)Irp;
  1781. CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
  1782. (REQUEST_MINOR_FUNCTION(Request) == TDI_LISTEN));
  1783. CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
  1784. Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
  1785. NB_GET_LOCK (&Connection->Lock, &LockHandle1);
  1786. if ((Connection->State == CONNECTION_STATE_LISTENING) &&
  1787. (Connection->SubState == CONNECTION_SUBSTATE_L_WAITING) &&
  1788. (Connection->ListenRequest == Request)) {
  1789. //
  1790. // When the reference count goes to 0, we will set the
  1791. // state to INACTIVE and deassign the connection ID.
  1792. //
  1793. NB_DEBUG2 (CONNECTION, ("Cancelled listen on %lx\n", Connection));
  1794. NB_GET_LOCK (&Device->Lock, &LockHandle2);
  1795. Connection->ListenRequest = NULL;
  1796. RemoveEntryList (REQUEST_LINKAGE(Request));
  1797. NB_FREE_LOCK (&Device->Lock, LockHandle2);
  1798. NB_FREE_LOCK (&Connection->Lock, LockHandle1);
  1799. IoReleaseCancelSpinLock (Irp->CancelIrql);
  1800. REQUEST_INFORMATION(Request) = 0;
  1801. REQUEST_STATUS(Request) = STATUS_CANCELLED;
  1802. NbiCompleteRequest (Request);
  1803. NbiFreeRequest(Device, Request);
  1804. NbiDereferenceConnection (Connection, CREF_LISTEN);
  1805. } else {
  1806. NB_DEBUG (CONNECTION, ("Cancel listen on invalid connection %lx\n", Connection));
  1807. NB_FREE_LOCK (&Connection->Lock, LockHandle1);
  1808. IoReleaseCancelSpinLock (Irp->CancelIrql);
  1809. }
  1810. } /* NbiCancelListen */
  1811. VOID
  1812. NbiCancelConnectFindName(
  1813. IN PDEVICE_OBJECT DeviceObject,
  1814. IN PIRP Irp
  1815. )
  1816. /*++
  1817. Routine Description:
  1818. This routine is called by the I/O system to cancel a connect
  1819. request which is waiting for the name to be found.
  1820. NOTE: This routine is called with the CancelSpinLock held and
  1821. is responsible for releasing it.
  1822. Arguments:
  1823. DeviceObject - Pointer to the device object for this driver.
  1824. Irp - Pointer to the request packet representing the I/O request.
  1825. Return Value:
  1826. none.
  1827. --*/
  1828. {
  1829. PCONNECTION Connection;
  1830. CTELockHandle LockHandle1, LockHandle2;
  1831. PDEVICE Device = (PDEVICE)DeviceObject;
  1832. PREQUEST Request = (PREQUEST)Irp;
  1833. PLIST_ENTRY p;
  1834. BOOLEAN fCanceled = TRUE;
  1835. CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
  1836. (REQUEST_MINOR_FUNCTION(Request) == TDI_CONNECT));
  1837. CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
  1838. Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
  1839. NB_GET_LOCK (&Connection->Lock, &LockHandle1);
  1840. if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
  1841. (Connection->SubState == CONNECTION_SUBSTATE_C_FIND_NAME) &&
  1842. (Connection->ConnectRequest == Request)) {
  1843. //
  1844. // Make sure the request is still on the queue
  1845. // before cancelling it.
  1846. //
  1847. NB_GET_LOCK (&Device->Lock, &LockHandle2);
  1848. for (p = Device->WaitingConnects.Flink;
  1849. p != &Device->WaitingConnects;
  1850. p = p->Flink) {
  1851. if (LIST_ENTRY_TO_REQUEST(p) == Request) {
  1852. break;
  1853. }
  1854. }
  1855. if (p != &Device->WaitingConnects) {
  1856. NB_DEBUG2 (CONNECTION, ("Cancelled find name connect on %lx\n", Connection));
  1857. //
  1858. // When the reference count goes to 0, we will set the
  1859. // state to INACTIVE and deassign the connection ID.
  1860. //
  1861. Connection->ConnectRequest = NULL;
  1862. RemoveEntryList (REQUEST_LINKAGE(Request));
  1863. NB_FREE_LOCK (&Device->Lock, LockHandle2);
  1864. Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
  1865. NB_FREE_LOCK (&Connection->Lock, LockHandle1);
  1866. IoReleaseCancelSpinLock (Irp->CancelIrql);
  1867. REQUEST_STATUS(Request) = STATUS_CANCELLED;
  1868. #ifdef RASAUTODIAL
  1869. if (Connection->Flags & CONNECTION_FLAGS_AUTOCONNECTING)
  1870. fCanceled = NbiCancelTdiConnect(Device, Request, Connection);
  1871. #endif // RASAUTODIAL
  1872. if (fCanceled) {
  1873. NbiCompleteRequest (Request);
  1874. NbiFreeRequest(Device, Request);
  1875. }
  1876. NbiDereferenceConnection (Connection, CREF_WAIT_CACHE);
  1877. NbiDereferenceConnection (Connection, CREF_CONNECT);
  1878. } else {
  1879. NB_DEBUG (CONNECTION, ("Cancel connect not found on queue %lx\n", Connection));
  1880. NB_FREE_LOCK (&Device->Lock, LockHandle2);
  1881. NB_FREE_LOCK (&Connection->Lock, LockHandle1);
  1882. IoReleaseCancelSpinLock (Irp->CancelIrql);
  1883. }
  1884. } else {
  1885. NB_DEBUG (CONNECTION, ("Cancel connect on invalid connection %lx\n", Connection));
  1886. NB_FREE_LOCK (&Connection->Lock, LockHandle1);
  1887. IoReleaseCancelSpinLock (Irp->CancelIrql);
  1888. }
  1889. } /* NbiCancelConnectFindName */
  1890. VOID
  1891. NbiCancelConnectWaitResponse(
  1892. IN PDEVICE_OBJECT DeviceObject,
  1893. IN PIRP Irp
  1894. )
  1895. /*++
  1896. Routine Description:
  1897. This routine is called by the I/O system to cancel a connect
  1898. request which is waiting for a rip or session init response
  1899. from the remote.
  1900. NOTE: This routine is called with the CancelSpinLock held and
  1901. is responsible for releasing it.
  1902. Arguments:
  1903. DeviceObject - Pointer to the device object for this driver.
  1904. Irp - Pointer to the request packet representing the I/O request.
  1905. Return Value:
  1906. none.
  1907. --*/
  1908. {
  1909. PCONNECTION Connection;
  1910. CTELockHandle LockHandle1;
  1911. PDEVICE Device = (PDEVICE)DeviceObject;
  1912. PREQUEST Request = (PREQUEST)Irp;
  1913. BOOLEAN TimerWasStopped = FALSE;
  1914. CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
  1915. (REQUEST_MINOR_FUNCTION(Request) == TDI_CONNECT));
  1916. CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
  1917. Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
  1918. NB_GET_LOCK (&Connection->Lock, &LockHandle1);
  1919. if ((Connection->State == CONNECTION_STATE_CONNECTING) &&
  1920. (Connection->SubState != CONNECTION_SUBSTATE_C_DISCONN) &&
  1921. (Connection->ConnectRequest == Request)) {
  1922. //
  1923. // When the reference count goes to 0, we will set the
  1924. // state to INACTIVE and deassign the connection ID.
  1925. //
  1926. NB_DEBUG2 (CONNECTION, ("Cancelled wait response connect on %lx\n", Connection));
  1927. Connection->ConnectRequest = NULL;
  1928. Connection->SubState = CONNECTION_SUBSTATE_C_DISCONN;
  1929. if (CTEStopTimer (&Connection->Timer)) {
  1930. TimerWasStopped = TRUE;
  1931. }
  1932. NB_FREE_LOCK (&Connection->Lock, LockHandle1);
  1933. IoReleaseCancelSpinLock (Irp->CancelIrql);
  1934. REQUEST_STATUS(Request) = STATUS_CANCELLED;
  1935. NbiCompleteRequest (Request);
  1936. NbiFreeRequest(Device, Request);
  1937. NbiDereferenceConnection (Connection, CREF_CONNECT);
  1938. if (TimerWasStopped) {
  1939. NbiDereferenceConnection (Connection, CREF_TIMER);
  1940. }
  1941. } else {
  1942. NB_DEBUG (CONNECTION, ("Cancel connect on invalid connection %lx\n", Connection));
  1943. NB_FREE_LOCK (&Connection->Lock, LockHandle1);
  1944. IoReleaseCancelSpinLock (Irp->CancelIrql);
  1945. }
  1946. } /* NbiCancelConnectWaitResponse */
  1947. VOID
  1948. NbiCancelDisconnectWait(
  1949. IN PDEVICE_OBJECT DeviceObject,
  1950. IN PIRP Irp
  1951. )
  1952. /*++
  1953. Routine Description:
  1954. This routine is called by the I/O system to cancel a posted
  1955. disconnect wait.
  1956. NOTE: This routine is called with the CancelSpinLock held and
  1957. is responsible for releasing it.
  1958. Arguments:
  1959. DeviceObject - Pointer to the device object for this driver.
  1960. Irp - Pointer to the request packet representing the I/O request.
  1961. Return Value:
  1962. none.
  1963. --*/
  1964. {
  1965. PCONNECTION Connection;
  1966. CTELockHandle LockHandle1, LockHandle2;
  1967. PDEVICE Device = (PDEVICE)DeviceObject;
  1968. PREQUEST Request = (PREQUEST)Irp;
  1969. CTEAssert ((REQUEST_MAJOR_FUNCTION(Request) == IRP_MJ_INTERNAL_DEVICE_CONTROL) &&
  1970. (REQUEST_MINOR_FUNCTION(Request) == TDI_DISCONNECT));
  1971. CTEAssert (REQUEST_OPEN_TYPE(Request) == (PVOID)TDI_CONNECTION_FILE);
  1972. Connection = (PCONNECTION)REQUEST_OPEN_CONTEXT(Request);
  1973. NB_GET_LOCK (&Connection->Lock, &LockHandle1);
  1974. NB_GET_LOCK (&Device->Lock, &LockHandle2);
  1975. if (Connection->DisconnectWaitRequest == Request) {
  1976. Connection->DisconnectWaitRequest = NULL;
  1977. NB_FREE_LOCK (&Device->Lock, LockHandle2);
  1978. NB_FREE_LOCK (&Connection->Lock, LockHandle1);
  1979. IoReleaseCancelSpinLock (Irp->CancelIrql);
  1980. REQUEST_INFORMATION(Request) = 0;
  1981. REQUEST_STATUS(Request) = STATUS_CANCELLED;
  1982. NbiCompleteRequest (Request);
  1983. NbiFreeRequest(Device, Request);
  1984. } else {
  1985. NB_FREE_LOCK (&Device->Lock, LockHandle2);
  1986. NB_FREE_LOCK (&Connection->Lock, LockHandle1);
  1987. IoReleaseCancelSpinLock (Irp->CancelIrql);
  1988. }
  1989. } /* NbiCancelDisconnectWait */
  1990. PCONNECTION
  1991. NbiLookupConnectionByContext(
  1992. IN PADDRESS_FILE AddressFile,
  1993. IN CONNECTION_CONTEXT ConnectionContext
  1994. )
  1995. /*++
  1996. Routine Description:
  1997. This routine looks up a connection based on the context.
  1998. The connection is assumed to be associated with the
  1999. specified address file.
  2000. Arguments:
  2001. AddressFile - Pointer to an address file.
  2002. ConnectionContext - Connection context to find.
  2003. Return Value:
  2004. A pointer to the connection we found
  2005. --*/
  2006. {
  2007. CTELockHandle LockHandle1, LockHandle2;
  2008. PLIST_ENTRY p;
  2009. PADDRESS Address = AddressFile->Address;
  2010. PCONNECTION Connection;
  2011. NB_GET_LOCK (&Address->Lock, &LockHandle1);
  2012. for (p=AddressFile->ConnectionDatabase.Flink;
  2013. p != &AddressFile->ConnectionDatabase;
  2014. p=p->Flink) {
  2015. Connection = CONTAINING_RECORD (p, CONNECTION, AddressFileLinkage);
  2016. NB_GET_LOCK (&Connection->Lock, &LockHandle2);
  2017. //
  2018. // Does this spinlock ordering hurt us somewhere else?
  2019. //
  2020. if (Connection->Context == ConnectionContext) {
  2021. NbiReferenceConnection (Connection, CREF_BY_CONTEXT);
  2022. NB_FREE_LOCK (&Connection->Lock, LockHandle2);
  2023. NB_FREE_LOCK (&Address->Lock, LockHandle1);
  2024. return Connection;
  2025. }
  2026. NB_FREE_LOCK (&Connection->Lock, LockHandle2);
  2027. }
  2028. NB_FREE_LOCK (&Address->Lock, LockHandle1);
  2029. return NULL;
  2030. } /* NbiLookupConnectionByContext */
  2031. PCONNECTION
  2032. NbiCreateConnection(
  2033. IN PDEVICE Device
  2034. )
  2035. /*++
  2036. Routine Description:
  2037. This routine creates a transport connection and associates it with
  2038. the specified transport device context. The reference count in the
  2039. connection is automatically set to 1, and the reference count of the
  2040. device context is incremented.
  2041. Arguments:
  2042. Device - Pointer to the device context (which is really just
  2043. the device object with its extension) to be associated with the
  2044. connection.
  2045. Return Value:
  2046. The newly created connection, or NULL if none can be allocated.
  2047. --*/
  2048. {
  2049. PCONNECTION Connection;
  2050. PNB_SEND_RESERVED SendReserved;
  2051. ULONG ConnectionSize;
  2052. ULONG HeaderLength;
  2053. NTSTATUS Status;
  2054. CTELockHandle LockHandle;
  2055. HeaderLength = Device->Bind.MacHeaderNeeded + sizeof(NB_CONNECTION);
  2056. ConnectionSize = FIELD_OFFSET (CONNECTION, SendPacketHeader[0]) + HeaderLength;
  2057. Connection = (PCONNECTION)NbiAllocateMemory (ConnectionSize, MEMORY_CONNECTION, "Connection");
  2058. if (Connection == NULL) {
  2059. NB_DEBUG (CONNECTION, ("Create connection failed\n"));
  2060. return NULL;
  2061. }
  2062. NB_DEBUG2 (CONNECTION, ("Create connection %lx\n", Connection));
  2063. RtlZeroMemory (Connection, ConnectionSize);
  2064. #if defined(NB_OWN_PACKETS)
  2065. NB_GET_LOCK (&Device->Lock, &LockHandle);
  2066. if (NbiInitializeSendPacket(
  2067. Device,
  2068. Connection->SendPacketPoolHandle,
  2069. &Connection->SendPacket,
  2070. Connection->SendPacketHeader,
  2071. HeaderLength) != STATUS_SUCCESS) {
  2072. NB_FREE_LOCK (&Device->Lock, LockHandle);
  2073. NB_DEBUG (CONNECTION, ("Could not initialize connection packet %lx\n", &Connection->SendPacket));
  2074. Connection->SendPacketInUse = TRUE;
  2075. } else {
  2076. NB_FREE_LOCK (&Device->Lock, LockHandle);
  2077. SendReserved = SEND_RESERVED(&Connection->SendPacket);
  2078. SendReserved->u.SR_CO.Connection = Connection;
  2079. SendReserved->OwnedByConnection = TRUE;
  2080. #ifdef NB_TRACK_POOL
  2081. SendReserved->Pool = NULL;
  2082. #endif
  2083. }
  2084. #else // !NB_OWN_PACKETS
  2085. //
  2086. // if we are using ndis packets, first create packet pool for 1 packet descriptor
  2087. //
  2088. Connection->SendPacketPoolHandle = (NDIS_HANDLE) NDIS_PACKET_POOL_TAG_FOR_NWLNKNB; // Dbg info for Ndis!
  2089. NdisAllocatePacketPoolEx (&Status, &Connection->SendPacketPoolHandle, 1, 0, sizeof(NB_SEND_RESERVED));
  2090. if (!NT_SUCCESS(Status)){
  2091. NB_DEBUG (CONNECTION, ("Could not allocatee connection packet %lx\n", Status));
  2092. Connection->SendPacketInUse = TRUE;
  2093. } else {
  2094. NdisSetPacketPoolProtocolId (Connection->SendPacketPoolHandle, NDIS_PROTOCOL_ID_IPX);
  2095. NB_GET_LOCK (&Device->Lock, &LockHandle);
  2096. if (NbiInitializeSendPacket(
  2097. Device,
  2098. Connection->SendPacketPoolHandle,
  2099. &Connection->SendPacket,
  2100. Connection->SendPacketHeader,
  2101. HeaderLength) != STATUS_SUCCESS) {
  2102. NB_FREE_LOCK (&Device->Lock, LockHandle);
  2103. NB_DEBUG (CONNECTION, ("Could not initialize connection packet %lx\n", &Connection->SendPacket));
  2104. Connection->SendPacketInUse = TRUE;
  2105. //
  2106. // Also free up the pool which we allocated above.
  2107. //
  2108. NdisFreePacketPool(Connection->SendPacketPoolHandle);
  2109. } else {
  2110. NB_FREE_LOCK (&Device->Lock, LockHandle);
  2111. SendReserved = SEND_RESERVED(&Connection->SendPacket);
  2112. SendReserved->u.SR_CO.Connection = Connection;
  2113. SendReserved->OwnedByConnection = TRUE;
  2114. #ifdef NB_TRACK_POOL
  2115. SendReserved->Pool = NULL;
  2116. #endif
  2117. }
  2118. }
  2119. #endif NB_OWN_PACKETS
  2120. Connection->Type = NB_CONNECTION_SIGNATURE;
  2121. Connection->Size = (USHORT)ConnectionSize;
  2122. #if 0
  2123. Connection->AddressFileLinked = FALSE;
  2124. Connection->AddressFile = NULL;
  2125. #endif
  2126. Connection->State = CONNECTION_STATE_INACTIVE;
  2127. #if 0
  2128. Connection->SubState = 0;
  2129. Connection->ReferenceCount = 0;
  2130. #endif
  2131. Connection->CanBeDestroyed = TRUE;
  2132. Connection->TickCount = 1;
  2133. Connection->HopCount = 1;
  2134. //
  2135. // Device->InitialRetransmissionTime is in milliseconds, as is
  2136. // SHORT_TIMER_DELTA.
  2137. //
  2138. Connection->BaseRetransmitTimeout = Device->InitialRetransmissionTime / SHORT_TIMER_DELTA;
  2139. Connection->CurrentRetransmitTimeout = Connection->BaseRetransmitTimeout;
  2140. //
  2141. // Device->KeepAliveTimeout is in half-seconds, while LONG_TIMER_DELTA
  2142. // is in milliseconds.
  2143. //
  2144. Connection->WatchdogTimeout = (Device->KeepAliveTimeout * 500) / LONG_TIMER_DELTA;
  2145. Connection->LocalConnectionId = 0xffff;
  2146. //
  2147. // When the connection becomes active we will replace the
  2148. // destination address of this header with the correct
  2149. // information.
  2150. //
  2151. RtlCopyMemory(&Connection->RemoteHeader, &Device->ConnectionlessHeader, sizeof(IPX_HEADER));
  2152. Connection->Device = Device;
  2153. Connection->DeviceLock = &Device->Lock;
  2154. CTEInitLock (&Connection->Lock.Lock);
  2155. CTEInitTimer (&Connection->Timer);
  2156. InitializeListHead (&Connection->NdisSendQueue);
  2157. #if 0
  2158. Connection->NdisSendsInProgress = 0;
  2159. Connection->DisassociatePending = NULL;
  2160. Connection->ClosePending = NULL;
  2161. Connection->SessionInitAckData = NULL;
  2162. Connection->SessionInitAckDataLength = 0;
  2163. Connection->PiggybackAckTimeout = FALSE;
  2164. Connection->ReceivesWithoutAck = 0;
  2165. #endif
  2166. Connection->Flags = 0;
  2167. NbiReferenceDevice (Device, DREF_CONNECTION);
  2168. return Connection;
  2169. } /* NbiCreateConnection */
  2170. NTSTATUS
  2171. NbiVerifyConnection (
  2172. IN PCONNECTION Connection
  2173. )
  2174. /*++
  2175. Routine Description:
  2176. This routine is called to verify that the pointer given us in a file
  2177. object is in fact a valid connection object. We reference
  2178. it to keep it from disappearing while we use it.
  2179. Arguments:
  2180. Connection - potential pointer to a CONNECTION object
  2181. Return Value:
  2182. STATUS_SUCCESS if all is well; STATUS_INVALID_CONNECTION otherwise
  2183. --*/
  2184. {
  2185. CTELockHandle LockHandle;
  2186. NTSTATUS status = STATUS_SUCCESS;
  2187. PDEVICE Device = NbiDevice;
  2188. BOOLEAN LockHeld = FALSE;
  2189. try
  2190. {
  2191. if ((Connection->Size == FIELD_OFFSET (CONNECTION, SendPacketHeader[0]) +
  2192. NbiDevice->Bind.MacHeaderNeeded + sizeof(NB_CONNECTION)) &&
  2193. (Connection->Type == NB_CONNECTION_SIGNATURE))
  2194. {
  2195. NB_GET_LOCK (&Device->Lock, &LockHandle);
  2196. LockHeld = TRUE;
  2197. if (Connection->State != CONNECTION_STATE_CLOSING)
  2198. {
  2199. NbiReferenceConnectionLock (Connection, CREF_VERIFY);
  2200. }
  2201. else
  2202. {
  2203. NbiPrint1("NbiVerifyConnection: C %lx closing\n", Connection);
  2204. status = STATUS_INVALID_CONNECTION;
  2205. }
  2206. NB_FREE_LOCK (&Device->Lock, LockHandle);
  2207. }
  2208. else
  2209. {
  2210. NbiPrint1("NbiVerifyConnection: C %lx bad signature\n", Connection);
  2211. status = STATUS_INVALID_CONNECTION;
  2212. }
  2213. }
  2214. except(EXCEPTION_EXECUTE_HANDLER)
  2215. {
  2216. NbiPrint1("NbiVerifyConnection: C %lx exception\n", Connection);
  2217. if (LockHeld)
  2218. {
  2219. NB_FREE_LOCK (&Device->Lock, LockHandle);
  2220. }
  2221. return GetExceptionCode();
  2222. }
  2223. return status;
  2224. } /* NbiVerifyConnection */
  2225. VOID
  2226. NbiDestroyConnection(
  2227. IN PCONNECTION Connection
  2228. )
  2229. /*++
  2230. Routine Description:
  2231. This routine destroys a transport connection and removes all references
  2232. made by it to other objects in the transport. The connection structure
  2233. is returned to nonpaged system pool.
  2234. Arguments:
  2235. Connection - Pointer to a transport connection structure to be destroyed.
  2236. Return Value:
  2237. None.
  2238. --*/
  2239. {
  2240. PDEVICE Device = Connection->Device;
  2241. #if 0
  2242. CTELockHandle LockHandle;
  2243. #endif
  2244. NB_DEBUG2 (CONNECTION, ("Destroy connection %lx\n", Connection));
  2245. if (!Connection->SendPacketInUse) {
  2246. NbiDeinitializeSendPacket (Device, &Connection->SendPacket, Device->Bind.MacHeaderNeeded + sizeof(NB_CONNECTION));
  2247. #if !defined(NB_OWN_PACKETS)
  2248. NdisFreePacketPool(Connection->SendPacketPoolHandle);
  2249. #endif
  2250. }
  2251. NbiFreeMemory (Connection, (ULONG)Connection->Size, MEMORY_CONNECTION, "Connection");
  2252. NbiDereferenceDevice (Device, DREF_CONNECTION);
  2253. } /* NbiDestroyConnection */
  2254. #if DBG
  2255. VOID
  2256. NbiRefConnection(
  2257. IN PCONNECTION Connection
  2258. )
  2259. /*++
  2260. Routine Description:
  2261. This routine increments the reference count on a transport connection.
  2262. Arguments:
  2263. Connection - Pointer to a transport connection object.
  2264. Return Value:
  2265. none.
  2266. --*/
  2267. {
  2268. (VOID)ExInterlockedAddUlong (
  2269. &Connection->ReferenceCount,
  2270. 1,
  2271. &Connection->DeviceLock->Lock);
  2272. Connection->CanBeDestroyed = FALSE;
  2273. CTEAssert (Connection->ReferenceCount > 0);
  2274. } /* NbiRefConnection */
  2275. VOID
  2276. NbiRefConnectionLock(
  2277. IN PCONNECTION Connection
  2278. )
  2279. /*++
  2280. Routine Description:
  2281. This routine increments the reference count on a transport connection
  2282. when the device lock is already held.
  2283. Arguments:
  2284. Connection - Pointer to a transport connection object.
  2285. Return Value:
  2286. none.
  2287. --*/
  2288. {
  2289. ++Connection->ReferenceCount;
  2290. Connection->CanBeDestroyed = FALSE;
  2291. CTEAssert (Connection->ReferenceCount > 0);
  2292. } /* NbiRefConnectionLock */
  2293. VOID
  2294. NbiRefConnectionSync(
  2295. IN PCONNECTION Connection
  2296. )
  2297. /*++
  2298. Routine Description:
  2299. This routine increments the reference count on a transport connection
  2300. when we are in a sync routine.
  2301. Arguments:
  2302. Connection - Pointer to a transport connection object.
  2303. Return Value:
  2304. none.
  2305. --*/
  2306. {
  2307. (VOID)NB_ADD_ULONG (
  2308. &Connection->ReferenceCount,
  2309. 1,
  2310. Connection->DeviceLock);
  2311. Connection->CanBeDestroyed = FALSE;
  2312. CTEAssert (Connection->ReferenceCount > 0);
  2313. } /* NbiRefConnectionSync */
  2314. VOID
  2315. NbiDerefConnection(
  2316. IN PCONNECTION Connection
  2317. )
  2318. /*++
  2319. Routine Description:
  2320. This routine dereferences a transport connection by decrementing the
  2321. reference count contained in the structure. If, after being
  2322. decremented, the reference count is zero, then this routine calls
  2323. NbiHandleConnectionZero to complete any disconnect, disassociate,
  2324. or close requests that have pended on the connection.
  2325. Arguments:
  2326. Connection - Pointer to a transport connection object.
  2327. Return Value:
  2328. none.
  2329. --*/
  2330. {
  2331. ULONG oldvalue;
  2332. CTELockHandle LockHandle;
  2333. NB_GET_LOCK( Connection->DeviceLock, &LockHandle );
  2334. CTEAssert( Connection->ReferenceCount );
  2335. if ( !(--Connection->ReferenceCount) ) {
  2336. Connection->ThreadsInHandleConnectionZero++;
  2337. NB_FREE_LOCK( Connection->DeviceLock, LockHandle );
  2338. //
  2339. // If the refcount has dropped to 0, then the connection can
  2340. // become inactive. We reacquire the spinlock and if it has not
  2341. // jumped back up then we handle any disassociates and closes
  2342. // that have pended.
  2343. //
  2344. NbiHandleConnectionZero (Connection);
  2345. } else {
  2346. NB_FREE_LOCK( Connection->DeviceLock, LockHandle );
  2347. }
  2348. } /* NbiDerefConnection */
  2349. #endif
  2350. VOID
  2351. NbiHandleConnectionZero(
  2352. IN PCONNECTION Connection
  2353. )
  2354. /*++
  2355. Routine Description:
  2356. This routine handles a connection's refcount going to 0.
  2357. If two threads are in this at the same time and
  2358. the close has already come through, one of them might
  2359. destroy the connection while the other one is looking
  2360. at it. We minimize the chance of this by not derefing
  2361. the connection after calling CloseConnection.
  2362. Arguments:
  2363. Connection - Pointer to a transport connection object.
  2364. Return Value:
  2365. none.
  2366. --*/
  2367. {
  2368. CTELockHandle LockHandle;
  2369. PDEVICE Device;
  2370. PADDRESS_FILE AddressFile;
  2371. PADDRESS Address;
  2372. PREQUEST DisconnectPending;
  2373. PREQUEST DisassociatePending;
  2374. PREQUEST ClosePending;
  2375. Device = Connection->Device;
  2376. NB_GET_LOCK (&Device->Lock, &LockHandle);
  2377. #if DBG
  2378. //
  2379. // Make sure if our reference count is zero, all the
  2380. // sub-reference counts are also zero.
  2381. //
  2382. if (Connection->ReferenceCount == 0) {
  2383. UINT i;
  2384. for (i = 0; i < CREF_TOTAL; i++) {
  2385. if (Connection->RefTypes[i] != 0) {
  2386. DbgPrint ("NBI: Connection reftype mismatch on %lx\n", Connection);
  2387. DbgBreakPoint();
  2388. }
  2389. }
  2390. }
  2391. #endif
  2392. //
  2393. // If the connection was assigned an ID, then remove it
  2394. // (it is assigned one when it leaves INACTIVE).
  2395. //
  2396. if (Connection->LocalConnectionId != 0xffff) {
  2397. NbiDeassignConnectionId (Device, Connection);
  2398. }
  2399. //
  2400. // Complete any pending disconnects.
  2401. //
  2402. if (Connection->DisconnectRequest != NULL) {
  2403. DisconnectPending = Connection->DisconnectRequest;
  2404. Connection->DisconnectRequest = NULL;
  2405. NB_FREE_LOCK (&Device->Lock, LockHandle);
  2406. REQUEST_STATUS(DisconnectPending) = STATUS_SUCCESS;
  2407. NbiCompleteRequest (DisconnectPending);
  2408. NbiFreeRequest (Device, DisconnectPending);
  2409. NB_GET_LOCK (&Device->Lock, &LockHandle);
  2410. }
  2411. //
  2412. // This should have been completed by NbiStopConnection,
  2413. // or else not allowed to be queued.
  2414. //
  2415. CTEAssert (Connection->DisconnectWaitRequest == NULL);
  2416. Connection->State = CONNECTION_STATE_INACTIVE;
  2417. RtlZeroMemory (&Connection->ConnectionInfo, sizeof(TDI_CONNECTION_INFO));
  2418. Connection->TickCount = 1;
  2419. Connection->HopCount = 1;
  2420. Connection->BaseRetransmitTimeout = Device->InitialRetransmissionTime / SHORT_TIMER_DELTA;
  2421. Connection->ConnectionInfo.TransmittedTsdus = 0;
  2422. Connection->ConnectionInfo.TransmissionErrors = 0;
  2423. Connection->ConnectionInfo.ReceivedTsdus = 0;
  2424. Connection->ConnectionInfo.ReceiveErrors = 0;
  2425. //
  2426. // See if we need to do a disassociate now.
  2427. //
  2428. if ((Connection->ReferenceCount == 0) &&
  2429. (Connection->DisassociatePending != NULL)) {
  2430. //
  2431. // A disassociate pended, now we complete it.
  2432. //
  2433. DisassociatePending = Connection->DisassociatePending;
  2434. Connection->DisassociatePending = NULL;
  2435. if (AddressFile = Connection->AddressFile) {
  2436. //
  2437. // Set this so nobody else tries to disassociate.
  2438. //
  2439. Connection->AddressFile = (PVOID)-1;
  2440. NB_FREE_LOCK (&Device->Lock, LockHandle);
  2441. //
  2442. // Take this connection out of the address file's list.
  2443. //
  2444. Address = AddressFile->Address;
  2445. NB_GET_LOCK (&Address->Lock, &LockHandle);
  2446. if (Connection->AddressFileLinked) {
  2447. Connection->AddressFileLinked = FALSE;
  2448. RemoveEntryList (&Connection->AddressFileLinkage);
  2449. }
  2450. //
  2451. // We are done.
  2452. //
  2453. Connection->AddressFile = NULL;
  2454. NB_FREE_LOCK (&Address->Lock, LockHandle);
  2455. //
  2456. // Clean up the reference counts and complete any
  2457. // disassociate requests that pended.
  2458. //
  2459. NbiDereferenceAddressFile (AddressFile, AFREF_CONNECTION);
  2460. }
  2461. else {
  2462. NB_FREE_LOCK (&Device->Lock, LockHandle);
  2463. }
  2464. if (DisassociatePending != (PVOID)-1) {
  2465. REQUEST_STATUS(DisassociatePending) = STATUS_SUCCESS;
  2466. NbiCompleteRequest (DisassociatePending);
  2467. NbiFreeRequest (Device, DisassociatePending);
  2468. }
  2469. } else {
  2470. NB_FREE_LOCK (&Device->Lock, LockHandle);
  2471. }
  2472. //
  2473. // If a close was pending, complete that.
  2474. //
  2475. NB_GET_LOCK (&Device->Lock, &LockHandle);
  2476. if ((Connection->ReferenceCount == 0) &&
  2477. (Connection->ClosePending)) {
  2478. ClosePending = Connection->ClosePending;
  2479. Connection->ClosePending = NULL;
  2480. //
  2481. // If we are associated with an address, we need
  2482. // to simulate a disassociate at this point.
  2483. //
  2484. if ((Connection->AddressFile != NULL) &&
  2485. (Connection->AddressFile != (PVOID)-1)) {
  2486. AddressFile = Connection->AddressFile;
  2487. Connection->AddressFile = (PVOID)-1;
  2488. NB_FREE_LOCK (&Device->Lock, LockHandle);
  2489. //
  2490. // Take this connection out of the address file's list.
  2491. //
  2492. Address = AddressFile->Address;
  2493. NB_GET_LOCK (&Address->Lock, &LockHandle);
  2494. if (Connection->AddressFileLinked) {
  2495. Connection->AddressFileLinked = FALSE;
  2496. RemoveEntryList (&Connection->AddressFileLinkage);
  2497. }
  2498. //
  2499. // We are done.
  2500. //
  2501. NB_FREE_LOCK (&Address->Lock, LockHandle);
  2502. Connection->AddressFile = NULL;
  2503. //
  2504. // Clean up the reference counts and complete any
  2505. // disassociate requests that pended.
  2506. //
  2507. NbiDereferenceAddressFile (AddressFile, AFREF_CONNECTION);
  2508. } else {
  2509. NB_FREE_LOCK (&Device->Lock, LockHandle);
  2510. }
  2511. //
  2512. // Even if the ref count is zero and we just cleaned up everything,
  2513. // we can not destroy the connection bcoz some other thread might still be
  2514. // in HandleConnectionZero routine. This could happen when 2 threads call into
  2515. // HandleConnectionZero, one thread runs thru completion, close comes along
  2516. // and the other thread is still in HandleConnectionZero routine.
  2517. //
  2518. CTEAssert( Connection->ThreadsInHandleConnectionZero );
  2519. if (ExInterlockedAddUlong ( &Connection->ThreadsInHandleConnectionZero, (ULONG)-1, &Device->Lock.Lock) == 1) {
  2520. NbiDestroyConnection(Connection);
  2521. }
  2522. REQUEST_STATUS(ClosePending) = STATUS_SUCCESS;
  2523. NbiCompleteRequest (ClosePending);
  2524. NbiFreeRequest (Device, ClosePending);
  2525. } else {
  2526. if ( Connection->ReferenceCount == 0 ) {
  2527. Connection->CanBeDestroyed = TRUE;
  2528. }
  2529. CTEAssert( Connection->ThreadsInHandleConnectionZero );
  2530. Connection->ThreadsInHandleConnectionZero--;
  2531. NB_FREE_LOCK (&Device->Lock, LockHandle);
  2532. }
  2533. } /* NbiHandleConnectionZero */