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.

3005 lines
97 KiB

  1. // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil -*- (for GNU Emacs)
  2. //
  3. // Copyright (c) 1985-2000 Microsoft Corporation
  4. //
  5. // This file is part of the Microsoft Research IPv6 Network Protocol Stack.
  6. // You should have received a copy of the Microsoft End-User License Agreement
  7. // for this software along with this release; see the file "license.txt".
  8. // If not, please see http://www.research.microsoft.com/msripv6/license.htm,
  9. // or write to Microsoft Research, One Microsoft Way, Redmond, WA 98052-6399.
  10. //
  11. // Abstract:
  12. //
  13. // Code for TCP connection management.
  14. //
  15. // This file contains the code handling TCP connection related requests,
  16. // such as connecting and disconnecting.
  17. //
  18. #include "oscfg.h"
  19. #include "ndis.h"
  20. #include "ip6imp.h"
  21. #include "ip6def.h"
  22. #include "tdi.h"
  23. #include "tdint.h"
  24. #include "tdistat.h"
  25. #include "queue.h"
  26. #include "transprt.h"
  27. #include "addr.h"
  28. #include "tcp.h"
  29. #include "tcb.h"
  30. #include "tcpconn.h"
  31. #include "tcpsend.h"
  32. #include "tcprcv.h"
  33. #include "tcpdeliv.h"
  34. #include "info.h"
  35. #include "tcpcfg.h"
  36. #include "route.h"
  37. #include "security.h"
  38. #include "tcpmd5.h"
  39. #include "md5.h"
  40. #include "crypto\rc4.h"
  41. #include "ntddksec.h"
  42. SLIST_HEADER ConnReqFree; // Connection request free list.
  43. //
  44. // ISN globals.
  45. //
  46. #define ISN_KEY_SIZE 256 // 2048 bits.
  47. #define ISN_DEF_RAND_STORE_SIZE 256
  48. #define ISN_MIN_RAND_STORE_SIZE 1
  49. #define ISN_MAX_RAND_STORE_SIZE 16384
  50. typedef struct _ISN_RAND_STORE {
  51. MD5_CONTEXT Md5Context;
  52. ulong iBuf;
  53. ushort* pBuf;
  54. } ISN_RAND_STORE, *PISN_RAND_STORE;
  55. RC4_KEYSTRUCT ISNRC4Key;
  56. PISN_RAND_STORE ISNStore;
  57. uint ISNStoreSize = ISN_DEF_RAND_STORE_SIZE;
  58. uint ISNStoreMask;
  59. SeqNum ISNMonotonicPortion = 0;
  60. int ISNCredits;
  61. int ISNLastIsnUpdateTime;
  62. int ISNMaxCredits;
  63. extern PDRIVER_OBJECT TCPDriverObject;
  64. KSPIN_LOCK ConnReqFreeLock; // Lock to protect conn req free list.
  65. uint NumConnReq; // Current number of ConnReqs.
  66. uint MaxConnReq = 0xffffffff; // Maximum allowed number of ConnReqs.
  67. uint ConnPerBlock = MAX_CONN_PER_BLOCK;
  68. uint NextConnBlock = 0; // Cached index of next unfilled block.
  69. uint MaxAllocatedConnBlocks = 0; // Current number of blocks in the
  70. // ConnTable.
  71. TCPConnBlock **ConnTable = NULL; // The current connection table.
  72. KSPIN_LOCK ConnTableLock;
  73. extern KSPIN_LOCK AddrObjTableLock;
  74. extern KSPIN_LOCK TCBTableLock;
  75. TCPAddrCheckElement *AddrCheckTable = NULL; // The current check table.
  76. extern void RemoveConnFromAO(AddrObj *AO, TCPConn *Conn);
  77. //
  78. // All of the init code can be discarded.
  79. //
  80. #ifdef ALLOC_PRAGMA
  81. int InitTCPConn(void);
  82. int InitISNGenerator(void);
  83. void UnloadISNGenerator(void);
  84. int GetRandBits();
  85. uint GetDeltaTime();
  86. #pragma alloc_text(INIT, InitTCPConn)
  87. #pragma alloc_text(INIT, InitISNGenerator)
  88. #pragma alloc_text(PAGE, UnloadISNGenerator)
  89. #endif // ALLOC_PRAGMA
  90. void CompleteConnReq(TCB *CmpltTCB, TDI_STATUS Status);
  91. //* UnloadISNGenerator - Unload the support for the ISN generator.
  92. //
  93. // Called when we are unloading the driver.
  94. //
  95. void // Returns: Nothing.
  96. UnloadISNGenerator(void)
  97. {
  98. CCHAR i;
  99. ASSERT(ISNStore);
  100. for (i = 0; i < KeNumberProcessors; i++) {
  101. if (ISNStore[i].pBuf != NULL) {
  102. ExFreePool(ISNStore[i].pBuf);
  103. ISNStore[i].pBuf = NULL;
  104. }
  105. }
  106. ExFreePool(ISNStore);
  107. ISNStore = NULL;
  108. }
  109. //* InitISNGenerator - Initialize the support for the ISN generator.
  110. //
  111. // Called when the driver is loaded. Get 2048 bits of randomness and
  112. // use them to create an RC4 key.
  113. //
  114. int //Returns: TRUE if successful.
  115. InitISNGenerator(void)
  116. {
  117. UNICODE_STRING DeviceName;
  118. NTSTATUS NtStatus;
  119. PFILE_OBJECT pFileObject;
  120. PDEVICE_OBJECT pDeviceObject;
  121. unsigned char pBuf[ISN_KEY_SIZE];
  122. PIRP pIrp;
  123. IO_STATUS_BLOCK ioStatusBlock;
  124. KEVENT kEvent;
  125. ULONG cBits = 0;
  126. ULONG i;
  127. ULONG cProcs = KeNumberProcessors;
  128. ULONG ISNRandomValue;
  129. //
  130. // Start with the credits that would last for 1 tick.
  131. //
  132. ISNMaxCredits = ISNCredits = MAX_ISN_INCREMENTABLE_CONNECTIONS_PER_100MS;
  133. ISNLastIsnUpdateTime = (int)X100NSTOMS(KeQueryInterruptTime());
  134. //
  135. // Request a block of random bits from the KSecDD driver.
  136. // To do so, retrieve its device object pointer, build an I/O control
  137. // request to be submitted to the driver, and submit the request.
  138. // If any failure occurs, we fall back on the somewhat less-random
  139. // approach of requesting the bits from the randlibk library.
  140. //
  141. do {
  142. RtlInitUnicodeString(&DeviceName,
  143. DD_KSEC_DEVICE_NAME_U);
  144. KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE);
  145. //
  146. // Get the file and device objects for KDSECDD,
  147. // acquire a reference to the device-object,
  148. // release the unneeded reference to the file-object,
  149. // and build the I/O control request to issued to KSecDD.
  150. //
  151. NtStatus = IoGetDeviceObjectPointer(&DeviceName,
  152. FILE_ALL_ACCESS,
  153. &pFileObject,
  154. &pDeviceObject);
  155. if (!NT_SUCCESS(NtStatus)) {
  156. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_RARE,
  157. "Tcpip: IoGetDeviceObjectPointer(KSecDD)=%08x\n",
  158. NtStatus));
  159. break;
  160. }
  161. ObReferenceObject(pDeviceObject);
  162. ObDereferenceObject(pFileObject);
  163. pIrp = IoBuildDeviceIoControlRequest(IOCTL_KSEC_RNG,
  164. pDeviceObject,
  165. NULL, // No input buffer.
  166. 0,
  167. pBuf, // Output buffer stores rng.
  168. ISN_KEY_SIZE,
  169. FALSE,
  170. &kEvent,
  171. &ioStatusBlock);
  172. if (pIrp == NULL) {
  173. ObDereferenceObject(pDeviceObject);
  174. NtStatus = STATUS_UNSUCCESSFUL;
  175. break;
  176. }
  177. //
  178. // Issue the I/O control request, wait for it to complete
  179. // if necessary, and release the reference to KSecDD's device-object.
  180. //
  181. NtStatus = IoCallDriver(pDeviceObject, pIrp);
  182. if (NtStatus == STATUS_PENDING) {
  183. KeWaitForSingleObject(&kEvent,
  184. Executive,
  185. KernelMode,
  186. FALSE, // Not alertable.
  187. NULL); // No timeout.
  188. NtStatus = ioStatusBlock.Status;
  189. }
  190. ObDereferenceObject(pDeviceObject);
  191. if (!NT_SUCCESS(NtStatus)) {
  192. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_RARE,
  193. "Tcpip: IoCallDriver IOCTL_KSEC_RNG failed %#x\n",
  194. NtStatus));
  195. break;
  196. }
  197. } while (FALSE);
  198. if (!NT_SUCCESS(NtStatus)) {
  199. return FALSE;
  200. }
  201. //
  202. // Generate the key control structure.
  203. //
  204. rc4_key(&ISNRC4Key, ISN_KEY_SIZE, pBuf);
  205. //
  206. // Initalialize the current sequence number to a random value.
  207. //
  208. rc4(&ISNRC4Key, sizeof(SeqNum), (uchar*)&ISNMonotonicPortion);
  209. //
  210. // Obtain a random value to be used along with the invariants to compute the
  211. // MD5 hash .
  212. //
  213. rc4(&ISNRC4Key, sizeof(ISNRandomValue), (uchar*)&ISNRandomValue);
  214. //
  215. // Round down the store size to power of 2. Verify in range.
  216. //
  217. while (ISNStoreSize = ISNStoreSize >> 1) {
  218. cBits++;
  219. }
  220. ISNStoreSize = 1 << cBits;
  221. if (ISNStoreSize < ISN_MIN_RAND_STORE_SIZE ||
  222. ISNStoreSize > ISN_MAX_RAND_STORE_SIZE) {
  223. ISNStoreSize = ISN_DEF_RAND_STORE_SIZE;
  224. }
  225. //
  226. // The mask is store size - 1.
  227. //
  228. ISNStoreMask = ISNStoreSize - 1;
  229. //
  230. // Initialize the random ISN store. One array/index per processor.
  231. //
  232. ISNStore = ExAllocatePool(NonPagedPool, cProcs * sizeof(ISN_RAND_STORE));
  233. if (ISNStore == NULL) {
  234. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_RARE,
  235. "Tcpip: failed to allocate ISN rand store\n"));
  236. return FALSE;
  237. }
  238. RtlZeroMemory(ISNStore, sizeof(ISN_RAND_STORE) * cProcs);
  239. for (i = 0; i < cProcs; i++) {
  240. ISNStore[i].pBuf = ExAllocatePool(NonPagedPool, sizeof(ushort) * ISNStoreSize);
  241. if (ISNStore[i].pBuf == NULL) {
  242. goto error1;
  243. }
  244. rc4(&ISNRC4Key,
  245. sizeof(ushort) * ISNStoreSize,
  246. (uchar*)ISNStore[i].pBuf);
  247. //
  248. // Initialize structures required to call the MD5 transform.
  249. //
  250. MD5InitializeData(&ISNStore[i].Md5Context, ISNRandomValue);
  251. }
  252. return TRUE;
  253. error1:
  254. UnloadISNGenerator();
  255. return FALSE;
  256. }
  257. //* GetRandomISN - Gets a random Initial Sequence Number.
  258. //
  259. // Called when an Initial Sequence Number (ISN) is needed. Calls crypto
  260. // functions for random number generation.
  261. //
  262. void // Returns: Nothing.
  263. GetRandomISN(
  264. SeqNum *Seq, // Returned sequence number
  265. uchar *TcbInvariants) // Connection invariants
  266. {
  267. ulong randbits;
  268. ulong iProc;
  269. KIRQL irql;
  270. PMD5_CONTEXT Md5Context;
  271. //
  272. // Raise IRQL to DISPATCH so that we don't get swapped out while accessing
  273. // the processor specific array. Check to see if already at DISPATCH
  274. // before doing the work.
  275. //
  276. ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
  277. iProc = KeGetCurrentProcessorNumber();
  278. //
  279. // Add the random number only if the number of connections that can
  280. // increment the sequence number within this time period is non zero.
  281. // [Note: This could make the ISNCredits less than 0, but it is not a
  282. // problem].
  283. //
  284. if ((ISNCredits > 0) && (InterlockedDecrement(&ISNCredits) > 0)) {
  285. randbits = GetRandBits();
  286. //
  287. // We want to add between 16K and 32K of random, so adjust. There are
  288. // 15 bits of randomness, just ensure that the high order bit is set
  289. // and we have >= 16K and <= (32K-1)::14bits of randomness.
  290. //
  291. randbits &= 0x7FFF;
  292. randbits |= 0x4000;
  293. } else {
  294. int Delta = GetDeltaTime();
  295. if (Delta > 0) {
  296. randbits = GetRandBits();
  297. //
  298. // We can add anywhere from 256 to 512 per ms.
  299. //
  300. randbits &= 0x1FF;
  301. randbits |= 0x100;
  302. randbits *= Delta;
  303. } else {
  304. randbits = 0;
  305. }
  306. }
  307. //
  308. // Update global CurISN. InterlockedExchangeAdd returns initial value
  309. // (not the added value).
  310. //
  311. *Seq = InterlockedExchangeAdd(&ISNMonotonicPortion, randbits);
  312. //
  313. // Move the invariants from the connection.
  314. //
  315. Md5Context = &ISNStore[iProc].Md5Context;
  316. MD5InitializeScratch(Md5Context);
  317. RtlCopyMemory(Md5Context->Data, TcbInvariants, TCP_MD5_DATA_LENGTH);
  318. TransformMD5(Md5Context->Scratch, Md5Context->Data);
  319. //
  320. // Add the Invariant hash to the sequence number.
  321. //
  322. *Seq += (ULONG)(Md5Context->Scratch[0]);
  323. return;
  324. }
  325. //* GetRandBits
  326. //
  327. // Returns 16 random bits from the random number array generated using RC4.
  328. // When the store is exhausted, it will be replenished.
  329. //
  330. int // Returns: 16 bits of random data.
  331. GetRandBits()
  332. {
  333. ulong iStore;
  334. int randbits;
  335. ulong iProc = KeGetCurrentProcessorNumber();
  336. //
  337. // Get index into the random store. Mask performs mod operation.
  338. //
  339. iStore = ++ISNStore[iProc].iBuf & ISNStoreMask;
  340. ASSERT(iStore < ISNStoreSize);
  341. randbits = ISNStore[iProc].pBuf[iStore];
  342. if (iStore == 0) {
  343. rc4(&ISNRC4Key,
  344. sizeof(ushort) * ISNStoreSize,
  345. (uchar*) ISNStore[iProc].pBuf);
  346. }
  347. return randbits;
  348. }
  349. //* GetRandBits
  350. //
  351. // Tracks the time-based updates of ISN. It will return the time elapsed since
  352. // the last time this function was called. This would be used by the caller to
  353. // increment the ISN by an appropriate amount. Note that the maximum value
  354. // is function returns is 200 MS.
  355. //
  356. uint // Returns: Delta time in milli-seconds.
  357. GetDeltaTime()
  358. {
  359. //
  360. // If the time has changed since the ISN was updated last time, it
  361. // can be incremented now.
  362. //
  363. int PreviousUpdateTime, Delta;
  364. int CurrentUpdateTime = (int)X100NSTOMS(KeQueryInterruptTime());
  365. PreviousUpdateTime = InterlockedExchange(&ISNLastIsnUpdateTime,
  366. CurrentUpdateTime);
  367. Delta = CurrentUpdateTime - PreviousUpdateTime;
  368. if (Delta > 0) {
  369. return MIN(Delta, 200);
  370. } else {
  371. return 0;
  372. }
  373. }
  374. //
  375. // Routines for handling conn refcount going to 0.
  376. //
  377. //* DummyDone - Called when nothing to do.
  378. //
  379. // Called with TCPConnBlock.cb_lock held.
  380. //
  381. void // Returns: Nothing.
  382. DummyDone(TCPConn *Conn, // Connection going to 0.
  383. KIRQL PreLockIrql) // IRQL prior to TCPConnBlock.cb_lock acquisition.
  384. {
  385. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, PreLockIrql);
  386. }
  387. //* DummyCmplt - Dummy close completion routine.
  388. void
  389. DummyCmplt(PVOID Dummy1, uint Dummy2, uint Dummy3)
  390. {
  391. }
  392. //* CloseDone - Called when we need to complete a close.
  393. //
  394. // Called with TCPConnBlock.cb_lock held.
  395. //
  396. void // Returns: Nothing.
  397. CloseDone(TCPConn *Conn, // Connection going to 0.
  398. KIRQL Irql0) // IRQL prior to TCPConnBlock.cb_lock acquisition.
  399. {
  400. RequestCompleteRoutine Rtn; // Completion routine.
  401. PVOID Context; // User context for completion routine.
  402. AddrObj *AO;
  403. KIRQL Irql1, Irql2;
  404. ASSERT(Conn->tc_flags & CONN_CLOSING);
  405. Rtn = Conn->tc_rtn;
  406. Context = Conn->tc_rtncontext;
  407. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql0);
  408. KeAcquireSpinLock(&AddrObjTableLock, &Irql0);
  409. KeAcquireSpinLock(&Conn->tc_ConnBlock->cb_lock, &Irql1);
  410. if ((AO = Conn->tc_ao) != NULL) {
  411. CHECK_STRUCT(AO, ao);
  412. // It's associated.
  413. KeAcquireSpinLock(&AO->ao_lock, &Irql2);
  414. RemoveConnFromAO(AO, Conn);
  415. // We've pulled him from the AO, we can free the lock now.
  416. KeReleaseSpinLock(&AO->ao_lock, Irql2);
  417. }
  418. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql1);
  419. KeReleaseSpinLock(&AddrObjTableLock, Irql0);
  420. ExFreePool(Conn);
  421. (*Rtn)(Context, TDI_SUCCESS, 0);
  422. }
  423. //* DisassocDone - Called when we need to complete a disassociate.
  424. //
  425. // Called with TCPConnBlock.cb_lock held.
  426. //
  427. void // Returns: Nothing.
  428. DisassocDone(TCPConn *Conn, // Connection going to 0.
  429. KIRQL Irql0) // IRQL prior to TCPConnBlock.cb_lock acquisition.
  430. {
  431. RequestCompleteRoutine Rtn; // Completion routine.
  432. PVOID Context; // User context for completion routine.
  433. AddrObj *AO;
  434. uint NeedClose = FALSE;
  435. KIRQL Irql1, Irql2;
  436. ASSERT(Conn->tc_flags & CONN_DISACC);
  437. ASSERT(!(Conn->tc_flags & CONN_CLOSING));
  438. ASSERT(Conn->tc_refcnt == 0);
  439. Rtn = Conn->tc_rtn;
  440. Context = Conn->tc_rtncontext;
  441. Conn->tc_refcnt = 1;
  442. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql0);
  443. KeAcquireSpinLock(&AddrObjTableLock, &Irql0);
  444. KeAcquireSpinLock(&Conn->tc_ConnBlock->cb_lock, &Irql1);
  445. if (!(Conn->tc_flags & CONN_CLOSING)) {
  446. AO = Conn->tc_ao;
  447. if (AO != NULL) {
  448. KeAcquireSpinLock(&AO->ao_lock, &Irql2);
  449. RemoveConnFromAO(AO, Conn);
  450. KeReleaseSpinLock(&AO->ao_lock, Irql2);
  451. }
  452. ASSERT(Conn->tc_refcnt == 1);
  453. Conn->tc_flags &= ~CONN_DISACC;
  454. } else
  455. NeedClose = TRUE;
  456. Conn->tc_refcnt = 0;
  457. KeReleaseSpinLock(&AddrObjTableLock, Irql1);
  458. if (NeedClose) {
  459. CloseDone(Conn, Irql0);
  460. } else {
  461. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql0);
  462. (*Rtn)(Context, TDI_SUCCESS, 0);
  463. }
  464. }
  465. //* FreeConnReq - Free a connection request structure.
  466. //
  467. // Called to free a connection request structure.
  468. //
  469. void // Returns: Nothing.
  470. FreeConnReq(
  471. TCPConnReq *FreedReq) // Connection request structure to be freed.
  472. {
  473. PSLIST_ENTRY BufferLink;
  474. CHECK_STRUCT(FreedReq, tcr);
  475. BufferLink = CONTAINING_RECORD(&(FreedReq->tcr_req.tr_q.q_next),
  476. SLIST_ENTRY, Next);
  477. ExInterlockedPushEntrySList(&ConnReqFree, BufferLink, &ConnReqFreeLock);
  478. }
  479. //* GetConnReq - Get a connection request structure.
  480. //
  481. // Called to get a connection request structure.
  482. //
  483. TCPConnReq * // Returns: Pointer to ConnReq structure, or NULL if none.
  484. GetConnReq(void) // Nothing.
  485. {
  486. TCPConnReq *Temp;
  487. PSLIST_ENTRY BufferLink;
  488. Queue *QueuePtr;
  489. TCPReq *ReqPtr;
  490. BufferLink = ExInterlockedPopEntrySList(&ConnReqFree, &ConnReqFreeLock);
  491. if (BufferLink != NULL) {
  492. QueuePtr = CONTAINING_RECORD(BufferLink, Queue, q_next);
  493. ReqPtr = CONTAINING_RECORD(QueuePtr, TCPReq, tr_q);
  494. Temp = CONTAINING_RECORD(ReqPtr, TCPConnReq, tcr_req);
  495. CHECK_STRUCT(Temp, tcr);
  496. } else {
  497. if (NumConnReq < MaxConnReq)
  498. Temp = ExAllocatePool(NonPagedPool, sizeof(TCPConnReq));
  499. else
  500. Temp = NULL;
  501. if (Temp != NULL) {
  502. ExInterlockedAddUlong(&NumConnReq, 1, &ConnReqFreeLock);
  503. #if DBG
  504. Temp->tcr_req.tr_sig = tr_signature;
  505. Temp->tcr_sig = tcr_signature;
  506. #endif
  507. }
  508. }
  509. return Temp;
  510. }
  511. //* GetConnFromConnID - Get a Connection from a connection ID.
  512. //
  513. // Called to obtain a Connection pointer from a ConnID. We don't actually
  514. // check the connection pointer here, but we do bounds check the input ConnID
  515. // and make sure the instance fields match.
  516. // If successful, returns with TCPConnBlock.cb_lock held.
  517. //
  518. TCPConn * // Returns: Pointer to the TCPConn, or NULL.
  519. GetConnFromConnID(
  520. uint ConnID, // Connection ID to find a pointer for.
  521. KIRQL* Irql) // Receives IRQL prior to TCPConnBlock.cb_lock acquisition.
  522. {
  523. uint ConnIndex = CONN_INDEX(ConnID);
  524. uint ConnBlockId = CONN_BLOCKID(ConnID);
  525. TCPConn *MatchingConn = NULL;
  526. TCPConnBlock *ConnBlock;
  527. if (ConnIndex < MAX_CONN_PER_BLOCK && ConnBlockId < MaxAllocatedConnBlocks) {
  528. ConnBlock = ConnTable[ConnBlockId];
  529. if (ConnBlock) {
  530. MatchingConn = ConnBlock->cb_conn[ConnIndex];
  531. }
  532. if (MatchingConn != NULL) {
  533. KeAcquireSpinLock(&ConnBlock->cb_lock, Irql);
  534. CHECK_STRUCT(MatchingConn, tc);
  535. if (MatchingConn->tc_inst != CONN_INST(ConnID)) {
  536. MatchingConn = NULL;
  537. KeReleaseSpinLock(&ConnBlock->cb_lock, *Irql);
  538. }
  539. }
  540. } else
  541. MatchingConn = NULL;
  542. return MatchingConn;
  543. }
  544. //* GetConnID - Get a ConnTable slot.
  545. //
  546. // Called during OpenConnection to find a free slot in the ConnTable and
  547. // set it up with a connection.
  548. // If successful, returns with TCPConnBlock.cb_lock held.
  549. //
  550. uint // Returns: A ConnId to use.
  551. GetConnID(
  552. TCPConn *NewConn, // Connection to enter into slot.
  553. KIRQL *Irql0) // Receives IRQL prior to TCPConnBlock.cb_lock
  554. // acquisition.
  555. {
  556. uint CurrConnID = NewConn->tc_connid;
  557. uint i, j, BlockID, ConnIndex;
  558. //
  559. // If NewConn contains a valid ConnID and that location is unoccupied,
  560. // reuse it.
  561. //
  562. if (CurrConnID != INVALID_CONN_ID &&
  563. !NewConn->tc_ConnBlock->cb_conn[CONN_INDEX(CurrConnID)]) {
  564. KeAcquireSpinLock(&NewConn->tc_ConnBlock->cb_lock, Irql0);
  565. //
  566. // Reconfirm under lock that the location is unoccupied and, if so,
  567. // claim it.
  568. //
  569. if (!NewConn->tc_ConnBlock->cb_conn[CONN_INDEX(CurrConnID)]) {
  570. NewConn->tc_ConnBlock->cb_conn[CONN_INDEX(CurrConnID)] = NewConn;
  571. NewConn->tc_ConnBlock->cb_freecons--;
  572. NewConn->tc_inst = NewConn->tc_ConnBlock->cb_conninst++;
  573. NewConn->tc_connid = MAKE_CONN_ID(CONN_INDEX(CurrConnID),
  574. NewConn->tc_ConnBlock->cb_blockid,
  575. NewConn->tc_inst);
  576. return NewConn->tc_connid;
  577. }
  578. KeReleaseSpinLock(&NewConn->tc_ConnBlock->cb_lock, *Irql0);
  579. }
  580. //
  581. // NewConn's last spot is taken; search from the block from which
  582. // a ConnID was claimed most recently.
  583. //
  584. if (MaxAllocatedConnBlocks) {
  585. //
  586. // Capture the global counters without acquiring the lock.
  587. //
  588. uint TempMaxAllocatedConnBlocks = MaxAllocatedConnBlocks;
  589. uint TempNextConnBlock = NextConnBlock;
  590. for (i = 0; i < TempMaxAllocatedConnBlocks; i++) {
  591. BlockID = (TempNextConnBlock + i) % TempMaxAllocatedConnBlocks;
  592. if (!ConnTable[BlockID]->cb_freecons) {
  593. continue;
  594. }
  595. //
  596. // Reconfirm under lock that the TCPConnBlock has free slots.
  597. //
  598. KeAcquireSpinLock(&ConnTable[BlockID]->cb_lock, Irql0);
  599. if (!ConnTable[BlockID]->cb_freecons) {
  600. KeReleaseSpinLock(&ConnTable[BlockID]->cb_lock, *Irql0);
  601. continue;
  602. }
  603. for (j = 0; j < MAX_CONN_PER_BLOCK; j++) {
  604. ConnIndex = (ConnTable[BlockID]->cb_nextfree + j) %
  605. MAX_CONN_PER_BLOCK;
  606. if (ConnTable[BlockID]->cb_conn[ConnIndex]) {
  607. continue;
  608. }
  609. //
  610. // Found the free slot; fill it in.
  611. //
  612. ConnTable[BlockID]->cb_conn[ConnIndex] = NewConn;
  613. ConnTable[BlockID]->cb_nextfree = ConnIndex + 1;
  614. ConnTable[BlockID]->cb_freecons--;
  615. if (!ConnTable[BlockID]->cb_freecons) {
  616. InterlockedCompareExchange(&NextConnBlock,
  617. TempNextConnBlock,
  618. TempNextConnBlock + 1);
  619. }
  620. NewConn->tc_ConnBlock = ConnTable[BlockID];
  621. NewConn->tc_inst = ConnTable[BlockID]->cb_conninst++;
  622. NewConn->tc_connid = MAKE_CONN_ID(ConnIndex, BlockID,
  623. NewConn->tc_inst);
  624. return NewConn->tc_connid;
  625. }
  626. KeReleaseSpinLock(&ConnTable[BlockID]->cb_lock, *Irql0);
  627. }
  628. }
  629. //
  630. // The entire table is occupied; if we have room to grow,
  631. // allocate a new block.
  632. //
  633. KeAcquireSpinLock(&ConnTableLock, Irql0);
  634. if (MaxAllocatedConnBlocks < MaxConnBlocks) {
  635. TCPConnBlock* ConnBlock;
  636. BlockID = MaxAllocatedConnBlocks;
  637. ConnBlock = ExAllocatePool(NonPagedPool, sizeof(TCPConnBlock));
  638. if (ConnBlock) {
  639. RtlZeroMemory(ConnBlock, sizeof(TCPConnBlock));
  640. KeInitializeSpinLock(&ConnBlock->cb_lock);
  641. KeAcquireSpinLockAtDpcLevel(&ConnBlock->cb_lock);
  642. ConnBlock->cb_blockid = BlockID;
  643. ConnBlock->cb_freecons = MAX_CONN_PER_BLOCK - 1;
  644. ConnBlock->cb_nextfree = 1;
  645. ConnBlock->cb_conninst = 2;
  646. ConnBlock->cb_conn[0] = NewConn;
  647. NewConn->tc_ConnBlock = ConnBlock;
  648. NewConn->tc_inst = 1;
  649. NewConn->tc_connid = MAKE_CONN_ID(0, BlockID, NewConn->tc_inst);
  650. ConnTable[BlockID] = ConnBlock;
  651. InterlockedIncrement(&MaxAllocatedConnBlocks);
  652. KeReleaseSpinLockFromDpcLevel(&ConnTableLock);
  653. return NewConn->tc_connid;
  654. }
  655. }
  656. KeReleaseSpinLock(&ConnTableLock, *Irql0);
  657. return INVALID_CONN_ID;
  658. }
  659. //* FreeConnID - Free a ConnTable slot.
  660. //
  661. // Called when we're done with a ConnID. We assume the caller holds the lock
  662. // on the TCPConnBlock when we are called.
  663. //
  664. void // Returns: Nothing.
  665. FreeConnID(
  666. TCPConn *Conn) // Conn to be freed.
  667. {
  668. uint ConnIndex = CONN_INDEX(Conn->tc_connid); // Index into conn table.
  669. uint BlockID = CONN_BLOCKID(Conn->tc_connid);
  670. TCPConnBlock* ConnBlock = Conn->tc_ConnBlock;
  671. ASSERT(ConnIndex < MAX_CONN_PER_BLOCK);
  672. ASSERT(BlockID < MaxAllocatedConnBlocks);
  673. ASSERT(ConnBlock->cb_conn[ConnIndex] != NULL);
  674. if (ConnBlock->cb_conn[ConnIndex]) {
  675. ConnBlock->cb_conn[ConnIndex] = NULL;
  676. ConnBlock->cb_freecons++;
  677. ConnBlock->cb_nextfree = ConnIndex;
  678. ASSERT(ConnBlock->cb_freecons <= MAX_CONN_PER_BLOCK);
  679. } else {
  680. ASSERT(0);
  681. }
  682. }
  683. //* MapIPError - Map an IP error to a TDI error.
  684. //
  685. // Called to map an input IP error code to a TDI error code. If we can't,
  686. // we return the provided default.
  687. //
  688. TDI_STATUS // Returns: Mapped TDI error.
  689. MapIPError(
  690. IP_STATUS IPError, // Error code to be mapped.
  691. TDI_STATUS Default) // Default error code to return.
  692. {
  693. switch (IPError) {
  694. case IP_DEST_NO_ROUTE:
  695. return TDI_DEST_NET_UNREACH;
  696. case IP_DEST_ADDR_UNREACHABLE:
  697. return TDI_DEST_HOST_UNREACH;
  698. case IP_UNRECOGNIZED_NEXT_HEADER:
  699. return TDI_DEST_PROT_UNREACH;
  700. case IP_DEST_PORT_UNREACHABLE:
  701. return TDI_DEST_PORT_UNREACH;
  702. default:
  703. return Default;
  704. }
  705. }
  706. //* FinishRemoveTCBFromConn - Finish removing a TCB from a conn structure.
  707. //
  708. // Called when we have the locks we need and we just want to pull the
  709. // TCB off the connection.
  710. //
  711. void // Returns: Nothing.
  712. FinishRemoveTCBFromConn(
  713. TCB *RemovedTCB) // TCB to be removed.
  714. {
  715. TCPConn *Conn;
  716. AddrObj *AO;
  717. KIRQL Irql;
  718. TCPConnBlock *ConnBlock = NULL;
  719. if (((Conn = RemovedTCB->tcb_conn) != NULL) &&
  720. (Conn->tc_tcb == RemovedTCB)) {
  721. CHECK_STRUCT(Conn, tc);
  722. ConnBlock = Conn->tc_ConnBlock;
  723. KeAcquireSpinLock(&ConnBlock->cb_lock, &Irql);
  724. AO = Conn->tc_ao;
  725. if (AO != NULL) {
  726. KeAcquireSpinLockAtDpcLevel(&AO->ao_lock);
  727. if (AO_VALID(AO)) {
  728. KeAcquireSpinLockAtDpcLevel(&RemovedTCB->tcb_lock);
  729. // Need to double check this is still correct.
  730. if (Conn == RemovedTCB->tcb_conn) {
  731. // Everything still looks good.
  732. REMOVEQ(&Conn->tc_q);
  733. PUSHQ(&AO->ao_idleq, &Conn->tc_q);
  734. } else
  735. Conn = RemovedTCB->tcb_conn;
  736. } else {
  737. KeAcquireSpinLockAtDpcLevel(&RemovedTCB->tcb_lock);
  738. Conn = RemovedTCB->tcb_conn;
  739. }
  740. KeReleaseSpinLockFromDpcLevel(&AO->ao_lock);
  741. } else {
  742. KeAcquireSpinLockAtDpcLevel(&RemovedTCB->tcb_lock);
  743. Conn = RemovedTCB->tcb_conn;
  744. }
  745. if (Conn != NULL) {
  746. if (Conn->tc_tcb == RemovedTCB)
  747. Conn->tc_tcb = NULL;
  748. else
  749. ASSERT(Conn->tc_tcb == NULL);
  750. }
  751. KeReleaseSpinLockFromDpcLevel(&RemovedTCB->tcb_lock);
  752. KeReleaseSpinLock(&ConnBlock->cb_lock, Irql);
  753. }
  754. }
  755. //* RemoveTCBFromConn - Remove a TCB from a Conn structure.
  756. //
  757. // Called when we need to disassociate a TCB from a connection structure.
  758. // All we do is get the appropriate locks and call FinishRemoveTCBFromConn.
  759. //
  760. void // Returns: Nothing.
  761. RemoveTCBFromConn(
  762. TCB *RemovedTCB) // TCB to be removed.
  763. {
  764. CHECK_STRUCT(RemovedTCB, tcb);
  765. FinishRemoveTCBFromConn(RemovedTCB);
  766. }
  767. //* RemoveConnFromTCB - Remove a conn from a TCB.
  768. //
  769. // Called when we want to break the final association between a connection
  770. // and a TCB.
  771. //
  772. void // Returns: Nothing.
  773. RemoveConnFromTCB(
  774. TCB *RemoveTCB) // TCB to be removed.
  775. {
  776. ConnDoneRtn DoneRtn = NULL;
  777. KIRQL Irql;
  778. TCPConn *Conn;
  779. if ((Conn = RemoveTCB->tcb_conn) != NULL) {
  780. KeAcquireSpinLock(&Conn->tc_ConnBlock->cb_lock, &Irql);
  781. KeAcquireSpinLockAtDpcLevel(&RemoveTCB->tcb_lock);
  782. CHECK_STRUCT(Conn, tc);
  783. if (--(Conn->tc_refcnt) == 0)
  784. DoneRtn = Conn->tc_donertn;
  785. RemoveTCB->tcb_conn = NULL;
  786. KeReleaseSpinLockFromDpcLevel(&RemoveTCB->tcb_lock);
  787. }
  788. if (DoneRtn != NULL)
  789. (*DoneRtn)(Conn, Irql);
  790. else if (Conn) {
  791. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql);
  792. }
  793. }
  794. //* CloseTCB - Close a TCB.
  795. //
  796. // Called when we are done with a TCB, and want to free it. We'll remove
  797. // him from any tables that he's in, and destroy any outstanding requests.
  798. //
  799. void // Returns: Nothing.
  800. CloseTCB(
  801. TCB *ClosedTCB, // TCB to be closed.
  802. KIRQL OldIrql) // IRQL prior to acquiring TCB lock.
  803. {
  804. uchar OrigState = ClosedTCB->tcb_state;
  805. TDI_STATUS Status;
  806. uint OKToFree;
  807. CHECK_STRUCT(ClosedTCB, tcb);
  808. ASSERT(ClosedTCB->tcb_refcnt == 0);
  809. ASSERT(ClosedTCB->tcb_state != TCB_CLOSED);
  810. ASSERT(ClosedTCB->tcb_pending & DEL_PENDING);
  811. //
  812. // We'll check to make sure that our state isn't CLOSED. This should never
  813. // happen, since nobody should call TryToCloseTCB when the state is
  814. // closed, or take the reference count if we're closing. Nevertheless,
  815. // we'll double check as a safety measure.
  816. //
  817. if (ClosedTCB->tcb_state == TCB_CLOSED) {
  818. KeReleaseSpinLock(&ClosedTCB->tcb_lock, OldIrql);
  819. return;
  820. }
  821. //
  822. // Update SNMP counters. If we're in SYN-SENT or SYN-RCVD, this is a
  823. // failed connection attempt. If we're in ESTABLISED or CLOSE-WAIT,
  824. // treat this as an 'Established Reset' event.
  825. //
  826. if (ClosedTCB->tcb_state == TCB_SYN_SENT ||
  827. ClosedTCB->tcb_state == TCB_SYN_RCVD)
  828. TStats.ts_attemptfails++;
  829. else
  830. if (ClosedTCB->tcb_state == TCB_ESTAB ||
  831. ClosedTCB->tcb_state == TCB_CLOSE_WAIT) {
  832. TStats.ts_estabresets++;
  833. TStats.ts_currestab--;
  834. ASSERT(*(int *)&TStats.ts_currestab >= 0);
  835. }
  836. ClosedTCB->tcb_state = TCB_CLOSED;
  837. KeReleaseSpinLockFromDpcLevel(&ClosedTCB->tcb_lock);
  838. //
  839. // Remove the TCB from it's associated TCPConn structure, if it has one.
  840. //
  841. FinishRemoveTCBFromConn(ClosedTCB);
  842. KeAcquireSpinLockAtDpcLevel(&TCBTableLock);
  843. KeAcquireSpinLockAtDpcLevel(&ClosedTCB->tcb_lock);
  844. OKToFree = RemoveTCB(ClosedTCB);
  845. //
  846. // He's been pulled from the appropriate places so nobody can find him.
  847. // Free the locks, and proceed to destroy any requests, etc.
  848. //
  849. KeReleaseSpinLockFromDpcLevel(&ClosedTCB->tcb_lock);
  850. KeReleaseSpinLock(&TCBTableLock, OldIrql);
  851. if (SYNC_STATE(OrigState) && !GRACEFUL_CLOSED_STATE(OrigState)) {
  852. if (ClosedTCB->tcb_flags & NEED_RST)
  853. SendRSTFromTCB(ClosedTCB);
  854. }
  855. //
  856. // REVIEW: Is this the right place to drop the reference on our RCE?
  857. // REVIEW: The IPv4 code called down to IP to close the RCE here.
  858. //
  859. if (ClosedTCB->tcb_rce != NULL)
  860. ReleaseRCE(ClosedTCB->tcb_rce);
  861. if (ClosedTCB->tcb_closereason & TCB_CLOSE_RST)
  862. Status = TDI_CONNECTION_RESET;
  863. else if (ClosedTCB->tcb_closereason & TCB_CLOSE_ABORTED)
  864. Status = TDI_CONNECTION_ABORTED;
  865. else if (ClosedTCB->tcb_closereason & TCB_CLOSE_TIMEOUT)
  866. Status = MapIPError(ClosedTCB->tcb_error, TDI_TIMED_OUT);
  867. else if (ClosedTCB->tcb_closereason & TCB_CLOSE_REFUSED)
  868. Status = TDI_CONN_REFUSED;
  869. else if (ClosedTCB->tcb_closereason & TCB_CLOSE_UNREACH)
  870. Status = MapIPError(ClosedTCB->tcb_error, TDI_DEST_UNREACHABLE);
  871. else
  872. Status = TDI_SUCCESS;
  873. //
  874. // Now complete any outstanding requests on the TCB.
  875. //
  876. if (ClosedTCB->tcb_connreq != NULL) {
  877. TCPConnReq *ConnReq = ClosedTCB->tcb_connreq;
  878. CHECK_STRUCT(ConnReq, tcr);
  879. (*ConnReq->tcr_req.tr_rtn)(ConnReq->tcr_req.tr_context, Status, 0);
  880. FreeConnReq(ConnReq);
  881. }
  882. if (ClosedTCB->tcb_discwait != NULL) {
  883. TCPConnReq *ConnReq = ClosedTCB->tcb_discwait;
  884. CHECK_STRUCT(ConnReq, tcr);
  885. (*ConnReq->tcr_req.tr_rtn)(ConnReq->tcr_req.tr_context, Status, 0);
  886. FreeConnReq(ConnReq);
  887. }
  888. while (!EMPTYQ(&ClosedTCB->tcb_sendq)) {
  889. TCPReq *Req;
  890. TCPSendReq *SendReq;
  891. long Result;
  892. DEQUEUE(&ClosedTCB->tcb_sendq, Req, TCPReq, tr_q);
  893. CHECK_STRUCT(Req, tr);
  894. SendReq = (TCPSendReq *)Req;
  895. CHECK_STRUCT(SendReq, tsr);
  896. //
  897. // Decrement the initial reference put on the buffer when it was
  898. // allocated. This reference would have been decremented if the
  899. // send had been acknowledged, but then the send would not still
  900. // be on the tcb_sendq.
  901. //
  902. Result = InterlockedDecrement(&(SendReq->tsr_refcnt));
  903. ASSERT(Result >= 0);
  904. if (Result <= 0) {
  905. // If we've sent directly from this send, NULL out the next
  906. // pointer for the last buffer in the chain.
  907. if (SendReq->tsr_lastbuf != NULL) {
  908. NDIS_BUFFER_LINKAGE(SendReq->tsr_lastbuf) = NULL;
  909. SendReq->tsr_lastbuf = NULL;
  910. }
  911. (*Req->tr_rtn)(Req->tr_context, Status, 0);
  912. FreeSendReq(SendReq);
  913. } else {
  914. // The send request will be freed when all outstanding references
  915. // to it have completed.
  916. SendReq->tsr_req.tr_status = Status;
  917. }
  918. }
  919. while (ClosedTCB->tcb_rcvhead != NULL) {
  920. TCPRcvReq *RcvReq;
  921. RcvReq = ClosedTCB->tcb_rcvhead;
  922. CHECK_STRUCT(RcvReq, trr);
  923. ClosedTCB->tcb_rcvhead = RcvReq->trr_next;
  924. (*RcvReq->trr_rtn)(RcvReq->trr_context, Status, 0);
  925. FreeRcvReq(RcvReq);
  926. }
  927. while (ClosedTCB->tcb_exprcv != NULL) {
  928. TCPRcvReq *RcvReq;
  929. RcvReq = ClosedTCB->tcb_exprcv;
  930. CHECK_STRUCT(RcvReq, trr);
  931. ClosedTCB->tcb_exprcv = RcvReq->trr_next;
  932. (*RcvReq->trr_rtn)(RcvReq->trr_context, Status, 0);
  933. FreeRcvReq(RcvReq);
  934. }
  935. if (ClosedTCB->tcb_pendhead != NULL)
  936. FreePacketChain(ClosedTCB->tcb_pendhead);
  937. if (ClosedTCB->tcb_urgpending != NULL)
  938. FreePacketChain(ClosedTCB->tcb_urgpending);
  939. while (ClosedTCB->tcb_raq != NULL) {
  940. TCPRAHdr *Hdr;
  941. Hdr = ClosedTCB->tcb_raq;
  942. CHECK_STRUCT(Hdr, trh);
  943. ClosedTCB->tcb_raq = Hdr->trh_next;
  944. if (Hdr->trh_buffer != NULL)
  945. FreePacketChain(Hdr->trh_buffer);
  946. ExFreePool(Hdr);
  947. }
  948. RemoveConnFromTCB(ClosedTCB);
  949. if (OKToFree) {
  950. FreeTCB(ClosedTCB);
  951. } else {
  952. KeAcquireSpinLock(&TCBTableLock, &OldIrql);
  953. ClosedTCB->tcb_walkcount--;
  954. if (ClosedTCB->tcb_walkcount == 0) {
  955. FreeTCB(ClosedTCB);
  956. }
  957. KeReleaseSpinLock(&TCBTableLock, OldIrql);
  958. }
  959. }
  960. //* TryToCloseTCB - Try to close a TCB.
  961. //
  962. // Called when we need to close a TCB, but don't know if we can.
  963. // If the reference count is 0, we'll call CloseTCB to deal with it.
  964. // Otherwise we'll set the DELETE_PENDING bit and deal with it when the
  965. // ref. count goes to 0. We assume the TCB is locked when we are called.
  966. //
  967. void // Returns: Nothing.
  968. TryToCloseTCB (
  969. TCB *ClosedTCB, // TCB to be closed.
  970. uchar Reason, // Reason we're closing.
  971. KIRQL PreLockIrql) // IRQL prior to acquiring the TCB lock.
  972. {
  973. CHECK_STRUCT(ClosedTCB, tcb);
  974. ASSERT(ClosedTCB->tcb_state != TCB_CLOSED);
  975. ClosedTCB->tcb_closereason |= Reason;
  976. if (ClosedTCB->tcb_pending & DEL_PENDING) {
  977. KeReleaseSpinLock(&ClosedTCB->tcb_lock, PreLockIrql);
  978. return;
  979. }
  980. ClosedTCB->tcb_pending |= DEL_PENDING;
  981. ClosedTCB->tcb_slowcount++;
  982. ClosedTCB->tcb_fastchk |= TCP_FLAG_SLOW;
  983. if (ClosedTCB->tcb_refcnt == 0)
  984. CloseTCB(ClosedTCB, PreLockIrql);
  985. else {
  986. KeReleaseSpinLock(&ClosedTCB->tcb_lock, PreLockIrql);
  987. }
  988. }
  989. //* DerefTCB - Dereference a TCB.
  990. //
  991. // Called when we're done with a TCB, and want to let exclusive user
  992. // have a shot. We dec. the refcount, and if it goes to zero and there
  993. // are pending actions, we'll perform one of the pending actions.
  994. //
  995. void // Returns: Nothing.
  996. DerefTCB(
  997. TCB *DoneTCB, // TCB to be dereffed.
  998. KIRQL PreLockIrql) // IRQL prior to acquiring the TCB lock.
  999. {
  1000. ASSERT(DoneTCB->tcb_refcnt != 0);
  1001. if (--DoneTCB->tcb_refcnt == 0) {
  1002. if (DoneTCB->tcb_pending == 0) {
  1003. KeReleaseSpinLock(&DoneTCB->tcb_lock, PreLockIrql);
  1004. return;
  1005. } else {
  1006. if (DoneTCB->tcb_pending & DEL_PENDING)
  1007. CloseTCB(DoneTCB, PreLockIrql);
  1008. else
  1009. DbgBreakPoint(); // Fatal condition.
  1010. return;
  1011. }
  1012. }
  1013. KeReleaseSpinLock(&DoneTCB->tcb_lock, PreLockIrql);
  1014. return;
  1015. }
  1016. //* CalculateMSSForTCB - Update MSS, etc. after PMTU changes.
  1017. //
  1018. // Calculate our connection's MSS based on our PMTU, the sizes
  1019. // of various headers, and the remote side's advertised MSS.
  1020. // It's expected that this routine will be called whenever
  1021. // our cached copy of the PMTU has been updated to a new value.
  1022. //
  1023. void
  1024. CalculateMSSForTCB(
  1025. TCB *ThisTCB) // The TCB we're running our calculations on.
  1026. {
  1027. uint PMTU;
  1028. IPSecProc *IPSecToDo;
  1029. uint TrailerLength = 0;
  1030. uint IPSecBytes = 0;
  1031. uint Dummy;
  1032. ASSERT(ThisTCB->tcb_pmtu != 0); // Should be set before entering.
  1033. //
  1034. // First check that the PMTU size is reasonable. IP won't
  1035. // let it get below minimum, but we have our own maximum since
  1036. // currently TCP can only handle an MSS that fits in 16 bits.
  1037. // TBD: If we add IPv6 Jumbogram support, we should also add LFN
  1038. // TBD: support to TCP and change this to handle a larger MSS.
  1039. //
  1040. PMTU = ThisTCB->tcb_pmtu;
  1041. if (PMTU > 65535) {
  1042. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_RARE,
  1043. "TCPSend: PMTU update value too large %u\n", PMTU));
  1044. PMTU = 65535;
  1045. }
  1046. //
  1047. // Determine size of IPSec headers, if any.
  1048. //
  1049. IPSecToDo = OutboundSPLookup(&ThisTCB->tcb_saddr, &ThisTCB->tcb_daddr,
  1050. IP_PROTOCOL_TCP,
  1051. net_short(ThisTCB->tcb_sport),
  1052. net_short(ThisTCB->tcb_dport),
  1053. ThisTCB->tcb_rce->NTE->IF, &Dummy);
  1054. if (IPSecToDo != NULL) {
  1055. //
  1056. // Calculate the space needed for the IPSec headers.
  1057. //
  1058. IPSecBytes = IPSecBytesToInsert(IPSecToDo, &Dummy, &TrailerLength);
  1059. FreeIPSecToDo(IPSecToDo, IPSecToDo->BundleSize);
  1060. IPSecBytes += TrailerLength;
  1061. }
  1062. IF_TCPDBG(TCP_DEBUG_MSS) {
  1063. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1064. "CalculateMSSForTCB: IPSecBytes is %u\n", IPSecBytes));
  1065. }
  1066. //
  1067. // Subtract out the header sizes to yield the TCP MSS.
  1068. // If there is an ESP trailer on this connection, round down
  1069. // the MSS to allow the trailer to end on a 4-byte boundary.
  1070. //
  1071. PMTU -= sizeof(IPv6Header) + sizeof(TCPHeader) + IPSecBytes;
  1072. if (TrailerLength)
  1073. PMTU -= (PMTU & 3);
  1074. //
  1075. // Don't let MSS exceed what our peer advertised, regardless of how
  1076. // large the Path MTU is.
  1077. //
  1078. IF_TCPDBG(TCP_DEBUG_MSS) {
  1079. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1080. "CalculateMSSForTCB: Old MSS is %u ", ThisTCB->tcb_mss));
  1081. }
  1082. ThisTCB->tcb_mss = (ushort)MIN(PMTU, ThisTCB->tcb_remmss);
  1083. IF_TCPDBG(TCP_DEBUG_MSS) {
  1084. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1085. "New MSS is %u\n", ThisTCB->tcb_mss));
  1086. }
  1087. ASSERT(ThisTCB->tcb_mss != 0);
  1088. //
  1089. // We don't want our Congestion Window to be smaller than one maximum
  1090. // segment, so we may need to increase it when our MSS grows.
  1091. //
  1092. if (ThisTCB->tcb_cwin < ThisTCB->tcb_mss) {
  1093. ThisTCB->tcb_cwin = ThisTCB->tcb_mss;
  1094. //
  1095. // Make sure the slow start threshold is at
  1096. // least 2 segments.
  1097. //
  1098. if (ThisTCB->tcb_ssthresh < ((uint) ThisTCB->tcb_mss * 2)) {
  1099. ThisTCB->tcb_ssthresh = ThisTCB->tcb_mss * 2;
  1100. }
  1101. }
  1102. }
  1103. //** TdiOpenConnection - Open a connection.
  1104. //
  1105. // This is the TDI Open Connection entry point. We open a connection,
  1106. // and save the caller's connection context. A TCPConn structure is allocated
  1107. // here, but a TCB isn't allocated until the Connect or Listen is done.
  1108. //
  1109. TDI_STATUS // Returns: Status of attempt to open connection.
  1110. TdiOpenConnection(
  1111. PTDI_REQUEST Request, // This TDI request.
  1112. PVOID Context) // Connection context to be save for connection.
  1113. {
  1114. TCPConn *NewConn; // The newly opened connection.
  1115. KIRQL OldIrql; // Irql prior to acquiring TCPConnBlock lock.
  1116. uint ConnID; // New ConnID.
  1117. TDI_STATUS Status; // Status of this request.
  1118. NewConn = ExAllocatePool(NonPagedPool, sizeof(TCPConn));
  1119. if (NewConn != NULL) {
  1120. //
  1121. // We allocated a connection.
  1122. //
  1123. RtlZeroMemory(NewConn, sizeof(TCPConn));
  1124. #if DBG
  1125. NewConn->tc_sig = tc_signature;
  1126. #endif
  1127. NewConn->tc_tcb = NULL;
  1128. NewConn->tc_ao = NULL;
  1129. NewConn->tc_context = Context;
  1130. NewConn->tc_connid = INVALID_CONN_ID;
  1131. ConnID = GetConnID(NewConn, &OldIrql);
  1132. if (ConnID != INVALID_CONN_ID) {
  1133. //
  1134. // We successfully got a ConnID.
  1135. //
  1136. Request->Handle.ConnectionContext = (CONNECTION_CONTEXT)UIntToPtr(ConnID);
  1137. NewConn->tc_refcnt = 0;
  1138. NewConn->tc_flags = 0;
  1139. NewConn->tc_tcbflags = NAGLING | (BSDUrgent ? BSD_URGENT : 0);
  1140. if (DefaultRcvWin != 0) {
  1141. NewConn->tc_window = DefaultRcvWin;
  1142. NewConn->tc_flags |= CONN_WINSET;
  1143. } else
  1144. NewConn->tc_window = DEFAULT_RCV_WIN;
  1145. NewConn->tc_donertn = DummyDone;
  1146. NewConn->tc_owningpid = HandleToUlong(PsGetCurrentProcessId());
  1147. Status = TDI_SUCCESS;
  1148. KeReleaseSpinLock(&NewConn->tc_ConnBlock->cb_lock, OldIrql);
  1149. } else {
  1150. ExFreePool(NewConn);
  1151. Status = TDI_NO_RESOURCES;
  1152. }
  1153. return Status;
  1154. }
  1155. //
  1156. // Couldn't get a connection.
  1157. //
  1158. return TDI_NO_RESOURCES;
  1159. }
  1160. //* RemoveConnFromAO - Remove a connection from an AddrObj.
  1161. //
  1162. // A little utility routine to remove a connection from an AddrObj.
  1163. // We run down the connections on the AO, and when we find him we splice
  1164. // him out. We assume the caller holds the locks on the AddrObj and the
  1165. // TCPConnBlock lock.
  1166. //
  1167. void // Returns: Nothing.
  1168. RemoveConnFromAO(
  1169. AddrObj *AO, // AddrObj to remove from.
  1170. TCPConn *Conn) // Conn to remove.
  1171. {
  1172. CHECK_STRUCT(AO, ao);
  1173. CHECK_STRUCT(Conn, tc);
  1174. REMOVEQ(&Conn->tc_q);
  1175. Conn->tc_ao = NULL;
  1176. }
  1177. //* TdiCloseConnection - Close a connection.
  1178. //
  1179. // Called when the user is done with a connection, and wants to close it.
  1180. // We look the connection up in our table, and if we find it we'll remove
  1181. // the connection from the AddrObj it's associate with (if any). If there's
  1182. // a TCB associated with the connection we'll close it also.
  1183. //
  1184. // There are some interesting wrinkles related to closing while a TCB
  1185. // is still referencing the connection (i.e. tc_refcnt != 0) or while a
  1186. // disassociate address is in progress. See below for more details.
  1187. //
  1188. TDI_STATUS // Returns: Status of attempt to close.
  1189. TdiCloseConnection(
  1190. PTDI_REQUEST Request) // Request identifying connection to be closed.
  1191. {
  1192. uint ConnID = PtrToUlong(Request->Handle.ConnectionContext);
  1193. KIRQL Irql0;
  1194. TCPConn *Conn;
  1195. TDI_STATUS Status;
  1196. //
  1197. // We have the locks we need. Try to find a connection.
  1198. //
  1199. Conn = GetConnFromConnID(ConnID, &Irql0);
  1200. if (Conn != NULL) {
  1201. KIRQL Irql1;
  1202. TCB *ConnTCB;
  1203. //
  1204. // We found the connection. Free the ConnID and mark the connection
  1205. // as closing.
  1206. //
  1207. CHECK_STRUCT(Conn, tc);
  1208. FreeConnID(Conn);
  1209. Conn->tc_flags |= CONN_CLOSING;
  1210. //
  1211. // See if there's a TCB referencing this connection.
  1212. // If there is, we'll need to wait until he's done before closing him.
  1213. // We'll hurry the process along if we still have a pointer to him.
  1214. //
  1215. if (Conn->tc_refcnt != 0) {
  1216. RequestCompleteRoutine Rtn;
  1217. PVOID Context;
  1218. //
  1219. // A connection still references him. Save the current rtn stuff
  1220. // in case we are in the middle of disassociating him from an
  1221. // address, and store the caller's callback routine and our done
  1222. // routine.
  1223. //
  1224. Rtn = Conn->tc_rtn;
  1225. Context = Conn->tc_rtncontext;
  1226. Conn->tc_rtn = Request->RequestNotifyObject;
  1227. Conn->tc_rtncontext = Request->RequestContext;
  1228. Conn->tc_donertn = CloseDone;
  1229. //
  1230. // See if we're in the middle of disassociating him.
  1231. //
  1232. if (Conn->tc_flags & CONN_DISACC) {
  1233. //
  1234. // We are disassociating him. We'll free the conn table lock
  1235. // now and fail the disassociate request. Note that when
  1236. // we free the lock the refcount could go to zero. This is
  1237. // OK, because we've already stored the neccessary info. in
  1238. // the connection so the caller will get called back if it
  1239. // does. From this point out we return PENDING, so a callback
  1240. // is OK. We've marked him as closing, so the disassoc done
  1241. // routine will bail out if we've interrupted him. If the ref.
  1242. // count does go to zero, Conn->tc_tcb would have to be NULL,
  1243. // so in that case we'll just fall out of this routine.
  1244. //
  1245. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql0);
  1246. (*Rtn)(Context, (uint) TDI_REQ_ABORTED, 0);
  1247. KeAcquireSpinLock(&Conn->tc_ConnBlock->cb_lock, &Irql0);
  1248. }
  1249. ConnTCB = Conn->tc_tcb;
  1250. if (ConnTCB != NULL) {
  1251. CHECK_STRUCT(ConnTCB, tcb);
  1252. //
  1253. // We have a TCB. Take the lock on him and get ready to
  1254. // close him.
  1255. //
  1256. KeAcquireSpinLock(&ConnTCB->tcb_lock, &Irql1);
  1257. if (ConnTCB->tcb_state != TCB_CLOSED) {
  1258. ConnTCB->tcb_flags |= NEED_RST;
  1259. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql1);
  1260. if (!CLOSING(ConnTCB))
  1261. TryToCloseTCB(ConnTCB, TCB_CLOSE_ABORTED, Irql0);
  1262. else
  1263. KeReleaseSpinLock(&ConnTCB->tcb_lock, Irql0);
  1264. return TDI_PENDING;
  1265. } else {
  1266. //
  1267. // He's already closing. This should be harmless, but
  1268. // check this case.
  1269. //
  1270. KeReleaseSpinLock(&ConnTCB->tcb_lock, Irql1);
  1271. }
  1272. }
  1273. Status = TDI_PENDING;
  1274. } else {
  1275. //
  1276. // We have a connection that we can close. Finish the close.
  1277. //
  1278. Conn->tc_rtn = DummyCmplt;
  1279. CloseDone(Conn, Irql0);
  1280. return TDI_SUCCESS;
  1281. }
  1282. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql0);
  1283. } else
  1284. Status = TDI_INVALID_CONNECTION;
  1285. //
  1286. // We're done with the connection. Go ahead and free him.
  1287. //
  1288. return Status;
  1289. }
  1290. //* TdiAssociateAddress - Associate an address with a connection.
  1291. //
  1292. // Called to associate an address with a connection. We do a minimal
  1293. // amount of sanity checking, and then put the connection on the AddrObj's
  1294. // list.
  1295. //
  1296. TDI_STATUS // Returns: Status of attempt to associate.
  1297. TdiAssociateAddress(
  1298. PTDI_REQUEST Request, // Structure for this request.
  1299. HANDLE AddrHandle) // Address handle to associate connection with.
  1300. {
  1301. KIRQL Irql0, Irql1; // One per lock nesting level.
  1302. AddrObj *AO;
  1303. uint ConnID = PtrToUlong(Request->Handle.ConnectionContext);
  1304. TCPConn *Conn;
  1305. TDI_STATUS Status;
  1306. AO = (AddrObj *)AddrHandle;
  1307. CHECK_STRUCT(AO, ao);
  1308. Conn = GetConnFromConnID(ConnID, &Irql0);
  1309. KeAcquireSpinLock(&AO->ao_lock, &Irql1);
  1310. if (!AO_VALID(AO)) {
  1311. KeReleaseSpinLock(&AO->ao_lock, Irql1);
  1312. if (Conn != NULL) {
  1313. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql0);
  1314. }
  1315. return TDI_INVALID_PARAMETER;
  1316. }
  1317. if (Conn != NULL) {
  1318. CHECK_STRUCT(Conn, tc);
  1319. if (Conn->tc_ao != NULL) {
  1320. //
  1321. // It's already associated. Error out.
  1322. //
  1323. KdBreakPoint();
  1324. Status = TDI_ALREADY_ASSOCIATED;
  1325. } else {
  1326. Conn->tc_ao = AO;
  1327. ASSERT(Conn->tc_tcb == NULL);
  1328. PUSHQ(&AO->ao_idleq, &Conn->tc_q);
  1329. Status = TDI_SUCCESS;
  1330. }
  1331. KeReleaseSpinLock(&AO->ao_lock, Irql1);
  1332. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql0);
  1333. return Status;
  1334. } else
  1335. Status = TDI_INVALID_CONNECTION;
  1336. KeReleaseSpinLock(&AO->ao_lock, Irql1);
  1337. return Status;
  1338. }
  1339. //* TdiDisAssociateAddress - Disassociate a connection from an address.
  1340. //
  1341. // The TDI entry point to disassociate a connection from an address. The
  1342. // connection must actually be associated and not connected to anything.
  1343. //
  1344. TDI_STATUS // Returns: Status of request.
  1345. TdiDisAssociateAddress(
  1346. PTDI_REQUEST Request) // Structure for this request.
  1347. {
  1348. uint ConnID = PtrToUlong(Request->Handle.ConnectionContext);
  1349. KIRQL Irql0, Irql1, Irql2; // One per lock nesting level.
  1350. TCPConn *Conn;
  1351. AddrObj *AO;
  1352. TDI_STATUS Status;
  1353. KeAcquireSpinLock(&AddrObjTableLock, &Irql0);
  1354. Conn = GetConnFromConnID(ConnID, &Irql1);
  1355. if (Conn != NULL) {
  1356. //
  1357. // The connection actually exists!
  1358. //
  1359. CHECK_STRUCT(Conn, tc);
  1360. AO = Conn->tc_ao;
  1361. if (AO != NULL) {
  1362. CHECK_STRUCT(AO, ao);
  1363. //
  1364. // And it's associated.
  1365. //
  1366. KeAcquireSpinLock(&AO->ao_lock, &Irql2);
  1367. //
  1368. // If there's no connection currently active, go ahead and remove
  1369. // him from the AddrObj. If a connection is active error the
  1370. // request out.
  1371. //
  1372. if (Conn->tc_tcb == NULL) {
  1373. if (Conn->tc_refcnt == 0) {
  1374. RemoveConnFromAO(AO, Conn);
  1375. Status = TDI_SUCCESS;
  1376. } else {
  1377. //
  1378. // He shouldn't be closing, or we couldn't have found him.
  1379. //
  1380. ASSERT(!(Conn->tc_flags & CONN_CLOSING));
  1381. Conn->tc_rtn = Request->RequestNotifyObject;
  1382. Conn->tc_rtncontext = Request->RequestContext;
  1383. Conn->tc_donertn = DisassocDone;
  1384. Conn->tc_flags |= CONN_DISACC;
  1385. Status = TDI_PENDING;
  1386. }
  1387. } else
  1388. Status = TDI_CONNECTION_ACTIVE;
  1389. KeReleaseSpinLock(&AO->ao_lock, Irql2);
  1390. } else
  1391. Status = TDI_NOT_ASSOCIATED;
  1392. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql1);
  1393. } else
  1394. Status = TDI_INVALID_CONNECTION;
  1395. KeReleaseSpinLock(&AddrObjTableLock, Irql0);
  1396. return Status;
  1397. }
  1398. //* ProcessUserOptions - Process options from the user.
  1399. //
  1400. // A utility routine to process options from the user. We fill in the
  1401. // optinfo structure, and if we have options we call ip to check on them.
  1402. //
  1403. TDI_STATUS // Returns: TDI_STATUS of attempt.
  1404. ProcessUserOptions(
  1405. PTDI_CONNECTION_INFORMATION Info) // Contains options to be processed.
  1406. {
  1407. #if 0
  1408. TDI_STATUS Status;
  1409. if (Info != NULL && Info->Options != NULL) {
  1410. IP_STATUS OptStatus;
  1411. // REVIEW: IPv4 had code here to call into IP to copy options here.
  1412. if (OptStatus != IP_SUCCESS) {
  1413. if (OptStatus == IP_NO_RESOURCES)
  1414. Status = TDI_NO_RESOURCES;
  1415. else
  1416. Status = TDI_BAD_OPTION;
  1417. } else
  1418. Status = TDI_SUCCESS;
  1419. } else {
  1420. Status = TDI_SUCCESS;
  1421. }
  1422. return Status;
  1423. #else
  1424. return TDI_SUCCESS;
  1425. #endif
  1426. }
  1427. //* InitTCBFromConn - Initialize a TCB from information in a Connection.
  1428. //
  1429. // Called from Connect and Listen processing to initialize a new TCB from
  1430. // information in the connection. We assume the AddrObjTableLock and
  1431. // TCPConnBlock locks are held when we are called, or that the caller has some
  1432. // other way of making sure that the referenced AO doesn't go away in the
  1433. // middle of operation.
  1434. //
  1435. // Input: Conn - Connection to initialize from.
  1436. // NewTCB - TCB to be initialized.
  1437. // Addr - Remote addressing and option info for NewTCB.
  1438. // AOLocked - True if the called has the address object locked.
  1439. //
  1440. //
  1441. TDI_STATUS // Returns: TDI_STATUS of init attempt.
  1442. InitTCBFromConn(
  1443. TCPConn *Conn, // Connection to initialize from.
  1444. TCB *NewTCB, // TCB to be initialized.
  1445. PTDI_CONNECTION_INFORMATION Addr, // Remove addr info, etc. for NewTCB.
  1446. uint AOLocked) // True if caller has addr object lock.
  1447. {
  1448. KIRQL OldIrql;
  1449. TDI_STATUS Status;
  1450. CHECK_STRUCT(Conn, tc);
  1451. //
  1452. // We have a connection. Make sure it's associated with an address and
  1453. // doesn't already have a TCB attached.
  1454. //
  1455. if (Conn->tc_flags & CONN_INVALID)
  1456. return TDI_INVALID_CONNECTION;
  1457. if (Conn->tc_tcb == NULL) {
  1458. AddrObj *ConnAO;
  1459. ConnAO = Conn->tc_ao;
  1460. if (ConnAO != NULL) {
  1461. CHECK_STRUCT(ConnAO, ao);
  1462. if (!AOLocked) {
  1463. KeAcquireSpinLock(&ConnAO->ao_lock, &OldIrql);
  1464. }
  1465. if (!(NewTCB->tcb_flags & ACCEPT_PENDING)) {
  1466. //
  1467. // These fields are already initialized
  1468. // when ACCEPT_PENDING is on.
  1469. //
  1470. NewTCB->tcb_saddr = ConnAO->ao_addr;
  1471. NewTCB->tcb_sscope_id = ConnAO->ao_scope_id;
  1472. NewTCB->tcb_sport = ConnAO->ao_port;
  1473. NewTCB->tcb_defaultwin = Conn->tc_window;
  1474. NewTCB->tcb_rcvwin = Conn->tc_window;
  1475. }
  1476. NewTCB->tcb_rcvind = ConnAO->ao_rcv;
  1477. NewTCB->tcb_ricontext = ConnAO->ao_rcvcontext;
  1478. if (NewTCB->tcb_rcvind == NULL)
  1479. NewTCB->tcb_rcvhndlr = PendData;
  1480. else
  1481. NewTCB->tcb_rcvhndlr = IndicateData;
  1482. NewTCB->tcb_conncontext = Conn->tc_context;
  1483. NewTCB->tcb_flags |= Conn->tc_tcbflags;
  1484. if (Conn->tc_flags & CONN_WINSET)
  1485. NewTCB->tcb_flags |= WINDOW_SET;
  1486. if (NewTCB->tcb_flags & KEEPALIVE) {
  1487. NewTCB->tcb_alive = TCPTime;
  1488. NewTCB->tcb_kacount = 0;
  1489. }
  1490. if (!AOLocked) {
  1491. KeReleaseSpinLock(&ConnAO->ao_lock, OldIrql);
  1492. }
  1493. //
  1494. // If we've been given options, we need to process them now.
  1495. //
  1496. if (Addr != NULL && Addr->Options != NULL)
  1497. NewTCB->tcb_flags |= CLIENT_OPTIONS;
  1498. Status = ProcessUserOptions(Addr);
  1499. return Status;
  1500. } else
  1501. return TDI_NOT_ASSOCIATED;
  1502. } else
  1503. return TDI_CONNECTION_ACTIVE;
  1504. }
  1505. //* TdiConnect - Establish a connection.
  1506. //
  1507. // The TDI connection establishment routine. Called when the client wants to
  1508. // establish a connection, we validate his incoming parameters and kick
  1509. // things off by sending a SYN.
  1510. //
  1511. // Note: The format of the timeout (TO) parameter is system specific -
  1512. // we use a macro to convert to ticks.
  1513. //
  1514. TDI_STATUS // Returns: Status of attempt to connect.
  1515. TdiConnect(
  1516. PTDI_REQUEST Request, // This command request.
  1517. void *TO, // How long to wait for request.
  1518. PTDI_CONNECTION_INFORMATION RequestAddr, // Describes the destination.
  1519. PTDI_CONNECTION_INFORMATION ReturnAddr) // Where to return information.
  1520. {
  1521. TCPConnReq *ConnReq; // Connection request to use.
  1522. IPv6Addr DestAddr;
  1523. ulong DestScopeId;
  1524. ushort DestPort;
  1525. TCPConn *Conn;
  1526. TCB *NewTCB;
  1527. uint ConnID = PtrToUlong(Request->Handle.ConnectionContext);
  1528. KIRQL Irql0, Irql1, Irql2; // One per lock nesting level.
  1529. AddrObj *AO;
  1530. TDI_STATUS Status;
  1531. IP_STATUS IPStatus;
  1532. ushort MSS;
  1533. TCP_TIME *Timeout;
  1534. NetTableEntry *NTE;
  1535. NetTableEntryOrInterface *NTEorIF;
  1536. int WildcardSourceAddress = FALSE;
  1537. //
  1538. // First, get and validate the remote address.
  1539. //
  1540. if (RequestAddr == NULL || RequestAddr->RemoteAddress == NULL ||
  1541. !GetAddress((PTRANSPORT_ADDRESS)RequestAddr->RemoteAddress, &DestAddr,
  1542. &DestScopeId, &DestPort))
  1543. return TDI_BAD_ADDR;
  1544. //
  1545. // REVIEW: IPv4 performed other remote address sanity checks here.
  1546. // REVIEW: E.g., should we check that remote addr isn't multicast?
  1547. //
  1548. //
  1549. // REVIEW: I can't find an RFC which states 0 is not a valid port number.
  1550. //
  1551. if (DestPort == 0)
  1552. return TDI_BAD_ADDR;
  1553. //
  1554. // Get a connection request. If we can't, bail out now.
  1555. //
  1556. ConnReq = GetConnReq();
  1557. if (ConnReq == NULL)
  1558. return TDI_NO_RESOURCES;
  1559. //
  1560. // Get a TCB, assuming we'll need one.
  1561. //
  1562. NewTCB = AllocTCB();
  1563. if (NewTCB == NULL) {
  1564. // Couldn't get a TCB.
  1565. FreeConnReq(ConnReq);
  1566. return TDI_NO_RESOURCES;
  1567. }
  1568. Timeout = (TCP_TIME *)TO;
  1569. if (Timeout != NULL && !INFINITE_CONN_TO(*Timeout)) {
  1570. ulong Ticks = TCP_TIME_TO_TICKS(*Timeout);
  1571. if (Ticks > MAX_CONN_TO_TICKS)
  1572. Ticks = MAX_CONN_TO_TICKS;
  1573. else
  1574. Ticks++;
  1575. ConnReq->tcr_timeout = (ushort)Ticks;
  1576. } else
  1577. ConnReq->tcr_timeout = 0;
  1578. ConnReq->tcr_flags = 0;
  1579. ConnReq->tcr_conninfo = ReturnAddr;
  1580. ConnReq->tcr_addrinfo = NULL;
  1581. ConnReq->tcr_req.tr_rtn = Request->RequestNotifyObject;
  1582. ConnReq->tcr_req.tr_context = Request->RequestContext;
  1583. NewTCB->tcb_daddr = DestAddr;
  1584. NewTCB->tcb_dscope_id = DestScopeId;
  1585. NewTCB->tcb_dport = DestPort;
  1586. //
  1587. // Now find the real connection.
  1588. //
  1589. KeAcquireSpinLock(&AddrObjTableLock, &Irql0);
  1590. Conn = GetConnFromConnID(ConnID, &Irql1);
  1591. if (Conn != NULL) {
  1592. uint Inserted;
  1593. CHECK_STRUCT(Conn, tc);
  1594. //
  1595. // We found the connection. Check for an associated address object.
  1596. //
  1597. AO = Conn->tc_ao;
  1598. if (AO != NULL) {
  1599. KeAcquireSpinLock(&AO->ao_lock, &Irql2);
  1600. CHECK_STRUCT(AO, ao);
  1601. Status = InitTCBFromConn(Conn, NewTCB, RequestAddr, TRUE);
  1602. if (Status == TDI_SUCCESS) {
  1603. //
  1604. // We've initialized our TCB. Mark it that we initiated this
  1605. // connection (i.e. active open). Also, we're done with the
  1606. // AddrObjTable, so we can free it's lock.
  1607. //
  1608. NewTCB->tcb_flags |= ACTIVE_OPEN;
  1609. KeReleaseSpinLock(&AddrObjTableLock, Irql2);
  1610. //
  1611. // Determine NTE to send on (if user cares).
  1612. //
  1613. if (IsUnspecified(&NewTCB->tcb_saddr)) {
  1614. //
  1615. // Caller didn't specify a source address.
  1616. // Let the routing code pick one.
  1617. //
  1618. NTE = NULL;
  1619. NTEorIF = NULL;
  1620. WildcardSourceAddress = TRUE;
  1621. } else {
  1622. //
  1623. // Our TCB has a specific source address. Determine
  1624. // which NTE corresponds to it and the scope id.
  1625. //
  1626. NTE = FindNetworkWithAddress(&NewTCB->tcb_saddr,
  1627. NewTCB->tcb_sscope_id);
  1628. if (NTE == NULL) {
  1629. //
  1630. // Bad source address. We don't have a network with
  1631. // the requested address. Error out.
  1632. //
  1633. // REVIEW: Will the AddrObj code even let this happen?
  1634. //
  1635. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_USER_ERROR,
  1636. "TdiConnect: Bad source address\n"));
  1637. KeReleaseSpinLock(&AO->ao_lock, Irql1);
  1638. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql0);
  1639. Status = TDI_BAD_ADDR;
  1640. goto error;
  1641. }
  1642. NTEorIF = CastFromNTE(NTE);
  1643. }
  1644. //
  1645. // Get the route.
  1646. //
  1647. ASSERT(NewTCB->tcb_rce == NULL);
  1648. IPStatus = RouteToDestination(&DestAddr, DestScopeId,
  1649. NTEorIF, RTD_FLAG_NORMAL,
  1650. &NewTCB->tcb_rce);
  1651. if (NTE != NULL)
  1652. ReleaseNTE(NTE);
  1653. NTE = NULL; // Protect against accidental use.
  1654. if (IPStatus != IP_SUCCESS) {
  1655. //
  1656. // Failed to get a route to the destination. Error out.
  1657. //
  1658. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INTERNAL_ERROR,
  1659. "TdiConnect: Failed to get route to dest.\n"));
  1660. KeReleaseSpinLock(&AO->ao_lock, Irql1);
  1661. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql0);
  1662. if ((IPStatus == IP_PARAMETER_PROBLEM) ||
  1663. (IPStatus == IP_BAD_ROUTE))
  1664. Status = TDI_BAD_ADDR;
  1665. else if (IPStatus == IP_NO_RESOURCES)
  1666. Status = TDI_NO_RESOURCES;
  1667. else
  1668. Status = TDI_DEST_UNREACHABLE;
  1669. goto error;
  1670. }
  1671. ASSERT(NewTCB->tcb_rce != NULL);
  1672. if (IsDisconnectedAndNotLoopbackRCE(NewTCB->tcb_rce)) {
  1673. //
  1674. // Fail new connection requests for TCBs with a
  1675. // disconnected outgoing interface, except when a
  1676. // loopback route is used.
  1677. //
  1678. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INTERNAL_ERROR,
  1679. "TdiConnect: Interface disconnected.\n"));
  1680. KeReleaseSpinLock(&AO->ao_lock, Irql1);
  1681. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql0);
  1682. //
  1683. // Drop the reference on the route we obtained.
  1684. //
  1685. ReleaseRCE(NewTCB->tcb_rce);
  1686. Status = TDI_INVALID_STATE;
  1687. goto error;
  1688. }
  1689. //
  1690. // OK, we got a route. Enter the TCB into the connection
  1691. // and send a SYN.
  1692. //
  1693. KeAcquireSpinLock(&NewTCB->tcb_lock, &Irql2);
  1694. Conn->tc_tcb = NewTCB;
  1695. Conn->tc_refcnt++;
  1696. NewTCB->tcb_conn = Conn;
  1697. NewTCB->tcb_connid = Conn->tc_connid;
  1698. REMOVEQ(&Conn->tc_q);
  1699. ENQUEUE(&AO->ao_activeq, &Conn->tc_q);
  1700. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql2);
  1701. KeReleaseSpinLock(&AO->ao_lock, Irql1);
  1702. //
  1703. // Initialize path-specific TCB settings, based on the RCE:
  1704. //
  1705. // If packets on the path will be looped back in software,
  1706. // don't use the Nagle algorithm for this TCB.
  1707. //
  1708. if (IsLoopbackRCE(NewTCB->tcb_rce)) {
  1709. NewTCB->tcb_flags &= ~NAGLING;
  1710. }
  1711. if (WildcardSourceAddress) {
  1712. //
  1713. // We let the routing code pick the source NTE above.
  1714. // Remember this address for later use.
  1715. //
  1716. // REVIEW: Hold onto the NTE instead? It's more changes...
  1717. //
  1718. NewTCB->tcb_saddr = NewTCB->tcb_rce->NTE->Address;
  1719. NewTCB->tcb_sscope_id =
  1720. DetermineScopeId(&NewTCB->tcb_saddr,
  1721. NewTCB->tcb_rce->NTE->IF);
  1722. }
  1723. //
  1724. // Similarly, the routing code may have picked
  1725. // the destination scope id if it was left unspecified.
  1726. // REVIEW - getpeername will not return the new DestScopeId.
  1727. //
  1728. DestScopeId = DetermineScopeId(&NewTCB->tcb_daddr,
  1729. NewTCB->tcb_rce->NTE->IF);
  1730. ASSERT((NewTCB->tcb_dscope_id == DestScopeId) ||
  1731. (NewTCB->tcb_dscope_id == 0));
  1732. NewTCB->tcb_dscope_id = DestScopeId;
  1733. //
  1734. // Initialize our Maximum Segment Size (MSS).
  1735. // Cache our current Path Maximum Transmission Unit (PMTU)
  1736. // so that we'll know if it changes.
  1737. //
  1738. NewTCB->tcb_pmtu = GetEffectivePathMTUFromRCE(NewTCB->tcb_rce);
  1739. IF_TCPDBG(TCP_DEBUG_MSS) {
  1740. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1741. "TCP TdiConnect: PMTU from RCE is %d\n",
  1742. NewTCB->tcb_pmtu));
  1743. }
  1744. NewTCB->tcb_remmss = MAXUSHORT;
  1745. NewTCB->tcb_security = SecurityStateValidationCounter;
  1746. CalculateMSSForTCB(NewTCB);
  1747. // Now initialize our send state.
  1748. InitSendState(NewTCB);
  1749. NewTCB->tcb_refcnt = 1;
  1750. NewTCB->tcb_state = TCB_SYN_SENT;
  1751. TStats.ts_activeopens++;
  1752. // Need to put the ConnReq on the TCB now, in case the timer
  1753. // fires after we've inserted.
  1754. NewTCB->tcb_connreq = ConnReq;
  1755. KeReleaseSpinLock(&NewTCB->tcb_lock, Irql0);
  1756. Inserted = InsertTCB(NewTCB);
  1757. KeAcquireSpinLock(&NewTCB->tcb_lock, &Irql0);
  1758. if (!Inserted) {
  1759. // Insert failed. We must already have a connection. Pull
  1760. // the connreq from the TCB first, so we can return the
  1761. // correct error code for it.
  1762. NewTCB->tcb_connreq = NULL;
  1763. NewTCB->tcb_refcnt--;
  1764. TryToCloseTCB(NewTCB, TCB_CLOSE_ABORTED, Irql0);
  1765. FreeConnReq(ConnReq);
  1766. return TDI_ADDR_IN_USE;
  1767. }
  1768. // If it's closing somehow, stop now. It can't have gone to
  1769. // closed, as we hold a reference on it. It could have gone
  1770. // to some other state (for example SYN-RCVD) so we need to
  1771. // check that now too.
  1772. if (!CLOSING(NewTCB) && NewTCB->tcb_state == TCB_SYN_SENT) {
  1773. SendSYN(NewTCB, Irql0);
  1774. KeAcquireSpinLock(&NewTCB->tcb_lock, &Irql0);
  1775. }
  1776. DerefTCB(NewTCB, Irql0);
  1777. return TDI_PENDING;
  1778. } else
  1779. KeReleaseSpinLock(&AO->ao_lock, Irql2);
  1780. } else
  1781. Status = TDI_NOT_ASSOCIATED;
  1782. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql1);
  1783. } else
  1784. Status = TDI_INVALID_CONNECTION;
  1785. KeReleaseSpinLock(&AddrObjTableLock, Irql0);
  1786. error:
  1787. FreeTCB(NewTCB);
  1788. FreeConnReq(ConnReq);
  1789. return Status;
  1790. }
  1791. //* TdiListen - Listen for a connection.
  1792. //
  1793. // The TDI listen handling routine. Called when the client wants to
  1794. // post a listen, we validate his incoming parameters, allocate a TCB
  1795. // and return.
  1796. //
  1797. TDI_STATUS // Returns: Status of attempt to connect.
  1798. TdiListen(
  1799. PTDI_REQUEST Request, // Structure for this request.
  1800. ushort Flags, // Listen flags for listen.
  1801. PTDI_CONNECTION_INFORMATION AcceptableAddr, // Acceptable remote addrs.
  1802. PTDI_CONNECTION_INFORMATION ConnectedAddr) // Where to return conn addr.
  1803. {
  1804. TCPConnReq *ConnReq; // Connection request to use.
  1805. IPv6Addr RemoteAddr; // Remote address to take conn. from.
  1806. ulong RemoteScopeId; // Scope identifier for remote addr (0 is none).
  1807. ushort RemotePort; // Acceptable remote port.
  1808. TCPConn *Conn; // Pointer to the Connection being listened upon.
  1809. TCB *NewTCB; // Pointer to the new TCB we'll use.
  1810. uint ConnID = PtrToUlong(Request->Handle.ConnectionContext);
  1811. KIRQL OldIrql; // Save IRQL value prior to taking lock.
  1812. TDI_STATUS Status;
  1813. //
  1814. // If we've been given remote addressing criteria, check it out.
  1815. //
  1816. if (AcceptableAddr != NULL && AcceptableAddr->RemoteAddress != NULL) {
  1817. if (!GetAddress((PTRANSPORT_ADDRESS)AcceptableAddr->RemoteAddress,
  1818. &RemoteAddr, &RemoteScopeId, &RemotePort))
  1819. return TDI_BAD_ADDR;
  1820. //
  1821. // REVIEW: IPv4 version did some other address sanity checks here.
  1822. // REVIEW: E.g., should we check that remote addr isn't multicast?
  1823. //
  1824. } else {
  1825. RemoteAddr = UnspecifiedAddr;
  1826. RemoteScopeId = 0;
  1827. RemotePort = 0;
  1828. }
  1829. //
  1830. // The remote address is valid. Get a ConnReq, and maybe a TCB.
  1831. //
  1832. ConnReq = GetConnReq();
  1833. if (ConnReq == NULL)
  1834. return TDI_NO_RESOURCES; // Couldn't get one.
  1835. //
  1836. // Now try to get a TCB.
  1837. //
  1838. NewTCB = AllocTCB();
  1839. if (NewTCB == NULL) {
  1840. //
  1841. // Couldn't get a TCB. Return an error.
  1842. //
  1843. FreeConnReq(ConnReq);
  1844. return TDI_NO_RESOURCES;
  1845. }
  1846. //
  1847. // We have the resources we need. Initialize them, and then check the
  1848. // state of the connection.
  1849. //
  1850. ConnReq->tcr_flags = Flags;
  1851. ConnReq->tcr_conninfo = ConnectedAddr;
  1852. ConnReq->tcr_addrinfo = NULL;
  1853. ConnReq->tcr_req.tr_rtn = Request->RequestNotifyObject;
  1854. ConnReq->tcr_req.tr_context = Request->RequestContext;
  1855. NewTCB->tcb_connreq = ConnReq;
  1856. NewTCB->tcb_daddr = RemoteAddr;
  1857. NewTCB->tcb_dscope_id = RemoteScopeId;
  1858. NewTCB->tcb_dport = RemotePort;
  1859. NewTCB->tcb_state = TCB_LISTEN;
  1860. //
  1861. // Now find the real connection. If we find it, we'll make sure it's
  1862. // associated.
  1863. //
  1864. Conn = GetConnFromConnID(ConnID, &OldIrql);
  1865. if (Conn != NULL) {
  1866. AddrObj *ConnAO;
  1867. CHECK_STRUCT(Conn, tc);
  1868. //
  1869. // We have a connection. Make sure it's associated with an address and
  1870. // doesn't already have a TCB attached.
  1871. //
  1872. ConnAO = Conn->tc_ao;
  1873. if (ConnAO != NULL) {
  1874. CHECK_STRUCT(ConnAO, ao);
  1875. KeAcquireSpinLockAtDpcLevel(&ConnAO->ao_lock);
  1876. if (AO_VALID(ConnAO)) {
  1877. Status = InitTCBFromConn(Conn, NewTCB, AcceptableAddr, TRUE);
  1878. } else {
  1879. Status = TDI_ADDR_INVALID;
  1880. }
  1881. if (Status == TDI_SUCCESS) {
  1882. //
  1883. // The initialization worked. Assign the new TCB to the
  1884. // connection, and return.
  1885. //
  1886. REMOVEQ(&Conn->tc_q);
  1887. PUSHQ(&ConnAO->ao_listenq, &Conn->tc_q);
  1888. Conn->tc_tcb = NewTCB;
  1889. NewTCB->tcb_conn = Conn;
  1890. NewTCB->tcb_connid = Conn->tc_connid;
  1891. Conn->tc_refcnt++;
  1892. ConnAO->ao_listencnt++;
  1893. KeReleaseSpinLockFromDpcLevel(&ConnAO->ao_lock);
  1894. Status = TDI_PENDING;
  1895. } else {
  1896. FreeTCB(NewTCB);
  1897. KeReleaseSpinLockFromDpcLevel(&ConnAO->ao_lock);
  1898. }
  1899. } else {
  1900. FreeTCB(NewTCB);
  1901. Status = TDI_NOT_ASSOCIATED;
  1902. }
  1903. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, OldIrql);
  1904. } else {
  1905. FreeTCB(NewTCB);
  1906. Status = TDI_INVALID_CONNECTION;
  1907. }
  1908. //
  1909. // We're all done.
  1910. //
  1911. return Status;
  1912. }
  1913. //* InitRCE - Initialize an RCE.
  1914. //
  1915. // A utility routine to open an RCE and determine the maximum segment size
  1916. // for a connection. This function is called with the TCB lock held
  1917. // when transitioning out of the SYN_SENT or LISTEN states.
  1918. //
  1919. void // Returns: Nothing.
  1920. InitRCE(
  1921. TCB *NewTCB) // TCB for which an RCE is to be opened.
  1922. {
  1923. NetTableEntry *NTE;
  1924. IP_STATUS Status;
  1925. ushort MSS;
  1926. //
  1927. // We are called when receiving an incoming connection attempt,
  1928. // so tcb_saddr will always be initialized.
  1929. //
  1930. ASSERT(! IsUnspecified(&NewTCB->tcb_saddr));
  1931. //
  1932. // Determine NTE we're using for this connection.
  1933. //
  1934. NTE = FindNetworkWithAddress(&NewTCB->tcb_saddr,
  1935. NewTCB->tcb_sscope_id);
  1936. if (NTE == NULL) {
  1937. //
  1938. // Failed to get a route to the destination.
  1939. //
  1940. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INTERNAL_ERROR,
  1941. "TCP InitRCE: Can't find the NTE for address?!?\n"));
  1942. goto ErrorReturn;
  1943. }
  1944. //
  1945. // Get the route.
  1946. //
  1947. ASSERT(NewTCB->tcb_rce == NULL);
  1948. Status = RouteToDestination(&NewTCB->tcb_daddr, NewTCB->tcb_dscope_id,
  1949. CastFromNTE(NTE), RTD_FLAG_NORMAL,
  1950. &NewTCB->tcb_rce);
  1951. ReleaseNTE(NTE);
  1952. if (Status != IP_SUCCESS) {
  1953. //
  1954. // Failed to get a route to the destination.
  1955. //
  1956. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INTERNAL_ERROR,
  1957. "TCP InitRCE: Can't get a route?!?\n"));
  1958. ErrorReturn:
  1959. //
  1960. // Until we have a real route, use conservative values.
  1961. //
  1962. NewTCB->tcb_pmtu = IPv6_MINIMUM_MTU;
  1963. NewTCB->tcb_mss = (ushort)MIN(DEFAULT_MSS, NewTCB->tcb_remmss);
  1964. return;
  1965. }
  1966. //
  1967. // Initialize path-specific TCB settings, based on the RCE:
  1968. //
  1969. // If packets on the path will be looped back in software,
  1970. // don't use the Nagle algorithm for this TCB.
  1971. //
  1972. if (IsLoopbackRCE(NewTCB->tcb_rce)) {
  1973. NewTCB->tcb_flags &= ~NAGLING;
  1974. }
  1975. //
  1976. // Initialize the maximum segement size (MSS) for this connection.
  1977. // Cache our current Path Maximum Transmission Unit (PMTU)
  1978. // so that we'll know if it changes.
  1979. //
  1980. NewTCB->tcb_pmtu = GetEffectivePathMTUFromRCE(NewTCB->tcb_rce);
  1981. IF_TCPDBG(TCP_DEBUG_MSS) {
  1982. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  1983. "TCP InitRCE: PMTU from RCE is %d\n", NewTCB->tcb_pmtu));
  1984. }
  1985. NewTCB->tcb_security = SecurityStateValidationCounter;
  1986. CalculateMSSForTCB(NewTCB);
  1987. }
  1988. //* AcceptConn - Accept a connection on a TCB.
  1989. //
  1990. // Called to accept a connection on a TCB, either from an incoming
  1991. // receive segment or via a user's accept. We initialize the RCE
  1992. // and the send state, and send out a SYN. We assume the TCB is locked
  1993. // and referenced when we get it.
  1994. //
  1995. void // Returns: Nothing.
  1996. AcceptConn(
  1997. TCB *AcceptTCB, // TCB to accept on.
  1998. KIRQL PreLockIrql) // IRQL prior to acquiring TCB lock.
  1999. {
  2000. CHECK_STRUCT(AcceptTCB, tcb);
  2001. ASSERT(AcceptTCB->tcb_refcnt != 0);
  2002. InitRCE(AcceptTCB);
  2003. InitSendState(AcceptTCB);
  2004. AdjustRcvWin(AcceptTCB);
  2005. SendSYN(AcceptTCB, PreLockIrql);
  2006. KeAcquireSpinLock(&AcceptTCB->tcb_lock, &PreLockIrql);
  2007. DerefTCB(AcceptTCB, PreLockIrql);
  2008. }
  2009. //* TdiAccept - Accept a connection.
  2010. //
  2011. // The TDI accept routine. Called when the client wants to
  2012. // accept a connection for which a listen had previously completed. We
  2013. // examine the state of the connection - it has to be in SYN-RCVD, with
  2014. // a TCB, with no pending connreq, etc.
  2015. //
  2016. TDI_STATUS // Returns: Status of attempt to connect.
  2017. TdiAccept(
  2018. PTDI_REQUEST Request, // Structure for this request.
  2019. PTDI_CONNECTION_INFORMATION AcceptInfo, // Info for this accept.
  2020. PTDI_CONNECTION_INFORMATION ConnectedInfo) // Where to return conn addr.
  2021. {
  2022. TCPConnReq *ConnReq; // ConnReq we'll use for this connection.
  2023. uint ConnID = PtrToUlong(Request->Handle.ConnectionContext);
  2024. TCPConn *Conn; // Connection being accepted upon.
  2025. TCB *AcceptTCB; // TCB for Conn.
  2026. KIRQL Irql0, Irql1; // One per lock nesting level.
  2027. TDI_STATUS Status;
  2028. //
  2029. // First, get the ConnReq we'll need.
  2030. //
  2031. ConnReq = GetConnReq();
  2032. if (ConnReq == NULL)
  2033. return TDI_NO_RESOURCES;
  2034. ConnReq->tcr_conninfo = ConnectedInfo;
  2035. ConnReq->tcr_addrinfo = NULL;
  2036. ConnReq->tcr_req.tr_rtn = Request->RequestNotifyObject;
  2037. ConnReq->tcr_req.tr_context = Request->RequestContext;
  2038. //
  2039. // Now look up the connection.
  2040. //
  2041. Conn = GetConnFromConnID(ConnID, &Irql0);
  2042. if (Conn != NULL) {
  2043. CHECK_STRUCT(Conn, tc);
  2044. //
  2045. // We have the connection. Make sure is has a TCB, and that the
  2046. // TCB is in the SYN-RCVD state, etc.
  2047. //
  2048. AcceptTCB = Conn->tc_tcb;
  2049. if (AcceptTCB != NULL) {
  2050. CHECK_STRUCT(AcceptTCB, tcb);
  2051. KeAcquireSpinLock(&AcceptTCB->tcb_lock, &Irql1);
  2052. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql1);
  2053. if (!CLOSING(AcceptTCB) && AcceptTCB->tcb_state == TCB_SYN_RCVD) {
  2054. //
  2055. // State is valid. Make sure this TCB had a delayed accept on
  2056. // it, and that there is currently no connect request pending.
  2057. //
  2058. if (!(AcceptTCB->tcb_flags & CONN_ACCEPTED) &&
  2059. AcceptTCB->tcb_connreq == NULL) {
  2060. //
  2061. // If the caller gave us options, they'll override any
  2062. // that are already present, if they're valid.
  2063. //
  2064. if (AcceptInfo != NULL && AcceptInfo->Options != NULL) {
  2065. //
  2066. // We have options.
  2067. // Copy them to make sure they're valid.
  2068. //
  2069. Status = ProcessUserOptions(AcceptInfo);
  2070. if (Status == TDI_SUCCESS) {
  2071. AcceptTCB->tcb_flags |= CLIENT_OPTIONS;
  2072. } else
  2073. goto connerror;
  2074. }
  2075. AcceptTCB->tcb_connreq = ConnReq;
  2076. AcceptTCB->tcb_flags |= CONN_ACCEPTED;
  2077. AcceptTCB->tcb_refcnt++;
  2078. //
  2079. // Everything's set. Accept the connection now.
  2080. //
  2081. AcceptConn(AcceptTCB, Irql0);
  2082. return TDI_PENDING;
  2083. }
  2084. }
  2085. connerror:
  2086. KeReleaseSpinLock(&AcceptTCB->tcb_lock, Irql0);
  2087. Status = TDI_INVALID_CONNECTION;
  2088. goto error;
  2089. }
  2090. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql0);
  2091. }
  2092. Status = TDI_INVALID_CONNECTION;
  2093. error:
  2094. FreeConnReq(ConnReq);
  2095. return Status;
  2096. }
  2097. //* TdiDisConnect - Disconnect a connection.
  2098. //
  2099. // The TDI disconnection routine. Called when the client wants to disconnect
  2100. // a connection. There are two types of disconnection we support, graceful
  2101. // and abortive. A graceful close will cause us to send a FIN and not complete
  2102. // the request until we get the ACK back. An abortive close causes us to send
  2103. // a RST. In that case we'll just get things going and return immediately.
  2104. //
  2105. // Note: The format of the Timeout (TO) is system specific - we use
  2106. // a macro to convert to ticks.
  2107. //
  2108. TDI_STATUS // Returns: Status of attempt to disconnect.
  2109. TdiDisconnect(
  2110. PTDI_REQUEST Request, // Structure for this request.
  2111. void *TO, // How long to wait.
  2112. ushort Flags, // Type of disconnect.
  2113. PTDI_CONNECTION_INFORMATION DiscConnInfo, // Ignored.
  2114. PTDI_CONNECTION_INFORMATION ReturnInfo) // Ignored.
  2115. {
  2116. TCPConnReq *ConnReq; // Connection request to use.
  2117. TCPConn *Conn;
  2118. TCB *DiscTCB;
  2119. KIRQL Irql0, Irql1; // One per lock nesting level.
  2120. TDI_STATUS Status;
  2121. TCP_TIME *Timeout;
  2122. Conn = GetConnFromConnID(PtrToUlong(Request->Handle.ConnectionContext),
  2123. &Irql0);
  2124. if (Conn != NULL) {
  2125. CHECK_STRUCT(Conn, tc);
  2126. DiscTCB = Conn->tc_tcb;
  2127. if (DiscTCB != NULL) {
  2128. CHECK_STRUCT(DiscTCB, tcb);
  2129. KeAcquireSpinLock(&DiscTCB->tcb_lock, &Irql1);
  2130. //
  2131. // We have the TCB. See what kind of disconnect this is.
  2132. //
  2133. if (Flags & TDI_DISCONNECT_ABORT) {
  2134. //
  2135. // This is an abortive disconnect. If we're not already
  2136. // closed or closing, blow the connection away.
  2137. //
  2138. if (DiscTCB->tcb_state != TCB_CLOSED) {
  2139. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql1);
  2140. if (!CLOSING(DiscTCB)) {
  2141. DiscTCB->tcb_flags |= NEED_RST;
  2142. TryToCloseTCB(DiscTCB, TCB_CLOSE_ABORTED,
  2143. Irql0);
  2144. } else
  2145. KeReleaseSpinLock(&DiscTCB->tcb_lock, Irql0);
  2146. return TDI_SUCCESS;
  2147. } else {
  2148. //
  2149. // The TCB isn't connected.
  2150. //
  2151. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql1);
  2152. KeReleaseSpinLock(&DiscTCB->tcb_lock, Irql0);
  2153. return TDI_INVALID_STATE;
  2154. }
  2155. } else {
  2156. //
  2157. // This is not an abortive close. For graceful close we'll
  2158. // need a ConnReq.
  2159. //
  2160. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql1);
  2161. //
  2162. // Make sure we aren't in the middle of an abortive close.
  2163. //
  2164. if (CLOSING(DiscTCB)) {
  2165. KeReleaseSpinLock(&DiscTCB->tcb_lock, Irql0);
  2166. return TDI_INVALID_CONNECTION;
  2167. }
  2168. ConnReq = GetConnReq();
  2169. if (ConnReq != NULL) {
  2170. //
  2171. // Got the ConnReq. See if this is a DISCONNECT_WAIT
  2172. // primitive or not.
  2173. //
  2174. ConnReq->tcr_flags = 0;
  2175. ConnReq->tcr_conninfo = NULL;
  2176. ConnReq->tcr_addrinfo = NULL;
  2177. ConnReq->tcr_req.tr_rtn = Request->RequestNotifyObject;
  2178. ConnReq->tcr_req.tr_context = Request->RequestContext;
  2179. if (!(Flags & TDI_DISCONNECT_WAIT)) {
  2180. Timeout = (TCP_TIME *)TO;
  2181. if (Timeout != NULL && !INFINITE_CONN_TO(*Timeout)) {
  2182. ulong Ticks = TCP_TIME_TO_TICKS(*Timeout);
  2183. if (Ticks > MAX_CONN_TO_TICKS)
  2184. Ticks = MAX_CONN_TO_TICKS;
  2185. else
  2186. Ticks++;
  2187. ConnReq->tcr_timeout = (ushort)Ticks;
  2188. } else
  2189. ConnReq->tcr_timeout = 0;
  2190. //
  2191. // OK, we're just about set. We need to update
  2192. // the TCB state, and send the FIN.
  2193. //
  2194. if (DiscTCB->tcb_state == TCB_ESTAB) {
  2195. DiscTCB->tcb_state = TCB_FIN_WAIT1;
  2196. //
  2197. // Since we left established, we're off the fast
  2198. // receive path.
  2199. //
  2200. DiscTCB->tcb_slowcount++;
  2201. DiscTCB->tcb_fastchk |= TCP_FLAG_SLOW;
  2202. } else
  2203. if (DiscTCB->tcb_state == TCB_CLOSE_WAIT)
  2204. DiscTCB->tcb_state = TCB_LAST_ACK;
  2205. else {
  2206. KeReleaseSpinLock(&DiscTCB->tcb_lock, Irql0);
  2207. FreeConnReq(ConnReq);
  2208. return TDI_INVALID_STATE;
  2209. }
  2210. TStats.ts_currestab--; // Update SNMP info.
  2211. ASSERT(*(int *)&TStats.ts_currestab >= 0);
  2212. ASSERT(DiscTCB->tcb_connreq == NULL);
  2213. DiscTCB->tcb_connreq = ConnReq;
  2214. DiscTCB->tcb_flags |= FIN_NEEDED;
  2215. DiscTCB->tcb_refcnt++;
  2216. TCPSend(DiscTCB, Irql0);
  2217. return TDI_PENDING;
  2218. } else {
  2219. //
  2220. // This is a DISC_WAIT request.
  2221. //
  2222. ConnReq->tcr_timeout = 0;
  2223. if (DiscTCB->tcb_discwait == NULL) {
  2224. DiscTCB->tcb_discwait = ConnReq;
  2225. Status = TDI_PENDING;
  2226. } else
  2227. Status = TDI_INVALID_STATE;
  2228. KeReleaseSpinLock(&DiscTCB->tcb_lock, Irql0);
  2229. return Status;
  2230. }
  2231. } else {
  2232. //
  2233. // Couldn't get a ConnReq.
  2234. //
  2235. KeReleaseSpinLock(&DiscTCB->tcb_lock, Irql0);
  2236. return TDI_NO_RESOURCES;
  2237. }
  2238. }
  2239. } else
  2240. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql0);
  2241. }
  2242. //
  2243. // No Conn, or no TCB on conn. Return an error.
  2244. //
  2245. return TDI_INVALID_CONNECTION;
  2246. }
  2247. //* OKToNotify - See if it's OK to notify about a DISC.
  2248. //
  2249. // A little utility function, called to see it it's OK to notify the client
  2250. // of an incoming FIN.
  2251. //
  2252. uint // Returns: TRUE if it's OK, False otherwise.
  2253. OKToNotify(
  2254. TCB *NotifyTCB) // TCB to check.
  2255. {
  2256. CHECK_STRUCT(NotifyTCB, tcb);
  2257. if (NotifyTCB->tcb_pendingcnt == 0 && NotifyTCB->tcb_urgcnt == 0 &&
  2258. NotifyTCB->tcb_rcvhead == NULL && NotifyTCB->tcb_exprcv == NULL)
  2259. return TRUE;
  2260. else
  2261. return FALSE;
  2262. }
  2263. //* NotifyOfDisc - Notify a client that a TCB is being disconnected.
  2264. //
  2265. // Called when we're disconnecting a TCB because we've received a FIN or
  2266. // RST from the remote peer, or because we're aborting for some reason.
  2267. // We'll complete a DISCONNECT_WAIT request if we have one, or try and
  2268. // issue an indication otherwise. This is only done if we're in a
  2269. // synchronized state and not in TIMED-WAIT.
  2270. //
  2271. void // Returns: Nothing.
  2272. NotifyOfDisc(
  2273. TCB *DiscTCB, // TCB we're notifying.
  2274. TDI_STATUS Status) // Status code for notification.
  2275. {
  2276. KIRQL Irql0, Irql1;
  2277. TCPConnReq *DiscReq;
  2278. TCPConn *Conn;
  2279. AddrObj *DiscAO;
  2280. PVOID ConnContext;
  2281. CHECK_STRUCT(DiscTCB, tcb);
  2282. ASSERT(DiscTCB->tcb_refcnt != 0);
  2283. KeAcquireSpinLock(&DiscTCB->tcb_lock, &Irql0);
  2284. if (SYNC_STATE(DiscTCB->tcb_state) &&
  2285. !(DiscTCB->tcb_flags & DISC_NOTIFIED)) {
  2286. //
  2287. // We can't notify him if there's still data to be taken.
  2288. //
  2289. if (Status == TDI_GRACEFUL_DISC && !OKToNotify(DiscTCB)) {
  2290. DiscTCB->tcb_flags |= DISC_PENDING;
  2291. KeReleaseSpinLock(&DiscTCB->tcb_lock, Irql0);
  2292. return;
  2293. }
  2294. DiscTCB->tcb_flags |= DISC_NOTIFIED;
  2295. DiscTCB->tcb_flags &= ~DISC_PENDING;
  2296. //
  2297. // We're in a state where a disconnect is meaningful, and we haven't
  2298. // already notified the client.
  2299. // See if we have a DISC-WAIT request pending.
  2300. //
  2301. if ((DiscReq = DiscTCB->tcb_discwait) != NULL) {
  2302. //
  2303. // We have a disconnect wait request. Complete it and we're done.
  2304. //
  2305. DiscTCB->tcb_discwait = NULL;
  2306. KeReleaseSpinLock(&DiscTCB->tcb_lock, Irql0);
  2307. (*DiscReq->tcr_req.tr_rtn)(DiscReq->tcr_req.tr_context, Status, 0);
  2308. FreeConnReq(DiscReq);
  2309. return;
  2310. }
  2311. //
  2312. // No DISC-WAIT. Find the AddrObj for the connection, and see if
  2313. // there is a disconnect handler registered.
  2314. //
  2315. ConnContext = DiscTCB->tcb_conncontext;
  2316. KeReleaseSpinLock(&DiscTCB->tcb_lock, Irql0);
  2317. KeAcquireSpinLock(&AddrObjTableLock, &Irql0);
  2318. if ((Conn = DiscTCB->tcb_conn) != NULL) {
  2319. CHECK_STRUCT(Conn, tc);
  2320. KeAcquireSpinLock(&Conn->tc_ConnBlock->cb_lock, &Irql1);
  2321. DiscAO = Conn->tc_ao;
  2322. if (DiscAO != NULL) {
  2323. KIRQL Irql2;
  2324. PDisconnectEvent DiscEvent;
  2325. PVOID DiscContext;
  2326. CHECK_STRUCT(DiscAO, ao);
  2327. KeAcquireSpinLock(&DiscAO->ao_lock, &Irql2);
  2328. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql2);
  2329. KeReleaseSpinLock(&AddrObjTableLock, Irql1);
  2330. DiscEvent = DiscAO->ao_disconnect;
  2331. DiscContext = DiscAO->ao_disconncontext;
  2332. if (DiscEvent != NULL) {
  2333. REF_AO(DiscAO);
  2334. KeReleaseSpinLock(&DiscAO->ao_lock, Irql0);
  2335. IF_TCPDBG(TCP_DEBUG_CLOSE) {
  2336. KdPrintEx((DPFLTR_TCPIP6_ID, DPFLTR_INFO_TCPDBG,
  2337. "TCP: indicating %s disconnect\n",
  2338. (Status == TDI_GRACEFUL_DISC) ?
  2339. "graceful" : "abortive"));
  2340. }
  2341. (*DiscEvent)(DiscContext, ConnContext, 0, NULL, 0,
  2342. NULL, (Status == TDI_GRACEFUL_DISC) ?
  2343. TDI_DISCONNECT_RELEASE :
  2344. TDI_DISCONNECT_ABORT);
  2345. DELAY_DEREF_AO(DiscAO);
  2346. return;
  2347. } else {
  2348. KeReleaseSpinLock(&DiscAO->ao_lock, Irql0);
  2349. return;
  2350. }
  2351. }
  2352. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql1);
  2353. }
  2354. KeReleaseSpinLock(&AddrObjTableLock, Irql0);
  2355. return;
  2356. }
  2357. KeReleaseSpinLock(&DiscTCB->tcb_lock, Irql0);
  2358. }
  2359. //* GracefulClose - Complete the transition to a gracefully closed state.
  2360. //
  2361. // Called when we need to complete the transition to a gracefully closed
  2362. // state, either TIME_WAIT or CLOSED. This completion involves removing
  2363. // the TCB from it's associated connection (if it has one), notifying the
  2364. // upper layer client either via completing a request or calling a disc.
  2365. // notification handler, and actually doing the transition.
  2366. //
  2367. // The tricky part here is if we need to notify him (instead of completing
  2368. // a graceful disconnect request). We can't notify him if there is pending
  2369. // data on the connection, so in that case we have to pend the disconnect
  2370. // notification until we deliver the data.
  2371. //
  2372. void // Returns: Nothing.
  2373. GracefulClose(
  2374. TCB *CloseTCB, // TCB to transition.
  2375. uint ToTimeWait, // TRUE if we're going to TIME_WAIT, FALSE if
  2376. // we're going to close the TCB.
  2377. uint Notify, // TRUE if via notification, FALSE if via completing
  2378. // a disconnect request.
  2379. KIRQL PreLockIrql) // IRQL prior to acquiring TCB lock.
  2380. {
  2381. CHECK_STRUCT(CloseTCB, tcb);
  2382. ASSERT(CloseTCB->tcb_refcnt != 0);
  2383. //
  2384. // First, see if we need to notify the client of a FIN.
  2385. //
  2386. if (Notify) {
  2387. //
  2388. // We do need to notify him. See if it's OK to do so.
  2389. //
  2390. if (OKToNotify(CloseTCB)) {
  2391. //
  2392. // We can notify him. Change his state, pull him from the conn.,
  2393. // and notify him.
  2394. //
  2395. if (ToTimeWait) {
  2396. //
  2397. // Save the time we went into time wait, in case we need to
  2398. // scavenge.
  2399. //
  2400. CloseTCB->tcb_alive = SystemUpTime();
  2401. CloseTCB->tcb_state = TCB_TIME_WAIT;
  2402. KeReleaseSpinLock(&CloseTCB->tcb_lock, PreLockIrql);
  2403. } else {
  2404. //
  2405. // He's going to close. Mark him as closing with TryToCloseTCB
  2406. // (he won't actually close since we have a ref. on him). We
  2407. // do this so that anyone touching him after we free the
  2408. // lock will fail.
  2409. //
  2410. TryToCloseTCB(CloseTCB, TDI_SUCCESS, PreLockIrql);
  2411. }
  2412. RemoveTCBFromConn(CloseTCB);
  2413. NotifyOfDisc(CloseTCB, TDI_GRACEFUL_DISC);
  2414. } else {
  2415. //
  2416. // Can't notify him now. Set the appropriate flags, and return.
  2417. //
  2418. CloseTCB->tcb_flags |= (GC_PENDING |
  2419. (ToTimeWait ? TW_PENDING : 0));
  2420. DerefTCB(CloseTCB, PreLockIrql);
  2421. return;
  2422. }
  2423. } else {
  2424. //
  2425. // We're not notifying this guy, we just need to complete a conn. req.
  2426. // We need to check and see if he's been notified, and if not
  2427. // we'll complete the request and notify him later.
  2428. //
  2429. if (CloseTCB->tcb_flags & DISC_NOTIFIED) {
  2430. //
  2431. // He's been notified.
  2432. //
  2433. if (ToTimeWait) {
  2434. //
  2435. // Save the time we went into time wait, in case we need to
  2436. // scavenge.
  2437. //
  2438. CloseTCB->tcb_alive = SystemUpTime();
  2439. CloseTCB->tcb_state = TCB_TIME_WAIT;
  2440. KeReleaseSpinLock(&CloseTCB->tcb_lock, PreLockIrql);
  2441. } else {
  2442. //
  2443. // Mark him as closed. See comments above.
  2444. //
  2445. TryToCloseTCB(CloseTCB, TDI_SUCCESS, PreLockIrql);
  2446. }
  2447. RemoveTCBFromConn(CloseTCB);
  2448. KeAcquireSpinLock(&CloseTCB->tcb_lock, &PreLockIrql);
  2449. CompleteConnReq(CloseTCB, TDI_SUCCESS);
  2450. KeReleaseSpinLock(&CloseTCB->tcb_lock, PreLockIrql);
  2451. } else {
  2452. //
  2453. // He hasn't been notified. He should be pending already.
  2454. //
  2455. ASSERT(CloseTCB->tcb_flags & DISC_PENDING);
  2456. CloseTCB->tcb_flags |= (GC_PENDING |
  2457. (ToTimeWait ? TW_PENDING : 0));
  2458. CompleteConnReq(CloseTCB, TDI_SUCCESS);
  2459. DerefTCB(CloseTCB, PreLockIrql);
  2460. return;
  2461. }
  2462. }
  2463. //
  2464. // If we're going to TIME_WAIT, start the TIME_WAIT timer now.
  2465. // Otherwise close the TCB.
  2466. //
  2467. KeAcquireSpinLock(&CloseTCB->tcb_lock, &PreLockIrql);
  2468. if (!CLOSING(CloseTCB) && ToTimeWait) {
  2469. START_TCB_TIMER(CloseTCB->tcb_rexmittimer, MAX_REXMIT_TO);
  2470. KeReleaseSpinLock(&CloseTCB->tcb_lock, PreLockIrql);
  2471. RemoveConnFromTCB(CloseTCB);
  2472. KeAcquireSpinLock(&CloseTCB->tcb_lock, &PreLockIrql);
  2473. }
  2474. DerefTCB(CloseTCB, PreLockIrql);
  2475. }
  2476. #if 0 // REVIEW: Unused function?
  2477. //* ConnCheckPassed - Check to see if we have exceeded the connect limit.
  2478. //
  2479. // Called when a SYN is received to determine whether we will accept
  2480. // the incoming connection. If there is an empty slot or if the IP address
  2481. // is already in the table, we accept it.
  2482. //
  2483. int // Returns: TRUE is connect is accepted, FALSE if rejected.
  2484. ConnCheckPassed(
  2485. IPv6Addr *Src, // Source address of incoming connection.
  2486. ulong Prt) // Destination port of incoming connection.
  2487. {
  2488. UNREFERENCED_PARAMETER(Src);
  2489. UNREFERENCED_PARAMETER(Prt);
  2490. return TRUE;
  2491. }
  2492. #endif
  2493. void InitAddrChecks()
  2494. {
  2495. return;
  2496. }
  2497. //* EnumerateConnectionList - Enumerate Connection List database.
  2498. //
  2499. // This routine enumerates the contents of the connection limit database.
  2500. //
  2501. // Note: The comments found with this routine upon IPv6 port imply that
  2502. // there may have been code here once that actually did something.
  2503. // What's here now is a no-op.
  2504. //
  2505. void // Returns: Nothing.
  2506. EnumerateConnectionList(
  2507. uchar *Buffer, // Buffer to fill with connection list entries.
  2508. ulong BufferSize, // Size of Buffer in bytes.
  2509. ulong *EntriesReturned, // Where to put the number of entries returned.
  2510. ulong *EntriesAvailable) // Where to return number of avail conn. entries.
  2511. {
  2512. UNREFERENCED_PARAMETER(Buffer);
  2513. UNREFERENCED_PARAMETER(BufferSize);
  2514. *EntriesAvailable = 0;
  2515. *EntriesReturned = 0;
  2516. return;
  2517. }
  2518. #pragma BEGIN_INIT
  2519. //* InitTCPConn - Initialize TCP connection management code.
  2520. //
  2521. // Called during init time to initialize our TCP connection management.
  2522. //
  2523. int // Returns: TRUE.
  2524. InitTCPConn(
  2525. void) // Input: Nothing.
  2526. {
  2527. ExInitializeSListHead(&ConnReqFree);
  2528. KeInitializeSpinLock(&ConnReqFreeLock);
  2529. KeInitializeSpinLock(&ConnTableLock);
  2530. MaxAllocatedConnBlocks = 0;
  2531. ConnTable = ExAllocatePool(NonPagedPool,
  2532. MaxConnBlocks * sizeof(TCPConnBlock *));
  2533. if (ConnTable == NULL) {
  2534. return FALSE;
  2535. }
  2536. return TRUE;
  2537. }
  2538. #pragma END_INIT
  2539. //* UnloadTCPConn
  2540. //
  2541. // Cleanup and prepare for stack unload.
  2542. //
  2543. void
  2544. UnloadTCPConn(void)
  2545. {
  2546. PSLIST_ENTRY BufferLink;
  2547. KIRQL OldIrql;
  2548. TCPConnBlock **OldTable;
  2549. while ((BufferLink = ExInterlockedPopEntrySList(&ConnReqFree,
  2550. &ConnReqFreeLock))
  2551. != NULL) {
  2552. Queue *QueuePtr = CONTAINING_RECORD(BufferLink, Queue, q_next);
  2553. TCPReq *Req = CONTAINING_RECORD(QueuePtr, TCPReq, tr_q);
  2554. TCPConnReq *ConnReq = CONTAINING_RECORD(Req, TCPConnReq, tcr_req);
  2555. CHECK_STRUCT(ConnReq, tcr);
  2556. ExFreePool(ConnReq);
  2557. }
  2558. KeAcquireSpinLock(&ConnTableLock, &OldIrql);
  2559. OldTable = ConnTable;
  2560. ConnTable = NULL;
  2561. KeReleaseSpinLock(&ConnTableLock, OldIrql);
  2562. if (OldTable != NULL) {
  2563. uint i;
  2564. for (i = 0; i < MaxAllocatedConnBlocks; i++) {
  2565. ExFreePool(OldTable[i]);
  2566. }
  2567. ExFreePool(OldTable);
  2568. }
  2569. }