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.

1778 lines
56 KiB

  1. /*++
  2. Copyright (c) 1989-1993 Microsoft Corporation
  3. Module Name:
  4. Udpsend.c
  5. Abstract:
  6. This file handles building udp(and Tcp) requests, formated to the Tdi specification
  7. to pass to Tdiout. Tdiout formats the request in an Os specific manner and
  8. passes it on to the transport.
  9. This file handles name service type functions such as query name or
  10. register name, datagram sends. It also handles building Tcp packets.
  11. Author:
  12. Jim Stewart (Jimst) 10-2-92
  13. Revision History:
  14. --*/
  15. #include "precomp.h" // procedure headings
  16. #include <ipinfo.h>
  17. #include "udpsend.tmh"
  18. VOID
  19. SessionRespDone(
  20. IN PVOID pContext,
  21. IN NTSTATUS status,
  22. IN ULONG lInfo);
  23. VOID
  24. NDgramSendCompleted(
  25. PVOID pContext,
  26. NTSTATUS status,
  27. ULONG lInfo
  28. );
  29. //----------------------------------------------------------------------------
  30. NTSTATUS
  31. UdpSendNSBcast(
  32. IN tNAMEADDR *pNameAddr,
  33. IN PCHAR pScope,
  34. IN tDGRAM_SEND_TRACKING *pTrackerRequest,
  35. IN PVOID pTimeoutRoutine,
  36. IN PVOID pClientContext,
  37. IN PVOID pClientCompletion,
  38. IN ULONG Retries,
  39. IN ULONG Timeout,
  40. IN enum eNSTYPE eNsType,
  41. IN BOOL SendFlag
  42. )
  43. /*++
  44. Routine Description:
  45. This routine sends a name registration or a name query
  46. as a broadcast on the subnet or directed to the name server.
  47. Arguments:
  48. Return Value:
  49. NTSTATUS - success or not
  50. --*/
  51. {
  52. NTSTATUS status;
  53. tNAMEHDR *pNameHdr;
  54. ULONG uLength;
  55. CTELockHandle OldIrq;
  56. ULONG UNALIGNED *pHdrIpAddress;
  57. ULONG IpAddress;
  58. USHORT Port;
  59. USHORT NameType;
  60. tDGRAM_SEND_TRACKING *pTrackerDgram;
  61. tTIMERQENTRY *pTimerQEntry;
  62. PFILE_OBJECT pFileObject;
  63. tDEVICECONTEXT *pDeviceContext = pTrackerRequest->pDeviceContext;
  64. COMPLETIONCLIENT pOldCompletion;
  65. PVOID pOldContext;
  66. if (pNameAddr->NameTypeState & (NAMETYPE_GROUP | NAMETYPE_INET_GROUP))
  67. {
  68. NameType = NBT_GROUP;
  69. }
  70. else
  71. {
  72. NameType = NBT_UNIQUE;
  73. }
  74. // build the correct type of pdu depending on the request type
  75. status = GetTracker (&pTrackerDgram, NBT_TRACKER_SEND_NSBCAST);
  76. if (!NT_SUCCESS(status))
  77. {
  78. return(STATUS_INSUFFICIENT_RESOURCES);
  79. }
  80. pHdrIpAddress = (ULONG UNALIGNED *)CreatePdu(pNameAddr->Name,
  81. pScope,
  82. 0L, // we don't know the IP address yet
  83. NameType,
  84. eNsType,
  85. (PVOID)&pNameHdr,
  86. &uLength,
  87. pTrackerRequest);
  88. if (!pHdrIpAddress)
  89. {
  90. IF_DBG(NBT_DEBUG_NAMESRV)
  91. KdPrint(("Nbt:Failed to Create Pdu to send to WINS PduType= %X\n", eNsType));
  92. FreeTracker (pTrackerDgram, RELINK_TRACKER);
  93. return(STATUS_INSUFFICIENT_RESOURCES);
  94. }
  95. //
  96. // change the dgram header for name refreshes
  97. //
  98. if (eNsType == eNAME_REFRESH)
  99. {
  100. pNameHdr->OpCodeFlags = NbtConfig.OpRefresh;
  101. }
  102. else
  103. if ( (eNsType == eNAME_QUERY)
  104. #ifdef VXD
  105. || (eNsType == eDNS_NAME_QUERY)
  106. #endif
  107. )
  108. {
  109. pHdrIpAddress = NULL;
  110. }
  111. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  112. // fill in the Datagram hdr info in the tracker structure.
  113. // There is never a client buffer to send.
  114. //
  115. // Set the fields here instead of after the timer is started
  116. // since they may be accessed by the Timer completion function
  117. //
  118. pTrackerRequest->pNameAddr = pNameAddr;
  119. pTrackerRequest->TransactionId = pNameHdr->TransactId; // save for response checks.
  120. pTrackerDgram->SendBuffer.pDgramHdr = NULL; // to catch erroneous free's
  121. pTrackerDgram->SendBuffer.pDgramHdr = pNameHdr;
  122. pTrackerDgram->SendBuffer.HdrLength = uLength;
  123. pTrackerDgram->SendBuffer.pBuffer = NULL;
  124. pTrackerDgram->SendBuffer.Length = 0;
  125. pTrackerDgram->pNameAddr = pNameAddr;
  126. pTrackerDgram->pDeviceContext = pDeviceContext;
  127. // start the timer now...We didn't start it before because it could
  128. // have expired during the dgram setup, perhaps before the Tracker was
  129. // fully setup.
  130. //
  131. if (Timeout)
  132. {
  133. //
  134. // Before we over-write the current pTimer field in pNameAddr below,
  135. // we need to check if there is any timer running, and if so, we will
  136. // have to stop it right now
  137. //
  138. while (pTimerQEntry = pNameAddr->pTimer)
  139. {
  140. pNameAddr->pTimer = NULL;
  141. status = StopTimer(pTimerQEntry, &pOldCompletion, &pOldContext);
  142. if (pOldCompletion)
  143. {
  144. CTESpinFree(&NbtConfig.JointLock, OldIrq);
  145. (*pOldCompletion) (pOldContext, STATUS_TIMEOUT);
  146. CTESpinLock(&NbtConfig.JointLock, OldIrq);
  147. }
  148. }
  149. status = StartTimer(pTimeoutRoutine,
  150. Timeout,
  151. (PVOID)pTrackerRequest, // context value
  152. NULL,
  153. pClientContext,
  154. pClientCompletion,
  155. pDeviceContext,
  156. &pTimerQEntry,
  157. (USHORT)Retries,
  158. TRUE);
  159. if (!NT_SUCCESS(status))
  160. {
  161. // we need to differentiate the timer failing versus lack
  162. // of resources
  163. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  164. CTEMemFree(pNameHdr);
  165. FreeTracker(pTrackerDgram,RELINK_TRACKER);
  166. return(STATUS_INVALID_PARAMETER_6);
  167. }
  168. //
  169. // Cross link the nameaddr and the timer so we can stop the timer
  170. // when the name query response occurs
  171. //
  172. pTimerQEntry->pCacheEntry = pNameAddr;
  173. pNameAddr->pTimer = pTimerQEntry;
  174. }
  175. //
  176. // Check the Flag value in the tracker and see if we should do a broadcast
  177. // or a directed send to the name server
  178. //
  179. if (pTrackerRequest->Flags & NBT_BROADCAST)
  180. {
  181. //
  182. // set the broadcast bit in the header to be ON since this may be
  183. // an M or MS node that is changing to broadcast from directed sends.
  184. //
  185. ((PUCHAR)pTrackerDgram->SendBuffer.pDgramHdr)[3] |= FL_BROADCAST_BYTE;
  186. Port = NBT_NAMESERVICE_UDP_PORT;
  187. IpAddress = pDeviceContext->BroadcastAddress;
  188. }
  189. else
  190. {
  191. //
  192. // turn off the broadcast bit in the header since this may be
  193. // an M or MS node that is changing to directed sends from broadcasts.
  194. //
  195. ((PUCHAR)pTrackerDgram->SendBuffer.pDgramHdr)[3] &= ~FL_BROADCAST_BYTE;
  196. // check for a zero first byte in the name passed to the name server
  197. ASSERT(((PUCHAR)pTrackerDgram->SendBuffer.pDgramHdr)[12]);
  198. //
  199. // for Multihomed hosts, UNIQUE name registrations use a special new
  200. // code (0x0F) to tell the name server this is a multihomed name that
  201. // will have several ip addresses
  202. //
  203. if (NbtConfig.MultiHomed && ((eNsType == eNAME_REGISTRATION) && (NameType == NBT_UNIQUE)))
  204. {
  205. //
  206. // if it is a multihomed host, then use a new special registration opcode (0xF)
  207. //
  208. ((PUCHAR)pTrackerDgram->SendBuffer.pDgramHdr)[2] |= OP_REGISTER_MULTI;
  209. }
  210. Port = NbtConfig.NameServerPort;
  211. // name srvr, backup name srvr, dns srvr, backup dnr srvr:which one?
  212. if (pTrackerRequest->Flags & NBT_NAME_SERVER)
  213. {
  214. IpAddress = pDeviceContext->lNameServerAddress;
  215. }
  216. #ifdef MULTIPLE_WINS
  217. //
  218. // IMPORTANT: Check for NAME_SERVER_OTHERS flag has to be before check
  219. // for NAME_SERVER_BACKUP flag, since both flags will be set when we
  220. // we are querying "other" servers
  221. //
  222. else if (pTrackerRequest->Flags & NBT_NAME_SERVER_OTHERS) // Try "other" servers
  223. {
  224. if (0 == pTrackerRequest->NSOthersLeft) // Do LOOP_BACK
  225. {
  226. IpAddress = LOOP_BACK;
  227. }
  228. else
  229. {
  230. IpAddress = pTrackerRequest->pDeviceContext->lOtherServers[pTrackerRequest->NSOthersIndex];
  231. }
  232. }
  233. #endif
  234. else
  235. #ifndef VXD
  236. {
  237. IpAddress = pDeviceContext->lBackupServer;
  238. }
  239. #else
  240. if (pTrackerRequest->Flags & NBT_NAME_SERVER_BACKUP)
  241. {
  242. IpAddress = pDeviceContext->lBackupServer;
  243. }
  244. else
  245. if (pTrackerRequest->Flags & NBT_DNS_SERVER)
  246. {
  247. IpAddress = pDeviceContext->lDnsServerAddress;
  248. Port = NbtConfig.DnsServerPort;
  249. }
  250. else // ----- if (pTrackerRequest->Flags & NBT_DNS_SERVER_BACKUP) ----
  251. {
  252. IpAddress = pDeviceContext->lDnsBackupServer;
  253. Port = NbtConfig.DnsServerPort;
  254. }
  255. #endif
  256. //
  257. // is it is a send to WINS on this machine
  258. //
  259. if (pNameHdr->AnCount == (UCHAR)WINS_SIGNATURE)
  260. {
  261. //
  262. // on RAS links, we don't want to register with the local wins
  263. // but with the wins that RAS told us about.
  264. // (of course, if RAS didn't give us a wins address, at least
  265. // register with the local guy!)
  266. //
  267. if ((pDeviceContext->IpInterfaceFlags & IP_INTFC_FLAG_P2P) && // Check for PointToPoint
  268. (pDeviceContext->lNameServerAddress != LOOP_BACK))
  269. {
  270. // Don't do anything;
  271. }
  272. else
  273. {
  274. IpAddress = pDeviceContext->IpAddress;
  275. }
  276. }
  277. }
  278. ASSERT(pTrackerRequest->Flags);
  279. // each adapter has a different source Ip address for registrations
  280. // pHdrIpAddress will be NULL for NameQueries
  281. if (pHdrIpAddress)
  282. {
  283. // If the Source IP address is to be different from the device we are
  284. // sending the Datagram on, fill it in!
  285. if (pTrackerRequest->Flags & NBT_USE_UNIQUE_ADDR)
  286. {
  287. *pHdrIpAddress = htonl(pTrackerRequest->RemoteIpAddress);
  288. }
  289. else
  290. {
  291. *pHdrIpAddress = htonl(pDeviceContext->IpAddress);
  292. }
  293. }
  294. //
  295. // in the event that DHCP has just removed the IP address, use a null
  296. // FileObject to signal UdpSendDatagram not to do the send
  297. // Also, if the device has been destroyed, dont send anything.
  298. //
  299. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  300. status = UdpSendDatagram(pTrackerDgram,
  301. IpAddress,
  302. NDgramSendCompleted,
  303. pTrackerDgram,
  304. Port,
  305. (SendFlag ? NBT_NAME_SERVICE : 0));
  306. if (!NT_SUCCESS(status))
  307. {
  308. //
  309. // Since pTrackerDgram is associated only with the Datagram send,
  310. // it should be free'ed here only!
  311. //
  312. FreeTracker (pTrackerDgram, FREE_HDR | RELINK_TRACKER);
  313. }
  314. return(status);
  315. }
  316. //----------------------------------------------------------------------------
  317. PVOID
  318. CreatePdu(
  319. IN PCHAR pName,
  320. IN PCHAR pScope,
  321. IN ULONG IpAddress,
  322. IN USHORT NameType,
  323. IN enum eNSTYPE eNsType,
  324. OUT PVOID *pHdrs,
  325. OUT PULONG pLength,
  326. IN tDGRAM_SEND_TRACKING *pTrackerRequest
  327. )
  328. /*++
  329. Routine Description:
  330. This routine builds a registration pdu
  331. Arguments:
  332. Return Value:
  333. PULONG - a ptr to the ip address in the pdu so it can be filled in later
  334. --*/
  335. {
  336. tNAMEHDR *pNameHdr;
  337. ULONG uLength;
  338. ULONG uScopeSize;
  339. tGENERALRR *pGeneral;
  340. CTELockHandle OldIrq;
  341. #ifdef VXD
  342. if ( (eNsType == eDNS_NAME_QUERY) || (eNsType == eDIRECT_DNS_NAME_QUERY) )
  343. {
  344. uScopeSize = domnamelen(pTrackerRequest->pchDomainName) + 1; // +1 for len byte
  345. if (uScopeSize > 1)
  346. {
  347. uScopeSize++; // for the null byte
  348. }
  349. }
  350. else
  351. #endif
  352. uScopeSize = strlen(pScope) +1; // +1 for null too
  353. // size is size of the namehdr structure -1 for the NetbiosName[1]
  354. // + the 32 bytes for the half ascii name +
  355. // scope + size of the General RR structure
  356. uLength = sizeof(tNAMEHDR) - 1
  357. + (NETBIOS_NAME_SIZE << 1)
  358. + uScopeSize;
  359. if (eNsType == eNAME_QUERY)
  360. {
  361. uLength = uLength + sizeof(ULONG);
  362. }
  363. #ifdef VXD
  364. // there is no half-ascii conversion in DNS. we added 32 bytes above, but
  365. // we need only 16. so, subtract 16.
  366. else if (eNsType == eDNS_NAME_QUERY)
  367. {
  368. uLength = uLength - NETBIOS_NAME_SIZE + sizeof(ULONG);
  369. }
  370. // This is a "raw" DNS name query. Substitute raw string length of pName
  371. // for NETBIOS_NAME_SIZE.
  372. else if (eNsType == eDIRECT_DNS_NAME_QUERY)
  373. {
  374. uLength = uLength - (NETBIOS_NAME_SIZE << 1) + sizeof(ULONG) + strlen(pName) + 1;
  375. }
  376. #endif
  377. else
  378. {
  379. uLength += sizeof(tGENERALRR);
  380. }
  381. // Note that this memory must be deallocated when the send completes in
  382. // tdiout.DgramSendCompletion
  383. pNameHdr = NbtAllocMem((USHORT)uLength ,NBT_TAG('X'));
  384. if (!pNameHdr)
  385. {
  386. return(NULL);
  387. }
  388. CTEZeroMemory((PVOID)pNameHdr,uLength);
  389. //
  390. // for resends of the same name query or name registration, do not increment
  391. // the transaction id
  392. //
  393. if (pTrackerRequest->TransactionId)
  394. {
  395. pNameHdr->TransactId = pTrackerRequest->TransactionId;
  396. }
  397. else
  398. {
  399. pNameHdr->TransactId = htons(GetTransactId());
  400. }
  401. pNameHdr->QdCount = 1;
  402. pNameHdr->AnCount = 0;
  403. pNameHdr->NsCount = 0;
  404. #ifdef VXD
  405. if ((eNsType != eDNS_NAME_QUERY)&&(eNsType != eDIRECT_DNS_NAME_QUERY))
  406. {
  407. #endif
  408. // Convert the name to half ascii and copy!! ... adding the scope too
  409. pGeneral = (tGENERALRR *)ConvertToHalfAscii(
  410. (PCHAR)&pNameHdr->NameRR.NameLength,
  411. pName,
  412. pScope,
  413. uScopeSize);
  414. pGeneral->Question.QuestionTypeClass = htonl(QUEST_NBINTERNET);
  415. #ifdef VXD
  416. }
  417. #endif
  418. *pHdrs = (PVOID)pNameHdr;
  419. *pLength = uLength;
  420. switch (eNsType)
  421. {
  422. #ifdef VXD
  423. case eDNS_NAME_QUERY:
  424. case eDIRECT_DNS_NAME_QUERY:
  425. // copy the netbios name ... adding the scope too
  426. pGeneral = (tGENERALRR *)DnsStoreName(
  427. (PCHAR)&pNameHdr->NameRR.NameLength,
  428. pName,
  429. pTrackerRequest->pchDomainName,
  430. eNsType);
  431. pGeneral->Question.QuestionTypeClass = htonl(QUEST_DNSINTERNET);
  432. pNameHdr->OpCodeFlags = (FL_RECURDESIRE);
  433. pNameHdr->ArCount = 0;
  434. // we just need to return something non-null to succeed.
  435. return((PULONG)pNameHdr);
  436. #endif
  437. case eNAME_QUERY:
  438. if (NodeType & BNODE)
  439. {
  440. pNameHdr->OpCodeFlags = (FL_BROADCAST | FL_RECURDESIRE);
  441. }
  442. else
  443. pNameHdr->OpCodeFlags = (FL_RECURDESIRE);
  444. pNameHdr->ArCount = 0;
  445. // we just need to return something non-null to succeed.
  446. return((PULONG)pNameHdr);
  447. break;
  448. case eNAME_REGISTRATION_OVERWRITE:
  449. case eNAME_REFRESH:
  450. case eNAME_REGISTRATION:
  451. //
  452. // The broadcast bit is set in UdpSendNSBcast so we don't
  453. // need to set it here. - just set the op code, since the broadcast
  454. // bit is a function of whether we are talking to the nameserver or doing
  455. // a broadcast. This code handles the multi-homed case with a new
  456. // opcode for registration, and that opcode is set in the routine that
  457. //
  458. // The final name registration in Broadcast is called an Overwrite request
  459. // and it does not have the FL_RECURSION Desired bit set.
  460. //
  461. if (eNsType == eNAME_REGISTRATION_OVERWRITE)
  462. {
  463. pNameHdr->OpCodeFlags = (OP_REGISTRATION);
  464. }
  465. else
  466. {
  467. pNameHdr->OpCodeFlags = (FL_RECURDESIRE | OP_REGISTRATION);
  468. }
  469. pGeneral->Ttl = htonl(DEFAULT_TTL);
  470. // *** NOTE: There is no BREAK here by DESIGN!!
  471. case eNAME_RELEASE:
  472. // this code sets the Broadcast bit based on the node type rather than the
  473. // type of send....UdpSendNSBcast, resets the code according to the type of
  474. // name, so this code may not need to set the Broadcast bit
  475. //
  476. if (eNsType == eNAME_RELEASE)
  477. {
  478. pNameHdr->OpCodeFlags = OP_RELEASE;
  479. //
  480. // TTL for release is zero
  481. //
  482. pGeneral->Ttl = 0;
  483. }
  484. pNameHdr->ArCount = 1; // 1 additional resource record included
  485. //
  486. // If WINS is on the same machine adjust the PDU to be able to tell
  487. // WINS that this pdu came from the local machine
  488. //
  489. #ifndef VXD
  490. if (pWinsInfo && (pTrackerRequest->Flags & NBT_NAME_SERVER))
  491. {
  492. pNameHdr->AnCount = (UCHAR)WINS_SIGNATURE;
  493. }
  494. #endif
  495. pGeneral->RrName.uSizeLabel = PTR_TO_NAME; // set top two bits to signify ptr
  496. // the offset ptr to the name added above
  497. pGeneral->RrName.pLabel[0] = sizeof(tNAMEHDR) - sizeof(tNETBIOS_NAME);
  498. pGeneral->RrTypeClass = htonl(QUEST_NBINTERNET);
  499. pGeneral->Length = htons(6);
  500. pGeneral->Flags = htons((USHORT)((NameType << 15) | NbtConfig.PduNodeType));
  501. pGeneral->IpAddress = htonl(IpAddress);
  502. break;
  503. }
  504. // return the ptr to the IP address so this can be filled in later if necessary
  505. return((PVOID)&pGeneral->IpAddress);
  506. }
  507. //----------------------------------------------------------------------------
  508. VOID
  509. NameDgramSendCompleted(
  510. PVOID pContext,
  511. NTSTATUS status,
  512. ULONG lInfo
  513. )
  514. /*++
  515. Routine Description:
  516. This routine frees the name service datagram that was allocated for
  517. this name query or name registration in UdpSendNsBcast.
  518. Arguments:
  519. pContext = ptr to datagram header
  520. Return Value:
  521. --*/
  522. {
  523. tDGRAM_SEND_TRACKING *pTracker;
  524. CTELockHandle OldIrq;
  525. pTracker = (tDGRAM_SEND_TRACKING *)pContext;
  526. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  527. CTEMemFree(pTracker->SendBuffer.pDgramHdr);
  528. pTracker->SendBuffer.pDgramHdr = NULL;
  529. NBT_DEREFERENCE_TRACKER(pTracker, TRUE);
  530. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  531. }
  532. //----------------------------------------------------------------------------
  533. VOID
  534. NDgramSendCompleted(
  535. PVOID pContext,
  536. NTSTATUS status,
  537. ULONG lInfo
  538. )
  539. /*++
  540. Routine Description:
  541. This routine frees the name service datagram that was allocated for
  542. this name query or name registration in UdpSendNsBcast.
  543. Arguments:
  544. pContext = ptr to datagram header
  545. Return Value:
  546. --*/
  547. {
  548. tDGRAM_SEND_TRACKING *pTracker;
  549. CTELockHandle OldIrq;
  550. pTracker = (tDGRAM_SEND_TRACKING *)pContext;
  551. FreeTracker(pTracker, FREE_HDR | RELINK_TRACKER);
  552. }
  553. //----------------------------------------------------------------------------
  554. NTSTATUS
  555. UdpSendResponse(
  556. IN ULONG lNameSize,
  557. IN tNAMEHDR UNALIGNED *pNameHdrIn,
  558. IN tNAMEADDR *pNameAddr,
  559. IN PTDI_ADDRESS_IP pDestIpAddress,
  560. IN tDEVICECONTEXT *pDeviceContext,
  561. IN ULONG Rcode,
  562. IN enum eNSTYPE NsType,
  563. IN CTELockHandle OldIrq
  564. )
  565. /*++
  566. Routine Description:
  567. This routine builds a Name Release/Registration/Query response pdu and
  568. sends it with the specified Rcode.
  569. Arguments:
  570. lSize - number of bytes in the name including scope in half ascii
  571. Return Value:
  572. NTSTATUS - success or not
  573. --*/
  574. {
  575. NTSTATUS status;
  576. tNAMEHDR *pNameHdr;
  577. ULONG uLength;
  578. tDGRAM_SEND_TRACKING *pTracker;
  579. tQUERYRESP UNALIGNED *pQuery;
  580. ULONG ToCopy;
  581. LONG i;
  582. BOOLEAN RespondWithOneAddr = TRUE;
  583. ULONG MultiHomedSize = 0;
  584. ULONG in_addr;
  585. USHORT in_port;
  586. ULONG IpAddress = 0;
  587. USHORT NameType = 0; // Assume we are Unique by default!
  588. BOOLEAN DoNonProxyCode = TRUE;
  589. in_addr = ntohl(pDestIpAddress->in_addr);
  590. in_port = ntohs(pDestIpAddress->sin_port);
  591. // a multihomed node can have the SingleResponse registry value set so
  592. // that it never returns a list of ip addresses. This allows multihoming
  593. // in disjoint WINS server domains. - for name Query responses only
  594. //
  595. if ((NbtConfig.MultiHomed) && (!pNameAddr || pNameAddr->Verify != REMOTE_NAME) &&
  596. (!NbtConfig.SingleResponse) &&
  597. (NsType == eNAME_QUERY_RESPONSE))
  598. {
  599. // if (SrcIsNameServer(in_addr,in_port))
  600. {
  601. RespondWithOneAddr = FALSE;
  602. MultiHomedSize = (NbtConfig.AdapterCount-1)*sizeof(tADDSTRUCT);
  603. }
  604. }
  605. // size is size of the namehdr structure -1 for NetBiosName[1]
  606. // + the 32 bytes for the half ascii name + the Query response record
  607. // + any scope size (including the null on the end of the name)
  608. // ( part of the lNameSize) + the number of extra adapters * the size
  609. // of the address structure (multihomed case).
  610. uLength = sizeof(tNAMEHDR)
  611. + sizeof(tQUERYRESP)
  612. + lNameSize
  613. - 1
  614. + MultiHomedSize;
  615. // Note that this memory must be deallocated when the send completes in
  616. // tdiout.DgramSendCompletion
  617. pNameHdr = NbtAllocMem((USHORT)uLength ,NBT_TAG('Y'));
  618. if (!pNameHdr)
  619. {
  620. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  621. return(STATUS_INSUFFICIENT_RESOURCES);
  622. }
  623. CTEZeroMemory((PVOID)pNameHdr,uLength);
  624. pNameHdr->QdCount = 0;
  625. pNameHdr->AnCount = 1;
  626. //
  627. // fill in the rest of the PDU explicitly
  628. //
  629. pQuery = (tQUERYRESP *)&pNameHdr->NameRR.NetBiosName[lNameSize];
  630. pQuery->RrTypeClass = htonl(QUEST_NBINTERNET);
  631. pQuery->Ttl = 0;
  632. pQuery->Length = htons(sizeof(tADDSTRUCT));
  633. pQuery->Flags = htons((USHORT)(NbtConfig.PduNodeType));
  634. // set the name type to 1 if it is a group so we can shift the 1 to the 16th
  635. // bit position
  636. // pNameAddr may not be set if we are sending a -ve NameQuery response, in which case, the field
  637. // is never looked at, or if we are sending a release response, which holds sends only
  638. // for a unique name, in which case we have already initialized the value to 0
  639. //
  640. if (pNameAddr != NULL)
  641. {
  642. NameType = (pNameAddr->NameTypeState & (NAMETYPE_GROUP | NAMETYPE_INET_GROUP)) ? 1 : 0;
  643. }
  644. pQuery->Flags = htons((USHORT)((NameType << 15) | NbtConfig.PduNodeType));
  645. // convert Rcode to network order
  646. Rcode = htons(Rcode);
  647. switch (NsType)
  648. {
  649. case eNAME_RELEASE:
  650. case eNAME_REGISTRATION_RESPONSE:
  651. // copy the source name and the 12 bytes preceeding it to complete the
  652. // response pdu
  653. //
  654. ToCopy = sizeof(tNAMEHDR) + lNameSize -1;
  655. CTEMemCopy((PVOID)pNameHdr,
  656. (PVOID)pNameHdrIn,
  657. ToCopy);
  658. if (NsType == eNAME_RELEASE)
  659. {
  660. // setup the fields in the response.
  661. pNameHdr->OpCodeFlags = (USHORT)(OP_RESPONSE | OP_RELEASE
  662. | FL_AUTHORITY
  663. | Rcode);
  664. }
  665. else
  666. {
  667. // setup the fields in the response.
  668. pNameHdr->OpCodeFlags = (USHORT)(OP_RESPONSE | OP_REGISTRATION |
  669. FL_RECURDESIRE | FL_RECURAVAIL | FL_AUTHORITY
  670. | Rcode);
  671. }
  672. // these two lines must be here because the memcopy above sets
  673. // them to wrong values.
  674. pNameHdr->QdCount = 0;
  675. pNameHdr->AnCount = 1;
  676. pNameHdr->ArCount = 0;
  677. pNameHdr->NsCount = 0;
  678. // this code will run in the proxy case where another node does a
  679. // registration of a unique name that conflicts with an internet
  680. // group name in the remote table. There are never any internet group
  681. // names in the local table - at least if there are, they are flagged
  682. // as simple groups.
  683. //
  684. if (pNameAddr)
  685. {
  686. if (pNameAddr->NameTypeState & NAMETYPE_INET_GROUP)
  687. {
  688. if (pNameAddr->pLmhSvcGroupList)
  689. {
  690. IpAddress = pNameAddr->pLmhSvcGroupList[0];
  691. }
  692. else
  693. {
  694. IpAddress = 0;
  695. }
  696. }
  697. else
  698. {
  699. // an ipaddress of 0 and a group name means it is a local name
  700. // table entry, where the 0 ipaddress should be switched to the
  701. // ipaddress of this adapter.
  702. //
  703. if ((pNameAddr->IpAddress == 0) &&
  704. (pNameAddr->NameTypeState & NAMETYPE_GROUP))
  705. {
  706. IpAddress = pDeviceContext->IpAddress;
  707. }
  708. else
  709. {
  710. IpAddress = pNameAddr->IpAddress;
  711. }
  712. }
  713. }
  714. else
  715. {
  716. IpAddress = 0;
  717. }
  718. break;
  719. case eNAME_QUERY_RESPONSE:
  720. pNameHdr->OpCodeFlags = ( OP_RESPONSE | FL_AUTHORITY | FL_RECURDESIRE );
  721. pNameHdr->TransactId = pNameHdrIn->TransactId;
  722. // add 1 for the name length byte on the front of the name - scope is already
  723. // included in lNameSize
  724. //
  725. CTEMemCopy(&pNameHdr->NameRR.NameLength, (PVOID)&pNameHdrIn->NameRR.NameLength, lNameSize+1);
  726. if (pNameAddr == NULL)
  727. {
  728. // this is a negative query response record since there is no
  729. // local name to be found
  730. //
  731. pNameHdr->OpCodeFlags |= htons(NAME_ERROR);
  732. pQuery->Length = 0;
  733. IpAddress = 0;
  734. }
  735. else
  736. {
  737. tDEVICECONTEXT *pDevContext;
  738. PLIST_ENTRY pHead;
  739. PLIST_ENTRY pEntry;
  740. // do not send name query responses for names not registered on
  741. // this net card, unless it is the name server for that net
  742. // card requesting the name query, since for Multihomed nodes
  743. // when it registers a name, WINS will do a query, which may
  744. // come in on the other net card that the name is not active on
  745. // yet - so we want to respond to this sort of query. Do not do
  746. // this check for a proxy since it is responding for a name
  747. // in the remote name table and it is not bound to an adapter.
  748. //
  749. if (!(NodeType & PROXY) &&
  750. !(pNameAddr->AdapterMask & pDeviceContext->AdapterMask) &&
  751. (!((in_port == NbtConfig.NameServerPort) &&
  752. (pDeviceContext->lNameServerAddress == in_addr) ||
  753. (pDeviceContext->lBackupServer == in_addr))))
  754. {
  755. //
  756. // Only return an address to the requestor if the
  757. // name is registered on that adapter
  758. //
  759. CTEMemFree(pNameHdr);
  760. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  761. return(STATUS_UNSUCCESSFUL);
  762. }
  763. pQuery->Ttl = htonl(DEFAULT_TTL);
  764. //
  765. // In case of PROXY, we send one IP address as response to an
  766. // internet group query. Note: there should not be any INET_GROUP
  767. // names in the local hash table, hence a non-proxy should not execute
  768. // this code
  769. //
  770. #ifdef PROXY_NODE
  771. //
  772. // When the proxy responds, the source node will see that it is a
  773. // group name and convert it to a broadcast, so the Ip address doesn't
  774. // really matter since the sender will not use it. Note that the
  775. // source node send may not actually reach any members of the
  776. // internet group since they may all be off the local subnet.
  777. //
  778. IF_PROXY(NodeType)
  779. {
  780. DoNonProxyCode = FALSE;
  781. if (pNameAddr->NameTypeState & (NAMETYPE_INET_GROUP))
  782. {
  783. IpAddress = 0;
  784. PickBestAddress (pNameAddr, pDeviceContext, &IpAddress);
  785. }
  786. else if (pNameAddr->Verify == LOCAL_NAME)
  787. {
  788. //
  789. // if this name is local and if this is a multihomed machine
  790. // we should treat it like a regular multihomed machine, even
  791. // though this is a Proxy node
  792. //
  793. DoNonProxyCode = TRUE;
  794. }
  795. else
  796. {
  797. IpAddress = pNameAddr->IpAddress;
  798. }
  799. if (IpAddress == 0)
  800. {
  801. // don't return 0, return the broadcast address
  802. //
  803. IpAddress = pDeviceContext->BroadcastAddress;
  804. }
  805. }
  806. if (DoNonProxyCode)
  807. #endif
  808. {
  809. // the node could be multihomed, but we are saying, only
  810. // respond with one address when this flag is set.
  811. if (RespondWithOneAddr)
  812. {
  813. // for multihomed hosts, SelectAdapter can be set to TRUE
  814. //
  815. if (NbtConfig.SelectAdapter)
  816. {
  817. CTESystemTime TimeValue;
  818. LONG Index;
  819. ULONG Count=0;
  820. // we are only going to return one address, but we
  821. // can randomly select it from the available adapters
  822. // Try to find a valid ip address 5 times.
  823. //
  824. IpAddress = 0;
  825. while ((IpAddress == 0) && (Count < 5))
  826. {
  827. Count++;
  828. CTEQuerySystemTime(TimeValue);
  829. Index = RandomizeFromTime( TimeValue, NbtConfig.AdapterCount ) ;
  830. pHead = &NbtConfig.DeviceContexts;
  831. pEntry = pHead->Flink;
  832. for (i = 0;i< Index;i++)
  833. pEntry = pEntry->Flink;
  834. pDevContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
  835. IpAddress = pDevContext->IpAddress;
  836. }
  837. //
  838. // if this adapter still has a null IpAddress then respond
  839. // with the adapter the request came in on, since the
  840. // other adapters could be idle RAS or waiting for a DHCP
  841. // address just now...
  842. //
  843. if (IpAddress == 0)
  844. {
  845. IpAddress = pDeviceContext->IpAddress;
  846. }
  847. }
  848. else
  849. {
  850. IpAddress = pDeviceContext->IpAddress;
  851. }
  852. }
  853. else
  854. {
  855. tADDSTRUCT *pAddStruct;
  856. USHORT Flags;
  857. ULONG Count = 0;
  858. // multihomed case - go through all the adapters making
  859. // up a structure of all adapters that the name is
  860. // registered against. Enough memory was allocated up
  861. // front to have the name registered against all adapeters
  862. // on this node.
  863. //
  864. Flags = pQuery->Flags;
  865. // set to zero so we don't try to set pQuery->IpAddress
  866. // below
  867. IpAddress = 0;
  868. pAddStruct = (tADDSTRUCT *)&pQuery->Flags;
  869. pHead = &NbtConfig.DeviceContexts;
  870. pEntry = pHead->Flink;
  871. while (pEntry != pHead)
  872. {
  873. pDevContext = CONTAINING_RECORD(pEntry,tDEVICECONTEXT,Linkage);
  874. //
  875. // only pass back addresses registered on this adapter
  876. // that are not null(i.e. not RAS adapters after a disconnect)
  877. //
  878. if ((pDevContext->AdapterMask & pNameAddr->AdapterMask) &&
  879. (pDevContext->IpAddress))
  880. {
  881. pAddStruct->NbFlags = Flags;
  882. pAddStruct->IpAddr = htonl(pDevContext->IpAddress);
  883. Count++;
  884. pAddStruct++;
  885. }
  886. pEntry = pEntry->Flink;
  887. }
  888. // re-adjust the length of the pdu if the name is not registered
  889. // against all adapters...
  890. //
  891. if (Count != NbtConfig.AdapterCount)
  892. {
  893. uLength -= (NbtConfig.AdapterCount - Count)*sizeof(tADDSTRUCT);
  894. }
  895. pQuery->Length = (USHORT)htons(Count*sizeof(tADDSTRUCT));
  896. }
  897. }
  898. }
  899. }
  900. if (IpAddress)
  901. {
  902. pQuery->IpAddress = htonl(IpAddress);
  903. }
  904. // get a tracker structure, which has a SendInfo structure in it
  905. status = GetTracker(&pTracker, NBT_TRACKER_SEND_RESPONSE_DGRAM);
  906. if (!NT_SUCCESS(status))
  907. {
  908. CTEMemFree((PVOID)pNameHdr);
  909. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  910. return(STATUS_INSUFFICIENT_RESOURCES);
  911. }
  912. // fill in the connection information
  913. pTracker->SendBuffer.HdrLength = uLength;
  914. pTracker->SendBuffer.pDgramHdr = (PVOID)pNameHdr;
  915. pTracker->SendBuffer.Length = 0;
  916. pTracker->SendBuffer.pBuffer = NULL;
  917. pTracker->pDeviceContext = pDeviceContext;
  918. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  919. status = UdpSendDatagram (pTracker,
  920. in_addr,
  921. QueryRespDone,
  922. pTracker,
  923. in_port,
  924. NBT_NAME_SERVICE);
  925. return(status);
  926. }
  927. //----------------------------------------------------------------------------
  928. VOID
  929. QueryRespDone(
  930. IN PVOID pContext,
  931. IN NTSTATUS status,
  932. IN ULONG lInfo)
  933. /*++
  934. Routine Description
  935. This routine handles cleaning up various data blocks used in conjunction
  936. with the sending the Query response.
  937. Arguments:
  938. pContext - ptr to the DGRAM_TRACKER block
  939. NTSTATUS - completion status
  940. Return Values:
  941. VOID
  942. --*/
  943. {
  944. tDGRAM_SEND_TRACKING *pTracker;
  945. CTELockHandle OldIrq;
  946. pTracker = (tDGRAM_SEND_TRACKING *)pContext;
  947. FreeTracker(pTracker,RELINK_TRACKER | FREE_HDR);
  948. }
  949. //----------------------------------------------------------------------------
  950. NTSTATUS
  951. UdpSendDatagram(
  952. IN tDGRAM_SEND_TRACKING *pDgramTracker,
  953. IN ULONG IpAddress,
  954. IN PVOID pCompletionRoutine,
  955. IN PVOID CompletionContext,
  956. IN USHORT Port,
  957. IN ULONG Service
  958. )
  959. /*++
  960. Routine Description:
  961. This routine sends a datagram across the TDI to be sent by Udp.
  962. Arguments:
  963. Return Value:
  964. NTSTATUS - success or not
  965. --*/
  966. {
  967. NTSTATUS status;
  968. TDI_REQUEST TdiRequest;
  969. ULONG uSentSize;
  970. TDI_CONNECTION_INFORMATION *pSendInfo;
  971. PTRANSPORT_ADDRESS pTransportAddr;
  972. ULONG Length;
  973. PFILE_OBJECT TransportFileObject = NULL;
  974. CTELockHandle OldIrq;
  975. tDEVICECONTEXT *pDeviceContext = NULL;
  976. tFILE_OBJECTS *pFileObjectsContext;
  977. status = STATUS_SUCCESS;
  978. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  979. if (NBT_REFERENCE_DEVICE (pDgramTracker->pDeviceContext, REF_DEV_UDP_SEND, TRUE))
  980. {
  981. pDeviceContext = pDgramTracker->pDeviceContext; // Assigned => referenced!
  982. if ((pDgramTracker->pDeviceContext->IpAddress) &&
  983. (pFileObjectsContext = pDgramTracker->pDeviceContext->pFileObjects))
  984. {
  985. switch (Service)
  986. {
  987. case (NBT_NAME_SERVICE):
  988. TransportFileObject = pDgramTracker->pDeviceContext->pFileObjects->pNameServerFileObject;
  989. break;
  990. case (NBT_DATAGRAM_SERVICE):
  991. TransportFileObject = pDgramTracker->pDeviceContext->pFileObjects->pDgramFileObject;
  992. break;
  993. default:
  994. ;
  995. }
  996. //
  997. // an address of 0 means do a broadcast. When '1C' internet group
  998. // names are built either from the Lmhost file or from the network
  999. // the broadcast address is inserted in the list as 0.
  1000. //
  1001. if (IpAddress == 0)
  1002. {
  1003. IpAddress = pDgramTracker->pDeviceContext->BroadcastAddress;
  1004. }
  1005. // when there is no WINS server set in the registry we set the WINS
  1006. // ip address to LOOP_BACK, so if it is set to that here, do not send
  1007. // the datagram. If There is no Ip Address then the Transport Handle
  1008. // will be null and we do not do the send in that case either.
  1009. //
  1010. if (IpAddress == LOOP_BACK)
  1011. {
  1012. TransportFileObject = NULL ;
  1013. }
  1014. }
  1015. //
  1016. // Dereference the Device if the request is going to fail, or
  1017. // there is no completion routine!
  1018. //
  1019. if ((!TransportFileObject) || (!pCompletionRoutine))
  1020. {
  1021. NBT_DEREFERENCE_DEVICE (pDeviceContext, REF_DEV_UDP_SEND, TRUE);
  1022. }
  1023. }
  1024. if (!TransportFileObject)
  1025. {
  1026. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1027. if (pCompletionRoutine)
  1028. {
  1029. (*(NBT_COMPLETION) pCompletionRoutine) (CompletionContext, STATUS_UNSUCCESSFUL, 0);
  1030. }
  1031. return(status);
  1032. }
  1033. pFileObjectsContext->RefCount++; // Dereferenced after the Send has completed
  1034. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1035. // the completion routine is setup to free the pDgramTracker memory block
  1036. TdiRequest.Handle.AddressHandle = (PVOID)TransportFileObject;
  1037. TdiRequest.RequestNotifyObject = pCompletionRoutine;
  1038. TdiRequest.RequestContext = (PVOID)CompletionContext;
  1039. // the send length is the client dgram length + the size of the dgram header
  1040. Length = pDgramTracker->SendBuffer.HdrLength + pDgramTracker->SendBuffer.Length;
  1041. // fill in the connection information
  1042. pSendInfo = pDgramTracker->pSendInfo;
  1043. pSendInfo->RemoteAddressLength = sizeof(TRANSPORT_ADDRESS) -1 + pNbtGlobConfig->SizeTransportAddress;
  1044. // fill in the remote address
  1045. pTransportAddr = (PTRANSPORT_ADDRESS)pSendInfo->RemoteAddress;
  1046. pTransportAddr->TAAddressCount = 1;
  1047. pTransportAddr->Address[0].AddressLength = pNbtGlobConfig->SizeTransportAddress;
  1048. pTransportAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
  1049. ((PTDI_ADDRESS_IP)pTransportAddr->Address[0].Address)->sin_port = htons(Port);
  1050. ((PTDI_ADDRESS_IP)pTransportAddr->Address[0].Address)->in_addr = htonl(IpAddress);
  1051. status = TdiSendDatagram (&TdiRequest, pSendInfo, Length, &uSentSize, pDgramTracker);
  1052. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  1053. if (--pFileObjectsContext->RefCount == 0)
  1054. {
  1055. NTQueueToWorkerThread(
  1056. &pFileObjectsContext->WorkItemCleanUp,
  1057. DelayedNbtCloseFileHandles,
  1058. NULL,
  1059. pFileObjectsContext,
  1060. NULL,
  1061. NULL,
  1062. TRUE
  1063. );
  1064. }
  1065. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1066. return(status);
  1067. }
  1068. //----------------------------------------------------------------------------
  1069. NTSTATUS
  1070. TcpSessionStart(
  1071. IN tDGRAM_SEND_TRACKING *pTracker,
  1072. IN ULONG IpAddress,
  1073. IN tDEVICECONTEXT *pDeviceContext,
  1074. IN PVOID pCompletionRoutine,
  1075. IN ULONG Port
  1076. )
  1077. /*++
  1078. Routine Description:
  1079. This routine sets up a tcp connection by passing a connect through TDI to
  1080. TCP.
  1081. Arguments:
  1082. Return Value:
  1083. NTSTATUS - success or not
  1084. --*/
  1085. {
  1086. NTSTATUS status;
  1087. TDI_REQUEST TdiRequest;
  1088. TDI_CONNECTION_INFORMATION *pSendInfo;
  1089. PTRANSPORT_ADDRESS pTransportAddr;
  1090. tCONNECTELE *pConnEle;
  1091. CTELockHandle OldIrq;
  1092. tLOWERCONNECTION *pLowerConn;
  1093. pSendInfo = pTracker->pSendInfo;
  1094. // we need to pass the file handle of the connection to TCP.
  1095. pConnEle = (tCONNECTELE *)pTracker->pConnEle;
  1096. CTESpinLock(pConnEle,OldIrq);
  1097. pLowerConn = pConnEle->pLowerConnId;
  1098. if (pLowerConn)
  1099. {
  1100. TdiRequest.Handle.AddressHandle = (PVOID)((tLOWERCONNECTION *)pConnEle->pLowerConnId)->pFileObject;
  1101. // the completion routine is setup to free the pTracker memory block
  1102. TdiRequest.RequestNotifyObject = pCompletionRoutine;
  1103. TdiRequest.RequestContext = (PVOID)pTracker;
  1104. // fill in the connection information
  1105. pSendInfo->RemoteAddressLength = sizeof(TRANSPORT_ADDRESS) -1 + pNbtGlobConfig->SizeTransportAddress;
  1106. pTransportAddr = (PTRANSPORT_ADDRESS)pSendInfo->RemoteAddress;
  1107. // fill in the remote address
  1108. pTransportAddr->TAAddressCount = 1;
  1109. pTransportAddr->Address[0].AddressLength = pNbtGlobConfig->SizeTransportAddress;
  1110. pTransportAddr->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
  1111. ((PTDI_ADDRESS_IP)pTransportAddr->Address[0].Address)->sin_port = htons((USHORT)Port);
  1112. ((PTDI_ADDRESS_IP)pTransportAddr->Address[0].Address)->in_addr = htonl(IpAddress);
  1113. CTESpinFree(pConnEle,OldIrq);
  1114. // pass through the TDI I/F on the bottom of NBT, to the transport
  1115. // pass in the original irp from the client so that the client can
  1116. // cancel it ok...rather than use one of NBT's irps
  1117. //
  1118. status = TdiConnect (&TdiRequest, (ULONG_PTR)pTracker->pTimeout, pSendInfo, pConnEle->pIrp);
  1119. }
  1120. else
  1121. {
  1122. CTESpinFree(pConnEle,OldIrq);
  1123. //
  1124. // Complete the request through the completion routine so it
  1125. // cleans up correctly
  1126. //
  1127. (*(NBT_COMPLETION)pCompletionRoutine)( (PVOID)pTracker, STATUS_CANCELLED, 0L );
  1128. status = STATUS_CANCELLED;
  1129. }
  1130. NbtTrace(NBT_TRACE_OUTBOUND, ("\tpTracker %p: %!status!", pTracker, status));
  1131. return(status);
  1132. }
  1133. //----------------------------------------------------------------------------
  1134. NTSTATUS
  1135. TcpSendSessionResponse(
  1136. IN tLOWERCONNECTION *pLowerConn,
  1137. IN ULONG lStatusCode,
  1138. IN ULONG lSessionStatus
  1139. )
  1140. /*++
  1141. Routine Description:
  1142. This routine sends a session PDU corresponding to the lStatusCode. This
  1143. could be a KeepAlive, PositiveSessionResponse, NegativeSessionResponse or
  1144. a Retarget (not implemented yet). For the Keep Alive case the completion
  1145. routine passed in is used rather than SessionRespDone, as is the case
  1146. for all other messages.
  1147. Arguments:
  1148. Return Value:
  1149. NTSTATUS - success or not
  1150. --*/
  1151. {
  1152. NTSTATUS status;
  1153. tDGRAM_SEND_TRACKING *pTracker;
  1154. tSESSIONERROR *pSessionHdr;
  1155. pSessionHdr = (tSESSIONERROR *)NbtAllocMem(sizeof(tSESSIONERROR),NBT_TAG('Z'));
  1156. if (!pSessionHdr)
  1157. {
  1158. return(STATUS_INSUFFICIENT_RESOURCES);
  1159. }
  1160. // get a tracker structure, which has a SendInfo structure in it
  1161. status = GetTracker(&pTracker, NBT_TRACKER_SEND_RESPONSE_SESSION);
  1162. if (NT_SUCCESS(status))
  1163. {
  1164. pTracker->SendBuffer.pDgramHdr = (PVOID)pSessionHdr;
  1165. pTracker->SendBuffer.pBuffer = NULL;
  1166. pTracker->SendBuffer.Length = 0;
  1167. pSessionHdr->Flags = NBT_SESSION_FLAGS;
  1168. pSessionHdr->Type = (UCHAR)lStatusCode;
  1169. switch (lStatusCode)
  1170. {
  1171. case NBT_NEGATIVE_SESSION_RESPONSE:
  1172. pTracker->SendBuffer.HdrLength = sizeof(tSESSIONERROR);
  1173. // this length is one byte longer for the error code - different type used here
  1174. pSessionHdr->Length = htons(1); // one error code byte
  1175. pSessionHdr->ErrorCode = (UCHAR)lSessionStatus;
  1176. break;
  1177. case NBT_POSITIVE_SESSION_RESPONSE:
  1178. pTracker->SendBuffer.HdrLength = sizeof(tSESSIONHDR);
  1179. pSessionHdr->Length = 0; // no data following the length byte
  1180. break;
  1181. }
  1182. NbtTrace(NBT_TRACE_INBOUND, ("pTracker %p: Session Response %d", pTracker, lStatusCode));
  1183. status = TcpSendSession(pTracker,
  1184. pLowerConn,
  1185. SessionRespDone);
  1186. }
  1187. else
  1188. {
  1189. CTEMemFree((PVOID)pSessionHdr);
  1190. }
  1191. return(status);
  1192. }
  1193. //----------------------------------------------------------------------------
  1194. NTSTATUS
  1195. TcpSendSession(
  1196. IN tDGRAM_SEND_TRACKING *pTracker,
  1197. IN tLOWERCONNECTION *pLowerConn,
  1198. IN PVOID pCompletionRoutine
  1199. )
  1200. /*++
  1201. Routine Description:
  1202. This routine sends a message on a tcp connection.
  1203. Arguments:
  1204. Return Value:
  1205. NTSTATUS - success or not
  1206. --*/
  1207. {
  1208. NTSTATUS status;
  1209. TDI_REQUEST TdiRequest;
  1210. ULONG lSentLength;
  1211. // we need to pass the file handle of the connection to TCP.
  1212. TdiRequest.Handle.AddressHandle = (PVOID)pLowerConn->pFileObject;
  1213. // the completion routine is setup to free the pTracker memory block
  1214. TdiRequest.RequestContext = (PVOID)pTracker;
  1215. // this completion routine just puts the tracker back on its list and
  1216. // frees the memory associated with the UserData buffer.
  1217. TdiRequest.RequestNotifyObject = pCompletionRoutine;
  1218. // pass through the TDI I/F on the bottom of NBT, to the transport
  1219. status = TdiSend(
  1220. &TdiRequest,
  1221. 0, // no send flags
  1222. (ULONG)pTracker->SendBuffer.HdrLength +
  1223. (ULONG)pTracker->SendBuffer.Length ,
  1224. &lSentLength,
  1225. &pTracker->SendBuffer,
  1226. 0); // no send flags set
  1227. NbtTrace(NBT_TRACE_OUTBOUND, ("\tpTracker %p: %!status!", pTracker, status));
  1228. return(status);
  1229. }
  1230. //----------------------------------------------------------------------------
  1231. VOID
  1232. SessionRespDone(
  1233. IN PVOID pContext,
  1234. IN NTSTATUS status,
  1235. IN ULONG lInfo)
  1236. /*++
  1237. Routine Description
  1238. This routine handles cleaning up various data blocks used in conjunction
  1239. sending a session response at session startup time. If the session
  1240. response was negative, then kill the connection.
  1241. Arguments:
  1242. pContext - ptr to the DGRAM_TRACKER block
  1243. NTSTATUS - completion status
  1244. Return Values:
  1245. VOID
  1246. --*/
  1247. {
  1248. tDGRAM_SEND_TRACKING *pTracker;
  1249. pTracker = (tDGRAM_SEND_TRACKING *)pContext;
  1250. FreeTracker(pTracker,FREE_HDR | RELINK_TRACKER);
  1251. }
  1252. //----------------------------------------------------------------------------
  1253. NTSTATUS
  1254. SendTcpDisconnect(
  1255. IN tLOWERCONNECTION *pLowerConnId
  1256. )
  1257. /*++
  1258. Routine Description
  1259. This routine disconnects a TCP connection in a graceful manner which
  1260. insures that any data still in the pipe gets to the other side. Mostly
  1261. it calls TcpDisconnect which does the work. This routine just gets a
  1262. tracker for the send.
  1263. Arguments:
  1264. pLowerConnID - ptr to the lower connection that has the file object in it
  1265. Return Values:
  1266. NTSTATUS - completion status
  1267. VOID
  1268. --*/
  1269. {
  1270. NTSTATUS status;
  1271. tDGRAM_SEND_TRACKING *pTracker;
  1272. status = GetTracker(&pTracker, NBT_TRACKER_SEND_DISCONNECT);
  1273. if (NT_SUCCESS(status))
  1274. {
  1275. pTracker->pConnEle = (PVOID)pLowerConnId;
  1276. status = TcpDisconnect(pTracker,NULL,TDI_DISCONNECT_RELEASE,FALSE);
  1277. }
  1278. return(status);
  1279. }
  1280. //----------------------------------------------------------------------------
  1281. NTSTATUS
  1282. TcpDisconnect(
  1283. IN tDGRAM_SEND_TRACKING *pTracker,
  1284. IN PVOID Timeout,
  1285. IN ULONG Flags,
  1286. IN BOOLEAN Wait
  1287. )
  1288. /*++
  1289. Routine Description
  1290. This routine disconnects a TCP connection in a graceful manner which
  1291. insures that any data still in the pipe gets to the other side.
  1292. Arguments:
  1293. pTracker - ptr to the DGRAM_TRACKER block
  1294. Return Values:
  1295. NTSTATUS - completion status
  1296. VOID
  1297. --*/
  1298. {
  1299. TDI_REQUEST TdiRequest;
  1300. NTSTATUS status;
  1301. // we need to pass the file handle of the connection to TCP.
  1302. TdiRequest.Handle.AddressHandle =
  1303. (PVOID)((tLOWERCONNECTION *)pTracker->pConnEle)->pFileObject;
  1304. // the completion routine is setup to free the pTracker memory block
  1305. TdiRequest.RequestContext = (PVOID)pTracker;
  1306. // this completion routine just puts the tracker back on its list and
  1307. // frees the memory associated with the UserData buffer.
  1308. TdiRequest.RequestNotifyObject = DisconnectDone;
  1309. pTracker->Flags = (USHORT)Flags;
  1310. status = TdiDisconnect(&TdiRequest,
  1311. Timeout,
  1312. Flags,
  1313. pTracker->pSendInfo,
  1314. ((tLOWERCONNECTION *)pTracker->pConnEle)->pIrp,
  1315. Wait);
  1316. NbtTrace(NBT_TRACE_DISCONNECT, ("pTracker %p: %!status!", pTracker, status));
  1317. return(status);
  1318. }
  1319. //----------------------------------------------------------------------------
  1320. VOID
  1321. DisconnectDone(
  1322. IN PVOID pContext,
  1323. IN NTSTATUS status,
  1324. IN ULONG lInfo)
  1325. /*++
  1326. Routine Description
  1327. This routine handles cleaning up after a disconnect is sent to the transport.
  1328. Arguments:
  1329. pContext - ptr to the DGRAM_TRACKER block
  1330. Return Values:
  1331. VOID
  1332. --*/
  1333. {
  1334. tDGRAM_SEND_TRACKING *pTracker;
  1335. tLOWERCONNECTION *pLowerConn;
  1336. CTELockHandle OldIrq;
  1337. PCTE_IRP pIrp;
  1338. BOOLEAN CleanupLower = FALSE;
  1339. NTSTATUS DiscWaitStatus;
  1340. tCONNECTELE *pConnEle;
  1341. PCTE_IRP pIrpClose;
  1342. tDEVICECONTEXT *pDeviceContext = NULL;
  1343. pTracker = (tDGRAM_SEND_TRACKING *)pContext;
  1344. pLowerConn = (tLOWERCONNECTION *)pTracker->pConnEle;
  1345. NbtTrace(NBT_TRACE_DISCONNECT, ("pTracker %p: pLowerConn %p pConnEle %p %!status!",
  1346. pTracker, pLowerConn, pLowerConn->pUpperConnection, status));
  1347. CTESpinLock(&NbtConfig.JointLock,OldIrq);
  1348. CTESpinLockAtDpc(pLowerConn);
  1349. ASSERT (NBT_VERIFY_HANDLE (pLowerConn, NBT_VERIFY_LOWERCONN));
  1350. IF_DBG(NBT_DEBUG_DISCONNECT)
  1351. KdPrint(("Nbt.DisconnectDone: Disconnect Irp has been returned...pLowerConn %X,state %X\n",
  1352. pLowerConn,pLowerConn->State));
  1353. //
  1354. // if the state is disconnected, then a disconnect indication
  1355. // has come from the transport.. . if still disconnecting,
  1356. // then we have not had a disconnect indication yet, so
  1357. // wait for the indication to go through DisconnectHndlrNotOs which
  1358. // will do the cleanup.
  1359. //
  1360. // Streams TCP always indicates before completing the disconnect request,
  1361. // so we always cleanup here for the Streams stack.
  1362. //
  1363. //
  1364. // If the disconnect was abortive, then there will not be a disconnect
  1365. // indication, so do the cleanup now.
  1366. //
  1367. if ((!StreamsStack) &&
  1368. (NT_SUCCESS (status)) &&
  1369. (pTracker->Flags == TDI_DISCONNECT_RELEASE) &&
  1370. (pLowerConn->State == NBT_DISCONNECTING))
  1371. {
  1372. SET_STATE_LOWER (pLowerConn, NBT_DISCONNECTED);
  1373. }
  1374. else if (pLowerConn->State != NBT_IDLE)
  1375. {
  1376. //
  1377. // change the state to idle so that the Disconnect handler will
  1378. // not attempt to do anything with it if for some reason the transport
  1379. // indicates a disconnect after this point.
  1380. //
  1381. ASSERT((pLowerConn->State == NBT_DISCONNECTED) || (pLowerConn->State == NBT_DISCONNECTING));
  1382. SET_STATE_LOWER (pLowerConn, NBT_IDLE);
  1383. CleanupLower = TRUE;
  1384. }
  1385. //
  1386. // there may be a disconnect wait irp, so return that first if there
  1387. // is one waiting around.
  1388. //
  1389. pConnEle = pLowerConn->pUpperConnection;
  1390. if (pConnEle && pConnEle->pIrpClose)
  1391. {
  1392. pIrpClose = pConnEle->pIrpClose;
  1393. CHECK_PTR(pConnEle);
  1394. pConnEle->pIrpClose = NULL ;
  1395. if (pConnEle->DiscFlag == TDI_DISCONNECT_ABORT)
  1396. {
  1397. DiscWaitStatus = STATUS_CONNECTION_RESET;
  1398. }
  1399. else
  1400. {
  1401. DiscWaitStatus = STATUS_GRACEFUL_DISCONNECT;
  1402. }
  1403. }
  1404. else
  1405. {
  1406. pIrpClose = NULL;
  1407. }
  1408. //
  1409. // This is the disconnect requesting Irp
  1410. //
  1411. pLowerConn->bDisconnectIrpPendingInTCP = FALSE;
  1412. if (pLowerConn->pIrp)
  1413. {
  1414. pIrp = pLowerConn->pIrp;
  1415. pLowerConn->pIrp = NULL ;
  1416. }
  1417. else
  1418. {
  1419. pIrp = NULL;
  1420. }
  1421. CTESpinFreeAtDpc(pLowerConn);
  1422. if (CleanupLower)
  1423. {
  1424. ASSERT(pLowerConn->RefCount > 1);
  1425. if (NBT_VERIFY_HANDLE (pLowerConn->pDeviceContext, NBT_VERIFY_DEVCONTEXT))
  1426. {
  1427. pDeviceContext = pLowerConn->pDeviceContext;
  1428. }
  1429. // this either puts the lower connection back on its free
  1430. // queue if inbound, or closes the connection with the transport
  1431. // if out bound. (it can't be done at dispatch level).
  1432. //
  1433. status = NTQueueToWorkerThread(
  1434. &pLowerConn->WorkItemCleanUpAndWipeOut,
  1435. DelayedCleanupAfterDisconnect,
  1436. NULL,
  1437. pLowerConn,
  1438. NULL,
  1439. pDeviceContext,
  1440. TRUE
  1441. );
  1442. }
  1443. CTESpinFree(&NbtConfig.JointLock,OldIrq);
  1444. FreeTracker(pTracker,RELINK_TRACKER);
  1445. if (pIrpClose)
  1446. {
  1447. CTEIoComplete( pIrpClose, DiscWaitStatus, 0 ) ;
  1448. }
  1449. if (pIrp)
  1450. {
  1451. CTEIoComplete( pIrp, status, 0 ) ;
  1452. }
  1453. }