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.

3955 lines
139 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. Hndlrs.c
  5. Abstract:
  6. This file contains the Non OS specific implementation of handlers that are
  7. called for Connects,Receives, Disconnects, and Errors.
  8. This file represents the TDI interface on the Bottom of NBT after it has
  9. been decoded into procedure call symantics from the Irp symantics used by
  10. NT.
  11. Author:
  12. Jim Stewart (Jimst) 10-2-92
  13. Revision History:
  14. Will Lees (wlees) Sep 11, 1997
  15. Added support for message-only devices
  16. --*/
  17. #ifdef VXD
  18. #define NTIndicateSessionSetup(pLowerConn,status) \
  19. DbgPrint("Skipping NTIndicateSessionSetup\n\r")
  20. #endif //VXD
  21. #include "precomp.h"
  22. #include "ctemacro.h"
  23. #include "hndlrs.tmh"
  24. __inline long
  25. myntohl(long x)
  26. {
  27. return((((x) >> 24) & 0x000000FFL) |
  28. (((x) >> 8) & 0x0000FF00L) |
  29. (((x) << 8) & 0x00FF0000L));
  30. }
  31. VOID
  32. ClearConnStructures (
  33. IN tLOWERCONNECTION *pLowerConn,
  34. IN tCONNECTELE *pConnectEle
  35. );
  36. NTSTATUS
  37. CompleteSessionSetup (
  38. IN tCLIENTELE *pClientEle,
  39. IN tLOWERCONNECTION *pLowerConn,
  40. IN tCONNECTELE *pConnectEle,
  41. IN PCTE_IRP pIrp
  42. );
  43. NTSTATUS
  44. MakeRemoteAddressStructure(
  45. IN PCHAR pHalfAsciiName,
  46. IN PVOID pSourceAddr,
  47. IN ULONG lMaxNameSize,
  48. OUT PVOID *ppRemoteAddress,
  49. OUT PULONG pRemoteAddressLength,
  50. IN ULONG NumAddr
  51. );
  52. VOID
  53. AddToRemoteHashTbl (
  54. IN tDGRAMHDR UNALIGNED *pDgram,
  55. IN ULONG BytesIndicated,
  56. IN tDEVICECONTEXT *pDeviceContext
  57. );
  58. VOID
  59. DoNothingComplete (
  60. IN PVOID pContext
  61. );
  62. VOID
  63. AllocLowerConn(
  64. IN tDEVICECONTEXT *pDeviceContext,
  65. IN PVOID pDeviceSpecial
  66. );
  67. VOID
  68. GetIrpIfNotCancelled2(
  69. IN tCONNECTELE *pConnEle,
  70. OUT PIRP *ppIrp
  71. );
  72. //----------------------------------------------------------------------------
  73. NTSTATUS
  74. Inbound(
  75. IN PVOID ReceiveEventContext,
  76. IN PVOID ConnectionContext,
  77. IN USHORT ReceiveFlags,
  78. IN ULONG BytesIndicated,
  79. IN ULONG BytesAvailable,
  80. OUT PULONG BytesTaken,
  81. IN PVOID pTsdu,
  82. OUT PVOID *RcvBuffer
  83. )
  84. /*++
  85. Routine Description:
  86. This routine is called to setup inbound session
  87. once the tcp connection is up. The transport calls this routine with
  88. a session setup request pdu.
  89. In message-only mode, this routine may be called to cause a session to be set up even
  90. though the session request was not received over the wire. A fake session request is
  91. crafted up and passed to this routine. In this mode, we don't want to send session rejections
  92. back over the wire.
  93. NOTE!!!
  94. // the LowerConn Lock is held prior to calling this routine
  95. Arguments:
  96. pClientEle - ptr to the connecition record for this session
  97. Return Value:
  98. NTSTATUS - Status of receive operation
  99. --*/
  100. {
  101. NTSTATUS status = STATUS_SUCCESS;
  102. tCLIENTELE *pClientEle;
  103. tSESSIONHDR UNALIGNED *pSessionHdr;
  104. tLOWERCONNECTION *pLowerConn;
  105. tCONNECTELE *pConnectEle;
  106. CTELockHandle OldIrq;
  107. PIRP pIrp;
  108. PLIST_ENTRY pEntry;
  109. CONNECTION_CONTEXT ConnectId;
  110. PTA_NETBIOS_ADDRESS pRemoteAddress;
  111. ULONG RemoteAddressLength;
  112. tDEVICECONTEXT *pDeviceContext;
  113. //
  114. // Verify that the DataSize >= sizeof (Sessionheader)
  115. // Bug# 126111
  116. //
  117. if (BytesIndicated < (sizeof(tSESSIONHDR)))
  118. {
  119. KdPrint (("Nbt.Inbound[1]: WARNING!!! Rejecting Request -- BytesIndicated=<%d> < <%d>\n",
  120. BytesIndicated, (sizeof(tSESSIONHDR))));
  121. NbtTrace(NBT_TRACE_INBOUND, ("Reject request on %Z: BytestIndicated %d < %d",
  122. &((tLOWERCONNECTION *)ConnectionContext)->pDeviceContext->BindName,
  123. BytesIndicated, sizeof(tSESSIONHDR)));
  124. return (STATUS_INTERNAL_ERROR);
  125. }
  126. pSessionHdr = (tSESSIONHDR UNALIGNED *)pTsdu;
  127. // get the ptrs to the lower and upper connections
  128. //
  129. pLowerConn = (tLOWERCONNECTION *)ConnectionContext;
  130. pConnectEle = pLowerConn->pUpperConnection;
  131. pDeviceContext = pLowerConn->pDeviceContext;
  132. //
  133. // fake out the transport so it frees its receive buffer (i.e. we
  134. // say that we accepted all of the data)
  135. //
  136. *BytesTaken = BytesIndicated;
  137. //
  138. // since we send keep alives on connections in the the inbound
  139. // state it is possible to get a keep alive, so just return in that
  140. // case
  141. //
  142. if (((tSESSIONHDR UNALIGNED *)pTsdu)->Type == NBT_SESSION_KEEP_ALIVE)
  143. {
  144. NbtTrace(NBT_TRACE_INBOUND, ("Return SUCCESS for NBT_SESSION_KEEP_ALIVE for %!ipaddr!", pLowerConn->SrcIpAddr));
  145. return(STATUS_SUCCESS);
  146. }
  147. //
  148. // Session ** INBOUND ** setup processing
  149. //
  150. if ((pSessionHdr->Type != NBT_SESSION_REQUEST) ||
  151. (BytesIndicated < (sizeof(tSESSIONHDR) + 2*(1+2*NETBIOS_NAME_SIZE+1))))
  152. {
  153. //
  154. // The Session Request packet is of the form:
  155. // -- Session Header = 4 bytes
  156. // -- Called name = 34+x (1 + 32 + 1(==ScopeLength) + x(==Scope))
  157. // -- Calling name= 34+y (1 + 32 + 1(==ScopeLength) + y(==Scope))
  158. //
  159. CTESpinFreeAtDpc(pLowerConn);
  160. KdPrint(("Nbt.Inbound[2]: ERROR -- Bad Session PDU - Type=<%x>, BytesInd=[%d]<[%d], Src=<%x>\n",
  161. pSessionHdr->Type, BytesIndicated, (sizeof(tSESSIONHDR)+2*(1+2*NETBIOS_NAME_SIZE+1)),pLowerConn->SrcIpAddr));
  162. NbtTrace(NBT_TRACE_INBOUND, ("Bad Session PDU - Type=<%x>, BytesInd=[%d]<[%d], Src=%!ipaddr! %Z\n",
  163. pSessionHdr->Type, BytesIndicated, (sizeof(tSESSIONHDR)+2*(1+2*NETBIOS_NAME_SIZE+1)),
  164. pLowerConn->SrcIpAddr, &pLowerConn->pDeviceContext->BindName));
  165. #ifdef _NETBIOSLESS
  166. status = STATUS_INTERNAL_ERROR;
  167. // In message-only mode, don't send session responses back over the wire
  168. if (!IsDeviceNetbiosless(pLowerConn->pDeviceContext))
  169. #endif
  170. {
  171. RejectSession(pLowerConn, NBT_NEGATIVE_SESSION_RESPONSE, SESSION_UNSPECIFIED_ERROR, TRUE);
  172. }
  173. goto Inbound_Exit1;
  174. }
  175. // the LowerConn Lock is held prior to calling this routine, so free it
  176. // here since we need to get the joint lock first
  177. CTESpinFreeAtDpc(pLowerConn);
  178. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  179. CTESpinLockAtDpc(pLowerConn);
  180. // it is possible for the disconnect handler to run while the pLowerConn
  181. // lock is released above, to get the ConnEle lock, and change the state
  182. // to disconnected.
  183. if (pLowerConn->State != NBT_SESSION_INBOUND)
  184. {
  185. CTESpinFreeAtDpc(pLowerConn);
  186. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  187. #ifdef _NETBIOSLESS
  188. status = STATUS_CONNECTION_DISCONNECTED;
  189. #endif
  190. NbtTrace(NBT_TRACE_INBOUND, ("Incorrect state %x %!ipaddr!", pLowerConn->State, pLowerConn->SrcIpAddr));
  191. goto Inbound_Exit1;
  192. }
  193. CTESpinFreeAtDpc(pLowerConn);
  194. IF_DBG(NBT_DEBUG_DISCONNECT)
  195. KdPrint(("Nbt.Inbound: In SessionSetupnotOS, connection state = %X\n",pLowerConn->State));
  196. status = FindSessionEndPoint(pTsdu,
  197. ConnectionContext,
  198. BytesIndicated,
  199. &pClientEle,
  200. &pRemoteAddress,
  201. &RemoteAddressLength);
  202. if (status != STATUS_SUCCESS)
  203. {
  204. //
  205. // could not find the desired end point so send a negative session
  206. // response pdu and then disconnect
  207. //
  208. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  209. NbtTrace(NBT_TRACE_INBOUND, ("FindSessionEndPoint return %!status! for %!ipaddr! %Z",
  210. status, pLowerConn->SrcIpAddr, &pLowerConn->pDeviceContext->BindName));
  211. #ifdef _NETBIOSLESS
  212. // In message-only mode, don't send session responses back over the wire
  213. if (!IsDeviceNetbiosless(pLowerConn->pDeviceContext))
  214. #endif
  215. {
  216. RejectSession(pLowerConn, NBT_NEGATIVE_SESSION_RESPONSE, status, TRUE);
  217. }
  218. KdPrint (("Nbt.Inbound[3]: WARNING!!! FindSessionEndPoint failed, Rejecting Request\n"));
  219. goto Inbound_Exit1;
  220. }
  221. //
  222. // we must first check for a valid LISTEN....
  223. //
  224. CTESpinLockAtDpc(pDeviceContext);
  225. CTESpinLockAtDpc(pClientEle);
  226. if (!IsListEmpty(&pClientEle->ListenHead))
  227. {
  228. tLISTENREQUESTS *pListen;
  229. tLISTENREQUESTS *pListenTarget ;
  230. //
  231. // Find the first listen that matches the remote name else
  232. // take a listen that specified '*'
  233. //
  234. pListenTarget = NULL;
  235. for ( pEntry = pClientEle->ListenHead.Flink ;
  236. pEntry != &pClientEle->ListenHead ;
  237. pEntry = pEntry->Flink )
  238. {
  239. pListen = CONTAINING_RECORD(pEntry,tLISTENREQUESTS,Linkage);
  240. // in NT-land the pConnInfo structure is passed in , but the
  241. // remote address field is nulled out... so we need to check
  242. // both of these before going on to check the remote address.
  243. if (pListen->pConnInfo && pListen->pConnInfo->RemoteAddress)
  244. {
  245. if (CTEMemEqu(((PTA_NETBIOS_ADDRESS)pListen->pConnInfo->RemoteAddress)->
  246. Address[0].Address[0].NetbiosName,
  247. pRemoteAddress->Address[0].Address[0].NetbiosName,
  248. NETBIOS_NAME_SIZE))
  249. {
  250. pListenTarget = pListen;
  251. break;
  252. }
  253. }
  254. else
  255. {
  256. //
  257. // Specified '*' for the remote name, save this,
  258. // look for listen on a real name - only save if it is
  259. // the first * listen found
  260. //
  261. if (!pListenTarget)
  262. {
  263. pListenTarget = pListen ;
  264. }
  265. }
  266. }
  267. if (pListenTarget)
  268. {
  269. PTA_NETBIOS_ADDRESS pRemoteAddr;
  270. RemoveEntryList( &pListenTarget->Linkage );
  271. //
  272. // Fill in the remote machines name to return to the client
  273. //
  274. if ((pListenTarget->pReturnConnInfo) &&
  275. (pRemoteAddr = pListenTarget->pReturnConnInfo->RemoteAddress))
  276. {
  277. CTEMemCopy(pRemoteAddr,pRemoteAddress,RemoteAddressLength);
  278. }
  279. //
  280. // get the upper connection end point out of the listen and
  281. // hook the upper and lower connections together.
  282. //
  283. pConnectEle = (tCONNECTELE *)pListenTarget->pConnectEle;
  284. CHECK_PTR(pConnectEle);
  285. CTESpinLockAtDpc(pConnectEle);
  286. pLowerConn->pUpperConnection = pConnectEle;
  287. pConnectEle->pLowerConnId = pLowerConn;
  288. pConnectEle->pIrpRcv = NULL;
  289. //
  290. // Previously, the LowerConnection was in the SESSION_INBOUND state
  291. // hence we have to remove it from the WaitingForInbound Q and put
  292. // it on the active LowerConnection list!
  293. //
  294. ASSERT (pLowerConn->State == NBT_SESSION_INBOUND);
  295. RemoveEntryList (&pLowerConn->Linkage);
  296. InsertTailList (&pLowerConn->pDeviceContext->LowerConnection, &pLowerConn->Linkage);
  297. InterlockedDecrement (&pLowerConn->pDeviceContext->NumWaitingForInbound);
  298. //
  299. // Change the RefCount Context to Connected!
  300. //
  301. NBT_SWAP_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_WAITING_INBOUND, REF_LOWC_CONNECTED, FALSE);
  302. //
  303. // put the upper connection on its active list
  304. //
  305. RemoveEntryList(&pConnectEle->Linkage);
  306. InsertTailList(&pConnectEle->pClientEle->ConnectActive, &pConnectEle->Linkage);
  307. //
  308. // Save the remote name while we still have it
  309. //
  310. CTEMemCopy (pConnectEle->RemoteName,
  311. pRemoteAddress->Address[0].Address[0].NetbiosName,
  312. NETBIOS_NAME_SIZE ) ;
  313. //
  314. // since the lower connection now points to pConnectEle, increment
  315. // the reference count so we can't free pConnectEle memory until
  316. // the lower conn no longer points to it.
  317. ClearConnStructures(pLowerConn,pConnectEle);
  318. NBT_REFERENCE_CONNECTION (pConnectEle, REF_CONN_CONNECT);
  319. if (pListenTarget->Flags & TDI_QUERY_ACCEPT)
  320. {
  321. SET_STATE_UPPER (pConnectEle, NBT_SESSION_WAITACCEPT);
  322. SET_STATE_LOWER (pLowerConn, NBT_SESSION_WAITACCEPT);
  323. SET_STATERCV_LOWER (pLowerConn, NORMAL, RejectAnyData);
  324. }
  325. else
  326. {
  327. SET_STATE_UPPER (pConnectEle, NBT_SESSION_UP);
  328. SET_STATE_LOWER (pLowerConn, NBT_SESSION_UP);
  329. SET_STATERCV_LOWER (pLowerConn, NORMAL, Normal);
  330. }
  331. CTESpinFreeAtDpc(pConnectEle);
  332. CTESpinFreeAtDpc(pClientEle);
  333. CTESpinFreeAtDpc(pDeviceContext);
  334. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  335. if (pListenTarget->Flags & TDI_QUERY_ACCEPT)
  336. {
  337. IF_DBG(NBT_DEBUG_DISCONNECT)
  338. KdPrint(("Nbt.Inbound: Completing Client's Irp to make client issue Accept\n"));
  339. //
  340. // complete the client listen irp, which will trigger him to
  341. // issue an accept, which should find the connection in the
  342. // WAIT_ACCEPT state, and subsequently cause a session response
  343. // to be sent.
  344. #ifndef VXD
  345. // the irp can't get cancelled because the cancel listen routine
  346. // also grabs the Client spin lock and removes the listen from the
  347. // list..
  348. CTEIoComplete( pListenTarget->pIrp,STATUS_SUCCESS,0);
  349. #else
  350. CTEIoComplete( pListenTarget->pIrp,STATUS_SUCCESS, (ULONG) pConnectEle);
  351. #endif
  352. }
  353. else
  354. {
  355. IF_DBG(NBT_DEBUG_DISCONNECT)
  356. KdPrint(("Nbt.Inbound: Calling CompleteSessionSetup to send session response PDU\n"));
  357. //
  358. // We need to send a session response PDU here, since
  359. // we do not have to wait for an accept in this case
  360. //
  361. CompleteSessionSetup(pClientEle, pLowerConn,pConnectEle, pListenTarget->pIrp);
  362. }
  363. CTEMemFree((PVOID)pRemoteAddress);
  364. CTEMemFree(pListenTarget);
  365. // now that we have notified the client, dereference it
  366. //
  367. NBT_DEREFERENCE_CLIENT(pClientEle);
  368. PUSH_LOCATION(0x60);
  369. IF_DBG(NBT_DEBUG_DISCONNECT)
  370. KdPrint(("Nbt.Inbound: Accepted Connection by a Listen %X LowerConn=%X, BytesTaken=<%x>\n",
  371. pConnectEle,pLowerConn, BytesAvailable));
  372. // fake out the transport so it frees its receive buffer (i.e. we
  373. // say that we accepted all of the data)
  374. *BytesTaken = BytesAvailable;
  375. status = STATUS_SUCCESS;
  376. goto Inbound_Exit1;
  377. }
  378. }
  379. CTESpinFreeAtDpc(pClientEle);
  380. CTESpinFreeAtDpc(pDeviceContext);
  381. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  382. //
  383. // No LISTEN, so check for an Event handler
  384. //
  385. if (!pClientEle->ConEvContext)
  386. {
  387. NbtTrace(NBT_TRACE_INBOUND, ("No listener for %!ipaddr! %!NBTNAME!<%02x> %Z",
  388. pLowerConn->SrcIpAddr, pRemoteAddress->Address[0].Address[0].NetbiosName,
  389. (unsigned)pRemoteAddress->Address[0].Address[0].NetbiosName[15],
  390. &pLowerConn->pDeviceContext->BindName));
  391. #ifdef _NETBIOSLESS
  392. status = STATUS_REMOTE_NOT_LISTENING;
  393. // In message-only mode, don't send session responses back over the wire
  394. if (!IsDeviceNetbiosless(pLowerConn->pDeviceContext))
  395. #endif
  396. {
  397. RejectSession(pLowerConn,
  398. NBT_NEGATIVE_SESSION_RESPONSE,
  399. SESSION_NOT_LISTENING_ON_CALLED_NAME,
  400. TRUE);
  401. }
  402. // undo the reference done in FindEndpoint
  403. //
  404. NBT_DEREFERENCE_CLIENT(pClientEle);
  405. //
  406. // free the memory allocated for the Remote address data structure
  407. //
  408. CTEMemFree((PVOID)pRemoteAddress);
  409. KdPrint (("Nbt.Inbound[4]: WARNING!!! Rejecting Request -- No Listen or EventHandler\n"));
  410. goto Inbound_Exit1;
  411. }
  412. #ifdef VXD
  413. else
  414. {
  415. ASSERT( FALSE ) ;
  416. }
  417. #endif
  418. // now call the client's connect handler...
  419. pIrp = NULL;
  420. #ifndef VXD // VXD doesn't support event handlers
  421. status = (*pClientEle->evConnect)(pClientEle->ConEvContext,
  422. RemoteAddressLength,
  423. pRemoteAddress,
  424. 0,
  425. NULL,
  426. 0, // options length
  427. NULL, // Options
  428. &ConnectId,
  429. &pIrp
  430. );
  431. if (!NT_SUCCESS(status)) {
  432. NbtTrace(NBT_TRACE_INBOUND, ("Client return %!status! for %!ipaddr! %!NBTNAME!<%02x> %Z",
  433. status, pLowerConn->SrcIpAddr, pRemoteAddress->Address[0].Address[0].NetbiosName,
  434. (unsigned)pRemoteAddress->Address[0].Address[0].NetbiosName[15],
  435. &pLowerConn->pDeviceContext->BindName));
  436. }
  437. //
  438. // With the new TDI semantics is it illegal to return STATUS_EVENT_DONE
  439. // or STATUS_EVENT_PENDING from the connect event handler
  440. //
  441. ASSERT(status != STATUS_EVENT_PENDING);
  442. ASSERT(status != STATUS_EVENT_DONE);
  443. // now that we have notified the client, dereference it
  444. //
  445. NBT_DEREFERENCE_CLIENT(pClientEle);
  446. // Check the returned status codes..
  447. if (status == STATUS_MORE_PROCESSING_REQUIRED && pIrp != NULL)
  448. {
  449. PIO_STACK_LOCATION pIrpSp;
  450. // the pConnEle ptr was stored in the FsContext value when the connection
  451. // was initially created.
  452. pIrpSp = IoGetCurrentIrpStackLocation(pIrp);
  453. pConnectEle = (tCONNECTELE *)pIrpSp->FileObject->FsContext;
  454. if (!NBT_VERIFY_HANDLE2 (pConnectEle, NBT_VERIFY_CONNECTION, NBT_VERIFY_CONNECTION_DOWN))
  455. {
  456. ASSERTMSG ("Nbt.Inbound: ERROR - Invalid Connection Handle\n", 0);
  457. status = STATUS_INTERNAL_ERROR;
  458. }
  459. else
  460. {
  461. //
  462. // Save the remote name while we still have it
  463. //
  464. CHECK_PTR(pConnectEle);
  465. CTEMemCopy( pConnectEle->RemoteName,
  466. pRemoteAddress->Address[0].Address[0].NetbiosName,
  467. NETBIOS_NAME_SIZE ) ;
  468. // be sure the connection is in the correct state
  469. //
  470. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  471. CTESpinLockAtDpc(pDeviceContext);
  472. CTESpinLockAtDpc(pClientEle);
  473. CTESpinLockAtDpc(pConnectEle);
  474. if (pConnectEle->state == NBT_ASSOCIATED)
  475. {
  476. //
  477. // Previously, the LowerConnection was in the SESSION_INBOUND state
  478. // hence we have to remove it from the WaitingForInbound Q and put
  479. // it on the active LowerConnection list!
  480. //
  481. ASSERT (pLowerConn->State == NBT_SESSION_INBOUND);
  482. RemoveEntryList (&pLowerConn->Linkage);
  483. InsertTailList (&pLowerConn->pDeviceContext->LowerConnection, &pLowerConn->Linkage);
  484. InterlockedDecrement (&pLowerConn->pDeviceContext->NumWaitingForInbound);
  485. //
  486. // Change the RefCount Context to Connected!
  487. //
  488. NBT_SWAP_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_WAITING_INBOUND,REF_LOWC_CONNECTED, FALSE);
  489. // since the lower connection now points to pConnectEle, increment
  490. // the reference count so we can't free pConnectEle memory until
  491. // the lower conn no longer points to it.
  492. //
  493. NBT_REFERENCE_CONNECTION (pConnectEle, REF_CONN_CONNECT);
  494. ClearConnStructures(pLowerConn,pConnectEle);
  495. SET_STATE_UPPER (pConnectEle, NBT_SESSION_UP);
  496. SET_STATE_LOWER (pLowerConn, NBT_SESSION_UP);
  497. SetStateProc (pLowerConn, Normal);
  498. RemoveEntryList(&pConnectEle->Linkage);
  499. InsertTailList(&pConnectEle->pClientEle->ConnectActive, &pConnectEle->Linkage);
  500. status = STATUS_SUCCESS;
  501. }
  502. else
  503. {
  504. status = STATUS_INTERNAL_ERROR;
  505. }
  506. CTESpinFreeAtDpc(pConnectEle);
  507. CTESpinFreeAtDpc(pClientEle);
  508. CTESpinFreeAtDpc(pDeviceContext);
  509. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  510. if (STATUS_SUCCESS == status)
  511. {
  512. CompleteSessionSetup(pClientEle,pLowerConn,pConnectEle,pIrp);
  513. }
  514. }
  515. }
  516. else
  517. {
  518. status = STATUS_DATA_NOT_ACCEPTED;
  519. }
  520. if (status != STATUS_SUCCESS)
  521. {
  522. IF_DBG(NBT_DEBUG_DISCONNECT)
  523. KdPrint(("Nbt.Inbound: The client rejected in the inbound connection status = %X\n", status));
  524. #ifdef _NETBIOSLESS
  525. // In message-only mode, don't send session responses back over the wire
  526. if (!IsDeviceNetbiosless(pLowerConn->pDeviceContext))
  527. #endif
  528. {
  529. RejectSession(pLowerConn,
  530. NBT_NEGATIVE_SESSION_RESPONSE,
  531. SESSION_CALLED_NAME_PRESENT_NO_RESRC,
  532. TRUE);
  533. }
  534. }
  535. #endif
  536. //
  537. // free the memory allocated for the Remote address data structure
  538. //
  539. CTEMemFree((PVOID)pRemoteAddress);
  540. Inbound_Exit1:
  541. // This spin lock is held by the routine that calls this one, and
  542. // freed when this routine starts, so we must regrab this lock before
  543. // returning
  544. //
  545. CTESpinLockAtDpc(pLowerConn);
  546. #ifdef _NETBIOSLESS
  547. // In message only mode, return the real status
  548. return (IsDeviceNetbiosless(pLowerConn->pDeviceContext) ? status : STATUS_SUCCESS );
  549. #else
  550. return(STATUS_SUCCESS);
  551. #endif
  552. }
  553. //----------------------------------------------------------------------------
  554. VOID
  555. ClearConnStructures (
  556. IN tLOWERCONNECTION *pLowerConn,
  557. IN tCONNECTELE *pConnectEle
  558. )
  559. /*++
  560. Routine Description:
  561. This routine sets various parts of the connection datastructures to
  562. zero, in preparation for a new connection.
  563. Arguments:
  564. Return Value:
  565. NTSTATUS - Status of receive operation
  566. --*/
  567. {
  568. CHECK_PTR(pConnectEle);
  569. #ifndef VXD
  570. pConnectEle->FreeBytesInMdl = 0;
  571. pConnectEle->CurrentRcvLen = 0;
  572. pLowerConn->BytesInIndicate = 0;
  573. #endif
  574. pConnectEle->ReceiveIndicated = 0;
  575. pConnectEle->BytesInXport = 0;
  576. pConnectEle->BytesRcvd = 0;
  577. pConnectEle->TotalPcktLen = 0;
  578. pConnectEle->OffsetFromStart = 0;
  579. pConnectEle->pIrpRcv = NULL;
  580. pConnectEle->pIrp = NULL;
  581. pConnectEle->pIrpDisc = NULL;
  582. pConnectEle->pIrpClose = NULL;
  583. pConnectEle->DiscFlag = 0;
  584. pConnectEle->JunkMsgFlag = FALSE;
  585. pConnectEle->pLowerConnId = pLowerConn;
  586. InitializeListHead(&pConnectEle->RcvHead);
  587. pLowerConn->pUpperConnection = pConnectEle;
  588. SET_STATERCV_LOWER(pLowerConn, NORMAL, pLowerConn->CurrentStateProc);
  589. pLowerConn->BytesRcvd = 0;
  590. pLowerConn->BytesSent = 0;
  591. }
  592. //----------------------------------------------------------------------------
  593. NTSTATUS
  594. CompleteSessionSetup (
  595. IN tCLIENTELE *pClientEle,
  596. IN tLOWERCONNECTION *pLowerConn,
  597. IN tCONNECTELE *pConnectEle,
  598. IN PCTE_IRP pIrp
  599. )
  600. /*++
  601. Routine Description:
  602. This routine is called to setup an outbound session
  603. once the tcp connection is up. The transport calls this routine with
  604. a session setup response pdu.
  605. The pConnectEle + Joinlock are held when this routine is called.
  606. Arguments:
  607. Return Value:
  608. NTSTATUS - Status of receive operation
  609. --*/
  610. {
  611. NTSTATUS status;
  612. CTELockHandle OldIrq;
  613. #ifdef _NETBIOSLESS
  614. // In message-only mode, don't send session responses back over the wire
  615. if (IsDeviceNetbiosless(pLowerConn->pDeviceContext))
  616. {
  617. status = STATUS_SUCCESS;
  618. }
  619. else
  620. #endif
  621. {
  622. status = TcpSendSessionResponse(pLowerConn, NBT_POSITIVE_SESSION_RESPONSE, 0L);
  623. }
  624. if (NT_SUCCESS(status))
  625. {
  626. IF_DBG(NBT_DEBUG_DISCONNECT)
  627. KdPrint(("Nbt.CompleteSessionSetup: Accepted ConnEle=%p LowerConn=%p\n",pConnectEle,pLowerConn));
  628. //
  629. // complete the client's accept Irp
  630. //
  631. #ifndef VXD
  632. CTEIoComplete (pIrp, STATUS_SUCCESS, 0);
  633. #else
  634. CTEIoComplete (pIrp, STATUS_SUCCESS, (ULONG)pConnectEle);
  635. #endif
  636. }
  637. else
  638. { //
  639. // if we have some trouble sending the Session response, then
  640. // disconnect the connection
  641. //
  642. IF_DBG(NBT_DEBUG_DISCONNECT)
  643. KdPrint(("Nbt.CompleteSessionSetup: Could not send Session Response, status = %X\n", status));
  644. RejectSession(pLowerConn, NBT_NEGATIVE_SESSION_RESPONSE, SESSION_CALLED_NAME_PRESENT_NO_RESRC, TRUE);
  645. CTESpinLock(&NbtConfig.JointLock, OldIrq);
  646. RelistConnection(pConnectEle);
  647. CTESpinFree(&NbtConfig.JointLock, OldIrq);
  648. // Disconnect To Client - i.e. a negative Accept
  649. // this will get done when the disconnect indication
  650. // comes back from the transport
  651. //
  652. GetIrpIfNotCancelled(pConnectEle,&pIrp);
  653. if (pIrp)
  654. {
  655. CTEIoComplete(pIrp,STATUS_UNSUCCESSFUL,0);
  656. }
  657. }
  658. return(STATUS_SUCCESS);
  659. }
  660. //----------------------------------------------------------------------------
  661. NTSTATUS
  662. Outbound (
  663. IN PVOID ReceiveEventContext,
  664. IN PVOID ConnectionContext,
  665. IN USHORT ReceiveFlags,
  666. IN ULONG BytesIndicated,
  667. IN ULONG BytesAvailable,
  668. OUT PULONG BytesTaken,
  669. IN PVOID pTsdu,
  670. OUT PVOID *RcvBuffer
  671. )
  672. /*++
  673. Routine Description:
  674. This routine is called while seting up an outbound session
  675. once the tcp connection is up. The transport calls this routine with
  676. a session setup response pdu .
  677. Arguments:
  678. pClientEle - ptr to the connection record for this session
  679. Return Value:
  680. NTSTATUS - Status of receive operation
  681. --*/
  682. {
  683. tSESSIONHDR UNALIGNED *pSessionHdr;
  684. tLOWERCONNECTION *pLowerConn;
  685. CTELockHandle OldIrq;
  686. PIRP pIrp;
  687. tTIMERQENTRY *pTimerEntry;
  688. tCONNECTELE *pConnEle;
  689. tDGRAM_SEND_TRACKING *pTracker;
  690. tDEVICECONTEXT *pDeviceContext;
  691. // get the ptr to the lower connection
  692. //
  693. pLowerConn = (tLOWERCONNECTION *)ConnectionContext;
  694. pSessionHdr = (tSESSIONHDR UNALIGNED *)pTsdu;
  695. pDeviceContext = pLowerConn->pDeviceContext;
  696. //
  697. // fake out the transport so it frees its receive buffer (i.e. we
  698. // say that we accepted all of the data)
  699. //
  700. *BytesTaken = BytesIndicated;
  701. //
  702. // since we send keep alives on connections in the the inbound
  703. // state it is possible to get a keep alive, so just return in that
  704. // case
  705. //
  706. if (((tSESSIONHDR UNALIGNED *)pTsdu)->Type == NBT_SESSION_KEEP_ALIVE)
  707. {
  708. NbtTrace(NBT_TRACE_OUTBOUND, ("Return success for NBT_SESSION_KEEP_ALIVE"));
  709. return(STATUS_SUCCESS);
  710. }
  711. // the LowerConn Lock is held prior to calling this routine, so free it
  712. // here since we need to get the joint lock first
  713. CTESpinFreeAtDpc(pLowerConn);
  714. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  715. CTESpinLockAtDpc(pLowerConn);
  716. //
  717. // it is possible for the disconnect handler to run while the pLowerConn
  718. // lock is released above, to get the ConnEle lock, and change the state
  719. // to disconnected.
  720. //
  721. if ((!(pConnEle = pLowerConn->pUpperConnection)) ||
  722. (pConnEle->state != NBT_SESSION_OUTBOUND))
  723. {
  724. if (pConnEle) {
  725. NbtTrace(NBT_TRACE_OUTBOUND, ("Reset outbound connection %lx", pConnEle->state));
  726. } else {
  727. NbtTrace(NBT_TRACE_OUTBOUND, ("Reset outbound connection"));
  728. }
  729. CTESpinFreeAtDpc(pLowerConn);
  730. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  731. RejectSession(pLowerConn,0,0,FALSE);
  732. goto ExitCode;
  733. }
  734. //
  735. // if no Connect Tracker, then SessionStartupCompletion has run and
  736. // the connection is about to be closed, so return.
  737. //
  738. if (!(pTracker = (tDGRAM_SEND_TRACKING *)pConnEle->pIrpRcv))
  739. {
  740. CTESpinFreeAtDpc(pLowerConn);
  741. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  742. NbtTrace(NBT_TRACE_OUTBOUND, ("No tracker"));
  743. goto ExitCode;
  744. }
  745. CHECK_PTR(pTracker);
  746. CHECK_PTR(pConnEle);
  747. pConnEle->pIrpRcv = NULL;
  748. //
  749. // Stop the timer started in SessionStartupCompletion to time the
  750. // Session Setup Response message - it is possible for this routine to
  751. // run before SessionStartupCompletion, in which case there will not be
  752. // any timer to stop.
  753. //
  754. if (pTimerEntry = pTracker->pTimer)
  755. {
  756. pTracker->pTimer = NULL;
  757. StopTimer(pTimerEntry,NULL,NULL);
  758. }
  759. if (pSessionHdr->Type == NBT_POSITIVE_SESSION_RESPONSE)
  760. {
  761. // zero out the number of bytes received so far, since this is a new connection
  762. CHECK_PTR(pConnEle);
  763. pConnEle->BytesRcvd = 0;
  764. SET_STATE_UPPER (pConnEle, NBT_SESSION_UP);
  765. SET_STATE_LOWER (pLowerConn, NBT_SESSION_UP);
  766. SetStateProc( pLowerConn, Normal ) ;
  767. CTESpinFreeAtDpc(pLowerConn);
  768. GetIrpIfNotCancelled2(pConnEle,&pIrp);
  769. //
  770. // if SessionSetupContinue has run, it has set the refcount to zero
  771. //
  772. if (pTracker->RefConn == 0)
  773. {
  774. //
  775. // remove the reference done when FindNameOrQuery was called, or when
  776. // SessionSetupContinue ran
  777. //
  778. NBT_DEREFERENCE_NAMEADDR (pTracker->pNameAddr, REF_NAME_CONNECT, TRUE);
  779. FreeTracker(pTracker,FREE_HDR | RELINK_TRACKER);
  780. }
  781. else
  782. {
  783. pTracker->RefConn--;
  784. }
  785. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  786. // the assumption is that if the connect irp was cancelled then the
  787. // client should be doing a disconnect or close shortly thereafter, so
  788. // there is no error handling code here.
  789. if (pIrp)
  790. {
  791. //
  792. // complete the client's connect request Irp
  793. //
  794. #ifndef VXD
  795. CTEIoComplete( pIrp, STATUS_SUCCESS, 0 ) ;
  796. #else
  797. CTEIoComplete( pIrp, STATUS_SUCCESS, (ULONG)pConnEle ) ;
  798. #endif
  799. }
  800. }
  801. else
  802. {
  803. ULONG ErrorCode;
  804. ULONG state;
  805. NTSTATUS status = STATUS_SUCCESS;
  806. state = pConnEle->state;
  807. if ((NbtConfig.Unloading) ||
  808. (!NBT_REFERENCE_DEVICE(pDeviceContext, REF_DEV_OUTBOUND, TRUE)))
  809. {
  810. NbtTrace(NBT_TRACE_OUTBOUND, ("Outbound() gets called while unloading driver %x", state));
  811. status = STATUS_INVALID_DEVICE_REQUEST;
  812. }
  813. // If the response is Retarget then setup another session
  814. // to the new Ip address and port number.
  815. //
  816. ErrorCode = (ULONG)((tSESSIONERROR *)pSessionHdr)->ErrorCode;
  817. NbtTrace(NBT_TRACE_OUTBOUND, ("state=%x (%s%d), (%s%s%s%s)",
  818. state,
  819. ((pSessionHdr->Type == NBT_RETARGET_SESSION_RESPONSE)? "Retarget Response ": ""),
  820. pConnEle->SessionSetupCount,
  821. ((NbtConfig.TryAllNameServers)? "TryAllNameServers ": ""),
  822. ((pSessionHdr->Type == NBT_NEGATIVE_SESSION_RESPONSE)? "NegativeSessionResponse ":""),
  823. ((pTracker->RemoteNameLength <= NETBIOS_NAME_SIZE)? "NetBIOS": "DNS_Name "),
  824. ((pTracker->ResolutionContextFlags != 0xFF)? "ContinueQuery ": "EndOfQuery")));
  825. #ifdef MULTIPLE_WINS
  826. if ( (status == STATUS_SUCCESS) &&
  827. ( ((pSessionHdr->Type == NBT_RETARGET_SESSION_RESPONSE) &&
  828. (pConnEle->SessionSetupCount--))
  829. ||
  830. ((NbtConfig.TryAllNameServers) &&
  831. (pSessionHdr->Type == NBT_NEGATIVE_SESSION_RESPONSE) &&
  832. pTracker->RemoteNameLength <= NETBIOS_NAME_SIZE && // Don't do it for DNS name
  833. (pTracker->ResolutionContextFlags != 0xFF)))) // Have not finished querying
  834. {
  835. #else
  836. if (pSessionHdr->Type == NBT_RETARGET_SESSION_RESPONSE)
  837. {
  838. //
  839. // retry the session setup if we haven't already exceeded the
  840. // count
  841. //
  842. if (pConnEle->SessionSetupCount--)
  843. {
  844. #endif
  845. PVOID Context=NULL;
  846. BOOLEAN Cancelled;
  847. SET_STATE_UPPER (pConnEle, NBT_ASSOCIATED);
  848. // for retarget the destination has specified an alternate
  849. // port to which the session should be established.
  850. if (pSessionHdr->Type == NBT_RETARGET_SESSION_RESPONSE)
  851. {
  852. pTracker->DestPort = ntohs(((tSESSIONRETARGET *)pSessionHdr)->Port);
  853. Context = ULongToPtr(ntohl(((tSESSIONRETARGET *)pSessionHdr)->IpAddress));
  854. }
  855. else
  856. #ifndef MULTIPLE_WINS
  857. if (ErrorCode == SESSION_CALLED_NAME_NOT_PRESENT)
  858. #endif
  859. {
  860. // to tell DelayedReconnect to use the current name(not a retarget)
  861. Context = NULL;
  862. }
  863. //
  864. // Unlink the lower and upper connections.
  865. //
  866. CHECK_PTR(pConnEle);
  867. CHECK_PTR(pLowerConn);
  868. NBT_DISASSOCIATE_CONNECTION (pConnEle, pLowerConn);
  869. CTESpinFreeAtDpc(pLowerConn);
  870. //
  871. // put the pconnele back on the Client's ConnectHead if it
  872. // has not been cleanedup yet.
  873. //
  874. if (state != NBT_IDLE)
  875. {
  876. RelistConnection(pConnEle);
  877. }
  878. // if a disconnect comes down in this state we we will handle it.
  879. SET_STATE_UPPER (pConnEle, NBT_RECONNECTING);
  880. CHECK_PTR(pConnEle);
  881. #ifdef MULTIPLE_WINS
  882. if (pSessionHdr->Type == NBT_RETARGET_SESSION_RESPONSE)
  883. {
  884. pConnEle->SessionSetupCount = 0;// only allow one retry
  885. }
  886. #else
  887. pConnEle->SessionSetupCount = 0;// only allow one retry
  888. #endif
  889. pIrp = pConnEle->pIrp;
  890. Cancelled = FALSE;
  891. IF_DBG(NBT_DEBUG_DISCONNECT)
  892. KdPrint(("Nbt.Outbound: Attempt Reconnect, error=%X LowerConn %X\n", ErrorCode,pLowerConn));
  893. #ifndef VXD
  894. // the irp can't be cancelled until the connection
  895. // starts up again - either when the Irp is in the transport
  896. // or when we set our cancel routine in SessionStartupCompletion
  897. // This disconnect handler cannot complete the Irp because
  898. // we set the pConnEle state to NBT_ASSOCIATED above, with
  899. // the spin lock held, which prevents the Disconnect handler
  900. // from doing anything.
  901. IoAcquireCancelSpinLock(&OldIrq);
  902. if (pIrp && !pConnEle->pIrp->Cancel)
  903. {
  904. IoSetCancelRoutine(pIrp,NULL);
  905. }
  906. else
  907. {
  908. Cancelled = TRUE;
  909. }
  910. IoReleaseCancelSpinLock(OldIrq);
  911. #endif
  912. if (!Cancelled)
  913. {
  914. //
  915. // The enqueuing can fail only if we run out of resources
  916. // because we have already verified the device state earlier
  917. // and have not released the JointLock since then, which
  918. // would not that state to be modified.
  919. //
  920. CTEQueueForNonDispProcessing(DelayedReConnect,
  921. pTracker,
  922. Context,
  923. NULL,
  924. pDeviceContext,
  925. TRUE);
  926. }
  927. // ...else The irp was already returned, since NtCancelSession
  928. // Must have already run, so just return
  929. NBT_DEREFERENCE_DEVICE(pDeviceContext, REF_DEV_OUTBOUND, TRUE);
  930. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  931. RejectSession(pLowerConn,0,0,FALSE);
  932. // remove the referenced added when the lower and upper
  933. // connections were attached in nbtconnect.
  934. //
  935. NBT_DEREFERENCE_CONNECTION (pConnEle, REF_CONN_CONNECT);
  936. goto ExitCode;
  937. #ifndef MULTIPLE_WINS
  938. }
  939. #endif
  940. }
  941. // the connection will be disconnected by the Call to RejectSession
  942. // below, so set the state to Associated so the disconnect indication
  943. // handler will not complete the client's irp too
  944. //
  945. CHECK_PTR(pConnEle);
  946. SET_STATE_UPPER (pConnEle, NBT_ASSOCIATED);
  947. pConnEle->pLowerConnId = NULL;
  948. CTESpinFreeAtDpc(pLowerConn);
  949. //
  950. // if nbtcleanupconnection has not been called yet, relist it.
  951. //
  952. if (state != NBT_IDLE)
  953. {
  954. RelistConnection(pConnEle);
  955. }
  956. IF_DBG(NBT_DEBUG_DISCONNECT)
  957. KdPrint(("Nbt.Outbound: Disconnecting... Failed connection Setup %X Lowercon %X\n",
  958. pConnEle,pLowerConn));
  959. GetIrpIfNotCancelled2(pConnEle,&pIrp);
  960. //
  961. // if SessionTimedOut has run, it has set the refcount to zero
  962. //
  963. if (pTracker->RefConn == 0)
  964. {
  965. //
  966. // remove the reference done when FindNameOrQuery was called, or when
  967. // SessionSetupContinue ran
  968. //
  969. if ((pTracker->pNameAddr->Verify == REMOTE_NAME) && // Remote names only!
  970. (pTracker->pNameAddr->NameTypeState & STATE_RESOLVED) &&
  971. (pTracker->pNameAddr->RefCount == 2))
  972. {
  973. //
  974. // If no one else is referencing the name, then delete it from
  975. // the hash table.
  976. //
  977. NBT_DEREFERENCE_NAMEADDR (pTracker->pNameAddr, REF_NAME_REMOTE, TRUE);
  978. }
  979. NBT_DEREFERENCE_NAMEADDR (pTracker->pNameAddr, REF_NAME_CONNECT, TRUE);
  980. FreeTracker(pTracker,FREE_HDR | RELINK_TRACKER);
  981. }
  982. else
  983. {
  984. pTracker->RefConn--;
  985. }
  986. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  987. if (status != STATUS_INVALID_DEVICE_REQUEST)
  988. {
  989. // this should cause a disconnect indication to come from the
  990. // transport which will close the connection to the transport
  991. //
  992. RejectSession(pLowerConn,0,0,FALSE);
  993. NBT_DEREFERENCE_DEVICE(pDeviceContext, REF_DEV_OUTBOUND, FALSE);
  994. }
  995. //
  996. // tell the client that the session setup failed and disconnect
  997. // the connection
  998. //
  999. if (pIrp)
  1000. {
  1001. status = STATUS_REMOTE_NOT_LISTENING;
  1002. if (ErrorCode != SESSION_CALLED_NAME_NOT_PRESENT)
  1003. {
  1004. status = STATUS_BAD_NETWORK_PATH;
  1005. }
  1006. CTEIoComplete(pIrp, status, 0 ) ;
  1007. }
  1008. }
  1009. ExitCode:
  1010. // the LowerConn Lock is held prior to calling this routine. It is freed
  1011. // at the start of this routine and held here again
  1012. CTESpinLockAtDpc(pLowerConn);
  1013. return(STATUS_SUCCESS);
  1014. }
  1015. //----------------------------------------------------------------------------
  1016. VOID
  1017. GetIrpIfNotCancelled2(
  1018. IN tCONNECTELE *pConnEle,
  1019. OUT PIRP *ppIrp
  1020. )
  1021. /*++
  1022. Routine Description:
  1023. This routine coordinates access to the Irp by getting the spin lock on
  1024. the client, getting the Irp and clearing the irp in the structure. The
  1025. Irp cancel routines also check the pConnEle->pIrp and if null they do not
  1026. find the irp, then they return without completing the irp.
  1027. This version of the routine is called with NbtConfig.JointLock held.
  1028. Arguments:
  1029. Return Value:
  1030. NTSTATUS - Status of receive operation
  1031. --*/
  1032. {
  1033. CTELockHandle OldIrq;
  1034. CTESpinLock(pConnEle,OldIrq);
  1035. *ppIrp = pConnEle->pIrp;
  1036. CHECK_PTR(pConnEle);
  1037. pConnEle->pIrp = NULL;
  1038. CTESpinFree(pConnEle,OldIrq);
  1039. }
  1040. //----------------------------------------------------------------------------
  1041. VOID
  1042. GetIrpIfNotCancelled(
  1043. IN tCONNECTELE *pConnEle,
  1044. OUT PIRP *ppIrp
  1045. )
  1046. /*++
  1047. Routine Description:
  1048. This routine coordinates access to the Irp by getting the spin lock on
  1049. the client, getting the Irp and clearing the irp in the structure. The
  1050. Irp cancel routines also check the pConnEle->pIrp and if null they do not
  1051. find the irp, then they return without completing the irp.
  1052. This version of the routine is called with NbtConfig.JointLock free.
  1053. Arguments:
  1054. Return Value:
  1055. NTSTATUS - Status of receive operation
  1056. --*/
  1057. {
  1058. CTELockHandle OldIrq;
  1059. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  1060. GetIrpIfNotCancelled2(pConnEle,ppIrp);
  1061. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1062. }
  1063. //----------------------------------------------------------------------------
  1064. NTSTATUS
  1065. RejectAnyData(
  1066. IN PVOID ReceiveEventContext,
  1067. IN tLOWERCONNECTION *pLowerConn,
  1068. IN USHORT ReceiveFlags,
  1069. IN ULONG BytesIndicated,
  1070. IN ULONG BytesAvailable,
  1071. OUT PULONG BytesTaken,
  1072. IN PVOID pTsdu,
  1073. OUT PVOID *ppIrp
  1074. )
  1075. /*++
  1076. Routine Description:
  1077. This routine is the receive event indication handler when the connection
  1078. is not up - i.e. nbt thinks no data should be arriving. We just eat the
  1079. data and return. This routine should not get called.
  1080. Arguments:
  1081. Return Value:
  1082. NTSTATUS - Status of receive operation
  1083. --*/
  1084. {
  1085. NTSTATUS status;
  1086. //
  1087. // take all of the data so that a disconnect will not be held up
  1088. // by data still in the transport.
  1089. //
  1090. *BytesTaken = BytesAvailable;
  1091. IF_DBG(NBT_DEBUG_DISCONNECT)
  1092. KdPrint(("Nbt.RejectAnyData: Got Session Data in state %X, StateRcv= %X\n",pLowerConn->State,
  1093. pLowerConn->StateRcv));
  1094. return(STATUS_SUCCESS);
  1095. }
  1096. //----------------------------------------------------------------------------
  1097. VOID
  1098. RejectSession(
  1099. IN tLOWERCONNECTION *pLowerConn,
  1100. IN ULONG StatusCode,
  1101. IN ULONG SessionStatus,
  1102. IN BOOLEAN SendNegativeSessionResponse
  1103. )
  1104. /*++
  1105. Routine Description:
  1106. This routine sends a negative session response (if the boolean is set)
  1107. and then disconnects the connection.
  1108. Cleanup connection could have been called to disconnect the call,
  1109. and it changes the state to disconnecting, so don't disconnected
  1110. again if that is happening.
  1111. Arguments:
  1112. Return Value:
  1113. The function value is the status of the operation.
  1114. --*/
  1115. {
  1116. CTELockHandle OldIrq;
  1117. CTELockHandle OldIrq1;
  1118. CTELockHandle OldIrq2;
  1119. NTSTATUS status;
  1120. tCONNECTELE *pConnEle;
  1121. BOOLEAN DerefConnEle=FALSE;
  1122. //
  1123. // There is no listen event handler so return a status code to
  1124. // the caller indicating that this end is between "listens" and
  1125. // that they should try the setup again in a few milliseconds.
  1126. //
  1127. IF_DBG(NBT_DEBUG_DISCONNECT)
  1128. KdPrint(("Nbt.RejectSession: No Listen or Connect Handlr so Disconnect! LowerConn=%X Session Status=%X\n",
  1129. pLowerConn,SessionStatus));
  1130. if (SendNegativeSessionResponse)
  1131. {
  1132. status = TcpSendSessionResponse(pLowerConn,
  1133. StatusCode,
  1134. SessionStatus);
  1135. }
  1136. // need to hold this lock if we are to un connect the lower and upper
  1137. // connnections
  1138. CTESpinLock(&NbtConfig.JointLock,OldIrq1);
  1139. CTESpinLock(pLowerConn->pDeviceContext,OldIrq2);
  1140. CTESpinLock(pLowerConn,OldIrq);
  1141. CHECK_PTR(pLowerConn);
  1142. if ((pLowerConn->State < NBT_DISCONNECTING) &&
  1143. (pLowerConn->State > NBT_CONNECTING))
  1144. {
  1145. if (pLowerConn->State == NBT_SESSION_INBOUND)
  1146. {
  1147. //
  1148. // Previously, the LowerConnection was in the SESSION_INBOUND state
  1149. // hence we have to remove it from the WaitingForInbound Q and put
  1150. // it on the active LowerConnection list!
  1151. //
  1152. RemoveEntryList (&pLowerConn->Linkage);
  1153. InsertTailList (&pLowerConn->pDeviceContext->LowerConnection, &pLowerConn->Linkage);
  1154. InterlockedDecrement (&pLowerConn->pDeviceContext->NumWaitingForInbound);
  1155. //
  1156. // Change the RefCount Context to Connected!
  1157. //
  1158. NBT_SWAP_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_WAITING_INBOUND, REF_LOWC_CONNECTED, TRUE);
  1159. }
  1160. SET_STATE_LOWER (pLowerConn, NBT_DISCONNECTING);
  1161. SetStateProc( pLowerConn, RejectAnyData ) ;
  1162. pConnEle = pLowerConn->pUpperConnection;
  1163. if (pConnEle)
  1164. {
  1165. CHECK_PTR(pConnEle);
  1166. DerefConnEle = TRUE;
  1167. NBT_DISASSOCIATE_CONNECTION (pConnEle, pLowerConn);
  1168. SET_STATE_UPPER (pConnEle, NBT_DISCONNECTING);
  1169. }
  1170. CTESpinFree(pLowerConn,OldIrq);
  1171. CTESpinFree(pLowerConn->pDeviceContext,OldIrq2);
  1172. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1173. SendTcpDisconnect((PVOID)pLowerConn);
  1174. }
  1175. else
  1176. {
  1177. CTESpinFree(pLowerConn,OldIrq);
  1178. CTESpinFree(pLowerConn->pDeviceContext,OldIrq2);
  1179. CTESpinFree(&NbtConfig.JointLock,OldIrq1);
  1180. }
  1181. if (DerefConnEle)
  1182. {
  1183. NBT_DEREFERENCE_CONNECTION (pConnEle, REF_CONN_CONNECT);
  1184. }
  1185. }
  1186. //----------------------------------------------------------------------------
  1187. NTSTATUS
  1188. FindSessionEndPoint(
  1189. IN PVOID pTsdu,
  1190. IN PVOID ConnectionContext,
  1191. IN ULONG BytesIndicated,
  1192. OUT tCLIENTELE **ppClientEle,
  1193. OUT PVOID *ppRemoteAddress,
  1194. OUT PULONG pRemoteAddressLength
  1195. )
  1196. /*++
  1197. Routine Description:
  1198. This routine attempts to find an end point on the node with the matching
  1199. net bios name. It is called at session setup time when a session request
  1200. PDU has arrived. The routine returns the Client Element ptr.
  1201. The JointLock is held prior to calling this routine!
  1202. Arguments:
  1203. Return Value:
  1204. NTSTATUS - Status of receive operation
  1205. --*/
  1206. {
  1207. NTSTATUS status;
  1208. tCLIENTELE *pClientEle;
  1209. tLOWERCONNECTION *pLowerConn;
  1210. CHAR pName[NETBIOS_NAME_SIZE];
  1211. PUCHAR pScope;
  1212. tNAMEADDR *pNameAddr;
  1213. tADDRESSELE *pAddressEle;
  1214. PLIST_ENTRY pEntry;
  1215. PLIST_ENTRY pHead;
  1216. ULONG lNameSize;
  1217. tSESSIONREQ UNALIGNED *pSessionReq = (tSESSIONREQ UNALIGNED *)pTsdu;
  1218. ULONG sType;
  1219. CTELockHandle OldIrq1;
  1220. CTELockHandle OldIrq2;
  1221. PUCHAR pSrcName;
  1222. BOOLEAN Found;
  1223. // get the ptr to the lower connection, and from that get the ptr to the
  1224. // upper connection block
  1225. pLowerConn = (tLOWERCONNECTION *)ConnectionContext;
  1226. if (pSessionReq->Hdr.Type != NBT_SESSION_REQUEST)
  1227. {
  1228. KdPrint (("Nbt.FindSessionEndPoint: WARNING!!! Rejecting Request, pSessionReq->Hdr.Type=<%d>!=<%d>\n",
  1229. pSessionReq->Hdr.Type, NBT_SESSION_REQUEST));
  1230. return(SESSION_UNSPECIFIED_ERROR);
  1231. }
  1232. // get the called name out of the PDU
  1233. status = ConvertToAscii ((PCHAR)&pSessionReq->CalledName,
  1234. BytesIndicated - FIELD_OFFSET(tSESSIONREQ,CalledName),
  1235. pName,
  1236. &pScope,
  1237. &lNameSize);
  1238. if (!NT_SUCCESS(status))
  1239. {
  1240. KdPrint (("Nbt.FindSessionEndPoint: WARNING!!! Rejecting Request, ConvertToAscii FAILed!\n"));
  1241. NbtTrace(NBT_TRACE_INBOUND, ("ConvertToAscii returns %!status!", status));
  1242. return(SESSION_UNSPECIFIED_ERROR);
  1243. }
  1244. // now try to find the called name in this node's Local table
  1245. //
  1246. //
  1247. // in case a disconnect came in while the spin lock was released
  1248. //
  1249. if (pLowerConn->State != NBT_SESSION_INBOUND)
  1250. {
  1251. return(STATUS_UNSUCCESSFUL);
  1252. }
  1253. pNameAddr = FindName (NBT_LOCAL,pName,pScope,&sType);
  1254. if (!pNameAddr)
  1255. {
  1256. NbtTrace(NBT_TRACE_INBOUND, ("FindName cannot find %!NBTNAME!<%02x>", pName, (unsigned)pName[15]));
  1257. return(SESSION_CALLED_NAME_NOT_PRESENT);
  1258. }
  1259. // we got to here because the name has resolved to a name on this node,
  1260. // so accept the Session setup.
  1261. //
  1262. pAddressEle = (tADDRESSELE *)pNameAddr->pAddressEle;
  1263. // lock the address structure until we find a client on the list
  1264. //
  1265. CTESpinLock(pAddressEle,OldIrq1);
  1266. if (IsListEmpty(&pAddressEle->ClientHead))
  1267. {
  1268. CTESpinFree(pAddressEle,OldIrq1);
  1269. NbtTrace(NBT_TRACE_INBOUND, ("No one is listening on %!NBTNAME!<%02x>", pName, (unsigned)pName[15]));
  1270. return(SESSION_NOT_LISTENING_ON_CALLED_NAME);
  1271. }
  1272. //
  1273. // get the first client on the list that is bound to the same
  1274. // devicecontext as the connection, with a listen posted, or a valid
  1275. // Connect event handler setup -
  1276. //
  1277. Found = FALSE;
  1278. pHead = &pAddressEle->ClientHead;
  1279. pEntry = pHead->Flink;
  1280. while (pEntry != pHead)
  1281. {
  1282. pClientEle = CONTAINING_RECORD(pEntry,tCLIENTELE,Linkage);
  1283. CTESpinLock(pClientEle,OldIrq2);
  1284. if ((pClientEle->pDeviceContext == pLowerConn->pDeviceContext) &&
  1285. (NBT_VERIFY_HANDLE(pClientEle, NBT_VERIFY_CLIENT))) // Ensure that client is not going away!
  1286. {
  1287. //
  1288. // if there is a listen posted or a Connect Event Handler
  1289. // then allow the connect attempt to carry on, otherwise go to the
  1290. // next client in the list
  1291. //
  1292. if ((!IsListEmpty(&pClientEle->ListenHead)) ||
  1293. (pClientEle->ConEvContext))
  1294. {
  1295. Found = TRUE;
  1296. break;
  1297. }
  1298. }
  1299. CTESpinFree(pClientEle,OldIrq2);
  1300. pEntry = pEntry->Flink;
  1301. }
  1302. if (!Found)
  1303. {
  1304. CTESpinFree(pAddressEle,OldIrq1);
  1305. NbtTrace(NBT_TRACE_INBOUND, ("No one is listening on %!NBTNAME!<%02x>", pName, (unsigned)pName[15]));
  1306. return(SESSION_NOT_LISTENING_ON_CALLED_NAME);
  1307. }
  1308. //
  1309. // Ensure we are calculating the Max Buffer size (3rd parameter) properly
  1310. // Bug# 126135
  1311. //
  1312. pSrcName = (PUCHAR)((PUCHAR)&pSessionReq->CalledName.NameLength + 1+lNameSize);
  1313. status = MakeRemoteAddressStructure(
  1314. pSrcName,
  1315. 0,
  1316. BytesIndicated-(FIELD_OFFSET(tSESSIONREQ,CalledName.NameLength)+1+lNameSize),
  1317. ppRemoteAddress,
  1318. pRemoteAddressLength,
  1319. 1);
  1320. if (!NT_SUCCESS(status))
  1321. {
  1322. CTESpinFree(pClientEle,OldIrq2);
  1323. CTESpinFree(pAddressEle,OldIrq1);
  1324. KdPrint (("Nbt.FindSessionEndPoint: WARNING!!! Rejecting Request, MakeRemoteAddressStructure FAILed!\n"));
  1325. NbtTrace(NBT_TRACE_INBOUND, ("MakeRemoteAddressStructure returns %!status! on %!NBTNAME!<%02x>",
  1326. status, pName, (unsigned)pName[15]));
  1327. if (status == STATUS_INSUFFICIENT_RESOURCES)
  1328. {
  1329. return(SESSION_CALLED_NAME_PRESENT_NO_RESRC);
  1330. }
  1331. else
  1332. {
  1333. return(SESSION_UNSPECIFIED_ERROR);
  1334. }
  1335. }
  1336. // prevent the client from disappearing before we can indicate to him
  1337. //
  1338. NBT_REFERENCE_CLIENT(pClientEle);
  1339. CTESpinFree(pClientEle,OldIrq2);
  1340. CTESpinFree(pAddressEle,OldIrq1);
  1341. *ppClientEle = pClientEle;
  1342. return(STATUS_SUCCESS);
  1343. }
  1344. //----------------------------------------------------------------------------
  1345. NTSTATUS
  1346. MakeRemoteAddressStructure(
  1347. IN PCHAR pHalfAsciiName,
  1348. IN PVOID pSourceAddr,
  1349. IN ULONG lMaxNameSize,
  1350. OUT PVOID *ppRemoteAddress,
  1351. OUT PULONG pRemoteAddressLength,
  1352. IN ULONG NumAddr
  1353. )
  1354. /*++
  1355. Routine Description:
  1356. This routine makes up the remote addres structure with the netbios name
  1357. of the source in it, so that the info can be passed to the client...what
  1358. a bother to do this!
  1359. Arguments:
  1360. Return Value:
  1361. NTSTATUS - Status of receive operation
  1362. --*/
  1363. {
  1364. NTSTATUS status;
  1365. ULONG lNameSize;
  1366. CHAR pName[NETBIOS_NAME_SIZE];
  1367. PUCHAR pScope;
  1368. PTA_NETBIOS_ADDRESS pRemoteAddress;
  1369. // make up the remote address data structure to pass to the client
  1370. status = ConvertToAscii(
  1371. pHalfAsciiName,
  1372. lMaxNameSize,
  1373. pName,
  1374. &pScope,
  1375. &lNameSize);
  1376. if (!NT_SUCCESS(status))
  1377. {
  1378. KdPrint (("Nbt.MakeRemoteAddressStructure: WARNING!!! Rejecting Request, ConvertToAscii FAILed!\n"));
  1379. return(status);
  1380. }
  1381. pRemoteAddress = (PTA_NETBIOS_ADDRESS)NbtAllocMem(
  1382. NumAddr * sizeof(TA_NETBIOS_ADDRESS),NBT_TAG('2'));
  1383. if (!pRemoteAddress)
  1384. {
  1385. return(STATUS_INSUFFICIENT_RESOURCES);
  1386. }
  1387. pRemoteAddress->TAAddressCount = NumAddr;
  1388. pRemoteAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_NETBIOS);
  1389. pRemoteAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_NETBIOS;
  1390. pRemoteAddress->Address[0].Address[0].NetbiosNameType = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
  1391. CTEMemCopy(pRemoteAddress->Address[0].Address[0].NetbiosName, pName,NETBIOS_NAME_SIZE);
  1392. *pRemoteAddressLength = FIELD_OFFSET(TA_NETBIOS_ADDRESS, Address[0].Address[0].NetbiosName[NETBIOS_NAME_SIZE]);
  1393. //
  1394. // Copy over the IP address also.
  1395. //
  1396. if (NumAddr == 2)
  1397. {
  1398. TA_ADDRESS *pTAAddr;
  1399. PTRANSPORT_ADDRESS pSourceAddress;
  1400. pSourceAddress = (PTRANSPORT_ADDRESS)pSourceAddr;
  1401. pTAAddr = (TA_ADDRESS *) (((PUCHAR)pRemoteAddress)
  1402. + pRemoteAddress->Address[0].AddressLength
  1403. + FIELD_OFFSET(TA_NETBIOS_ADDRESS, Address[0].Address));
  1404. pTAAddr->AddressLength = sizeof(TDI_ADDRESS_IP);
  1405. pTAAddr->AddressType = TDI_ADDRESS_TYPE_IP;
  1406. ((TDI_ADDRESS_IP UNALIGNED *)&pTAAddr->Address[0])->in_addr = ((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->in_addr;
  1407. *pRemoteAddressLength += (FIELD_OFFSET(TA_ADDRESS, Address) + pTAAddr->AddressLength);
  1408. }
  1409. *ppRemoteAddress = (PVOID)pRemoteAddress;
  1410. // *pRemoteAddressLength = sizeof(TA_NETBIOS_ADDRESS);
  1411. // *pRemoteAddressLength = FIELD_OFFSET(TA_NETBIOS_ADDRESS, Address[0].Address[0]);
  1412. return(STATUS_SUCCESS);
  1413. }
  1414. //----------------------------------------------------------------------------
  1415. NTSTATUS
  1416. ConnectHndlrNotOs (
  1417. IN PVOID pConnectionContext,
  1418. IN LONG RemoteAddressLength,
  1419. IN PVOID pRemoteAddress,
  1420. IN int UserDataLength,
  1421. IN VOID UNALIGNED *pUserData,
  1422. OUT CONNECTION_CONTEXT *ppConnectionId
  1423. )
  1424. /*++
  1425. Routine Description:
  1426. This routine is the receive connect indication handler.
  1427. It is called when a TCP connection is being setup for a NetBios session.
  1428. It simply allocates a connection and returns that information to the
  1429. transport so that the connect indication can be accepted.
  1430. Arguments:
  1431. pClientEle - ptr to the connecition record for this session
  1432. Return Value:
  1433. NTSTATUS - Status of receive operation
  1434. --*/
  1435. {
  1436. CTELockHandle OldIrq;
  1437. PLIST_ENTRY pList;
  1438. tLOWERCONNECTION *pLowerConn;
  1439. tDEVICECONTEXT *pDeviceContext;
  1440. PTRANSPORT_ADDRESS pSrcAddress;
  1441. NTSTATUS Status;
  1442. pDeviceContext = (tDEVICECONTEXT *)pConnectionContext;
  1443. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  1444. CTESpinLockAtDpc(pDeviceContext);
  1445. // check that the source is an IP address
  1446. //
  1447. pSrcAddress = pRemoteAddress;
  1448. if ((pSrcAddress->Address[0].AddressType != TDI_ADDRESS_TYPE_IP) ||
  1449. (IsListEmpty(&pDeviceContext->LowerConnFreeHead)) ||
  1450. ((IsDeviceNetbiosless(pDeviceContext)) && // Bug # 282190
  1451. (!pDeviceContext->NumServers)))
  1452. {
  1453. if (pSrcAddress->Address[0].AddressType != TDI_ADDRESS_TYPE_IP) {
  1454. NbtTrace(NBT_TRACE_INBOUND, ("Reject connection on %Z: Non-IP address", &pDeviceContext->BindName));
  1455. } else {
  1456. NbtTrace(NBT_TRACE_INBOUND, ("Reject connection from %!ipaddr!:%d: %s%Z NumServers=%d",
  1457. ((PTDI_ADDRESS_IP)&pSrcAddress->Address[0].Address[0])->in_addr,
  1458. ((PTDI_ADDRESS_IP)&pSrcAddress->Address[0].Address[0])->sin_port,
  1459. (IsListEmpty(&pDeviceContext->LowerConnFreeHead)?"Out of free LowerConnection ":""),
  1460. &pDeviceContext->BindName, pDeviceContext->NumServers));
  1461. }
  1462. Status = STATUS_DATA_NOT_ACCEPTED;
  1463. }
  1464. else
  1465. {
  1466. //
  1467. // get a free connection to the transport provider to accept this
  1468. // incoming connnection on.
  1469. //
  1470. pList = RemoveHeadList(&pDeviceContext->LowerConnFreeHead);
  1471. pLowerConn = CONTAINING_RECORD (pList,tLOWERCONNECTION,Linkage);
  1472. InterlockedDecrement (&pDeviceContext->NumFreeLowerConnections);
  1473. //
  1474. // Move the idle connection to the WaitingForInbound connection list
  1475. //
  1476. InsertTailList (&pDeviceContext->WaitingForInbound,pList);
  1477. InterlockedIncrement (&pDeviceContext->NumWaitingForInbound);
  1478. SET_STATE_LOWER (pLowerConn, NBT_SESSION_INBOUND);
  1479. SET_STATERCV_LOWER (pLowerConn, NORMAL, Inbound);
  1480. // increase the reference count because we are now connected. Decrement
  1481. // it when we disconnect.
  1482. //
  1483. NBT_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_WAITING_INBOUND);
  1484. pLowerConn->bOriginator = FALSE; // this end is NOT the originator
  1485. // save the source clients IP address into the connection Structure
  1486. // *TODO check if we need to do this or not
  1487. //
  1488. pLowerConn->SrcIpAddr = ((PTDI_ADDRESS_IP)&pSrcAddress->Address[0].Address[0])->in_addr;
  1489. *ppConnectionId = (PVOID)pLowerConn;
  1490. Status = STATUS_SUCCESS;
  1491. }
  1492. //
  1493. // If there are less than 2 connections remaining, we allocate another one. The check
  1494. // below is for 0 or 1 connection.
  1495. // In order to protect ourselves from SYN ATTACKS, allocate NbtConfig.SpecialConnIncrement more now until
  1496. // a certain (registry config) value is exhausted (NOTE this number is global and not
  1497. // per device).
  1498. //
  1499. if (((pDeviceContext->NumFreeLowerConnections < NbtConfig.MinFreeLowerConnections) ||
  1500. (pDeviceContext->NumFreeLowerConnections < (pDeviceContext->TotalLowerConnections/10))) &&
  1501. (pDeviceContext->NumQueuedForAlloc < (2*NbtConfig.SpecialConnIncrement)))
  1502. {
  1503. KdPrint(("Nbt.ConnectHndlrNotOs: Queueing SpecialLowerConn: pDevice=<%p>, NumSpecialLowerConn=%d\n",
  1504. pDeviceContext, pDeviceContext->NumSpecialLowerConn));
  1505. NbtTrace(NBT_TRACE_INBOUND, ("Increase special lower connection to %d %Z %!ipaddr!:%d",
  1506. pDeviceContext->NumSpecialLowerConn, &pDeviceContext->BindName,
  1507. pLowerConn->SrcIpAddr,
  1508. ((PTDI_ADDRESS_IP)&pSrcAddress->Address[0].Address[0])->sin_port));
  1509. #ifdef _PNP_POWER_
  1510. if (!NbtConfig.Unloading)
  1511. #endif // _PNP_POWER_
  1512. {
  1513. if (NT_SUCCESS (CTEQueueForNonDispProcessing( DelayedAllocLowerConnSpecial,
  1514. NULL,
  1515. NULL,
  1516. NULL,
  1517. pDeviceContext,
  1518. TRUE)))
  1519. {
  1520. InterlockedExchangeAdd (&pDeviceContext->NumQueuedForAlloc, NbtConfig.SpecialConnIncrement);
  1521. } else {
  1522. NbtTrace(NBT_TRACE_INBOUND, ("Out of memory"));
  1523. }
  1524. }
  1525. }
  1526. CTESpinFreeAtDpc(pDeviceContext);
  1527. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1528. return(Status);
  1529. }
  1530. //----------------------------------------------------------------------------
  1531. NTSTATUS
  1532. DisconnectHndlrNotOs (
  1533. PVOID EventContext,
  1534. PVOID ConnectionContext,
  1535. ULONG DisconnectDataLength,
  1536. PVOID pDisconnectData,
  1537. ULONG DisconnectInformationLength,
  1538. PVOID pDisconnectInformation,
  1539. ULONG DisconnectIndicators
  1540. )
  1541. /*++
  1542. Routine Description:
  1543. This routine is the receive disconnect indication handler. It is called
  1544. by the transport when a connection disconnects. It checks the state of
  1545. the lower connection and basically returns a disconnect request to the
  1546. transport, except in the case where there is an active session. In this
  1547. case it calls the the clients disconnect indication handler. The client
  1548. then turns around and calls NbtDisconnect(in some cases), which passes a disconnect
  1549. back to the transport. The transport won't disconnect until it receives
  1550. a disconnect request from its client (NBT). If the flag TDI_DISCONNECT_ABORT
  1551. is set then there is no need to pass back a disconnect to the transport.
  1552. Since the client doesn't always issue a disconnect (i.e. the server),
  1553. this routine always turns around and issues a disconnect to the transport.
  1554. In the disconnect done handling, the lower connection is put back on the
  1555. free list if it is an inbound connection. For out bound connection the
  1556. lower and upper connections are left connected, since these will always
  1557. receive a cleanup and close connection from the client (i.e. until the
  1558. client does a close the lower connection will not be freed for outbound
  1559. connections).
  1560. Arguments:
  1561. pClientEle - ptr to the connecition record for this session
  1562. Return Value:
  1563. NTSTATUS - Status of receive operation
  1564. --*/
  1565. {
  1566. NTSTATUS status;
  1567. CTELockHandle OldIrq;
  1568. CTELockHandle OldIrq2;
  1569. CTELockHandle OldIrq3;
  1570. CTELockHandle OldIrq4;
  1571. tLOWERCONNECTION *pLowerConn;
  1572. tCONNECTELE *pConnectEle;
  1573. tCLIENTELE *pClientEle;
  1574. enum eSTATE state, stateLower;
  1575. BOOLEAN CleanupLower=FALSE;
  1576. PIRP pIrp= NULL;
  1577. PIRP pIrpClose= NULL;
  1578. PIRP pIrpRcv= NULL;
  1579. tDGRAM_SEND_TRACKING *pTracker;
  1580. tTIMERQENTRY *pTimerEntry;
  1581. BOOLEAN InsertOnList=FALSE;
  1582. BOOLEAN DisconnectIt=FALSE;
  1583. ULONG StateRcv;
  1584. COMPLETIONCLIENT pCompletion;
  1585. tDEVICECONTEXT *pDeviceContext = NULL;
  1586. pLowerConn = (tLOWERCONNECTION *)ConnectionContext;
  1587. pConnectEle = pLowerConn->pUpperConnection;
  1588. PUSH_LOCATION(0x63);
  1589. CHECK_PTR(pLowerConn);
  1590. IF_DBG(NBT_DEBUG_DISCONNECT)
  1591. KdPrint(("Nbt.DisconnectHndlrNotOs: Disc Indication, LowerConn state = %X %X\n",
  1592. pLowerConn->State,pLowerConn));
  1593. // get the current state with the spin lock held to avoid a race condition
  1594. // with the client disconnecting
  1595. //
  1596. if (pConnectEle)
  1597. {
  1598. CHECK_PTR(pConnectEle);
  1599. if (!NBT_VERIFY_HANDLE2 (pConnectEle, NBT_VERIFY_CONNECTION, NBT_VERIFY_CONNECTION_DOWN))
  1600. {
  1601. ASSERTMSG ("Nbt.DisconnectHndlrNotOs: Disconnect indication after already disconnected!!\n", 0);
  1602. NbtTrace(NBT_TRACE_DISCONNECT, ("Disconnect indication after already disconnected!!"));
  1603. return STATUS_UNSUCCESSFUL ;
  1604. }
  1605. //
  1606. // We got a case where the ClientEle ptr was null. This shd not happen since the
  1607. // connection shd be associated at this time.
  1608. // Assert for that case to track this better.
  1609. //
  1610. pClientEle = pConnectEle->pClientEle;
  1611. CHECK_PTR(pClientEle);
  1612. if (!NBT_VERIFY_HANDLE2 (pClientEle, NBT_VERIFY_CLIENT, NBT_VERIFY_CLIENT_DOWN))
  1613. {
  1614. ASSERTMSG ("Nbt.DisconnectHndlrNotOs: Bad Client Handle!!\n", 0);
  1615. return STATUS_UNSUCCESSFUL ;
  1616. }
  1617. // need to hold the joint lock if unconnecting the lower and upper
  1618. // connections.
  1619. //
  1620. CTESpinLock(&NbtConfig.JointLock,OldIrq4);
  1621. CTESpinLock(pClientEle,OldIrq3);
  1622. CTESpinLock(pConnectEle,OldIrq2);
  1623. CTESpinLock(pLowerConn,OldIrq);
  1624. NbtTrace(NBT_TRACE_DISCONNECT, ("Disconnection Indication, LowerConn=%p UpperConn=%p ClientEle=%p "
  1625. "state=%x %!NBTNAME!<%02x> <==> %!NBTNAME!<%02x>",
  1626. pLowerConn, pConnectEle, pClientEle,
  1627. pLowerConn->State, pClientEle->pAddress->pNameAddr->Name,
  1628. (unsigned)pClientEle->pAddress->pNameAddr->Name[15],
  1629. pConnectEle->RemoteName, (unsigned)pConnectEle->RemoteName[15]));
  1630. state = pConnectEle->state;
  1631. stateLower = pLowerConn->State;
  1632. #ifdef VXD
  1633. DbgPrint("DisconnectHndlrNotOs: pConnectEle->state = 0x") ;
  1634. DbgPrintNum( (ULONG) state ) ;
  1635. DbgPrint("pLowerConn->state = 0x") ; DbgPrintNum( (ULONG) stateLower ) ;
  1636. DbgPrint("\r\n") ;
  1637. #endif
  1638. if ((state > NBT_ASSOCIATED) && (state < NBT_DISCONNECTING))
  1639. {
  1640. PUSH_LOCATION(0x63);
  1641. CHECK_PTR(pConnectEle);
  1642. //
  1643. // this irp gets returned to the client below in the case statement
  1644. // Except in the connecting state where the transport still has
  1645. // the irp. In that case we let SessionStartupContinue complete
  1646. // the irp.
  1647. //
  1648. if ((pConnectEle->pIrp) && (state > NBT_CONNECTING))
  1649. {
  1650. pIrp = pConnectEle->pIrp;
  1651. pConnectEle->pIrp = NULL;
  1652. }
  1653. //
  1654. // if there is a receive irp, get it out of pConnEle since pConnEle
  1655. // will be requeued and could get used again before we try to
  1656. // complete this irp down below. Null the cancel routine if not
  1657. // cancelled and just complete it below.
  1658. //
  1659. if (((state == NBT_SESSION_UP) || (state == NBT_SESSION_WAITACCEPT))
  1660. && (pConnectEle->pIrpRcv))
  1661. {
  1662. CTELockHandle OldIrql;
  1663. pIrpRcv = pConnectEle->pIrpRcv;
  1664. #ifndef VXD
  1665. IoAcquireCancelSpinLock(&OldIrql);
  1666. //
  1667. // if its already cancelled then don't complete it again
  1668. // down below
  1669. //
  1670. if (pIrpRcv->Cancel)
  1671. {
  1672. pIrpRcv = NULL;
  1673. }
  1674. else
  1675. {
  1676. IoSetCancelRoutine(pIrpRcv,NULL);
  1677. }
  1678. IoReleaseCancelSpinLock(OldIrql);
  1679. #endif
  1680. pConnectEle->pIrpRcv = NULL;
  1681. }
  1682. // This irp is used for DisconnectWait
  1683. //
  1684. if (pIrpClose = pConnectEle->pIrpClose)
  1685. {
  1686. pConnectEle->pIrpClose = NULL;
  1687. }
  1688. #ifdef VXD
  1689. if ( pLowerConn->StateRcv == PARTIAL_RCV &&
  1690. (pLowerConn->fOnPartialRcvList == TRUE) )
  1691. {
  1692. RemoveEntryList( &pLowerConn->PartialRcvList ) ;
  1693. pLowerConn->fOnPartialRcvList = FALSE;
  1694. InitializeListHead(&pLowerConn->PartialRcvList);
  1695. }
  1696. #endif
  1697. SET_STATE_UPPER (pConnectEle, NBT_ASSOCIATED);
  1698. SET_STATE_LOWER (pLowerConn, NBT_DISCONNECTING);
  1699. NBT_DISASSOCIATE_CONNECTION (pConnectEle, pLowerConn);
  1700. //
  1701. // save whether it is a disconnect abort or disconnect release
  1702. // in case the client does a disconnect wait and wants the
  1703. // real disconnect status i.e. they do not have a disconnect
  1704. // indication handler
  1705. //
  1706. pConnectEle->DiscFlag = (UCHAR)DisconnectIndicators;
  1707. //
  1708. // pConnectEle is dereferenced below, now that the lower conn
  1709. // no longer points to it.
  1710. //
  1711. InsertOnList = TRUE;
  1712. DisconnectIt = TRUE;
  1713. //
  1714. // put pConnEle back on the list of idle connection for this
  1715. // client
  1716. //
  1717. RemoveEntryList(&pConnectEle->Linkage);
  1718. InsertTailList(&pClientEle->ConnectHead,&pConnectEle->Linkage);
  1719. if (DisconnectIndicators == TDI_DISCONNECT_RELEASE)
  1720. {
  1721. // setting the state to disconnected will allow the DisconnectDone
  1722. // routine in updsend.c to Delayedcleanupafterdisconnect, when the disconnect
  1723. // completes (since we have been indicated)
  1724. //
  1725. SET_STATE_LOWER (pLowerConn, NBT_DISCONNECTED);
  1726. }
  1727. else
  1728. {
  1729. // there is no disconnect completion to wait for ...since it
  1730. // was an abortive disconnect indication
  1731. // Change the state of the lower conn incase the client has
  1732. // done a disconnect at the same time - we don't want DisconnectDone
  1733. // to also Queue up DelayedCleanupAfterDisconnect
  1734. //
  1735. SET_STATE_LOWER (pLowerConn, NBT_IDLE);
  1736. }
  1737. }
  1738. //
  1739. // the lower connection just went from disconnecting to disconnected
  1740. // so change the state - this signals the DisconnectDone routine to
  1741. // cleanup the connection when the disconnect request completes.
  1742. //
  1743. if (stateLower == NBT_DISCONNECTING)
  1744. {
  1745. SET_STATE_LOWER (pLowerConn, NBT_DISCONNECTED);
  1746. }
  1747. else if (stateLower == NBT_DISCONNECTED)
  1748. {
  1749. //
  1750. // we get to here if the disconnect request Irp completes before the
  1751. // disconnect indication comes back. The disconnect completes
  1752. // and checks the state, changing it to Disconnected if it
  1753. // isn't already - see disconnectDone in udpsend.c. Since
  1754. // the disconnect indication and the disconnect completion
  1755. // have occurred, cleanup the connection.
  1756. //
  1757. CleanupLower = TRUE;
  1758. // this is just a precaution that may not be needed, so we
  1759. // don't queue the cleanup twice...i.e. now that the lower state
  1760. // is disconnected, we change it's state to idle incase the
  1761. // transport hits us again with another disconnect indication.
  1762. // QueueCleanup is called below based on the value in statelower
  1763. SET_STATE_LOWER (pLowerConn, NBT_IDLE);
  1764. }
  1765. //
  1766. // During the time window that a connection is being setup and TCP
  1767. // completes the connect irp, we could get a disconnect indication.
  1768. // the RefCount must be incremented here so that DelayedCleanupAfterDisconnect
  1769. // does not delete the connection (i.e. it expects refcount >= 2).
  1770. //
  1771. if (stateLower <= NBT_CONNECTING)
  1772. {
  1773. NBT_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_CONNECTED);
  1774. }
  1775. CTESpinFree(pLowerConn,OldIrq);
  1776. CTESpinFree(pConnectEle,OldIrq2);
  1777. CTESpinFree(pClientEle,OldIrq3);
  1778. CTESpinFree(&NbtConfig.JointLock,OldIrq4);
  1779. }
  1780. else
  1781. {
  1782. CTESpinLock(&NbtConfig.JointLock,OldIrq2);
  1783. CTESpinLock(pLowerConn->pDeviceContext,OldIrq3);
  1784. CTESpinLock(pLowerConn,OldIrq);
  1785. stateLower = pLowerConn->State;
  1786. state = NBT_IDLE;
  1787. NbtTrace(NBT_TRACE_DISCONNECT, ("Disconnection Indication, LowerConn=%p state=%x on %!ipaddr!",
  1788. pLowerConn, pLowerConn->State, pLowerConn->pDeviceContext->IpAddress));
  1789. if ((stateLower > NBT_IDLE) && (stateLower < NBT_DISCONNECTING))
  1790. {
  1791. // flag so we send back a disconnect to the transport
  1792. DisconnectIt = TRUE;
  1793. if (stateLower == NBT_SESSION_INBOUND)
  1794. {
  1795. //
  1796. // Previously, the LowerConnection was in the SESSION_INBOUND state
  1797. // hence we have to remove it from the WaitingForInbound Q and put
  1798. // it on the active LowerConnection list!
  1799. //
  1800. ASSERT (pLowerConn->State == NBT_SESSION_INBOUND);
  1801. RemoveEntryList (&pLowerConn->Linkage);
  1802. InsertTailList (&pLowerConn->pDeviceContext->LowerConnection, &pLowerConn->Linkage);
  1803. InterlockedDecrement (&pLowerConn->pDeviceContext->NumWaitingForInbound);
  1804. //
  1805. // Change the RefCount Context to Connected!
  1806. //
  1807. NBT_SWAP_REFERENCE_LOWERCONN (pLowerConn, REF_LOWC_WAITING_INBOUND, REF_LOWC_CONNECTED, TRUE);
  1808. }
  1809. //
  1810. // set state so that DisconnectDone will cleanup the connection.
  1811. //
  1812. SET_STATE_LOWER (pLowerConn, NBT_DISCONNECTED);
  1813. //
  1814. // for an abortive disconnect we will do a cleanup below, so
  1815. // set the state to idle here
  1816. //
  1817. if (DisconnectIndicators != TDI_DISCONNECT_RELEASE)
  1818. {
  1819. SET_STATE_LOWER (pLowerConn, NBT_IDLE);
  1820. }
  1821. }
  1822. else if (stateLower == NBT_DISCONNECTING)
  1823. {
  1824. // a Disconnect has already been initiated by this side so when
  1825. // DisconnectDone runs it will cleanup
  1826. //
  1827. SET_STATE_LOWER (pLowerConn, NBT_DISCONNECTED);
  1828. }
  1829. else if ( stateLower == NBT_DISCONNECTED )
  1830. {
  1831. CleanupLower = TRUE;
  1832. SET_STATE_LOWER (pLowerConn, NBT_IDLE);
  1833. }
  1834. //
  1835. // During the time window that a connection is being setup and TCP
  1836. // completes the connect irp, we could get a disconnect indication.
  1837. // the RefCount must be incremented here so that DelayedCleanupAfterDisconnect
  1838. // does not delete the connection (i.e. it expects refcount >= 2).
  1839. //
  1840. if ((stateLower <= NBT_CONNECTING) &&
  1841. (stateLower > NBT_IDLE))
  1842. {
  1843. NBT_REFERENCE_LOWERCONN(pLowerConn, REF_LOWC_CONNECTED);
  1844. }
  1845. CTESpinFree(pLowerConn,OldIrq);
  1846. CTESpinFree(pLowerConn->pDeviceContext,OldIrq3);
  1847. CTESpinFree(&NbtConfig.JointLock,OldIrq2);
  1848. }
  1849. StateRcv = pLowerConn->StateRcv;
  1850. SetStateProc (pLowerConn, RejectAnyData);
  1851. if (DisconnectIt)
  1852. {
  1853. if (DisconnectIndicators == TDI_DISCONNECT_RELEASE)
  1854. {
  1855. // this disconnects the connection and puts the lowerconn back on
  1856. // its free queue. Note that OutOfRsrcKill calls this routine too
  1857. // with the DisconnectIndicators set to Abort, and the code correctly
  1858. // does not attempt to disconnect the connection since the OutOfRsrc
  1859. // routine had already disconnected it.
  1860. //
  1861. PUSH_LOCATION(0x6d);
  1862. NbtTrace(NBT_TRACE_DISCONNECT, ("Send TCP Disconnect LowerConn=%p on %!ipaddr!",
  1863. pLowerConn, pLowerConn->pDeviceContext->IpAddress));
  1864. status = SendTcpDisconnect((PVOID)pLowerConn);
  1865. }
  1866. else
  1867. {
  1868. // this is an abortive disconnect from the transport, so there is
  1869. // no need to send a disconnect request back to the transport.
  1870. // So we set a flag that tells us later in the routine to close
  1871. // the lower connection.
  1872. //
  1873. PUSH_LOCATION(0x69);
  1874. CleanupLower = TRUE;
  1875. NbtTrace(NBT_TRACE_DISCONNECT, ("Abort connection LowerConn=%p on %!ipaddr!",
  1876. pLowerConn, pLowerConn->pDeviceContext->IpAddress));
  1877. }
  1878. }
  1879. //
  1880. // for an orderly release, turn around and send a release to the transport
  1881. // if there is no client attached to the lower connection. If there is a
  1882. // client then we must pass the disconnect indication to the client and
  1883. // wait for the client to do the disconnect.
  1884. //
  1885. //
  1886. IF_DBG(NBT_DEBUG_DISCONNECT)
  1887. KdPrint(("Nbt.DisconnectHndlrNotOs: ConnEle=<%p>, state = %x\n", pConnectEle, state));
  1888. switch (state)
  1889. {
  1890. case NBT_SESSION_INBOUND:
  1891. case NBT_CONNECTING:
  1892. // if an originator, then the upper and lower connections are
  1893. // already associated, and there is a client irp to return.
  1894. // (NBT_SESSION_CONNECTING only)
  1895. //
  1896. if (pIrp)
  1897. {
  1898. if (pLowerConn->bOriginator)
  1899. {
  1900. CTEIoComplete(pIrp, STATUS_BAD_NETWORK_PATH, 0);
  1901. NbtTrace(NBT_TRACE_DISCONNECT, ("Complete connect IRP %p with %!status!", pIrp, status));
  1902. }
  1903. else
  1904. {
  1905. // this could be an inbound call that could not send the
  1906. // session response correctly.
  1907. //
  1908. CTEIoComplete(pIrp, STATUS_UNSUCCESSFUL, 0);
  1909. NbtTrace(NBT_TRACE_DISCONNECT, ("Complete inbound response IRP %p with STATUS_UNSUCCESSFUL", pIrp));
  1910. }
  1911. }
  1912. break;
  1913. case NBT_SESSION_OUTBOUND:
  1914. //
  1915. //
  1916. // Stop the timer started in SessionStartupCompletion to time the
  1917. // Session Setup Response message
  1918. //
  1919. // NbtConnect stores the tracker in the IrpRcv ptr so that this
  1920. // routine can access it
  1921. //
  1922. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  1923. CTESpinLock(pConnectEle,OldIrq2);
  1924. //
  1925. // check if anyone else has freed the tracker yet.
  1926. //
  1927. pTracker = (tDGRAM_SEND_TRACKING *)pConnectEle->pIrpRcv;
  1928. CHECK_PTR(pTracker);
  1929. if (pTracker)
  1930. {
  1931. //
  1932. // We received a Disconnect from Tcp while waiting in
  1933. // the Outbound state!
  1934. //
  1935. pConnectEle->pIrpRcv = NULL;
  1936. pTimerEntry = pTracker->pTimer;
  1937. pTracker->pTimer = NULL;
  1938. CTESpinFree(pConnectEle,OldIrq2);
  1939. //
  1940. // if the timer has expired it will not cleanup because the state
  1941. // will not be SESSION_OUTBOUND, since we changed it above to
  1942. // disconnected. So we always have to complete the irp and
  1943. // call Delayedcleanupafterdisconnect below.
  1944. //
  1945. if (pTimerEntry)
  1946. {
  1947. StopTimer(pTimerEntry,&pCompletion,NULL);
  1948. }
  1949. //
  1950. // Check if the SessionStartupCompletion has run; if so, RefConn will be 0.
  1951. // Else, decrement so that the tracker goes away when the session send completes.
  1952. //
  1953. if (pTracker->RefConn == 0)
  1954. {
  1955. NbtTrace(NBT_TRACE_OUTBOUND, ("Free tracker for %Z %!NBTNAME!<%02x>",
  1956. &pTracker->pDeviceContext->BindName, pTracker->pDestName, pTracker->pDestName[15]));
  1957. if ((pTracker->pNameAddr->Verify == REMOTE_NAME) && // Remote names only!
  1958. (pTracker->pNameAddr->NameTypeState & STATE_RESOLVED) &&
  1959. (pTracker->pNameAddr->RefCount == 2))
  1960. {
  1961. //
  1962. // If no one else is referencing the name, then delete it from
  1963. // the hash table.
  1964. //
  1965. NBT_DEREFERENCE_NAMEADDR (pTracker->pNameAddr, REF_NAME_REMOTE, TRUE);
  1966. }
  1967. NBT_DEREFERENCE_NAMEADDR (pTracker->pNameAddr, REF_NAME_CONNECT, TRUE);
  1968. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1969. FreeTracker(pTracker,FREE_HDR | RELINK_TRACKER);
  1970. }
  1971. else
  1972. {
  1973. pTracker->RefConn--;
  1974. NbtTrace(NBT_TRACE_OUTBOUND, ("Decrease pTracker->RefConn for %Z %!NBTNAME!<%02x>",
  1975. &pTracker->pDeviceContext->BindName, pTracker->pDestName, pTracker->pDestName[15]));
  1976. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1977. }
  1978. }
  1979. else
  1980. {
  1981. CTESpinFree(pConnectEle,OldIrq2);
  1982. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1983. }
  1984. if (pIrp)
  1985. {
  1986. NbtTrace(NBT_TRACE_OUTBOUND, ("Complete outbound request IRP %p with STATUS_REMOTE_NOT_LISTENING",
  1987. pIrp));
  1988. CTEIoComplete(pIrp,STATUS_REMOTE_NOT_LISTENING,0);
  1989. }
  1990. break;
  1991. case NBT_SESSION_WAITACCEPT:
  1992. case NBT_SESSION_UP:
  1993. if (pIrp)
  1994. {
  1995. CTEIoComplete(pIrp,STATUS_CANCELLED,0);
  1996. }
  1997. //
  1998. // check for any RcvIrp that may be still around. If the
  1999. // transport has the Irp now then pIrpRcv = NULL. There should
  2000. // be no race condition between completing it and CompletionRcv
  2001. // setting pIrpRcv again as long as we cannot be indicated
  2002. // for a disconnect during completion of a Receive. In any
  2003. // case the access is coordinated using the Io spin lock io
  2004. // IoCancelIrp - that routine will only complete the irp once,
  2005. // then it nulls the completion routine.
  2006. //
  2007. if ((StateRcv == FILL_IRP) && pIrpRcv)
  2008. {
  2009. PUSH_LOCATION(0x6f);
  2010. IF_DBG(NBT_DEBUG_DISCONNECT)
  2011. KdPrint(("Nbt.DisconnectHndlrNotOs: Cancelling RcvIrp on Disconnect Indication!!!\n"));
  2012. CTEIoComplete(pIrpRcv,STATUS_CANCELLED,0);
  2013. }
  2014. //
  2015. // this is a disconnect for an active session, so just inform the client
  2016. // and then it issues a Nbtdisconnect. We have already disconnected the
  2017. // lowerconnection with the transport, so all that remains is
  2018. // to cleanup for outgoing calls.
  2019. //
  2020. pClientEle = pConnectEle->pClientEle;
  2021. // now call the client's disconnect handler...NBT always does
  2022. // a abortive disconnect - i.e. the connection is closed when
  2023. // the disconnect indication occurs and does not REQUIRE a
  2024. // disconnect from the client to finish the job.( a disconnect
  2025. // from the client will not hurt though.
  2026. //
  2027. PUSH_LOCATION(0x64);
  2028. if ((pClientEle) &&
  2029. (pClientEle->evDisconnect ) &&
  2030. (!pIrpClose))
  2031. {
  2032. status = (*pClientEle->evDisconnect)(pClientEle->DiscEvContext,
  2033. pConnectEle->ConnectContext,
  2034. DisconnectDataLength,
  2035. pDisconnectData,
  2036. DisconnectInformationLength,
  2037. pDisconnectInformation,
  2038. TDI_DISCONNECT_ABORT);
  2039. NbtTrace(NBT_TRACE_DISCONNECT, ("Client disconnect handler returns %!status!", status));
  2040. }
  2041. else if (pIrpClose)
  2042. {
  2043. //
  2044. // the Client has issued a disconnect Wait irp, so complete
  2045. // it now, indicating to them that a disconnect has occurred.
  2046. //
  2047. if (DisconnectIndicators == TDI_DISCONNECT_RELEASE)
  2048. {
  2049. status = STATUS_GRACEFUL_DISCONNECT;
  2050. }
  2051. else
  2052. {
  2053. status = STATUS_CONNECTION_RESET;
  2054. }
  2055. NbtTrace(NBT_TRACE_DISCONNECT, ("Complete client disconnect wait IRP %p with %!status!",
  2056. pIrpClose, status));
  2057. CTEIoComplete(pIrpClose,status,0);
  2058. }
  2059. //
  2060. // return any rcv buffers that have been posted
  2061. //
  2062. CTESpinLock(pConnectEle,OldIrq);
  2063. FreeRcvBuffers(pConnectEle,&OldIrq);
  2064. CTESpinFree(pConnectEle,OldIrq);
  2065. break;
  2066. case NBT_DISCONNECTING:
  2067. // the retry session setup code expects the state to change
  2068. // to disconnected when the disconnect indication comes
  2069. // from the wire
  2070. SET_STATE_UPPER (pConnectEle, NBT_DISCONNECTED);
  2071. case NBT_DISCONNECTED:
  2072. case NBT_ASSOCIATED:
  2073. case NBT_IDLE:
  2074. //
  2075. // catch all other cases here to be sure the connect irp gets
  2076. // returned.
  2077. //
  2078. if (pIrp)
  2079. {
  2080. CTEIoComplete(pIrp,STATUS_CANCELLED,0);
  2081. NbtTrace(NBT_TRACE_DISCONNECT, ("Complete client IRP %p with STATUS_CANCELLED", pIrp));
  2082. }
  2083. break;
  2084. default:
  2085. ASSERTMSG("Nbt:Disconnect indication in unexpected state\n",0);
  2086. }
  2087. if (InsertOnList)
  2088. {
  2089. // undo the reference done when the NbtConnect Ran - this may cause
  2090. // pConnEle to be deleted if the Client had issued an NtClose before
  2091. // this routine ran. We only do this dereference if InsertOnList is
  2092. // TRUE, meaning that we just "unhooked" the lower from the Upper.
  2093. NBT_DEREFERENCE_CONNECTION (pConnectEle, REF_CONN_CONNECT);
  2094. }
  2095. // this either puts the lower connection back on its free
  2096. // queue if inbound, or closes the connection with the transport
  2097. // if out bound. (it can't be done at dispatch level).
  2098. //
  2099. if (CleanupLower)
  2100. {
  2101. IF_DBG(NBT_DEBUG_DISCONNECT)
  2102. KdPrint(("Nbt.DisconnectHndlrNotOs: Calling Worker thread to Cleanup %X\n",pLowerConn));
  2103. CTESpinLock(pLowerConn,OldIrq);
  2104. if ( pLowerConn->pIrp )
  2105. {
  2106. PCTE_IRP pIrp;
  2107. pIrp = pLowerConn->pIrp;
  2108. CHECK_PTR(pLowerConn);
  2109. pLowerConn->pIrp = NULL ;
  2110. CTESpinFree(pLowerConn,OldIrq);
  2111. // this is the irp to complete when the disconnect completes - essentially
  2112. // the irp requesting the disconnect.
  2113. CTEIoComplete( pIrp, STATUS_SUCCESS, 0 ) ;
  2114. }
  2115. else
  2116. {
  2117. CTESpinFree(pLowerConn,OldIrq);
  2118. }
  2119. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  2120. ASSERT (NBT_VERIFY_HANDLE (pLowerConn, NBT_VERIFY_LOWERCONN));
  2121. ASSERT (pLowerConn->RefCount > 1);
  2122. if (NBT_VERIFY_HANDLE (pLowerConn->pDeviceContext, NBT_VERIFY_DEVCONTEXT))
  2123. {
  2124. pDeviceContext = pLowerConn->pDeviceContext;
  2125. }
  2126. status = CTEQueueForNonDispProcessing (DelayedCleanupAfterDisconnect,
  2127. NULL,
  2128. pLowerConn,
  2129. NULL,
  2130. pDeviceContext,
  2131. TRUE);
  2132. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2133. }
  2134. return(STATUS_SUCCESS);
  2135. }
  2136. //----------------------------------------------------------------------------
  2137. VOID
  2138. DelayedCleanupAfterDisconnect(
  2139. IN tDGRAM_SEND_TRACKING *pUnused1,
  2140. IN PVOID pClientContext,
  2141. IN PVOID Unused2,
  2142. IN tDEVICECONTEXT *pDeviceContext
  2143. )
  2144. /*++
  2145. Routine Description:
  2146. This routine handles freeing lowerconnection data structures back to the
  2147. transport, by calling NTclose (outbound only) or by putting the connection
  2148. back on the connection free queue (inbound only). For the NT case this
  2149. routine runs within the context of an excutive worker thread.
  2150. Arguments:
  2151. Return Value:
  2152. NTSTATUS - Status of receive operation
  2153. --*/
  2154. {
  2155. NTSTATUS status;
  2156. tLOWERCONNECTION *pLowerConn;
  2157. PIRP pIrp=NULL;
  2158. pLowerConn = (tLOWERCONNECTION*) pClientContext;
  2159. IF_DBG(NBT_DEBUG_DISCONNECT)
  2160. KdPrint(("Nbt.DelayedCleanupAfterDisconnect: Originator= %X, pLowerConn=%X\n",
  2161. pLowerConn->bOriginator,pLowerConn));
  2162. //
  2163. // DEBUG to catch upper connections being put on lower conn QUEUE
  2164. //
  2165. ASSERT (NBT_VERIFY_HANDLE (pLowerConn, NBT_VERIFY_LOWERCONN));
  2166. ASSERT (pLowerConn->RefCount > 1);
  2167. ASSERT (pLowerConn->pUpperConnection == NULL);
  2168. if (!pLowerConn->bOriginator)
  2169. {
  2170. // ******** THIS WAS AN INCOMING CONNECTION *************
  2171. //
  2172. // Inbound lower connections just get put back on the queue, whereas
  2173. // outbound connections simply get closed.
  2174. //
  2175. if (pLowerConn->SpecialAlloc)
  2176. {
  2177. //
  2178. // Connections allocated due to SynAttack backlog measures are not re-allocated
  2179. // If this was a special connection block, decrement the count of such connections
  2180. //
  2181. if (pDeviceContext)
  2182. {
  2183. InterlockedDecrement(&pDeviceContext->NumSpecialLowerConn);
  2184. KdPrint(("Nbt.DelayedCleanupAfterDisconnect: pDevice=<%p>, NumSpecialLowerConn= %d\n",
  2185. pDeviceContext, pDeviceContext->NumSpecialLowerConn));
  2186. }
  2187. }
  2188. else if (pDeviceContext)
  2189. {
  2190. //
  2191. // Always close the connection and then Create another since there
  2192. // could be a Rcv Irp in TCP still that will be returned at some
  2193. // later time, perhaps after this connection gets reused again.
  2194. // In that case the Rcv Irp could be lost.
  2195. IF_DBG(NBT_DEBUG_DISCONNECT)
  2196. KdPrint(("Nbt.DelayedCleanupAfterDisconnect: LowerConn=<%x>, State=<%x>\n",
  2197. pLowerConn, pLowerConn->State));
  2198. if (pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT) {
  2199. DelayedAllocLowerConn (NULL, NULL, NULL, pDeviceContext);
  2200. }
  2201. }
  2202. }
  2203. // this deref removes the reference added when the connection
  2204. // connnected. When NbtDeleteLowerConn is called it dereferences
  2205. // one more time which delete the memory.
  2206. //
  2207. CHECK_PTR (pLowerConn);
  2208. ASSERT (pLowerConn->RefCount >= 2);
  2209. NBT_DEREFERENCE_LOWERCONN (pLowerConn, REF_LOWC_CONNECTED, FALSE);
  2210. // this does a close on the lower connection, so it can go ahead
  2211. // possibly before the disconnect has completed since the transport
  2212. // will not complete the close until is completes the disconnect.
  2213. //
  2214. status = NbtDeleteLowerConn(pLowerConn);
  2215. }
  2216. //----------------------------------------------------------------------------
  2217. VOID
  2218. AllocLowerConn(
  2219. IN tDEVICECONTEXT *pDeviceContext,
  2220. IN PVOID pDeviceSpecial
  2221. )
  2222. /*++
  2223. Routine Description:
  2224. Allocate a lowerconn block that will go on the lowerconnfreehead.
  2225. Arguments:
  2226. pDeviceContext - the device context
  2227. Return Value:
  2228. --*/
  2229. {
  2230. NTSTATUS status;
  2231. tLOWERCONNECTION *pLowerConn;
  2232. /*
  2233. * This should be ok since NbtOpenAndAssocConnection call NbtTdiOpenConnection which is PAGEABLE.
  2234. * Make sure we are at the right IRQL.
  2235. */
  2236. CTEPagedCode();
  2237. CTEExAcquireResourceExclusive(&NbtConfig.Resource,TRUE);
  2238. if (pDeviceContext->Verify != NBT_VERIFY_DEVCONTEXT) {
  2239. ASSERT (pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT_DOWN);
  2240. CTEExReleaseResource(&NbtConfig.Resource);
  2241. return;
  2242. }
  2243. if (pDeviceSpecial)
  2244. {
  2245. status = NbtOpenAndAssocConnection(pDeviceContext, NULL, &pLowerConn, '0');
  2246. }
  2247. else
  2248. {
  2249. status = NbtOpenAndAssocConnection(pDeviceContext, NULL, NULL, '1');
  2250. }
  2251. CTEExReleaseResource(&NbtConfig.Resource);
  2252. if (pDeviceSpecial)
  2253. {
  2254. //
  2255. // Special lowerconn for Syn attacks
  2256. //
  2257. if (NT_SUCCESS(status))
  2258. {
  2259. pLowerConn->SpecialAlloc = TRUE;
  2260. InterlockedIncrement(&pDeviceContext->NumSpecialLowerConn);
  2261. }
  2262. InterlockedDecrement(&pDeviceContext->NumQueuedForAlloc);
  2263. }
  2264. }
  2265. //----------------------------------------------------------------------------
  2266. VOID
  2267. DelayedAllocLowerConn(
  2268. IN tDGRAM_SEND_TRACKING *pUnused1,
  2269. IN PVOID pDeviceSpecial,
  2270. IN PVOID pUnused3,
  2271. IN tDEVICECONTEXT *pDeviceContext
  2272. )
  2273. /*++
  2274. Routine Description:
  2275. If lowerconn couldn't be alloced in AllocLowerConn, an event is scheduled
  2276. so that we can retry later. Well, this is "later"!
  2277. Arguments:
  2278. Return Value:
  2279. --*/
  2280. {
  2281. AllocLowerConn(pDeviceContext, pDeviceSpecial);
  2282. }
  2283. //----------------------------------------------------------------------------
  2284. VOID
  2285. DelayedAllocLowerConnSpecial(
  2286. IN tDGRAM_SEND_TRACKING *pUnused1,
  2287. IN PVOID pUnused2,
  2288. IN PVOID pUnused3,
  2289. IN tDEVICECONTEXT *pDeviceContext
  2290. )
  2291. /*++
  2292. Routine Description:
  2293. If lowerconn couldn't be alloced in AllocLowerConn, an event is scheduled
  2294. so that we can retry later. Well, this is "later"!
  2295. This is for SYN-ATTACK, so we shd create more than one to beat the incoming
  2296. requests. Create three at a time - this shd be controllable thru' registry.
  2297. Arguments:
  2298. Return Value:
  2299. --*/
  2300. {
  2301. ULONG i;
  2302. if (pDeviceContext->Verify != NBT_VERIFY_DEVCONTEXT) {
  2303. ASSERT (pDeviceContext->Verify == NBT_VERIFY_DEVCONTEXT_DOWN);
  2304. return;
  2305. }
  2306. KdPrint(("Nbt.DelayedAllocLowerConnSpecial: Allocing spl. %d lowerconn...\n",
  2307. NbtConfig.SpecialConnIncrement));
  2308. //
  2309. // Alloc SpecialConnIncrement number of more connections.
  2310. //
  2311. for (i=0; i<NbtConfig.SpecialConnIncrement; i++)
  2312. {
  2313. DelayedAllocLowerConn(NULL, pDeviceContext, NULL, pDeviceContext);
  2314. }
  2315. }
  2316. //----------------------------------------------------------------------------
  2317. VOID
  2318. AddToRemoteHashTbl (
  2319. IN tDGRAMHDR UNALIGNED *pDgram,
  2320. IN ULONG BytesIndicated,
  2321. IN tDEVICECONTEXT *pDeviceContext
  2322. )
  2323. /*++
  2324. Routine Description:
  2325. This routine adds the source address of an inbound datagram to the remote
  2326. hash table so that it can be used for subsequent return sends to that node.
  2327. This routine does not need to be called if the datagram message type is
  2328. Broadcast datagram, since these are sends to the broadcast name '*' and
  2329. there is no send caching this source name
  2330. Arguments:
  2331. Return Value:
  2332. NTSTATUS - Status of receive operation
  2333. --*/
  2334. {
  2335. tNAMEADDR *pNameAddr;
  2336. CTELockHandle OldIrq;
  2337. UCHAR pName[NETBIOS_NAME_SIZE];
  2338. NTSTATUS status;
  2339. LONG Length;
  2340. ULONG SrcIpAddr;
  2341. PUCHAR pScope;
  2342. //
  2343. // source ip addr should never be 0. This is a workaround for UB's NBDD
  2344. // which forwards the datagram, but client puts 0 in SourceIpAddr field
  2345. // of the datagram, we cache 0 and then end up doing a broadcast when we
  2346. // really meant to do a directed datagram to the sender.
  2347. //
  2348. SrcIpAddr = ntohl(pDgram->SrcIpAddr);
  2349. if ((!SrcIpAddr) ||
  2350. (!NT_SUCCESS (status = ConvertToAscii ((PCHAR)&pDgram->SrcName,
  2351. (BytesIndicated - FIELD_OFFSET(tDGRAMHDR,SrcName)),
  2352. pName,
  2353. &pScope,
  2354. &Length))))
  2355. {
  2356. return;
  2357. }
  2358. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  2359. //
  2360. // Add the name to the remote cache.
  2361. //
  2362. status = AddToHashTable(NbtConfig.pRemoteHashTbl,
  2363. pName,
  2364. pScope,
  2365. SrcIpAddr,
  2366. NBT_UNIQUE, // always a unique address since you can't send from a group name
  2367. NULL,
  2368. &pNameAddr,
  2369. pDeviceContext,
  2370. NAME_RESOLVED_BY_DGRAM_IN);
  2371. if (NT_SUCCESS(status))
  2372. {
  2373. //
  2374. // we only want the name to be in the remote cache for the shortest
  2375. // timeout allowed by the remote cache timer, so set the timeout
  2376. // count to 1 which is 1-2 minutes.
  2377. //
  2378. // the name is already in the cache when Pending is returned,
  2379. // so just update the ip address in case it is different.
  2380. //
  2381. if (status == STATUS_PENDING)
  2382. {
  2383. //
  2384. // If the name is resolved then it is ok to overwrite the
  2385. // ip address with the incoming one. But if it is resolving,
  2386. // then just let it continue resolving.
  2387. //
  2388. if ( (pNameAddr->NameTypeState & STATE_RESOLVED) &&
  2389. !(pNameAddr->NameTypeState & NAMETYPE_INET_GROUP))
  2390. {
  2391. pNameAddr->TimeOutCount = 1;
  2392. // only set the adapter mask for this adapter since we are
  2393. // only sure that this adapter can reach the dest.
  2394. pNameAddr->AdapterMask = pDeviceContext->AdapterMask;
  2395. }
  2396. }
  2397. else
  2398. {
  2399. pNameAddr->TimeOutCount = 1;
  2400. //
  2401. // change the state to resolved
  2402. //
  2403. pNameAddr->NameTypeState &= ~NAME_STATE_MASK;
  2404. pNameAddr->NameTypeState |= STATE_RESOLVED;
  2405. pNameAddr->AdapterMask |= pDeviceContext->AdapterMask;
  2406. }
  2407. }
  2408. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2409. }
  2410. //----------------------------------------------------------------------------
  2411. NTSTATUS
  2412. DgramHndlrNotOs (
  2413. IN PVOID ReceiveEventContext,
  2414. IN ULONG SourceAddrLength,
  2415. IN PVOID pSourceAddr,
  2416. IN ULONG OptionsLength,
  2417. IN PVOID pOptions,
  2418. IN ULONG ReceiveDatagramFlags,
  2419. IN ULONG BytesIndicated,
  2420. IN ULONG BytesAvailable,
  2421. OUT PULONG pBytesTaken,
  2422. IN PVOID pTsdu,
  2423. OUT PVOID *ppRcvBuffer,
  2424. IN tCLIENTLIST **ppClientList
  2425. )
  2426. /*++
  2427. Routine Description:
  2428. This routine is the receive datagram event indication handler.
  2429. It is called when an a datgram arrives from the network. The code
  2430. checks the type of datagram and then tries to route the datagram to
  2431. the correct destination on the node.
  2432. This procedure is called with the spin lock held on pDeviceContext.
  2433. Arguments:
  2434. ppRcvbuffer will contain the IRP/NCB if only one client is listening,
  2435. NULL if multiple clients are listening
  2436. ppClientList will contain the list clients that need to be completed,
  2437. NULL if only one client is listening
  2438. Return Value:
  2439. NTSTATUS - Status of receive operation
  2440. --*/
  2441. {
  2442. NTSTATUS status = STATUS_SUCCESS;
  2443. NTSTATUS LocStatus;
  2444. tCLIENTELE *pClientEle;
  2445. tCLIENTELE *pClientEleToDeref = NULL;
  2446. tNAMEADDR *pNameAddr;
  2447. tADDRESSELE *pAddress;
  2448. ULONG RetNameType;
  2449. CTELockHandle OldIrq;
  2450. CTELockHandle OldIrq1;
  2451. CHAR pName[NETBIOS_NAME_SIZE];
  2452. PUCHAR pScope;
  2453. ULONG lNameSize;
  2454. ULONG iLength = 0;
  2455. ULONG RemoteAddressLength;
  2456. PVOID pRemoteAddress;
  2457. tDEVICECONTEXT *pDeviceContext = (tDEVICECONTEXT *)ReceiveEventContext;
  2458. tDGRAMHDR UNALIGNED *pDgram = (tDGRAMHDR UNALIGNED *)pTsdu;
  2459. ULONG lClientBytesTaken;
  2460. ULONG lDgramHdrSize;
  2461. PIRP pIrp;
  2462. BOOLEAN MoreClients;
  2463. BOOLEAN UsingClientBuffer;
  2464. CTEULONGLONG AdapterMask;
  2465. ULONG BytesIndicatedOrig;
  2466. ULONG BytesAvailableOrig;
  2467. ULONG Offset;
  2468. //
  2469. // We will be processing only directed or broadcast datagrams
  2470. // Hence, there must be at least the header plus two half ascii names etc.
  2471. // which all adds up to 82 bytes with no user data
  2472. // ie. 14 + (1+32+1) + (1+32+1) ==> Assuming 0 Scopelength + 0 UserData
  2473. //
  2474. if ((BytesIndicated < 82) ||
  2475. (pDgram->MsgType < DIRECT_UNIQUE) ||
  2476. (pDgram->MsgType > BROADCAST_DGRAM))
  2477. {
  2478. KdPrint (("Nbt.DgramHndlrNotOs[1]: WARNING! Rejecting Dgram -- BytesIndicated=<%d>, MsgType=<0x%x>\n",
  2479. BytesIndicated, pDgram->MsgType));
  2480. NbtTrace(NBT_TRACE_RECVDGRAM, ("Rejecting Dgram: BytesIndicated=%d, MsgType=0x%x",
  2481. BytesIndicated, pDgram->MsgType));
  2482. return(STATUS_DATA_NOT_ACCEPTED);
  2483. }
  2484. // First, find the end of the SourceName .. it should end in a 0 byte,
  2485. // but use strnlen just to be safe! (BUG # 114996)
  2486. //
  2487. // Then, find the destination name in the local name service tables
  2488. //
  2489. Offset = FIELD_OFFSET(tDGRAMHDR,SrcName.NetBiosName[0]);
  2490. if ((!NT_SUCCESS (LocStatus = strnlen ((PCHAR)pDgram->SrcName.NetBiosName,
  2491. BytesIndicated-Offset,
  2492. &iLength))) ||
  2493. (BytesIndicated < (Offset+iLength+1+1+32+1)) ||
  2494. (!NT_SUCCESS (status = ConvertToAscii ((PCHAR)&pDgram->SrcName.NetBiosName[iLength+1],
  2495. BytesIndicated-(Offset+iLength+1), // Bug#: 124441
  2496. pName,
  2497. &pScope,
  2498. &lNameSize))))
  2499. {
  2500. NbtTrace(NBT_TRACE_RECVDGRAM, ("Rejecting Dgram: strnlen=%!status!, ConvertToAscii=%!status!",
  2501. LocStatus, status));
  2502. KdPrint (("Nbt.DgramHndlrNotOs: WARNING!!! Rejecting Dgram -- strnlen-><%x>, ConvertToAscii-><%x>\n",
  2503. LocStatus, status));
  2504. KdPrint (("Nbt.DgramHndlrNotOs: iLength=<%d>, Half-Ascii Dest=<%p>, Ascii Dest=<%p>\n",
  2505. iLength, &pDgram->SrcName.NetBiosName[iLength+1], pName));
  2506. // ASSERT (0);
  2507. return(STATUS_DATA_NOT_ACCEPTED);
  2508. }
  2509. //
  2510. // check length again, including scopes of names too. The Src
  2511. // scope length is returned in iLength, which also includes the
  2512. // half ascii length
  2513. //
  2514. if (BytesIndicated < ( 82 // 14(Hdr) + 2 HalfAscii names (2*(1+32+1))
  2515. +(iLength-(2*NETBIOS_NAME_SIZE)) // Src ScopeLength
  2516. +(NbtConfig.ScopeLength-1))) // Dest (ie Local) ScopeLength
  2517. {
  2518. KdPrint (("Nbt.DgramHndlrNoOs[2]: WARNING!!! Rejecting Dgram -- BytesIndicated=<%d> < <%d>\n",
  2519. BytesIndicated, 82+(iLength-(2*NETBIOS_NAME_SIZE))+(NbtConfig.ScopeLength-1)));
  2520. NbtTrace(NBT_TRACE_RECVDGRAM, ("Rejecting Dgram -- BytesIndicated=<%d> < <%d>\n",
  2521. BytesIndicated, 82+(iLength-(2*NETBIOS_NAME_SIZE))+(NbtConfig.ScopeLength-1)));
  2522. ASSERT (0);
  2523. return(STATUS_DATA_NOT_ACCEPTED);
  2524. }
  2525. status = STATUS_DATA_NOT_ACCEPTED;
  2526. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  2527. //
  2528. // Check for the full name first instead of considering any name with a '*' as
  2529. // the first char as a broadcast name (e.g. *SMBSERVER and *SMBDATAGRAM are not
  2530. // b'cast names).
  2531. //
  2532. pNameAddr = FindName (NBT_LOCAL, pName, pScope, &RetNameType);
  2533. //
  2534. // If we failed above, it might be because the name could start with '*' and is a
  2535. // bcast name.
  2536. //
  2537. if (!pNameAddr)
  2538. {
  2539. //
  2540. // be sure the broadcast name has 15 zeroes after it
  2541. //
  2542. if (pName[0] == '*')
  2543. {
  2544. CTEZeroMemory(&pName[1],NETBIOS_NAME_SIZE-1);
  2545. pNameAddr = FindName (NBT_LOCAL, pName, pScope, &RetNameType);
  2546. }
  2547. }
  2548. // Change the pTsdu ptr to pt to the users data
  2549. // -2 to account for the tNETBIOSNAME and +2 to add the length
  2550. // bytes for both names, +1 for the null on the end of the first
  2551. // name
  2552. lDgramHdrSize = sizeof(tDGRAMHDR) - 2 + 1+iLength+1 + 1+lNameSize;
  2553. pTsdu = (PVOID)((PUCHAR)pTsdu + lDgramHdrSize);
  2554. BytesAvailableOrig = BytesAvailable;
  2555. BytesAvailable -= lDgramHdrSize;
  2556. BytesIndicatedOrig = BytesIndicated;
  2557. BytesIndicated -= lDgramHdrSize;
  2558. //
  2559. // If the name is in the local table and has an address element
  2560. // associated with it AND the name is registered against
  2561. // this adapter, then execute the code in the 'if' block
  2562. //
  2563. AdapterMask = pDeviceContext->AdapterMask;
  2564. if ((pNameAddr) &&
  2565. (pNameAddr->pAddressEle) &&
  2566. (pNameAddr->AdapterMask & AdapterMask))
  2567. {
  2568. pAddress = pNameAddr->pAddressEle;
  2569. // Need to hold Address lock to traverse ClientHead
  2570. CTESpinLock(pAddress, OldIrq1);
  2571. if (!IsListEmpty(&pAddress->ClientHead))
  2572. {
  2573. PLIST_ENTRY pHead;
  2574. PLIST_ENTRY pEntry;
  2575. //
  2576. // Increment the reference count to prevent the
  2577. // pAddress from disappearing in the window between freeing
  2578. // the JOINT_LOCK and taking the ADDRESS_LOCK. We also need to
  2579. // keep the refcount if we are doing a multi client recv, since
  2580. // Clientlist access pAddressEle when distributing the rcv'd dgram
  2581. // in CompletionRcvDgram.
  2582. //
  2583. NBT_REFERENCE_ADDRESS (pAddress, REF_ADDR_DGRAM);
  2584. *pBytesTaken = lDgramHdrSize;
  2585. //
  2586. // Check if there is more than one client that should receive this
  2587. // datagram. If so then pass down a new buffer to get it and
  2588. // copy it to each client's buffer in the completion routine.
  2589. //
  2590. *ppRcvBuffer = NULL;
  2591. MoreClients = FALSE;
  2592. *ppClientList = NULL;
  2593. pHead = &pAddress->ClientHead;
  2594. pEntry = pHead->Flink;
  2595. while (pEntry != pHead)
  2596. {
  2597. PTDI_IND_RECEIVE_DATAGRAM EvRcvDgram;
  2598. PVOID RcvDgramEvContext;
  2599. PLIST_ENTRY pRcvEntry;
  2600. tRCVELE *pRcvEle;
  2601. ULONG MaxLength;
  2602. PLIST_ENTRY pSaveEntry;
  2603. pClientEle = CONTAINING_RECORD(pEntry,tCLIENTELE,Linkage);
  2604. // this client must be registered against this adapter to
  2605. // get the data
  2606. //
  2607. if (!(pClientEle->pDeviceContext) ||
  2608. (pClientEle->pDeviceContext != pDeviceContext))
  2609. {
  2610. pEntry = pEntry->Flink;
  2611. continue;
  2612. }
  2613. #ifdef VXD
  2614. //
  2615. // Move all of the RcvAnyFromAny Datagrams to this client's
  2616. // RcvDatagram list so they will be processed along with the
  2617. // outstanding datagrams for this client if this isn't a
  2618. // broadcast reception (RcvAnyFromAny dgrams
  2619. // don't receive broadcasts). The first client will
  2620. // empty the list, which is ok.
  2621. //
  2622. if (*pName != '*')
  2623. {
  2624. PLIST_ENTRY pDGEntry ;
  2625. while ( !IsListEmpty( &pDeviceContext->RcvDGAnyFromAnyHead ))
  2626. {
  2627. pDGEntry = RemoveHeadList(&pDeviceContext->RcvDGAnyFromAnyHead) ;
  2628. InsertTailList( &pClientEle->RcvDgramHead, pDGEntry ) ;
  2629. }
  2630. }
  2631. #endif
  2632. // check for datagrams posted to this name, and if not call
  2633. // the recv event handler. NOTE: this assumes that the clients
  2634. // use posted recv buffer OR and event handler, but NOT BOTH.
  2635. // If two clients open the same name, one with a posted rcv
  2636. // buffer and another with an event handler, the one with the
  2637. // event handler will NOT get the datagram!
  2638. //
  2639. if (!IsListEmpty(&pClientEle->RcvDgramHead))
  2640. {
  2641. MaxLength = 0;
  2642. pSaveEntry = pEntry;
  2643. //
  2644. // go through all clients finding one that has a large
  2645. // enough buffer
  2646. //
  2647. while (pEntry != pHead)
  2648. {
  2649. pClientEle = CONTAINING_RECORD(pEntry,tCLIENTELE,Linkage);
  2650. if (IsListEmpty(&pClientEle->RcvDgramHead))
  2651. {
  2652. continue;
  2653. }
  2654. pRcvEntry = pClientEle->RcvDgramHead.Flink;
  2655. pRcvEle = CONTAINING_RECORD(pRcvEntry,tRCVELE,Linkage);
  2656. if (pRcvEle->RcvLength >= BytesAvailable)
  2657. {
  2658. pSaveEntry = pEntry;
  2659. break;
  2660. }
  2661. else
  2662. {
  2663. // keep the maximum rcv length around incase none
  2664. // is large enough
  2665. //
  2666. if (pRcvEle->RcvLength > MaxLength)
  2667. {
  2668. pSaveEntry = pEntry;
  2669. MaxLength = pRcvEle->RcvLength;
  2670. }
  2671. pEntry = pEntry->Flink;
  2672. }
  2673. }
  2674. //
  2675. // Get the buffer off the list
  2676. //
  2677. pClientEle = CONTAINING_RECORD(pSaveEntry,tCLIENTELE,Linkage);
  2678. pRcvEntry = RemoveHeadList(&pClientEle->RcvDgramHead);
  2679. *ppRcvBuffer = pRcvEle->pIrp;
  2680. #ifdef VXD
  2681. ASSERT( pDgram->SrcName.NameLength <= NETBIOS_NAME_SIZE*2) ;
  2682. LocStatus = ConvertToAscii(
  2683. (PCHAR)&pDgram->SrcName,
  2684. pDgram->SrcName.NameLength+1,
  2685. ((NCB*)*ppRcvBuffer)->ncb_callname,
  2686. &pScope,
  2687. &lNameSize);
  2688. if ( !NT_SUCCESS(LocStatus) )
  2689. {
  2690. DbgPrint("ConvertToAscii failed\r\n") ;
  2691. }
  2692. #else //VXD
  2693. //
  2694. // put the source of the datagram into the return
  2695. // connection info structure.
  2696. //
  2697. if (pRcvEle->ReturnedInfo)
  2698. {
  2699. UCHAR pSrcName[NETBIOS_NAME_SIZE];
  2700. Offset = FIELD_OFFSET(tDGRAMHDR,SrcName); // Bug#: 124434
  2701. LocStatus = ConvertToAscii(
  2702. (PCHAR)&pDgram->SrcName,
  2703. BytesIndicatedOrig-Offset,
  2704. pSrcName,
  2705. &pScope,
  2706. &lNameSize);
  2707. if (pRcvEle->ReturnedInfo->RemoteAddressLength >=
  2708. sizeof(TA_NETBIOS_ADDRESS))
  2709. {
  2710. TdiBuildNetbiosAddress(pSrcName,
  2711. FALSE,
  2712. pRcvEle->ReturnedInfo->RemoteAddress);
  2713. }
  2714. }
  2715. //
  2716. // Null out the cancel routine since we are passing the
  2717. // irp to the transport
  2718. //
  2719. IoAcquireCancelSpinLock(&OldIrq);
  2720. IoSetCancelRoutine(pRcvEle->pIrp,NULL);
  2721. IoReleaseCancelSpinLock(OldIrq);
  2722. #endif
  2723. CTEMemFree((PVOID)pRcvEle);
  2724. if (pAddress->MultiClients)
  2725. {
  2726. // the multihomed host always passes the above test
  2727. // so we need a more discerning test for it.
  2728. if (!NbtConfig.MultiHomed)
  2729. {
  2730. // if the list is more than one on it,
  2731. // then there are several clients waiting
  2732. // to receive this datagram, so pass down a buffer to
  2733. // get it.
  2734. //
  2735. MoreClients = TRUE;
  2736. status = STATUS_SUCCESS;
  2737. UsingClientBuffer = TRUE;
  2738. // this break will jump down below where we check if
  2739. // MoreClients = TRUE
  2740. //
  2741. // We will need to keep the Client around when CompletionRcvDgram executes!
  2742. // Bug#: 124675
  2743. //
  2744. NBT_REFERENCE_CLIENT(pClientEle);
  2745. //
  2746. // Increment the RefCount by 1 here since there will be
  2747. // an extra Dereference in CompletionRcvDgram
  2748. //
  2749. NBT_REFERENCE_ADDRESS (pAddress, REF_ADDR_MULTICLIENTS);
  2750. break;
  2751. }
  2752. else
  2753. {
  2754. }
  2755. }
  2756. status = STATUS_SUCCESS;
  2757. //
  2758. // jump to end of while to check if we need to buffer
  2759. // the datagram source address
  2760. // in the remote hash table
  2761. //
  2762. break;
  2763. }
  2764. #ifdef VXD
  2765. break;
  2766. #else
  2767. EvRcvDgram = pClientEle->evRcvDgram;
  2768. RcvDgramEvContext = pClientEle->RcvDgramEvContext;
  2769. // don't want to call the default handler since it just
  2770. // returns data not accepted
  2771. if (pClientEle->evRcvDgram != TdiDefaultRcvDatagramHandler)
  2772. {
  2773. ULONG NumAddrs;
  2774. // finally found a real event handler set by a client
  2775. if (pAddress->MultiClients)
  2776. // if (pEntry->Flink != pHead)
  2777. {
  2778. // if the next element in the list is not the head
  2779. // of the list then there are several clients waiting
  2780. // to receive this datagram, so pass down a buffer to
  2781. // get it.
  2782. //
  2783. MoreClients = TRUE;
  2784. UsingClientBuffer = FALSE;
  2785. status = STATUS_SUCCESS;
  2786. //
  2787. // We will need to keep the Client around when CompletionRcvDgram executes!
  2788. // Bug#: 124675
  2789. //
  2790. NBT_REFERENCE_CLIENT(pClientEle);
  2791. //
  2792. // Increment the RefCount by 1 here since there will be
  2793. // an extra Dereference out of the while loop
  2794. //
  2795. NBT_REFERENCE_ADDRESS (pAddress, REF_ADDR_MULTICLIENTS);
  2796. break;
  2797. }
  2798. //
  2799. // make up an address datastructure - subtracting the
  2800. // number of bytes skipped from the total length so
  2801. // convert to Ascii can not bug chk on bogus names.
  2802. //
  2803. if (pClientEle->ExtendedAddress)
  2804. {
  2805. NumAddrs = 2;
  2806. }
  2807. else
  2808. {
  2809. NumAddrs = 1;
  2810. }
  2811. LocStatus = MakeRemoteAddressStructure(
  2812. (PCHAR)&pDgram->SrcName.NameLength,
  2813. pSourceAddr,
  2814. BytesIndicatedOrig - FIELD_OFFSET(tDGRAMHDR,SrcName.NameLength),
  2815. &pRemoteAddress, // the end of the pdu.
  2816. &RemoteAddressLength,
  2817. NumAddrs);
  2818. if (!NT_SUCCESS(LocStatus))
  2819. {
  2820. NbtTrace(NBT_TRACE_RECVDGRAM, ("MakeRemoteAddressStruture returns %!status!", status));
  2821. CTESpinFree(pAddress, OldIrq1);
  2822. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2823. if (pClientEleToDeref)
  2824. {
  2825. NBT_DEREFERENCE_CLIENT (pClientEleToDeref);
  2826. }
  2827. NBT_DEREFERENCE_ADDRESS (pAddress, REF_ADDR_DGRAM);
  2828. return(STATUS_DATA_NOT_ACCEPTED);
  2829. }
  2830. NBT_REFERENCE_CLIENT(pClientEle);
  2831. CTESpinFree(pAddress, OldIrq1);
  2832. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2833. if (pClientEleToDeref)
  2834. {
  2835. NBT_DEREFERENCE_CLIENT (pClientEleToDeref);
  2836. }
  2837. pClientEleToDeref = pClientEle;
  2838. pIrp = NULL;
  2839. lClientBytesTaken = 0;
  2840. LocStatus = (*EvRcvDgram)(RcvDgramEvContext,
  2841. RemoteAddressLength,
  2842. pRemoteAddress,
  2843. OptionsLength,
  2844. pOptions,
  2845. ReceiveDatagramFlags,
  2846. BytesIndicated,
  2847. BytesAvailable,
  2848. &lClientBytesTaken,
  2849. pTsdu,
  2850. &pIrp);
  2851. CTEMemFree((PVOID)pRemoteAddress);
  2852. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  2853. CTESpinLock(pAddress, OldIrq1);
  2854. if (pIrp)
  2855. {
  2856. // the client has passed back an irp so pass it
  2857. // on the transport
  2858. *pBytesTaken += lClientBytesTaken;
  2859. *ppRcvBuffer = pIrp;
  2860. status = STATUS_SUCCESS;
  2861. break;
  2862. }
  2863. else
  2864. {
  2865. NbtTrace(NBT_TRACE_RECVDGRAM, ("Indicate datagram to the client, client returns %!status!",
  2866. LocStatus));
  2867. status = STATUS_DATA_NOT_ACCEPTED;
  2868. }
  2869. }
  2870. pEntry = pEntry->Flink; // go to the next client in the list
  2871. #endif // VXD
  2872. }// of While
  2873. CTESpinFree(pAddress, OldIrq1);
  2874. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2875. if (pClientEleToDeref)
  2876. {
  2877. NBT_DEREFERENCE_CLIENT (pClientEleToDeref);
  2878. }
  2879. NBT_DEREFERENCE_ADDRESS (pAddress, REF_ADDR_DGRAM);
  2880. //
  2881. // Cache the source address in the remote hash table so that
  2882. // this node can send back to the source even if the name
  2883. // is not yet in the name server yet. (only if not on the
  2884. // same subnet)
  2885. //
  2886. if ((pDgram->MsgType != BROADCAST_DGRAM))
  2887. {
  2888. ULONG SrcAddress;
  2889. PTRANSPORT_ADDRESS pSourceAddress;
  2890. ULONG SubnetMask;
  2891. pSourceAddress = (PTRANSPORT_ADDRESS)pSourceAddr;
  2892. SrcAddress = ntohl(((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->in_addr);
  2893. SubnetMask = pDeviceContext->SubnetMask;
  2894. //
  2895. // - cache only if from off the subnet
  2896. // - cache if not sent to 1E,1D,01 name and not from ourselves
  2897. //
  2898. // don't cache dgrams from ourselves, or datagrams to the
  2899. // 1E name, 1D, or 01.
  2900. //
  2901. if (((SrcAddress & SubnetMask) !=
  2902. (pDeviceContext->IpAddress & SubnetMask))
  2903. ||
  2904. ((pName[NETBIOS_NAME_SIZE-1] != 0x1E) &&
  2905. (pName[NETBIOS_NAME_SIZE-1] != 0x1D) &&
  2906. (pName[NETBIOS_NAME_SIZE-1] != 0x01) &&
  2907. (!SrcIsUs(SrcAddress))))
  2908. {
  2909. AddToRemoteHashTbl(pDgram,BytesIndicatedOrig,pDeviceContext);
  2910. }
  2911. }
  2912. // alloc a block of memory to track where we are in the list
  2913. // of clients so completionrcvdgram can send the dgram to the
  2914. // other clients too.
  2915. //
  2916. if (MoreClients)
  2917. {
  2918. tCLIENTLIST *pClientList;
  2919. if (pClientList = (tCLIENTLIST *)NbtAllocMem(sizeof(tCLIENTLIST),NBT_TAG('4')))
  2920. {
  2921. CTEZeroMemory (pClientList, sizeof(tCLIENTLIST));
  2922. //
  2923. // Set fProxy field to FALSE since the client list is for
  2924. // real as versus the PROXY case
  2925. //
  2926. pClientList->fProxy = FALSE;
  2927. // save some context information so we can pass the
  2928. // datagram to the clients - none of the clients have
  2929. // recvd the datagram yet.
  2930. //
  2931. *ppClientList = (PVOID)pClientList;
  2932. pClientList->pAddress = pAddress;
  2933. pClientList->pClientEle = pClientEle; // used for VXD case
  2934. pClientList->fUsingClientBuffer = UsingClientBuffer;
  2935. pClientList->ReceiveDatagramFlags = ReceiveDatagramFlags;
  2936. // make up an address datastructure
  2937. // Bug # 452211 -- since one of the clients may have the Extended
  2938. // addressing field set, create an extended address
  2939. //
  2940. LocStatus = MakeRemoteAddressStructure(
  2941. (PCHAR)&pDgram->SrcName.NameLength,
  2942. pSourceAddr,
  2943. BytesIndicatedOrig -FIELD_OFFSET(tDGRAMHDR,SrcName.NameLength),// set a max number of bytes so we don't go beyond
  2944. &pRemoteAddress, // the end of the pdu.
  2945. &RemoteAddressLength,
  2946. 2);
  2947. if (NT_SUCCESS(LocStatus))
  2948. {
  2949. pClientList->pRemoteAddress = pRemoteAddress;
  2950. pClientList->RemoteAddressLength = RemoteAddressLength;
  2951. return(STATUS_SUCCESS);
  2952. }
  2953. else
  2954. {
  2955. *ppClientList = NULL;
  2956. CTEMemFree(pClientList);
  2957. NbtTrace(NBT_TRACE_RECVDGRAM, ("MakeRemoteAddressStruture returns %!status!", LocStatus));
  2958. status = STATUS_DATA_NOT_ACCEPTED;
  2959. }
  2960. }
  2961. else
  2962. {
  2963. status = STATUS_DATA_NOT_ACCEPTED;
  2964. }
  2965. //
  2966. // We failed, so Dereference the Client + Address we had
  2967. // reference earlier for multiple clients
  2968. //
  2969. NBT_DEREFERENCE_CLIENT (pClientEle);
  2970. NBT_DEREFERENCE_ADDRESS (pAddress, REF_ADDR_MULTICLIENTS);
  2971. }
  2972. }
  2973. else
  2974. {
  2975. CTESpinFree(pAddress, OldIrq1);
  2976. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2977. status = STATUS_DATA_NOT_ACCEPTED;
  2978. IF_DBG(NBT_DEBUG_NAMESRV)
  2979. KdPrint(("Nbt.DgramHndlrNotOs: No client attached to the Address %16.16s<%X>\n",
  2980. pAddress->pNameAddr->Name,pAddress->pNameAddr->Name[15]));
  2981. NbtTrace(NBT_TRACE_RECVDGRAM, ("No client attached to the address %!NBTNAME!<%02x>",
  2982. pAddress->pNameAddr->Name,pAddress->pNameAddr->Name[15]));
  2983. }
  2984. }
  2985. else
  2986. {
  2987. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  2988. status = STATUS_DATA_NOT_ACCEPTED;
  2989. }
  2990. #ifdef PROXY_NODE
  2991. IF_PROXY(NodeType)
  2992. {
  2993. ULONG SrcAddress;
  2994. PTRANSPORT_ADDRESS pSourceAddress;
  2995. pSourceAddress = (PTRANSPORT_ADDRESS)pSourceAddr;
  2996. SrcAddress = ntohl(((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->in_addr);
  2997. //
  2998. // check name in the remote name table. If it is there, it is
  2999. // an internet group and is in the resolved state, send the
  3000. // datagram to all the members except self. If it is in the
  3001. // resolving state, just return. The fact that we got a
  3002. // datagram send for an internet group name still in the
  3003. // resolving state indicates that there is a DC on the subnet
  3004. // that responded to the query for the group received
  3005. // earlier. This means that the DC will respond (unless it
  3006. // goes down) to this datagram send. If the DC is down, the
  3007. // client node will retry.
  3008. //
  3009. // Futures: Queue the Datagram if the name is in the resolving
  3010. // state.
  3011. //
  3012. // If Flags are zero then it is a non fragmented Bnode send. There
  3013. // is not point in doing datagram distribution for P,M,or H nodes
  3014. // can they can do their own.
  3015. //
  3016. if (((pDgram->Flags & SOURCE_NODE_MASK) == 0) &&
  3017. (pName[0] != '*') &&
  3018. (!SrcIsUs(SrcAddress)))
  3019. {
  3020. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  3021. pNameAddr = FindName (NBT_REMOTE, pName, pScope, &RetNameType);
  3022. if (pNameAddr)
  3023. {
  3024. //
  3025. // We have the name in the RESOLVED state.
  3026. //
  3027. //
  3028. // If the name is an internet group, do datagram distribution
  3029. // function
  3030. // Make sure we don't distribute a datagram that has been
  3031. // sent to us by another proxy. In other words, distribute
  3032. // the datagram only if we got it first-hand from original node
  3033. //
  3034. if ((pNameAddr->NameTypeState & NAMETYPE_INET_GROUP) &&
  3035. ((((PTDI_ADDRESS_IP)&pSourceAddress->Address[0].Address[0])->in_addr) == pDgram->SrcIpAddr))
  3036. {
  3037. //
  3038. // If BytesAvailable != BytesIndicated, it means that
  3039. // that we don't have the entire datagram. We need to
  3040. // get it
  3041. if (BytesAvailableOrig != BytesIndicatedOrig)
  3042. {
  3043. tCLIENTLIST *pClientList;
  3044. //
  3045. // Do some simulation to fake the caller of this fn
  3046. // (TdiRcvDatagramHndlr) into thinking that there are
  3047. // multiple clients. This will result in
  3048. // TdiRcvDatagramHndlr function getting all bytes
  3049. // available from TDI and calling
  3050. // ProxyDoDgramDist to do the datagram distribution
  3051. //
  3052. if (pClientList = (tCLIENTLIST *)NbtAllocMem(sizeof(tCLIENTLIST),NBT_TAG('5')))
  3053. {
  3054. CTEZeroMemory (pClientList, sizeof(tCLIENTLIST));
  3055. //
  3056. // save some context information in the Client List
  3057. // data structure
  3058. //
  3059. *ppClientList = (PVOID)pClientList;
  3060. //
  3061. // Set fProxy field to TRUE since the client list
  3062. // not for real
  3063. //
  3064. pClientList->fProxy = TRUE;
  3065. //
  3066. // Make use of the following fields to pass the
  3067. // information we would need in the
  3068. // CompletionRcvDgram
  3069. //
  3070. pClientList->pAddress = (tADDRESSELE *)pNameAddr;
  3071. pClientList->pRemoteAddress = pDeviceContext;
  3072. status = STATUS_DATA_NOT_ACCEPTED;
  3073. }
  3074. else
  3075. {
  3076. status = STATUS_UNSUCCESSFUL;
  3077. }
  3078. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  3079. } // end of if (we do not have the entire datagram)
  3080. else
  3081. {
  3082. //
  3083. // Increment the reference count so that this name
  3084. // does not disappear on us after we free the spin lock.
  3085. //
  3086. // DgramSendCleanupTracker will decrement the count
  3087. //
  3088. NBT_REFERENCE_NAMEADDR (pNameAddr, REF_NAME_SEND_DGRAM);
  3089. //
  3090. //We have the entire datagram.
  3091. //
  3092. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  3093. (VOID)ProxyDoDgramDist(pDgram,
  3094. BytesIndicatedOrig,
  3095. pNameAddr,
  3096. pDeviceContext);
  3097. NbtTrace(NBT_TRACE_PROXY, ("PROXY: Do Dgram distribution for %!NBTNAME!<%02x> from %!ipaddr!",
  3098. pName, (unsigned)pName[15], SrcAddress));
  3099. status = STATUS_DATA_NOT_ACCEPTED;
  3100. }
  3101. } // end of if (if name is an internet group name)
  3102. else
  3103. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  3104. } // end of if (Name is there in remote hash table)
  3105. else
  3106. {
  3107. tNAMEADDR *pResp;
  3108. //
  3109. // the name is not in the cache, so try to get it from
  3110. // WINS
  3111. //
  3112. status = FindOnPendingList(pName,NULL,TRUE,NETBIOS_NAME_SIZE,&pResp);
  3113. if (!NT_SUCCESS(status))
  3114. {
  3115. //
  3116. // cache the name and contact the name
  3117. // server to get the name to IP mapping
  3118. //
  3119. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  3120. NbtTrace(NBT_TRACE_PROXY, ("PROXY: Query name %!NBTNAME!<%02x> from %!ipaddr!",
  3121. pName, (unsigned)pName[15], SrcAddress));
  3122. status = RegOrQueryFromNet(
  3123. FALSE, //means it is a name query
  3124. pDeviceContext,
  3125. NULL,
  3126. lNameSize,
  3127. pName,
  3128. pScope);
  3129. }
  3130. else
  3131. {
  3132. //
  3133. // the name is on the pending list doing a name query
  3134. // now, so ignore this name query request
  3135. //
  3136. NbtTrace(NBT_TRACE_PROXY, ("PROXY: Ignore the name query %!NBTNAME!<%02x> from %!ipaddr!"
  3137. "because it is in the pending list doing a name query",
  3138. pName, (unsigned)pName[15], SrcAddress));
  3139. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  3140. }
  3141. status = STATUS_DATA_NOT_ACCEPTED;
  3142. }
  3143. } else {
  3144. NbtTrace(NBT_TRACE_PROXY, ("Discard datagram %!NBTNAME!<%02x> %!ipaddr!",
  3145. pName, (unsigned)pName[15], SrcAddress));
  3146. }
  3147. }
  3148. END_PROXY
  3149. #endif
  3150. return(status);
  3151. }
  3152. #ifdef PROXY_NODE
  3153. //----------------------------------------------------------------------------
  3154. NTSTATUS
  3155. ProxyDoDgramDist(
  3156. IN tDGRAMHDR UNALIGNED *pDgram,
  3157. IN DWORD DgramLen,
  3158. IN tNAMEADDR *pNameAddr,
  3159. IN tDEVICECONTEXT *pDeviceContext
  3160. )
  3161. /*++
  3162. Routine Description:
  3163. Arguments:
  3164. ppRcvbuffer will contain the IRP/NCB if only one client is listening,
  3165. NULL if multiple clients are listening
  3166. ppClientList will contain the list clients that need to be completed,
  3167. NULL if only one client is listening
  3168. Return Value:
  3169. NTSTATUS - Status of receive operation
  3170. Called By:
  3171. DgramHdlrNotOs, CompletionRcvDgram in tdihndlr.c
  3172. --*/
  3173. {
  3174. NTSTATUS status;
  3175. tDGRAM_SEND_TRACKING *pTracker;
  3176. tDGRAMHDR *pMyBuff;
  3177. //
  3178. // get a buffer for tracking Dgram Sends
  3179. //
  3180. status = GetTracker(&pTracker, NBT_TRACKER_PROXY_DGRAM_DIST);
  3181. if (!NT_SUCCESS(status))
  3182. {
  3183. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_SEND_DGRAM, FALSE);
  3184. return(STATUS_INSUFFICIENT_RESOURCES);
  3185. }
  3186. //
  3187. // Allocate a buffer and copy the contents of the datagram received
  3188. // into it. We do this because SndDgram may not have finished by the
  3189. // time we return.
  3190. //
  3191. if (!(pMyBuff = (tDGRAMHDR *) NbtAllocMem(DgramLen,NBT_TAG('6'))))
  3192. {
  3193. NBT_DEREFERENCE_NAMEADDR (pNameAddr, REF_NAME_SEND_DGRAM, FALSE);
  3194. FreeTracker (pTracker, RELINK_TRACKER);
  3195. return STATUS_INSUFFICIENT_RESOURCES ;
  3196. }
  3197. CTEMemCopy(pMyBuff, (PUCHAR)pDgram, DgramLen);
  3198. //
  3199. // fill in the tracker data block
  3200. // note that the passed in transport address must stay valid till this
  3201. // send completes
  3202. //
  3203. CHECK_PTR(pTracker);
  3204. pTracker->SendBuffer.pDgramHdr = (PVOID)pMyBuff;
  3205. pTracker->SendBuffer.HdrLength = DgramLen;
  3206. pTracker->SendBuffer.pBuffer = NULL;
  3207. pTracker->SendBuffer.Length = 0;
  3208. pTracker->pNameAddr = pNameAddr;
  3209. pTracker->pDeviceContext = (PVOID)pDeviceContext;
  3210. pTracker->p1CNameAddr = NULL;
  3211. //
  3212. // so DgramSendCleanupTracker does not decrement the bytes allocated
  3213. // to dgram sends, since we did not increment the count when we allocated
  3214. // the dgram buffer above.
  3215. //
  3216. pTracker->AllocatedLength = 0;
  3217. pTracker->pClientIrp = NULL;
  3218. pTracker->pClientEle = NULL;
  3219. KdPrint(("Nbt.ProxyDoDgramDist: Name is %16.16s(%X)\n", pNameAddr->Name,
  3220. pNameAddr->Name[15]));
  3221. //
  3222. // Send the datagram to each IP address in the Internet group
  3223. //
  3224. //
  3225. DatagramDistribution(pTracker,pNameAddr);
  3226. return(STATUS_SUCCESS);
  3227. }
  3228. #endif
  3229. //----------------------------------------------------------------------------
  3230. NTSTATUS
  3231. NameSrvHndlrNotOs (
  3232. IN tDEVICECONTEXT *pDeviceContext,
  3233. IN PVOID pSrcAddress,
  3234. IN tNAMEHDR UNALIGNED *pNameSrv,
  3235. IN ULONG uNumBytes,
  3236. IN BOOLEAN fBroadcast
  3237. )
  3238. /*++
  3239. Routine Description:
  3240. This routine is the receive datagram event indication handler.
  3241. It is called when an a datgram arrives from the network. The code
  3242. checks the type of datagram and then tries to route the datagram to
  3243. the correct destination on the node.
  3244. This procedure is called with the spin lock held on pDeviceContext.
  3245. Arguments:
  3246. Return Value:
  3247. NTSTATUS - Status of receive operation
  3248. --*/
  3249. {
  3250. USHORT OpCodeFlags;
  3251. NTSTATUS status;
  3252. // it appears that streams can pass a null data pointer some times
  3253. // and crash nbt...and zero length for the bytes
  3254. if (uNumBytes < sizeof(ULONG))
  3255. {
  3256. return(STATUS_DATA_NOT_ACCEPTED);
  3257. }
  3258. OpCodeFlags = pNameSrv->OpCodeFlags;
  3259. //Pnodes always ignore Broadcasts since they only talk to the NBNS unless
  3260. // this node is also a proxy
  3261. if ( ( ((NodeType) & PNODE)) && !((NodeType) & PROXY) )
  3262. {
  3263. if (OpCodeFlags & FL_BROADCAST)
  3264. {
  3265. return(STATUS_DATA_NOT_ACCEPTED);
  3266. }
  3267. }
  3268. // decide what type of name service packet it is by switching on the
  3269. // NM_Flags portion of the word
  3270. switch (OpCodeFlags & NM_FLAGS_MASK)
  3271. {
  3272. case OP_QUERY:
  3273. status = QueryFromNet(
  3274. pDeviceContext,
  3275. pSrcAddress,
  3276. pNameSrv,
  3277. uNumBytes, // >= NBT_MINIMUM_QUERY (== 50)
  3278. OpCodeFlags,
  3279. fBroadcast);
  3280. break;
  3281. case OP_REGISTRATION:
  3282. //
  3283. // we can get either a registration request or a response
  3284. //
  3285. // is this a request or a response? - if bit is set its a Response
  3286. if (OpCodeFlags & OP_RESPONSE)
  3287. {
  3288. // then this is a response to a previous reg. request
  3289. status = RegResponseFromNet(
  3290. pDeviceContext,
  3291. pSrcAddress,
  3292. pNameSrv,
  3293. uNumBytes, // >= NBT_MINIMUM_REGRESPONSE (== 62)
  3294. OpCodeFlags);
  3295. }
  3296. else
  3297. {
  3298. //
  3299. // check if someone else is trying to register a name
  3300. // owned by this node. Pnodes rely on the Name server to
  3301. // handle this...hence the check for Pnode
  3302. //
  3303. if (!(NodeType & PNODE))
  3304. {
  3305. status = CheckRegistrationFromNet(pDeviceContext,
  3306. pSrcAddress,
  3307. pNameSrv,
  3308. uNumBytes); // >= NBT_MINIMUM_REGREQUEST (== 68)
  3309. }
  3310. }
  3311. break;
  3312. case OP_RELEASE:
  3313. //
  3314. // handle other nodes releasing their names by deleting any
  3315. // cached info
  3316. //
  3317. status = NameReleaseFromNet(
  3318. pDeviceContext,
  3319. pSrcAddress,
  3320. pNameSrv,
  3321. uNumBytes); // >= NBT_MINIMUM_REGRESPONSE (== 62)
  3322. break;
  3323. case OP_WACK:
  3324. if (!(NodeType & BNODE))
  3325. {
  3326. // the TTL in the WACK tells us to increase our timeout
  3327. // of the corresponding request, which means we must find
  3328. // the transaction
  3329. status = WackFromNet(pDeviceContext,
  3330. pSrcAddress,
  3331. pNameSrv,
  3332. uNumBytes); // >= NBT_MINIMUM_WACK (== 58)
  3333. }
  3334. break;
  3335. case OP_REFRESH:
  3336. case OP_REFRESH_UB:
  3337. break;
  3338. default:
  3339. IF_DBG(NBT_DEBUG_HNDLRS)
  3340. KdPrint(("Nbt.NameSrvHndlrNotOs: Unknown Name Service Pdu type OpFlags = %X\n",
  3341. OpCodeFlags));
  3342. break;
  3343. }
  3344. return(STATUS_DATA_NOT_ACCEPTED);
  3345. }
  3346. VOID
  3347. DoNothingComplete (
  3348. IN PVOID pContext
  3349. )
  3350. /*++
  3351. Routine Description:
  3352. This routine is the completion routine for TdiDisconnect while we are
  3353. retrying connects. It does nothing.
  3354. This is required because you can't have a NULL TDI completion routine.
  3355. --*/
  3356. {
  3357. return ;
  3358. }