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

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