Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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