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.

3456 lines
111 KiB

  1. /********************************************************************/
  2. /** Microsoft LAN Manager **/
  3. /** Copyright(c) Microsoft Corp., 1990-2000 **/
  4. /********************************************************************/
  5. /* :ts=4 */
  6. //** TCPCONN.C - TCP connection mgmt code.
  7. //
  8. // This file contains the code handling TCP connection related requests,
  9. // such as connecting and disconnecting.
  10. //
  11. #include "precomp.h"
  12. #include "addr.h"
  13. #include "tcp.h"
  14. #include "tcb.h"
  15. #include "tcpconn.h"
  16. #include "tcpsend.h"
  17. #include "tcprcv.h"
  18. #include "tcpdeliv.h"
  19. #include "tlcommon.h"
  20. #include "info.h"
  21. #include "tcpcfg.h"
  22. #include "pplasl.h"
  23. #if !MILLEN
  24. #include "crypto\rc4.h"
  25. #include "ntddksec.h"
  26. #endif // !MILLEN
  27. uint MaxConnBlocks = DEFAULT_CONN_BLOCKS;
  28. uint ConnPerBlock = MAX_CONN_PER_BLOCK;
  29. uint NextConnBlock = 0;
  30. uint MaxAllocatedConnBlocks = 0;
  31. TCPConnBlock **ConnTable = NULL;
  32. HANDLE TcpConnPool;
  33. extern HANDLE TcpRequestPool;
  34. extern uint TcpHostOpts;
  35. extern uint GlobalMaxRcvWin;
  36. extern uint TCBWalkCount;
  37. extern TCB *PendingFreeList;
  38. extern CACHE_LINE_KSPIN_LOCK PendingFreeLock;
  39. //
  40. // ISN globals.
  41. //
  42. #if !MILLEN
  43. #define ISN_KEY_SIZE 256 // 2048 bits.
  44. #define ISN_DEF_RAND_STORE_SIZE 256
  45. #define ISN_MIN_RAND_STORE_SIZE 1
  46. #define ISN_MAX_RAND_STORE_SIZE 16384
  47. RC4_KEYSTRUCT g_rc4keyIsn;
  48. typedef struct _ISN_RAND_STORE {
  49. ulong iBuf;
  50. ushort* pBuf;
  51. } ISN_RAND_STORE, *PISN_RAND_STORE;
  52. PISN_RAND_STORE g_pRandIsnStore;
  53. ulong g_cRandIsnStore = ISN_DEF_RAND_STORE_SIZE;
  54. ulong g_maskRandIsnStore;
  55. #else // !MILLEN
  56. #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
  57. ulong g_dwRandom;
  58. #endif // MILLEN
  59. SeqNum g_CurISN = 0;
  60. uint
  61. InitIsnGenerator()
  62. /*++
  63. Routine Description:
  64. Initializes the ISN generator. In this case, calls in to get 2048 bits
  65. random and creates an RC4 key.
  66. Arguments:
  67. None.
  68. Return Value:
  69. TRUE - success.
  70. FALSE - failure.
  71. Called at PASSIVE level.
  72. --*/
  73. {
  74. #if MILLEN
  75. g_CurISN = CTESystemUpTime();
  76. g_dwRandom = g_CurISN;
  77. return TRUE;
  78. #else // MILLEN
  79. UNICODE_STRING DeviceName;
  80. NTSTATUS NtStatus;
  81. PFILE_OBJECT pFileObject;
  82. PDEVICE_OBJECT pDeviceObject;
  83. unsigned char pBuf[ISN_KEY_SIZE];
  84. PIRP pIrp;
  85. IO_STATUS_BLOCK ioStatusBlock;
  86. KEVENT kEvent;
  87. ULONG cBits = 0;
  88. ULONG i;
  89. ULONG cProcs = KeNumberProcessors;
  90. // Request a block of random bits from the KSecDD driver.
  91. // To do so, retrieve its device object pointer, build an I/O control
  92. // request to be submitted to the driver, and submit the request.
  93. // If any failure occurs, we fall back on the somewhat less-random
  94. // approach of requesting the bits from the randlibk library.
  95. do {
  96. RtlInitUnicodeString(
  97. &DeviceName,
  98. DD_KSEC_DEVICE_NAME_U);
  99. KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE);
  100. // Get the file and device objects for KDSECDD,
  101. // acquire a reference to the device-object,
  102. // release the unneeded reference to the file-object,
  103. // and build the I/O control request to issued to KSecDD.
  104. NtStatus = IoGetDeviceObjectPointer(
  105. &DeviceName,
  106. FILE_ALL_ACCESS,
  107. &pFileObject,
  108. &pDeviceObject);
  109. if (!NT_SUCCESS(NtStatus)) {
  110. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Tcpip: IoGetDeviceObjectPointer(KSecDD)=%08x\n",
  111. NtStatus));
  112. break;
  113. }
  114. ObReferenceObject(pDeviceObject);
  115. ObDereferenceObject(pFileObject);
  116. pIrp = IoBuildDeviceIoControlRequest(
  117. IOCTL_KSEC_RNG,
  118. pDeviceObject,
  119. NULL, // No input buffer.
  120. 0,
  121. pBuf, // Output buffer stores rng.
  122. ISN_KEY_SIZE,
  123. FALSE,
  124. &kEvent,
  125. &ioStatusBlock);
  126. if (pIrp == NULL) {
  127. ObDereferenceObject(pDeviceObject);
  128. NtStatus = STATUS_UNSUCCESSFUL;
  129. break;
  130. }
  131. // Issue the I/O control request, wait for it to complete
  132. // if necessary, and release the reference to KSecDD's device-object.
  133. NtStatus = IoCallDriver(pDeviceObject, pIrp);
  134. if (NtStatus == STATUS_PENDING) {
  135. KeWaitForSingleObject(
  136. &kEvent,
  137. Executive,
  138. KernelMode,
  139. FALSE, // Not alertable.
  140. NULL); // No timeout.
  141. NtStatus = ioStatusBlock.Status;
  142. }
  143. ObDereferenceObject(pDeviceObject);
  144. if (!NT_SUCCESS(NtStatus)) {
  145. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,
  146. "Tcpip: IoCallDriver IOCTL_KSEC_RNG failed %#x\n", NtStatus));
  147. break;
  148. }
  149. } while (FALSE);
  150. if (!NT_SUCCESS(NtStatus)) {
  151. return FALSE;
  152. }
  153. // Generate the key control structure.
  154. rc4_key(&g_rc4keyIsn, ISN_KEY_SIZE, pBuf);
  155. // Initalialize the current sequence number to a random value.
  156. rc4(&g_rc4keyIsn, sizeof(SeqNum), (uchar*)&g_CurISN);
  157. //
  158. // Round down the store size to power of 2. Verify in range.
  159. //
  160. while (g_cRandIsnStore = g_cRandIsnStore >> 1) {
  161. cBits++;
  162. }
  163. g_cRandIsnStore = 1 << cBits;
  164. if (g_cRandIsnStore < ISN_MIN_RAND_STORE_SIZE ||
  165. g_cRandIsnStore > ISN_MAX_RAND_STORE_SIZE) {
  166. g_cRandIsnStore = ISN_DEF_RAND_STORE_SIZE;
  167. }
  168. // The mask is store size - 1.
  169. g_maskRandIsnStore = g_cRandIsnStore - 1;
  170. //
  171. // Initialize the random ISN store. One array/index per processor.
  172. //
  173. g_pRandIsnStore = CTEAllocMemBoot(cProcs * sizeof(ISN_RAND_STORE));
  174. if (g_pRandIsnStore == NULL) {
  175. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Tcpip: failed to allocate ISN rand store\n"));
  176. return (FALSE);
  177. }
  178. memset(g_pRandIsnStore, 0, sizeof(ISN_RAND_STORE) * cProcs);
  179. for (i = 0; i < cProcs; i++) {
  180. g_pRandIsnStore[i].pBuf = CTEAllocMemBoot(sizeof(ushort) * g_cRandIsnStore);
  181. if (g_pRandIsnStore[i].pBuf == NULL) {
  182. goto error1;
  183. }
  184. rc4(
  185. &g_rc4keyIsn,
  186. sizeof(ushort) * g_cRandIsnStore,
  187. (uchar*)g_pRandIsnStore[i].pBuf);
  188. }
  189. return (TRUE);
  190. error1:
  191. for (i = 0; i < cProcs; i++) {
  192. if (g_pRandIsnStore[i].pBuf != NULL) {
  193. CTEFreeMem(g_pRandIsnStore[i].pBuf);
  194. }
  195. }
  196. CTEFreeMem(g_pRandIsnStore);
  197. return (FALSE);
  198. #endif // !MILLEN
  199. }
  200. VOID
  201. GetRandomISN(
  202. PULONG SeqNum
  203. )
  204. /*++
  205. Routine Description:
  206. Called when an Initial Sequence Number (ISN) is needed. Calls crypto
  207. functions for random number generation.
  208. Arguments:
  209. pTcb - TCB of connection being opened. Returns the sequence number in
  210. pTcb->tcb_sendnext.
  211. Return Value:
  212. None.
  213. Notes:
  214. iBuf is initialized to 0. Therefore first time through, iStore = 1. This
  215. ensures that we use the rand bits generated at init time. Also, it means
  216. that we should not generate new bits until AFTER we have used iStore = 0.
  217. --*/
  218. {
  219. #if MILLEN
  220. ulong randbits;
  221. // Pseudo random bits based on time.
  222. randbits = CTESystemUpTime() + *SeqNum;
  223. g_dwRandom = ROTATE_LEFT(randbits^g_dwRandom, 15);
  224. // We want to add between 32K and 64K of random, so adjust. There are 16
  225. // bits of randomness, just ensure that the high order bit is set and we
  226. // have >= 32K and <= (64K-1)::15bits of randomness.
  227. randbits = (g_dwRandom & 0xffff) | 0x8000;
  228. // Update global CurISN. InterlockedExchangeAdd returns initial value
  229. // (not the added value).
  230. *SeqNum = InterlockedExchangeAdd(&g_CurISN, randbits);
  231. // We don't need to add randbits here. We have randomized the global
  232. // counter which is good enough for next time we choose ISN.
  233. /* pTcb->tcb_sendnext += randbits; */
  234. return;
  235. #else // MILLEN
  236. ushort randbits;
  237. ulong iStore;
  238. ulong iProc;
  239. KIRQL irql;
  240. //
  241. // Raise IRQL to DISPATCH so that we don't get swapped out while accessing
  242. // the processor specific array. Check to see if already at DISPATCH
  243. // before doing the work.
  244. //
  245. ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
  246. iProc = KeGetCurrentProcessorNumber();
  247. // Get index into the random store. Mask performs mod operation.
  248. iStore = ++g_pRandIsnStore[iProc].iBuf & g_maskRandIsnStore;
  249. ASSERT(iStore < g_cRandIsnStore);
  250. randbits = g_pRandIsnStore[iProc].pBuf[iStore];
  251. // We want to add between 32K and 64K of random, so adjust. There are 16
  252. // bits of randomness, just ensure that the high order bit is set and we
  253. // have >= 32K and <= (64K-1)::15bits of randomness.
  254. randbits |= 0x8000;
  255. // Update global CurISN. InterlockedExchangeAdd returns initial value
  256. // (not the added value).
  257. *SeqNum = InterlockedExchangeAdd(&g_CurISN, randbits);
  258. // We don't need to add randbits here. We have randomized the global
  259. // counter which is good enough for next time we choose ISN.
  260. /* pTcb->tcb_sendnext += randbits; */
  261. // Does the random number store need to be regenerated?
  262. if (iStore == 0) {
  263. rc4(
  264. &g_rc4keyIsn,
  265. sizeof(ushort) * g_cRandIsnStore,
  266. (uchar*) g_pRandIsnStore[iProc].pBuf);
  267. }
  268. return;
  269. #endif // !MILLEN
  270. }
  271. extern PDRIVER_OBJECT TCPDriverObject;
  272. DEFINE_LOCK_STRUCTURE(ConnTableLock)
  273. extern CTELock *pTCBTableLock;
  274. extern CTELock *pTWTCBTableLock;
  275. TCPAddrCheckElement *AddrCheckTable = NULL; // The current check table
  276. extern IPInfo LocalNetInfo;
  277. extern void RemoveConnFromAO(AddrObj * AO, TCPConn * Conn);
  278. //
  279. // All of the init code can be discarded.
  280. //
  281. int InitTCPConn(void);
  282. void UnInitTCPConn(void);
  283. void NotifyConnLimitProc(CTEEvent * Event, void *Context);
  284. typedef struct ConnLimitExceededStruct {
  285. CTEEvent cle_event;
  286. IPAddr cle_addr;
  287. ulong cle_port;
  288. } ConnLimitExceededStruct;
  289. #ifdef ALLOC_PRAGMA
  290. #pragma alloc_text(INIT, InitTCPConn)
  291. #pragma alloc_text(INIT, UnInitTCPConn)
  292. #pragma alloc_text(PAGE, NotifyConnLimitProc)
  293. #endif
  294. void CompleteConnReq(TCB * CmpltTCB, IPOptInfo * OptInfo, TDI_STATUS Status);
  295. //** Routines for handling conn refcount going to 0.
  296. //* DummyDone - Called when nothing to do.
  297. //
  298. // Input: Conn - Conn goint to 0.
  299. // Handle - Lock handle for conn table lock.
  300. //
  301. // Returns: Nothing.
  302. //
  303. void
  304. DummyDone(TCPConn * Conn, CTELockHandle Handle)
  305. {
  306. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), Handle);
  307. }
  308. //* DummyCmplt - Dummy close completion routine.
  309. void
  310. DummyCmplt(PVOID Dummy1, uint Dummy2, uint Dummy3)
  311. {
  312. }
  313. //* CloseDone - Called when we need to complete a close.
  314. //
  315. // Input: Conn - Conn going to 0.
  316. // Handle - Lock handle for conn table lock.
  317. //
  318. // Returns: Nothing.
  319. //
  320. void
  321. CloseDone(TCPConn * Conn, CTELockHandle Handle)
  322. {
  323. CTEReqCmpltRtn Rtn; // Completion routine.
  324. PVOID Context; // User context for completion routine.
  325. CTELockHandle AOTableHandle, ConnTableHandle, AOHandle;
  326. AddrObj *AO;
  327. ASSERT(Conn->tc_flags & CONN_CLOSING);
  328. Rtn = Conn->tc_rtn;
  329. Context = Conn->tc_rtncontext;
  330. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), Handle);
  331. CTEGetLock(&AddrObjTableLock.Lock, &AOTableHandle);
  332. CTEGetLock(&(Conn->tc_ConnBlock->cb_lock), &ConnTableHandle);
  333. #if DBG
  334. Conn->tc_ConnBlock->line = (uint) __LINE__;
  335. Conn->tc_ConnBlock->module = (uchar *) __FILE__;
  336. #endif
  337. if ((AO = Conn->tc_ao) != NULL) {
  338. CTEStructAssert(AO, ao);
  339. // It's associated.
  340. CTEGetLock(&AO->ao_lock, &AOHandle);
  341. RemoveConnFromAO(AO, Conn);
  342. // We've pulled him from the AO, we can free the lock now.
  343. CTEFreeLock(&AO->ao_lock, AOHandle);
  344. }
  345. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), ConnTableHandle);
  346. CTEFreeLock(&AddrObjTableLock.Lock, AOTableHandle);
  347. FreeConn(Conn);
  348. (*Rtn) (Context, TDI_SUCCESS, 0);
  349. }
  350. //* DisassocDone - Called when we need to complete a disassociate.
  351. //
  352. // Input: Conn - Conn going to 0.
  353. // Handle - Lock handle for conn table lock.
  354. //
  355. // Returns: Nothing.
  356. //
  357. void
  358. DisassocDone(TCPConn * Conn, CTELockHandle Handle)
  359. {
  360. CTEReqCmpltRtn Rtn; // Completion routine.
  361. PVOID Context; // User context for completion routine.
  362. AddrObj *AO;
  363. CTELockHandle AOTableHandle, ConnTableHandle, AOHandle;
  364. uint NeedClose = FALSE;
  365. ASSERT(Conn->tc_flags & CONN_DISACC);
  366. ASSERT(!(Conn->tc_flags & CONN_CLOSING));
  367. ASSERT(Conn->tc_refcnt == 0);
  368. Rtn = Conn->tc_rtn;
  369. Context = Conn->tc_rtncontext;
  370. Conn->tc_refcnt = 1;
  371. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), Handle);
  372. CTEGetLock(&AddrObjTableLock.Lock, &AOTableHandle);
  373. CTEGetLock(&(Conn->tc_ConnBlock->cb_lock), &ConnTableHandle);
  374. #if DBG
  375. Conn->tc_ConnBlock->line = (uint) __LINE__;
  376. Conn->tc_ConnBlock->module = (uchar *) __FILE__;
  377. #endif
  378. if (!(Conn->tc_flags & CONN_CLOSING)) {
  379. AO = Conn->tc_ao;
  380. if (AO != NULL) {
  381. CTEGetLock(&AO->ao_lock, &AOHandle);
  382. RemoveConnFromAO(AO, Conn);
  383. CTEFreeLock(&AO->ao_lock, AOHandle);
  384. }
  385. ASSERT(Conn->tc_refcnt == 1);
  386. Conn->tc_flags &= ~CONN_DISACC;
  387. } else
  388. NeedClose = TRUE;
  389. Conn->tc_refcnt = 0;
  390. CTEFreeLock(&AddrObjTableLock.Lock, ConnTableHandle);
  391. if (NeedClose) {
  392. CloseDone(Conn, AOTableHandle);
  393. } else {
  394. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), AOTableHandle);
  395. (*Rtn) (Context, TDI_SUCCESS, 0);
  396. }
  397. }
  398. PVOID
  399. NTAPI
  400. TcpConnAllocate (
  401. IN POOL_TYPE PoolType,
  402. IN SIZE_T NumberOfBytes,
  403. IN ULONG Tag
  404. )
  405. {
  406. TCPConn *Conn;
  407. Conn = ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
  408. if (Conn) {
  409. NdisZeroMemory(Conn, sizeof(TCPConn));
  410. Conn->tc_connid = INVALID_CONN_ID;
  411. }
  412. return Conn;
  413. }
  414. VOID
  415. NTAPI
  416. TcpConnFree (
  417. IN PVOID Buffer
  418. )
  419. {
  420. ExFreePool(Buffer);
  421. }
  422. __inline
  423. VOID
  424. FreeConn(TCPConn *Conn)
  425. {
  426. PplFree(TcpConnPool, Conn);
  427. }
  428. TCPConn *
  429. GetConn()
  430. {
  431. TCPConn *Conn;
  432. uint id;
  433. TCPConnBlock *ConnBlock;
  434. LOGICAL FromList;
  435. Conn = PplAllocate(TcpConnPool, &FromList);
  436. if (Conn) {
  437. // If the allocation was satisifed from the lookaside list,
  438. // we need to reinitialize the connection structure.
  439. //
  440. if (FromList)
  441. {
  442. // Save these to avoid an expensive lookup later.
  443. //
  444. id = Conn->tc_connid;
  445. ConnBlock = Conn->tc_ConnBlock;
  446. NdisZeroMemory(Conn, sizeof(TCPConn));
  447. Conn->tc_connid = id;
  448. Conn->tc_ConnBlock = ConnBlock;
  449. }
  450. }
  451. return Conn;
  452. }
  453. //* FreeConnReq - Free a connection request structure.
  454. //
  455. // Called to free a connection request structure.
  456. //
  457. // Input: FreedReq - Connection request structure to be freed.
  458. //
  459. // Returns: Nothing.
  460. //
  461. __inline
  462. VOID
  463. FreeConnReq(TCPConnReq *Request)
  464. {
  465. PplFree(TcpRequestPool, Request);
  466. }
  467. //* GetConnReq - Get a connection request structure.
  468. //
  469. // Called to get a connection request structure.
  470. //
  471. // Input: Nothing.
  472. //
  473. // Returns: Pointer to ConnReq structure, or NULL if none.
  474. //
  475. __inline
  476. TCPConnReq *
  477. GetConnReq(VOID)
  478. {
  479. TCPConnReq *Request;
  480. LOGICAL FromList;
  481. Request = PplAllocate(TcpRequestPool, &FromList);
  482. if (Request) {
  483. #if DBG
  484. Request->tcr_req.tr_sig = tr_signature;
  485. Request->tcr_sig = tcr_signature;
  486. #endif
  487. }
  488. return Request;
  489. }
  490. //* GetConnFromConnID - Get a Connection from a connection ID.
  491. //
  492. // Called to obtain a Connection pointer from a ConnID. We don't actually
  493. // check the connection pointer here, but we do bounds check the input ConnID
  494. // and make sure the instance fields match.
  495. //
  496. // Input: ConnID - Connection ID to find a pointer for.
  497. //
  498. // Returns: Pointer to the TCPConn, or NULL.
  499. // Also, returns with conn block lock held.
  500. //
  501. TCPConn *
  502. GetConnFromConnID(uint ConnID, CTELockHandle * Handle)
  503. {
  504. uint ConnIndex = CONN_INDEX(ConnID);
  505. uint ConnBlockId = CONN_BLOCKID(ConnID);
  506. uchar inst = CONN_INST(ConnID);
  507. TCPConn *MatchingConn = NULL;
  508. TCPConnBlock *ConnBlock;
  509. if ((ConnIndex < MAX_CONN_PER_BLOCK) &&
  510. (ConnBlockId < MaxAllocatedConnBlocks)) {
  511. ConnBlock = (ConnTable)[ConnBlockId];
  512. if (ConnBlock) {
  513. MatchingConn = (ConnBlock->cb_conn)[ConnIndex];
  514. }
  515. if (MatchingConn != NULL) {
  516. CTEGetLock(&(ConnBlock->cb_lock), Handle);
  517. #if DBG
  518. ConnBlock->line = (uint) __LINE__;
  519. ConnBlock->module = (uchar *) __FILE__;
  520. #endif
  521. CTEStructAssert(MatchingConn, tc);
  522. if (inst != MatchingConn->tc_inst) {
  523. MatchingConn = NULL;
  524. CTEFreeLock(&(ConnBlock->cb_lock), *Handle);
  525. }
  526. }
  527. } else
  528. MatchingConn = NULL;
  529. return MatchingConn;
  530. }
  531. //* GetConnID - Get a ConnTable slot.
  532. //
  533. // Called during OpenConnection to find a free slot in the ConnTable and
  534. // set it up with a connection. We assume the caller holds the lock on the
  535. // TCB ConnTable when we are called.
  536. //
  537. // Input: NewConn - Connection to enter into slot..
  538. //
  539. // Returns: A ConnId to use.
  540. //
  541. uint
  542. GetConnID(TCPConn * NewConn, CTELockHandle * Handle)
  543. {
  544. uint CurrConnID = NewConn->tc_connid;
  545. uint i, j, block, k; // Index variable.
  546. uint cbindex;
  547. CTELockHandle TableHandle;
  548. uchar inst;
  549. //see if newconn has a valid conn id and if the slot is still free
  550. //assuming that this came from freelist
  551. if (CurrConnID != INVALID_CONN_ID) {
  552. //just peek first.
  553. //Assuming Connblock as still valid!!
  554. if (!(NewConn->tc_ConnBlock->cb_conn)[CONN_INDEX(CurrConnID)]) {
  555. CTEGetLock(&(NewConn->tc_ConnBlock->cb_lock), Handle);
  556. #if DBG
  557. NewConn->tc_ConnBlock->line = (uint) __LINE__;
  558. NewConn->tc_ConnBlock->module = (uchar *) __FILE__;
  559. #endif
  560. //make sure that this slot is still empty
  561. if (!(NewConn->tc_ConnBlock->cb_conn)[CONN_INDEX(CurrConnID)]) {
  562. (NewConn->tc_ConnBlock->cb_conn)[CONN_INDEX(CurrConnID)] = NewConn;
  563. NewConn->tc_ConnBlock->cb_freecons--;
  564. NewConn->tc_inst = NewConn->tc_ConnBlock->cb_conninst++;
  565. NewConn->tc_connid = MAKE_CONN_ID(CONN_INDEX(CurrConnID), NewConn->tc_ConnBlock->cb_blockid, NewConn->tc_inst);
  566. //return with this block_lock held.
  567. return NewConn->tc_connid;
  568. }
  569. CTEFreeLock(&(NewConn->tc_ConnBlock->cb_lock), *Handle);
  570. }
  571. }
  572. //Nope. try searching for a free slot from the last block that
  573. //we have seen
  574. if (MaxAllocatedConnBlocks) {
  575. uint TempMaxConnBlocks = MaxAllocatedConnBlocks;
  576. uint TempNextConnBlock = NextConnBlock;
  577. for (k = 0; k < TempMaxConnBlocks; k++) {
  578. if (TempNextConnBlock >= TempMaxConnBlocks) {
  579. //wrap around the allocated blocks
  580. TempNextConnBlock = 0;
  581. }
  582. i = TempNextConnBlock;
  583. //Since this is part of allocated, it can not be null
  584. ASSERT(ConnTable[TempNextConnBlock] != NULL);
  585. //Peek if this block has free slots
  586. if ((ConnTable[i])->cb_freecons) {
  587. CTEGetLock(&(ConnTable[i])->cb_lock, Handle);
  588. #if DBG
  589. ConnTable[i]->line = (uint) __LINE__;
  590. ConnTable[i]->module = (uchar *) __FILE__;
  591. #endif
  592. if ((ConnTable[i])->cb_freecons) {
  593. //it still has free slots if nextfree is valid
  594. // no need to loop around
  595. uint index = (ConnTable[i])->cb_nextfree;
  596. for (j = 0; j < MAX_CONN_PER_BLOCK; j++) {
  597. if (index >= MAX_CONN_PER_BLOCK) {
  598. index = 0;
  599. }
  600. if (!((ConnTable[i])->cb_conn)[index]) {
  601. ((ConnTable[i])->cb_conn)[index] = NewConn;
  602. (ConnTable[i])->cb_freecons--;
  603. inst = NewConn->tc_inst = (ConnTable[i])->cb_conninst++;
  604. block = (ConnTable[i])->cb_blockid;
  605. NewConn->tc_ConnBlock = ConnTable[i];
  606. NewConn->tc_connid = MAKE_CONN_ID(index, block, inst);
  607. (ConnTable[i])->cb_nextfree = index++;
  608. NextConnBlock = TempNextConnBlock++;
  609. if (NextConnBlock > MaxAllocatedConnBlocks) {
  610. NextConnBlock = 0;
  611. }
  612. return NewConn->tc_connid;
  613. }
  614. index++;
  615. }
  616. #if DBG
  617. // we should have got a slot if freecons is correct
  618. KdPrint(("Connid: Inconsistent freecon %x\n", ConnTable[i]));
  619. DbgBreakPoint();
  620. #endif
  621. }
  622. CTEFreeLock(&(ConnTable[i])->cb_lock, *Handle);
  623. }
  624. //no more freeslots. try next allocated block
  625. TempNextConnBlock++;
  626. }
  627. } //if MaxAllocatedConnBlocks
  628. //Need to create a conn block at next index.
  629. //we need a lock for mp safe
  630. CTEGetLock(&ConnTableLock, Handle);
  631. if (MaxAllocatedConnBlocks < MaxConnBlocks) {
  632. uint cbindex = MaxAllocatedConnBlocks;
  633. TCPConnBlock *ConnBlock;
  634. ConnBlock = CTEAllocMemN(sizeof(TCPConnBlock), 'CPCT');
  635. if (ConnBlock) {
  636. NdisZeroMemory(ConnBlock, sizeof(TCPConnBlock));
  637. CTEInitLock(&(ConnBlock->cb_lock));
  638. ConnBlock->cb_blockid = cbindex;
  639. //hang on to this lock while inserting
  640. CTEGetLock(&(ConnBlock->cb_lock), &TableHandle);
  641. #if DBG
  642. ConnBlock->line = (uint) __LINE__;
  643. ConnBlock->module = (uchar *) __FILE__;
  644. #endif
  645. //get the first slot for ourselves
  646. ConnBlock->cb_freecons = MAX_CONN_PER_BLOCK - 1;
  647. ConnBlock->cb_nextfree = 1;
  648. inst = ConnBlock->cb_conninst = 1;
  649. NewConn->tc_ConnBlock = ConnBlock;
  650. (ConnBlock->cb_conn)[0] = NewConn;
  651. NewConn->tc_connid = MAKE_CONN_ID(0, cbindex, inst);
  652. NewConn->tc_inst = inst;
  653. ConnBlock->cb_conninst++;
  654. //assignment is atomic!!
  655. ConnTable[cbindex] = ConnBlock;
  656. MaxAllocatedConnBlocks++;
  657. CTEFreeLock(&ConnTableLock, TableHandle);
  658. return NewConn->tc_connid;
  659. }
  660. }
  661. CTEFreeLock(&ConnTableLock, *Handle);
  662. return INVALID_CONN_ID;
  663. }
  664. //* FreeConnID - Free a ConnTable slot.
  665. //
  666. // Called when we're done with a ConnID. We assume the caller holds the lock
  667. // on the TCB ConnTable when we are called.
  668. //
  669. // Input: ConnID - Connection ID to be freed.
  670. //
  671. // Returns: Nothing.
  672. //
  673. void
  674. FreeConnID(TCPConn * Conn)
  675. {
  676. uint Index = CONN_INDEX(Conn->tc_connid); // Index into conn table.
  677. uint cbIndex = CONN_BLOCKID(Conn->tc_connid);
  678. TCPConnBlock *ConnBlock = Conn->tc_ConnBlock;
  679. ASSERT(Index < MAX_CONN_PER_BLOCK);
  680. ASSERT(cbIndex < MaxAllocatedConnBlocks);
  681. ASSERT((ConnBlock->cb_conn)[Index] != NULL);
  682. if ((ConnBlock->cb_conn)[Index]) {
  683. (ConnBlock->cb_conn)[Index] = NULL;
  684. ConnBlock->cb_freecons++;
  685. ConnBlock->cb_nextfree = Index;
  686. ASSERT(ConnBlock->cb_freecons <= MAX_CONN_PER_BLOCK);
  687. } else {
  688. ASSERT(0);
  689. }
  690. }
  691. //* MapIPError - Map an IP error to a TDI error.
  692. //
  693. // Called to map an input IP error code to a TDI error code. If we can't,
  694. // we return the provided default.
  695. //
  696. // Input: IPError - Error code to be mapped.
  697. // Default - Default error code to return.
  698. //
  699. // Returns: Mapped TDI error.
  700. //
  701. TDI_STATUS
  702. MapIPError(IP_STATUS IPError, TDI_STATUS Default)
  703. {
  704. switch (IPError) {
  705. case IP_DEST_NET_UNREACHABLE:
  706. return TDI_DEST_NET_UNREACH;
  707. case IP_DEST_HOST_UNREACHABLE:
  708. case IP_NEGOTIATING_IPSEC:
  709. return TDI_DEST_HOST_UNREACH;
  710. case IP_DEST_PROT_UNREACHABLE:
  711. return TDI_DEST_PROT_UNREACH;
  712. case IP_DEST_PORT_UNREACHABLE:
  713. return TDI_DEST_PORT_UNREACH;
  714. default:
  715. return Default;
  716. }
  717. }
  718. //* FinishRemoveTCBFromConn - Finish removing a TCB from a conn structure.
  719. //
  720. // Called when we have the locks we need and we just want to pull the
  721. // TCB off the connection. The caller must hold the ConnTableLock before
  722. // calling this.
  723. //
  724. // Input: RemovedTCB - TCB to be removed.
  725. //
  726. // Returns: Nothing.
  727. //
  728. void
  729. FinishRemoveTCBFromConn(TCB * RemovedTCB)
  730. {
  731. TCPConn *Conn;
  732. CTELockHandle AOHandle, TCBHandle, ConnHandle;
  733. AddrObj *AO;
  734. TCPConnBlock *ConnBlock = NULL;
  735. if (((Conn = RemovedTCB->tcb_conn) != NULL) &&
  736. (Conn->tc_tcb == RemovedTCB)) {
  737. CTEStructAssert(Conn, tc);
  738. ConnBlock = Conn->tc_ConnBlock;
  739. CTEGetLock(&(ConnBlock->cb_lock), &ConnHandle);
  740. #if DBG
  741. ConnBlock->line = (uint) __LINE__;
  742. ConnBlock->module = (uchar *) __FILE__;
  743. #endif
  744. AO = Conn->tc_ao;
  745. if (AO != NULL) {
  746. CTEGetLockAtDPC(&AO->ao_lock, &AOHandle);
  747. if (AO_VALID(AO)) {
  748. CTEGetLockAtDPC(&RemovedTCB->tcb_lock, &TCBHandle);
  749. // Need to double check this is still correct.
  750. if (Conn == RemovedTCB->tcb_conn) {
  751. // Everything still looks good.
  752. REMOVEQ(&Conn->tc_q);
  753. //ENQUEUE(&AO->ao_idleq, &Conn->tc_q);
  754. PUSHQ(&AO->ao_idleq, &Conn->tc_q);
  755. } else
  756. Conn = RemovedTCB->tcb_conn;
  757. } else {
  758. CTEGetLockAtDPC(&RemovedTCB->tcb_lock, &TCBHandle);
  759. Conn = RemovedTCB->tcb_conn;
  760. }
  761. CTEFreeLockFromDPC(&AO->ao_lock, TCBHandle);
  762. } else {
  763. CTEGetLockAtDPC(&RemovedTCB->tcb_lock, &AOHandle);
  764. Conn = RemovedTCB->tcb_conn;
  765. }
  766. if (Conn != NULL) {
  767. if (Conn->tc_tcb == RemovedTCB) {
  768. #if TRACE_EVENT
  769. PTDI_DATA_REQUEST_NOTIFY_ROUTINE CPCallBack;
  770. WMIData WMIInfo;
  771. CPCallBack = TCPCPHandlerRoutine;
  772. if (CPCallBack != NULL) {
  773. ulong GroupType;
  774. WMIInfo.wmi_srcaddr = RemovedTCB->tcb_saddr;
  775. WMIInfo.wmi_srcport = RemovedTCB->tcb_sport;
  776. WMIInfo.wmi_destaddr = RemovedTCB->tcb_daddr;
  777. WMIInfo.wmi_destport = RemovedTCB->tcb_dport;
  778. WMIInfo.wmi_context = RemovedTCB->tcb_cpcontext;
  779. WMIInfo.wmi_size = 0;
  780. GroupType = EVENT_TRACE_GROUP_TCPIP + EVENT_TRACE_TYPE_DISCONNECT;
  781. (*CPCallBack) (GroupType, (PVOID) &WMIInfo, sizeof(WMIInfo), NULL);
  782. }
  783. #endif
  784. Conn->tc_tcb = NULL;
  785. //RemovedTCB->tc_connid=0;
  786. Conn->tc_LastTCB = RemovedTCB;
  787. } else {
  788. ASSERT(Conn->tc_tcb == NULL);
  789. }
  790. }
  791. CTEFreeLockFromDPC(&RemovedTCB->tcb_lock, AOHandle);
  792. ASSERT(ConnBlock != NULL);
  793. CTEFreeLock(&(ConnBlock->cb_lock), ConnHandle);
  794. }
  795. }
  796. //* RemoveTCBFromConn - Remove a TCB from a Conn structure.
  797. //
  798. // Called when we need to disassociate a TCB from a connection structure.
  799. // All we do is get the appropriate locks and call FinishRemoveTCBFromConn.
  800. //
  801. // Input: RemovedTCB - TCB to be removed.
  802. //
  803. // Returns: Nothing.
  804. //
  805. void
  806. RemoveTCBFromConn(TCB * RemovedTCB)
  807. {
  808. CTELockHandle ConnHandle, TCBHandle;
  809. CTEStructAssert(RemovedTCB, tcb);
  810. FinishRemoveTCBFromConn(RemovedTCB);
  811. }
  812. //* RemoveConnFromTCB - Remove a conn from a TCB.
  813. //
  814. // Called when we want to break the final association between a connection
  815. // and a TCB.
  816. //
  817. // Input: RemoveTCB - TCB to be removed.
  818. //
  819. // Returns: Nothing.
  820. //
  821. void
  822. RemoveConnFromTCB(TCB * RemoveTCB)
  823. {
  824. ConnDoneRtn DoneRtn = NULL;
  825. CTELockHandle ConnHandle, TCBHandle;
  826. TCPConn *Conn;
  827. if ((Conn = RemoveTCB->tcb_conn) != NULL) {
  828. CTEGetLock(&(Conn->tc_ConnBlock->cb_lock), &ConnHandle);
  829. #if DBG
  830. Conn->tc_ConnBlock->line = (uint) __LINE__;
  831. Conn->tc_ConnBlock->module = (uchar *) __FILE__;
  832. #endif
  833. CTEGetLock(&RemoveTCB->tcb_lock, &TCBHandle);
  834. CTEStructAssert(Conn, tc);
  835. if (--(Conn->tc_refcnt) == 0)
  836. DoneRtn = Conn->tc_donertn;
  837. RemoveTCB->tcb_conn = NULL;
  838. CTEFreeLock(&RemoveTCB->tcb_lock, TCBHandle);
  839. }
  840. if (DoneRtn != NULL) {
  841. (*DoneRtn) (Conn, ConnHandle);
  842. } else {
  843. if (Conn) {
  844. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), ConnHandle);
  845. }
  846. //CTEFreeLock(&ConnTableLock, ConnHandle);
  847. }
  848. }
  849. //* CloseTCB - Close a TCB.
  850. //
  851. // Called when we are done with a TCB, and want to free it. We'll remove
  852. // him from any tables that he's in, and destroy any outstanding requests.
  853. //
  854. // Input: ClosedTCB - TCB to be closed.
  855. // Handle - Lock handle for TCB.
  856. //
  857. // Returns: Nothing.
  858. //
  859. void
  860. CloseTCB(TCB * ClosedTCB, CTELockHandle Handle)
  861. {
  862. CTELockHandle ConnTableHandle, TCBTableHandle, PendHandle;
  863. uchar OrigState = ClosedTCB->tcb_state;
  864. TDI_STATUS Status;
  865. uint OKToFree;
  866. uint Partition = ClosedTCB->tcb_partition;
  867. RouteCacheEntry* RCE = ClosedTCB->tcb_rce;
  868. CTEStructAssert(ClosedTCB, tcb);
  869. ASSERT(ClosedTCB->tcb_refcnt == 0);
  870. ASSERT(ClosedTCB->tcb_state != TCB_CLOSED);
  871. ASSERT(ClosedTCB->tcb_pending & DEL_PENDING);
  872. // We'll check to make sure that our state isn't CLOSED. This should never
  873. // happen, since nobody should call TryToCloseTCB when the state is
  874. // closed, or take the reference count if we're closing. Nevertheless,
  875. // we'll double check as a safety measure.
  876. if (ClosedTCB->tcb_state == TCB_CLOSED) {
  877. CTEFreeLock(&ClosedTCB->tcb_lock, Handle);
  878. return;
  879. } else {
  880. // Update SNMP counters. If we're in SYN-SENT or SYN-RCVD, this is a failed
  881. // connection attempt. If we're in ESTABLISED or CLOSE-WAIT, treat this
  882. // as an 'Established Reset' event.
  883. if (ClosedTCB->tcb_state == TCB_SYN_SENT ||
  884. ClosedTCB->tcb_state == TCB_SYN_RCVD)
  885. TStats.ts_attemptfails++;
  886. else if (ClosedTCB->tcb_state == TCB_ESTAB ||
  887. ClosedTCB->tcb_state == TCB_CLOSE_WAIT) {
  888. TStats.ts_estabresets++;
  889. TStats.ts_currestab--;
  890. }
  891. ClosedTCB->tcb_state = TCB_CLOSED;
  892. ClosedTCB->tcb_rce = NULL;
  893. CTEFreeLock(&ClosedTCB->tcb_lock, Handle);
  894. }
  895. // Remove the TCB from it's associated TCPConn structure, if it has one.
  896. //this takes the appropriate conntable lock.
  897. FinishRemoveTCBFromConn(ClosedTCB);
  898. if (SYNC_RCVD_STATE(OrigState) && !GRACEFUL_CLOSED_STATE(OrigState)) {
  899. if (ClosedTCB->tcb_flags & NEED_RST)
  900. SendRSTFromTCB(ClosedTCB, RCE);
  901. }
  902. (*LocalNetInfo.ipi_freeopts) (&ClosedTCB->tcb_opt);
  903. if (RCE) {
  904. (*LocalNetInfo.ipi_closerce)(RCE);
  905. }
  906. CTEGetLock(&ClosedTCB->tcb_lock, &Handle);
  907. if (ClosedTCB->tcb_closereason & TCB_CLOSE_RST)
  908. Status = TDI_CONNECTION_RESET;
  909. else if (ClosedTCB->tcb_closereason & TCB_CLOSE_ABORTED)
  910. Status = TDI_CONNECTION_ABORTED;
  911. else if (ClosedTCB->tcb_closereason & TCB_CLOSE_TIMEOUT)
  912. Status = MapIPError(ClosedTCB->tcb_error, TDI_TIMED_OUT);
  913. else if (ClosedTCB->tcb_closereason & TCB_CLOSE_REFUSED)
  914. Status = TDI_CONN_REFUSED;
  915. else if (ClosedTCB->tcb_closereason & TCB_CLOSE_UNREACH)
  916. Status = MapIPError(ClosedTCB->tcb_error, TDI_DEST_UNREACHABLE);
  917. else
  918. Status = TDI_SUCCESS;
  919. // Ref this TCB so that it will not go away until
  920. // we cleanup pending requests.
  921. ClosedTCB->tcb_refcnt++;
  922. // Now complete any outstanding requests on the TCB.
  923. if (ClosedTCB->tcb_connreq != NULL) {
  924. TCPConnReq *ConnReq = ClosedTCB->tcb_connreq;
  925. CTEStructAssert(ConnReq, tcr);
  926. CTEFreeLock(&ClosedTCB->tcb_lock, Handle);
  927. (*ConnReq->tcr_req.tr_rtn) (ConnReq->tcr_req.tr_context, Status, 0);
  928. FreeConnReq(ConnReq);
  929. CTEGetLock(&ClosedTCB->tcb_lock, &Handle);
  930. }
  931. if (ClosedTCB->tcb_discwait != NULL) {
  932. TCPConnReq *ConnReq = ClosedTCB->tcb_discwait;
  933. CTEStructAssert(ConnReq, tcr);
  934. CTEFreeLock(&ClosedTCB->tcb_lock, Handle);
  935. (*ConnReq->tcr_req.tr_rtn) (ConnReq->tcr_req.tr_context, Status, 0);
  936. FreeConnReq(ConnReq);
  937. CTEGetLock(&ClosedTCB->tcb_lock, &Handle);
  938. }
  939. while (!EMPTYQ(&ClosedTCB->tcb_sendq)) {
  940. TCPReq *Req;
  941. TCPSendReq *SendReq;
  942. long Result;
  943. uint SendReqFlags;
  944. DEQUEUE(&ClosedTCB->tcb_sendq, Req, TCPReq, tr_q);
  945. CTEStructAssert(Req, tr);
  946. SendReq = (TCPSendReq *) Req;
  947. CTEStructAssert(SendReq, tsr);
  948. // Decrement the initial reference put on the buffer when it was
  949. // allocated. This reference would have been decremented if the
  950. // send had been acknowledged, but then the send would not still
  951. // be on the tcb_sendq.
  952. SendReqFlags = SendReq->tsr_flags;
  953. if (SendReqFlags & TSR_FLAG_SEND_AND_DISC) {
  954. BOOLEAN BytesSentOkay=FALSE;
  955. ASSERT(ClosedTCB->tcb_fastchk & TCP_FLAG_SEND_AND_DISC);
  956. if ((ClosedTCB->tcb_unacked == 0) &&
  957. (ClosedTCB->tcb_sendnext == ClosedTCB->tcb_sendmax) &&
  958. (ClosedTCB->tcb_sendnext == (ClosedTCB->tcb_senduna + 1) ||
  959. (ClosedTCB->tcb_sendnext == ClosedTCB->tcb_senduna)) ) {
  960. BytesSentOkay=TRUE;
  961. }
  962. if (BytesSentOkay && !(ClosedTCB->tcb_closereason == TCB_CLOSE_TIMEOUT)){
  963. Status = TDI_SUCCESS;
  964. }
  965. }
  966. SendReq->tsr_req.tr_status = Status;
  967. Result = CTEInterlockedDecrementLong(&SendReq->tsr_refcnt);
  968. ASSERT(Result >= 0);
  969. if (Result <= 0) {
  970. // If we've sent directly from this send, NULL out the next
  971. // pointer for the last buffer in the chain.
  972. if (SendReq->tsr_lastbuf != NULL) {
  973. NDIS_BUFFER_LINKAGE(SendReq->tsr_lastbuf) = NULL;
  974. SendReq->tsr_lastbuf = NULL;
  975. }
  976. CTEFreeLock(&ClosedTCB->tcb_lock, Handle);
  977. (*Req->tr_rtn) (Req->tr_context, Status, Status == TDI_SUCCESS ? SendReq->tsr_size : 0);
  978. CTEGetLock(&ClosedTCB->tcb_lock, &Handle);
  979. FreeSendReq(SendReq);
  980. } else {
  981. // The send request will be freed when all outstanding references
  982. // to it have completed.
  983. //SendReq->tsr_req.tr_status = Status;
  984. if ((SendReqFlags & TSR_FLAG_SEND_AND_DISC) && (Result <= 1)) {
  985. // If we've sent directly from this send, NULL out the next
  986. // pointer for the last buffer in the chain.
  987. if (SendReq->tsr_lastbuf != NULL) {
  988. NDIS_BUFFER_LINKAGE(SendReq->tsr_lastbuf) = NULL;
  989. SendReq->tsr_lastbuf = NULL;
  990. }
  991. CTEFreeLock(&ClosedTCB->tcb_lock, Handle);
  992. (*Req->tr_rtn) (Req->tr_context, Status, Status == TDI_SUCCESS ? SendReq->tsr_size : 0);
  993. CTEGetLock(&ClosedTCB->tcb_lock, &Handle);
  994. FreeSendReq(SendReq);
  995. }
  996. }
  997. }
  998. while (ClosedTCB->tcb_rcvhead != NULL) {
  999. TCPRcvReq *RcvReq;
  1000. RcvReq = ClosedTCB->tcb_rcvhead;
  1001. CTEStructAssert(RcvReq, trr);
  1002. ClosedTCB->tcb_rcvhead = RcvReq->trr_next;
  1003. CTEFreeLock(&ClosedTCB->tcb_lock, Handle);
  1004. (*RcvReq->trr_rtn) (RcvReq->trr_context, Status, 0);
  1005. CTEGetLock(&ClosedTCB->tcb_lock, &Handle);
  1006. FreeRcvReq(RcvReq);
  1007. }
  1008. while (ClosedTCB->tcb_exprcv != NULL) {
  1009. TCPRcvReq *RcvReq;
  1010. RcvReq = ClosedTCB->tcb_exprcv;
  1011. CTEStructAssert(RcvReq, trr);
  1012. ClosedTCB->tcb_exprcv = RcvReq->trr_next;
  1013. CTEFreeLock(&ClosedTCB->tcb_lock, Handle);
  1014. (*RcvReq->trr_rtn) (RcvReq->trr_context, Status, 0);
  1015. CTEGetLock(&ClosedTCB->tcb_lock, &Handle);
  1016. FreeRcvReq(RcvReq);
  1017. }
  1018. if (ClosedTCB->tcb_pendhead != NULL)
  1019. FreeRBChain(ClosedTCB->tcb_pendhead);
  1020. if (ClosedTCB->tcb_urgpending != NULL)
  1021. FreeRBChain(ClosedTCB->tcb_urgpending);
  1022. while (ClosedTCB->tcb_raq != NULL) {
  1023. TCPRAHdr *Hdr;
  1024. Hdr = ClosedTCB->tcb_raq;
  1025. CTEStructAssert(Hdr, trh);
  1026. ClosedTCB->tcb_raq = Hdr->trh_next;
  1027. if (Hdr->trh_buffer != NULL)
  1028. FreeRBChain(Hdr->trh_buffer);
  1029. CTEFreeMem(Hdr);
  1030. }
  1031. CTEFreeLock(&ClosedTCB->tcb_lock, Handle);
  1032. RemoveConnFromTCB(ClosedTCB);
  1033. CTEGetLock(&pTCBTableLock[Partition], &TCBTableHandle);
  1034. CTEGetLockAtDPC(&ClosedTCB->tcb_lock, &Handle);
  1035. ClosedTCB->tcb_refcnt--;
  1036. OKToFree = RemoveTCB(ClosedTCB);
  1037. // He's been pulled from the appropriate places so nobody can find him.
  1038. // Free the locks, and proceed to destroy any requests, etc.
  1039. CTEFreeLockFromDPC(&ClosedTCB->tcb_lock, DISPATCH_LEVEL);
  1040. CTEFreeLock(&pTCBTableLock[Partition], TCBTableHandle);
  1041. if (OKToFree) {
  1042. FreeTCB(ClosedTCB);
  1043. }
  1044. }
  1045. //* TryToCloseTCB - Try to close a TCB.
  1046. //
  1047. // Called when we need to close a TCB, but don't know if we can. If
  1048. // the reference count is 0, we'll call CloseTCB to deal with it.
  1049. // Otherwise we'll set the DELETE_PENDING bit and deal with it when
  1050. // the ref. count goes to 0. We assume the TCB is locked when we are called.
  1051. //
  1052. // Input: ClosedTCB - TCB to be closed.
  1053. // Reason - Reason we're closing.
  1054. // Handle - Lock handle for TCB.
  1055. //
  1056. // Returns: Nothing.
  1057. //
  1058. void
  1059. TryToCloseTCB(TCB * ClosedTCB, uchar Reason, CTELockHandle Handle)
  1060. {
  1061. CTEStructAssert(ClosedTCB, tcb);
  1062. ASSERT(ClosedTCB->tcb_state != TCB_CLOSED);
  1063. ClosedTCB->tcb_closereason |= Reason;
  1064. if (ClosedTCB->tcb_pending & DEL_PENDING) {
  1065. CTEFreeLock(&ClosedTCB->tcb_lock, Handle);
  1066. return;
  1067. }
  1068. ClosedTCB->tcb_pending |= DEL_PENDING;
  1069. ClosedTCB->tcb_slowcount++;
  1070. ClosedTCB->tcb_fastchk |= TCP_FLAG_SLOW;
  1071. if (ClosedTCB->tcb_refcnt == 0)
  1072. CloseTCB(ClosedTCB, Handle);
  1073. else {
  1074. CTEFreeLock(&ClosedTCB->tcb_lock, Handle);
  1075. }
  1076. }
  1077. //* DerefTCB - Dereference a TCB.
  1078. //
  1079. // Called when we're done with a TCB, and want to let exclusive user
  1080. // have a shot. We dec. the refcount, and if it goes to zero and there
  1081. // are pending actions, we'll perform one of the pending actions.
  1082. //
  1083. // Input: DoneTCB - TCB to be dereffed.
  1084. // Handle - Lock handle to be used when freeing TCB lock.
  1085. //
  1086. // Returns: Nothing.
  1087. //
  1088. void
  1089. DerefTCB(TCB * DoneTCB, CTELockHandle Handle)
  1090. {
  1091. ASSERT(DoneTCB->tcb_refcnt != 0);
  1092. if (DEREFERENCE_TCB(DoneTCB) == 0) {
  1093. if (DoneTCB->tcb_pending == 0) {
  1094. CTEFreeLock(&DoneTCB->tcb_lock, Handle);
  1095. return;
  1096. } else {
  1097. if (DoneTCB->tcb_pending & DEL_PENDING)
  1098. CloseTCB(DoneTCB, Handle);
  1099. else if (DoneTCB->tcb_pending & FREE_PENDING) {
  1100. RouteCacheEntry* RCE = DoneTCB->tcb_rce;
  1101. DoneTCB->tcb_rce = NULL;
  1102. (*LocalNetInfo.ipi_freeopts) (&DoneTCB->tcb_opt);
  1103. // Need to take this TCB out of the timerwheel if it is in there.
  1104. if( DoneTCB->tcb_timerslot != DUMMY_SLOT) {
  1105. ASSERT( DoneTCB->tcb_timerslot < TIMER_WHEEL_SIZE );
  1106. RemoveFromTimerWheel( DoneTCB );
  1107. }
  1108. CTEFreeLock(&DoneTCB->tcb_lock, Handle);
  1109. // Close the RCE on this guy.
  1110. if (RCE) {
  1111. (*LocalNetInfo.ipi_closerce) (RCE);
  1112. }
  1113. CTEGetLock(&PendingFreeLock.Lock, &Handle);
  1114. if (TCBWalkCount != 0) {
  1115. #ifdef PENDING_FREE_DBG
  1116. if( DoneTCB->tcb_flags & IN_TCB_TABLE)
  1117. DbgBreakPoint();
  1118. #endif
  1119. //tcbtimeout is walking the table
  1120. //Let it free this tcb too.
  1121. DoneTCB->tcb_walkcount = TCBWalkCount + 1;
  1122. *(TCB **) & DoneTCB->tcb_delayq.q_next = PendingFreeList;
  1123. PendingFreeList = DoneTCB;
  1124. CTEFreeLock(&PendingFreeLock.Lock, Handle);
  1125. return;
  1126. } else {
  1127. CTEFreeLock(&PendingFreeLock.Lock, Handle);
  1128. }
  1129. //it is okay to free this.
  1130. FreeTCB(DoneTCB);
  1131. } else
  1132. ASSERT(0);
  1133. return;
  1134. }
  1135. }
  1136. CTEFreeLock(&DoneTCB->tcb_lock, Handle);
  1137. }
  1138. //** TdiOpenConnection - Open a connection.
  1139. //
  1140. // This is the TDI Open Connection entry point. We open a connection,
  1141. // and save the caller's connection context. A TCPConn structure is allocated
  1142. // here, but a TCB isn't allocated until the Connect or Listen is done.
  1143. //
  1144. // Input: Request - Pointed to a TDI request structure.
  1145. // Context - Connection context to be saved for connection.
  1146. //
  1147. // Returns: Status of attempt to open the connection.
  1148. //
  1149. TDI_STATUS
  1150. TdiOpenConnection(PTDI_REQUEST Request, PVOID Context)
  1151. {
  1152. TCPConn *NewConn; // The newly opened connection.
  1153. CTELockHandle Handle; // Lock handle for TCPConnTable.
  1154. uint ConnID; // New ConnID.
  1155. TDI_STATUS Status; // Status of this request.
  1156. NewConn = GetConn();
  1157. if (NewConn != NULL) { // We allocated a connection.
  1158. #if DBG
  1159. NewConn->tc_sig = tc_signature;
  1160. #endif
  1161. NewConn->tc_tcb = NULL;
  1162. NewConn->tc_ao = NULL;
  1163. NewConn->tc_context = Context;
  1164. ConnID = GetConnID(NewConn, &Handle);
  1165. if (ConnID != INVALID_CONN_ID) {
  1166. // We successfully got a ConnID.
  1167. Request->Handle.ConnectionContext = UintToPtr(ConnID);
  1168. NewConn->tc_refcnt = 0;
  1169. NewConn->tc_flags = 0;
  1170. NewConn->tc_tcbflags = NAGLING | (BSDUrgent ? BSD_URGENT : 0);
  1171. if (DefaultRcvWin != 0) {
  1172. if (!(TcpHostOpts & TCP_FLAG_WS) && DefaultRcvWin > 0xFFFF) {
  1173. NewConn->tc_window = 0xFFFF;
  1174. } else {
  1175. NewConn->tc_window = DefaultRcvWin;
  1176. }
  1177. NewConn->tc_flags |= CONN_WINSET;
  1178. } else {
  1179. NewConn->tc_window = DEFAULT_RCV_WIN;
  1180. }
  1181. NewConn->tc_donertn = DummyDone;
  1182. #if !MILLEN
  1183. NewConn->tc_owningpid = HandleToUlong(PsGetCurrentProcessId());
  1184. #endif
  1185. Request->RequestContext = NewConn;
  1186. Status = TDI_SUCCESS;
  1187. CTEFreeLock(&(NewConn->tc_ConnBlock->cb_lock), Handle);
  1188. } else {
  1189. FreeConn(NewConn);
  1190. Status = TDI_NO_RESOURCES;
  1191. }
  1192. return Status;
  1193. }
  1194. // Couldn't get a connection.
  1195. return TDI_NO_RESOURCES;
  1196. }
  1197. //* RemoveConnFromAO - Remove a connection from an AddrObj.
  1198. //
  1199. // A little utility routine to remove a connection from an AddrObj.
  1200. // We run down the connections on the AO, and when we find him we splice
  1201. // him out. We assume the caller holds the locks on the AddrObj and the
  1202. // TCPConnTable lock.
  1203. //
  1204. // Input: AO - AddrObj to remove from.
  1205. // Conn - Conn to remove.
  1206. //
  1207. // Returns: Nothing.
  1208. //
  1209. void
  1210. RemoveConnFromAO(AddrObj * AO, TCPConn * Conn)
  1211. {
  1212. CTEStructAssert(AO, ao);
  1213. CTEStructAssert(Conn, tc);
  1214. REMOVEQ(&Conn->tc_q);
  1215. Conn->tc_ao = NULL;
  1216. }
  1217. //* TdiCloseConnection - Close a connection.
  1218. //
  1219. // Called when the user is done with a connection, and wants to close it.
  1220. // We look the connection up in our table, and if we find it we'll remove
  1221. // the connection from the AddrObj it's associate with (if any). If there's
  1222. // a TCB associated with the connection we'll close it also.
  1223. //
  1224. // There are some interesting wrinkles related to closing while a TCB
  1225. // is still referencing the connection (i.e. tc_refcnt != 0) or while a
  1226. // disassociate address is in progress. See below for more details.
  1227. //
  1228. // Input: Request - Request identifying connection to be closed.
  1229. //
  1230. // Returns: Status of attempt to close.
  1231. //
  1232. TDI_STATUS
  1233. TdiCloseConnection(PTDI_REQUEST Request)
  1234. {
  1235. uint ConnID = PtrToUlong(Request->Handle.ConnectionContext);
  1236. CTELockHandle TableHandle;
  1237. TCPConn *Conn;
  1238. TDI_STATUS Status;
  1239. //CTEGetLock(&ConnTableLock, &TableHandle);
  1240. // We have the locks we need. Try to find a connection.
  1241. Conn = GetConnFromConnID(ConnID, &TableHandle);
  1242. if (Conn != NULL) {
  1243. CTELockHandle TCBHandle;
  1244. TCB *ConnTCB;
  1245. // We found the connection. Free the ConnID and mark the connection
  1246. // as closing.
  1247. CTEStructAssert(Conn, tc);
  1248. FreeConnID(Conn);
  1249. Conn->tc_flags |= CONN_CLOSING;
  1250. // See if there's a TCB referencing this connection.
  1251. // If there is, we'll need to wait until he's done before closing him.
  1252. // We'll hurry the process along if we still have a pointer to him.
  1253. if (Conn->tc_refcnt != 0) {
  1254. CTEReqCmpltRtn Rtn;
  1255. PVOID Context;
  1256. // A connection still references him. Save the current rtn stuff
  1257. // in case we are in the middle of disassociating him from an
  1258. // address, and store the caller's callback routine and our done
  1259. // routine.
  1260. Rtn = Conn->tc_rtn;
  1261. Context = Conn->tc_rtncontext;
  1262. Conn->tc_rtn = Request->RequestNotifyObject;
  1263. Conn->tc_rtncontext = Request->RequestContext;
  1264. Conn->tc_donertn = CloseDone;
  1265. // See if we're in the middle of disassociating him
  1266. if (Conn->tc_flags & CONN_DISACC) {
  1267. // We are disassociating him. We'll free the conn table lock
  1268. // now and fail the disassociate request. Note that when
  1269. // we free the lock the refcount could go to zero. This is
  1270. // OK, because we've already stored the neccessary info. in
  1271. // the connection so the caller will get called back if it
  1272. // does. From this point out we return PENDING, so a callback
  1273. // is OK. We've marked him as closing, so the disassoc done
  1274. // routine will bail out if we've interrupted him. If the ref.
  1275. // count does go to zero, Conn->tc_tcb would have to be NULL,
  1276. // so in that case we'll just fall out of this routine.
  1277. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), TableHandle);
  1278. (*Rtn) (Context, (uint) TDI_REQ_ABORTED, 0);
  1279. CTEGetLock(&(Conn->tc_ConnBlock->cb_lock), &TableHandle);
  1280. #if DBG
  1281. Conn->tc_ConnBlock->line = (uint) __LINE__;
  1282. Conn->tc_ConnBlock->module = (uchar *) __FILE__;
  1283. #endif
  1284. }
  1285. ConnTCB = Conn->tc_tcb;
  1286. if (ConnTCB != NULL) {
  1287. CTEStructAssert(ConnTCB, tcb);
  1288. // We have a TCB. Take the lock on him and get ready to
  1289. // close him.
  1290. CTEGetLock(&ConnTCB->tcb_lock, &TCBHandle);
  1291. if (ConnTCB->tcb_state != TCB_CLOSED) {
  1292. ConnTCB->tcb_flags |= NEED_RST;
  1293. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), TCBHandle);
  1294. //CTEFreeLock(&ConnTableLock, TCBHandle);
  1295. if (!CLOSING(ConnTCB))
  1296. TryToCloseTCB(ConnTCB, TCB_CLOSE_ABORTED, TableHandle);
  1297. else
  1298. CTEFreeLock(&ConnTCB->tcb_lock, TableHandle);
  1299. return TDI_PENDING;
  1300. } else {
  1301. // He's already closing. This should be harmless, but check
  1302. // this case.
  1303. CTEFreeLock(&ConnTCB->tcb_lock, TCBHandle);
  1304. }
  1305. }
  1306. Status = TDI_PENDING;
  1307. } else {
  1308. // We have a connection that we can close. Finish the close.
  1309. Conn->tc_rtn = DummyCmplt;
  1310. CloseDone(Conn, TableHandle);
  1311. return TDI_SUCCESS;
  1312. }
  1313. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), TableHandle);
  1314. } else
  1315. Status = TDI_INVALID_CONNECTION;
  1316. // We're done with the connection. Go ahead and free him.
  1317. //
  1318. return Status;
  1319. }
  1320. //* TdiAssociateAddress - Associate an address with a connection.
  1321. //
  1322. // Called to associate an address with a connection. We do a minimal
  1323. // amount of sanity checking, and then put the connection on the AddrObj's
  1324. // list.
  1325. //
  1326. // Input: Request - Pointer to request structure for this request.
  1327. // AddrHandle - Address handle to associate connection with.
  1328. //
  1329. // Returns: Status of attempt to associate.
  1330. //
  1331. TDI_STATUS
  1332. TdiAssociateAddress(PTDI_REQUEST Request, HANDLE AddrHandle)
  1333. {
  1334. CTELockHandle TableHandle, AOHandle;
  1335. AddrObj *AO;
  1336. uint ConnID = PtrToUlong(Request->Handle.ConnectionContext);
  1337. TCPConn *Conn;
  1338. TDI_STATUS Status;
  1339. DEBUGMSG(DBG_TRACE && DBG_TDI,
  1340. (DTEXT("+TdiAssociateAddress(%x, %x) Conn %x\n"),
  1341. Request, AddrHandle, Request->Handle.ConnectionContext));
  1342. AO = (AddrObj *) AddrHandle;
  1343. CTEStructAssert(AO, ao);
  1344. if (!AO_VALID(AO)) {
  1345. DEBUGMSG(DBG_ERROR && DBG_TDI, (DTEXT("TdiAssociateAddress: Invalid AO %x\n"), AO));
  1346. return TDI_INVALID_PARAMETER;
  1347. }
  1348. Conn = GetConnFromConnID(ConnID, &TableHandle);
  1349. CTEGetLock(&AO->ao_lock, &AOHandle);
  1350. if (Conn != NULL) {
  1351. CTEStructAssert(Conn, tc);
  1352. if (Conn->tc_ao != NULL) {
  1353. // It's already associated. Error out.
  1354. ASSERT(0);
  1355. DEBUGMSG(DBG_ERROR && DBG_TDI,
  1356. (DTEXT("TdiAssociateAddress: Already assoc Addr %x conn %x\n"),
  1357. AO, Conn));
  1358. Status = TDI_ALREADY_ASSOCIATED;
  1359. } else {
  1360. Conn->tc_ao = AO;
  1361. ASSERT(Conn->tc_tcb == NULL);
  1362. //ENQUEUE(&AO->ao_idleq, &Conn->tc_q);
  1363. PUSHQ(&AO->ao_idleq, &Conn->tc_q);
  1364. Status = TDI_SUCCESS;
  1365. }
  1366. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), AOHandle);
  1367. CTEFreeLock(&AO->ao_lock, TableHandle);
  1368. return Status;
  1369. } else {
  1370. DEBUGMSG(DBG_ERROR && DBG_TDI, (DTEXT("TdiAssociateAddress: Invalid ConnID %x\n"), ConnID));
  1371. Status = TDI_INVALID_CONNECTION;
  1372. }
  1373. CTEFreeLock(&AO->ao_lock, AOHandle);
  1374. DEBUGMSG(DBG_TRACE && DBG_TDI,
  1375. (DTEXT("-TdiAssociateAddress [%x]\n"), Status));
  1376. return Status;
  1377. }
  1378. //* TdiDisAssociateAddress - Disassociate a connection from an address.
  1379. //
  1380. // The TDI entry point to disassociate a connection from an address. The
  1381. // connection must actually be associated and not connected to anything.
  1382. //
  1383. // Input: Request - Pointer to the request structure for this
  1384. // command.
  1385. //
  1386. // Returns: Status of request.
  1387. //
  1388. TDI_STATUS
  1389. TdiDisAssociateAddress(PTDI_REQUEST Request)
  1390. {
  1391. uint ConnID = PtrToUlong(Request->Handle.ConnectionContext);
  1392. CTELockHandle AOTableHandle, ConnTableHandle, AOHandle;
  1393. TCPConn *Conn;
  1394. AddrObj *AO;
  1395. TDI_STATUS Status;
  1396. CTEGetLock(&AddrObjTableLock.Lock, &AOTableHandle);
  1397. Conn = GetConnFromConnID(ConnID, &ConnTableHandle);
  1398. if (Conn != NULL) {
  1399. // The connection actually exists!
  1400. CTEStructAssert(Conn, tc);
  1401. AO = Conn->tc_ao;
  1402. if (AO != NULL) {
  1403. CTEStructAssert(AO, ao);
  1404. // And it's associated.
  1405. CTEGetLock(&AO->ao_lock, &AOHandle);
  1406. // If there's no connection currently active, go ahead and remove
  1407. // him from the AddrObj. If a connection is active error the
  1408. // request out.
  1409. if (Conn->tc_tcb == NULL) {
  1410. if (Conn->tc_refcnt == 0) {
  1411. RemoveConnFromAO(AO, Conn);
  1412. Status = TDI_SUCCESS;
  1413. } else {
  1414. // He shouldn't be closing, or we couldn't have found him.
  1415. ASSERT(!(Conn->tc_flags & CONN_CLOSING));
  1416. Conn->tc_rtn = Request->RequestNotifyObject;
  1417. Conn->tc_rtncontext = Request->RequestContext;
  1418. Conn->tc_donertn = DisassocDone;
  1419. Conn->tc_flags |= CONN_DISACC;
  1420. Status = TDI_PENDING;
  1421. }
  1422. } else
  1423. Status = TDI_CONNECTION_ACTIVE;
  1424. CTEFreeLock(&AO->ao_lock, AOHandle);
  1425. } else
  1426. Status = TDI_NOT_ASSOCIATED;
  1427. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), ConnTableHandle);
  1428. } else
  1429. Status = TDI_INVALID_CONNECTION;
  1430. CTEFreeLock(&AddrObjTableLock.Lock, AOTableHandle);
  1431. return Status;
  1432. }
  1433. //* ProcessUserOptions - Process options from the user.
  1434. //
  1435. // A utility routine to process options from the user. We fill in the
  1436. // optinfo structure, and if we have options we call ip to check on them.
  1437. //
  1438. // Input: Info - Info structure containing options to be processed.
  1439. // OptInfo - Info structure to be filled in.
  1440. //
  1441. // Returns: TDI_STATUS of attempt.
  1442. //
  1443. TDI_STATUS
  1444. ProcessUserOptions(PTDI_CONNECTION_INFORMATION Info, IPOptInfo * OptInfo)
  1445. {
  1446. TDI_STATUS Status;
  1447. (*LocalNetInfo.ipi_initopts) (OptInfo);
  1448. if (Info != NULL && Info->Options != NULL) {
  1449. IP_STATUS OptStatus;
  1450. OptStatus = (*LocalNetInfo.ipi_copyopts) (Info->Options,
  1451. Info->OptionsLength, OptInfo);
  1452. if (OptStatus != IP_SUCCESS) {
  1453. if (OptStatus == IP_NO_RESOURCES)
  1454. Status = TDI_NO_RESOURCES;
  1455. else
  1456. Status = TDI_BAD_OPTION;
  1457. } else
  1458. Status = TDI_SUCCESS;
  1459. } else {
  1460. Status = TDI_SUCCESS;
  1461. }
  1462. return Status;
  1463. }
  1464. //* InitTCBFromConn - Initialize a TCB from information in a Connection.
  1465. //
  1466. // Called from Connect and Listen processing to initialize a new TCB from
  1467. // information in the connection. We assume the AddrObjTableLock and
  1468. // ConnTableLocks are held when we are called, or that the caller has some
  1469. // other way of making sure that the referenced AO doesn't go away in the middle
  1470. // of operation.
  1471. //
  1472. // Input: Conn - Connection to initialize from.
  1473. // NewTCB - TCB to be initialized.
  1474. // Addr - Remote addressing and option info for NewTCB.
  1475. // AOLocked - True if the called has the address object locked.
  1476. //
  1477. // Returns: TDI_STATUS of init attempt.
  1478. //
  1479. TDI_STATUS
  1480. InitTCBFromConn(TCPConn * Conn, TCB * NewTCB,
  1481. PTDI_CONNECTION_INFORMATION Addr, uint AOLocked)
  1482. {
  1483. CTELockHandle AOHandle;
  1484. TDI_STATUS Status;
  1485. int tos = 0;
  1486. uint UnicastIf;
  1487. CTEStructAssert(Conn, tc);
  1488. // We have a connection. Make sure it's associated with an address and
  1489. // doesn't already have a TCB attached.
  1490. if (Conn->tc_flags & CONN_INVALID)
  1491. return TDI_INVALID_CONNECTION;
  1492. if (Conn->tc_tcb == NULL) {
  1493. AddrObj *ConnAO;
  1494. ConnAO = Conn->tc_ao;
  1495. if (ConnAO != NULL) {
  1496. CTEStructAssert(ConnAO, ao);
  1497. if (!AOLocked) {
  1498. CTEGetLock(&ConnAO->ao_lock, &AOHandle);
  1499. }
  1500. if (!(NewTCB->tcb_fastchk & TCP_FLAG_ACCEPT_PENDING)) {
  1501. NewTCB->tcb_saddr = ConnAO->ao_addr;
  1502. NewTCB->tcb_defaultwin = Conn->tc_window;
  1503. NewTCB->tcb_rcvwin = Conn->tc_window;
  1504. // Compute rcv window scale based on the rcvwin
  1505. // From RFC 1323 - TCP_MAX_WINSHIFT is set to 14
  1506. NewTCB->tcb_rcvwinscale = 0;
  1507. if (TcpHostOpts & TCP_FLAG_WS) {
  1508. while ((NewTCB->tcb_rcvwinscale < TCP_MAX_WINSHIFT) &&
  1509. ((TCP_MAXWIN << NewTCB->tcb_rcvwinscale) < (int)Conn->tc_window)) {
  1510. NewTCB->tcb_rcvwinscale++;
  1511. }
  1512. }
  1513. }
  1514. NewTCB->tcb_sport = ConnAO->ao_port;
  1515. NewTCB->tcb_rcvind = ConnAO->ao_rcv;
  1516. NewTCB->tcb_chainedrcvind = ConnAO->ao_chainedrcv;
  1517. NewTCB->tcb_chainedrcvcontext = ConnAO->ao_chainedrcvcontext;
  1518. NewTCB->tcb_ricontext = ConnAO->ao_rcvcontext;
  1519. if (NewTCB->tcb_rcvind == NULL)
  1520. NewTCB->tcb_rcvhndlr = PendData;
  1521. else
  1522. NewTCB->tcb_rcvhndlr = IndicateData;
  1523. NewTCB->tcb_conncontext = Conn->tc_context;
  1524. NewTCB->tcb_flags |= Conn->tc_tcbflags;
  1525. #if TRACE_EVENT
  1526. NewTCB->tcb_cpcontext = Conn->tc_owningpid;
  1527. #endif
  1528. if (Conn->tc_flags & CONN_WINSET)
  1529. NewTCB->tcb_flags |= WINDOW_SET;
  1530. if (NewTCB->tcb_flags & KEEPALIVE) {
  1531. START_TCB_TIMER_R(NewTCB, KA_TIMER, Conn->tc_tcbkatime);
  1532. NewTCB->tcb_kacount = 0;
  1533. }
  1534. IF_TCPDBG(TCP_DEBUG_OPTIONS) {
  1535. TCPTRACE((
  1536. "setting TOS to %d on AO %lx in TCB %lx\n", ConnAO->ao_opt.ioi_tos, ConnAO, NewTCB
  1537. ));
  1538. }
  1539. if (ConnAO->ao_opt.ioi_tos) {
  1540. tos = ConnAO->ao_opt.ioi_tos;
  1541. }
  1542. UnicastIf = ConnAO->ao_opt.ioi_ucastif;
  1543. if (!AOLocked) {
  1544. CTEFreeLock(&ConnAO->ao_lock, AOHandle);
  1545. }
  1546. // If we've been given options, we need to process them now.
  1547. if (Addr != NULL && Addr->Options != NULL)
  1548. NewTCB->tcb_flags |= CLIENT_OPTIONS;
  1549. Status = ProcessUserOptions(Addr, &NewTCB->tcb_opt);
  1550. if (tos) {
  1551. NewTCB->tcb_opt.ioi_tos = (uchar) tos;
  1552. }
  1553. NewTCB->tcb_opt.ioi_ucastif = UnicastIf;
  1554. return Status;
  1555. } else
  1556. return TDI_NOT_ASSOCIATED;
  1557. } else
  1558. return TDI_CONNECTION_ACTIVE;
  1559. }
  1560. //* AdjustAckParameters - Initializes the ACK related parameters on a TCB.
  1561. //
  1562. // A utility routine to initialize and adjust the ACK parameters on a
  1563. // new TCB, with its tcb_rce field pointing to the RCE it is supposed to
  1564. // use.
  1565. //
  1566. // Input: NewTCB - TCB with RCE initialized.
  1567. //
  1568. // Returns: Nothing.
  1569. //
  1570. FORCEINLINE
  1571. VOID
  1572. AdjustAckParameters(TCB *NewTCB)
  1573. {
  1574. NewTCB->tcb_delackticks = NewTCB->tcb_rce->rce_TcpDelAckTicks;
  1575. if (NewTCB->tcb_rce->rce_TcpAckFrequency) {
  1576. NewTCB->tcb_numdelacks = NewTCB->tcb_rce->rce_TcpAckFrequency - 1;
  1577. }
  1578. // If the user setting says the number of delayed ack ticks is
  1579. // less than the default (which is also the minimum), then,
  1580. // they basically intend to turn delayed-acknowledgement off.
  1581. // We achieve that by setting the segments we wait for before
  1582. // sending an ACK to 0.
  1583. if (NewTCB->tcb_rce->rce_TcpDelAckTicks < DEL_ACK_TICKS) {
  1584. NewTCB->tcb_numdelacks = 0;
  1585. }
  1586. }
  1587. //* UdpConnect - Establish a pseudo udp connection
  1588. //
  1589. // The TDI connection establishment routine. Called when the client wants to
  1590. // establish a udp connection, we validate his incoming parameters
  1591. // initialize AO to point to a udp conection information block
  1592. //
  1593. //
  1594. // Input: Request - The request structure for this command.
  1595. // Timeout - How long to wait for the request. The format
  1596. // of this time is system specific - we use
  1597. // a macro to convert to ticks.
  1598. // RequestAddr - Pointer to a TDI_CONNECTION_INFORMATION
  1599. // structure describing the destination.
  1600. // ReturnAddr - Pointer to where to return information.
  1601. //
  1602. // Returns: Status of attempt to connect.
  1603. //
  1604. TDI_STATUS
  1605. UDPConnect(PTDI_REQUEST Request, void *TO,
  1606. PTDI_CONNECTION_INFORMATION RequestAddr,
  1607. PTDI_CONNECTION_INFORMATION ReturnAddr)
  1608. {
  1609. AddrObj *AO;
  1610. TDI_STATUS Status;
  1611. PTDI_CONNECTION_INFORMATION ConInf;
  1612. CTELockHandle AOHandle;
  1613. IPAddr DestAddr;
  1614. ushort DestPort;
  1615. uchar AddrType;
  1616. IPAddr SrcAddr;
  1617. ushort MSS;
  1618. IPOptInfo *OptInfo;
  1619. IPAddr OrigSrc;
  1620. // First, get and validate the remote address.
  1621. if (RequestAddr == NULL || RequestAddr->RemoteAddress == NULL ||
  1622. !GetAddress((PTRANSPORT_ADDRESS) RequestAddr->RemoteAddress, &DestAddr,
  1623. &DestPort))
  1624. return TDI_BAD_ADDR;
  1625. AddrType = (*LocalNetInfo.ipi_getaddrtype) (DestAddr);
  1626. if (AddrType == DEST_INVALID)
  1627. return TDI_BAD_ADDR;
  1628. AO = (AddrObj *) Request->Handle.AddressHandle;
  1629. //Save the connection information for the later use.
  1630. if (AO != NULL) {
  1631. CTEGetLock(&AO->ao_lock, &AOHandle);
  1632. CTEStructAssert(AO, ao);
  1633. RtlCopyMemory(&AO->ao_udpconn, RequestAddr, sizeof(TDI_CONNECTION_INFORMATION));
  1634. if (AO->ao_RemoteAddress) {
  1635. CTEFreeMem(AO->ao_RemoteAddress);
  1636. }
  1637. if (AO->ao_Options) {
  1638. CTEFreeMem(AO->ao_Options);
  1639. }
  1640. if (AO->ao_udpconn.RemoteAddressLength) {
  1641. IF_TCPDBG(TCP_DEBUG_CONUDP)
  1642. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Allocating remote address %d\n", AO->ao_udpconn.RemoteAddressLength));
  1643. AO->ao_RemoteAddress = CTEAllocMemN(AO->ao_udpconn.RemoteAddressLength, 'aPCT');
  1644. if (!AO->ao_RemoteAddress) {
  1645. IF_TCPDBG(TCP_DEBUG_CONUDP)
  1646. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"UDPConnect: remote address alloc failed\n"));
  1647. CTEFreeLock(&AO->ao_lock, AOHandle);
  1648. return TDI_NO_RESOURCES;
  1649. }
  1650. RtlCopyMemory(AO->ao_RemoteAddress, RequestAddr->RemoteAddress, RequestAddr->RemoteAddressLength);
  1651. }
  1652. if (AO->ao_udpconn.OptionsLength) {
  1653. IF_TCPDBG(TCP_DEBUG_CONUDP)
  1654. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Allocating options %d\n", AO->ao_udpconn.OptionsLength));
  1655. AO->ao_Options = CTEAllocMemN(AO->ao_udpconn.OptionsLength, 'aPCT');
  1656. if (!AO->ao_Options) {
  1657. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"UDPConnect: options alloc failed\n"));
  1658. CTEFreeLock(&AO->ao_lock, AOHandle);
  1659. return TDI_NO_RESOURCES;
  1660. }
  1661. RtlCopyMemory(AO->ao_Options, RequestAddr->Options, AO->ao_udpconn.OptionsLength);
  1662. } else {
  1663. AO->ao_Options = 0;
  1664. }
  1665. AO->ao_udpconn.RemoteAddress = AO->ao_RemoteAddress;
  1666. AO->ao_udpconn.Options = AO->ao_Options;
  1667. if (!CLASSD_ADDR(DestAddr)) {
  1668. OrigSrc = AO->ao_addr;
  1669. OptInfo = &AO->ao_opt;
  1670. } else {
  1671. OrigSrc = AO->ao_mcastaddr;
  1672. OptInfo = &AO->ao_mcastopt;
  1673. }
  1674. SrcAddr = (*LocalNetInfo.ipi_openrce) (DestAddr,
  1675. OrigSrc, &AO->ao_rce, &AddrType, &MSS,
  1676. OptInfo);
  1677. if (IP_ADDR_EQUAL(SrcAddr, NULL_IP_ADDR)) {
  1678. // The request failed. We know the destination is good
  1679. // (we verified it above), so it must be unreachable.
  1680. IF_TCPDBG(TCP_DEBUG_CONUDP)
  1681. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"UDPConnect: OpenRCE Failed\n"));
  1682. CTEFreeLock(&AO->ao_lock, AOHandle);
  1683. return TDI_DEST_UNREACHABLE;
  1684. }
  1685. IF_TCPDBG(TCP_DEBUG_CONUDP)
  1686. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"UDPConnect---AO %x OpenRCE %x\n", AO, AO->ao_rce));
  1687. AO->ao_rcesrc = SrcAddr;
  1688. //indicate that connection structure for udp is setup
  1689. SET_AO_CONNUDP(AO);
  1690. CTEFreeLock(&AO->ao_lock, AOHandle);
  1691. return TDI_SUCCESS;
  1692. }
  1693. return TDI_ADDR_INVALID;
  1694. }
  1695. //* UdpDisconnect - remve the "connection" info from AO
  1696. //
  1697. // Called when the client wants to
  1698. // break a udp connection, we validate his incoming parameters
  1699. // initialize AO to point to a udp conection information block
  1700. //
  1701. //
  1702. // Input: Request - The request structure for this command.
  1703. // Timeout - How long to wait for the request. The format
  1704. // of this time is system specific - we use
  1705. // a macro to convert to ticks.
  1706. // RequestAddr - Pointer to a TDI_CONNECTION_INFORMATION
  1707. // structure describing the destination.
  1708. // ReturnAddr - Pointer to where to return information.
  1709. //
  1710. // Returns: Status of attempt to connect.
  1711. //
  1712. TDI_STATUS
  1713. UDPDisconnect(PTDI_REQUEST Request, void *TO,
  1714. PTDI_CONNECTION_INFORMATION RequestAddr,
  1715. PTDI_CONNECTION_INFORMATION ReturnAddr)
  1716. {
  1717. AddrObj *AO;
  1718. TDI_STATUS Status;
  1719. PTDI_CONNECTION_INFORMATION ConInf;
  1720. CTELockHandle AOHandle;
  1721. IPAddr DestAddr;
  1722. ushort DestPort;
  1723. uchar AddrType;
  1724. IPAddr SrcAddr;
  1725. ushort MSS;
  1726. AO = (AddrObj *) Request->Handle.AddressHandle;
  1727. //Save the connection information for the later use.
  1728. if (AO != NULL) {
  1729. CTEGetLock(&AO->ao_lock, &AOHandle);
  1730. CTEStructAssert(AO, ao);
  1731. IF_TCPDBG(TCP_DEBUG_CONUDP)
  1732. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"UDPDisconnect: Closerce %x \n", AO->ao_rce));
  1733. if (AO->ao_rce)
  1734. (*LocalNetInfo.ipi_closerce) (AO->ao_rce);
  1735. AO->ao_rce = NULL;
  1736. if (AO->ao_RemoteAddress) {
  1737. IF_TCPDBG(TCP_DEBUG_CONUDP)
  1738. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"udpdisc: deleting remoteaddress %x %x\n", AO, AO->ao_RemoteAddress));
  1739. CTEFreeMem(AO->ao_RemoteAddress);
  1740. AO->ao_RemoteAddress = NULL;
  1741. }
  1742. if (AO->ao_Options) {
  1743. IF_TCPDBG(TCP_DEBUG_CONUDP)
  1744. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"udpdisc: deleting remoteaddress %x %x\n", AO, AO->ao_Options));
  1745. CTEFreeMem(AO->ao_Options);
  1746. AO->ao_Options = NULL;
  1747. }
  1748. CLEAR_AO_CONNUDP(AO);
  1749. CTEFreeLock(&AO->ao_lock, AOHandle);
  1750. return TDI_SUCCESS;
  1751. }
  1752. return TDI_ADDR_INVALID;
  1753. }
  1754. //* TdiConnect - Establish a connection.
  1755. //
  1756. // The TDI connection establishment routine. Called when the client wants to
  1757. // establish a connection, we validate his incoming parameters and kick
  1758. // things off by sending a SYN.
  1759. //
  1760. // Input: Request - The request structure for this command.
  1761. // Timeout - How long to wait for the request. The format
  1762. // of this time is system specific - we use
  1763. // a macro to convert to ticks.
  1764. // RequestAddr - Pointer to a TDI_CONNECTION_INFORMATION
  1765. // structure describing the destination.
  1766. // ReturnAddr - Pointer to where to return information.
  1767. //
  1768. // Returns: Status of attempt to connect.
  1769. //
  1770. TDI_STATUS
  1771. TdiConnect(PTDI_REQUEST Request, void *TO,
  1772. PTDI_CONNECTION_INFORMATION RequestAddr,
  1773. PTDI_CONNECTION_INFORMATION ReturnAddr)
  1774. {
  1775. TCPConnReq *ConnReq; // Connection request to use.
  1776. IPAddr DestAddr;
  1777. ushort DestPort;
  1778. uchar AddrType;
  1779. TCPConn *Conn;
  1780. TCB *NewTCB;
  1781. uint ConnID = PtrToUlong(Request->Handle.ConnectionContext);
  1782. CTELockHandle AOTableHandle, ConnTableHandle, AOHandle;
  1783. AddrObj *AO;
  1784. TDI_STATUS Status;
  1785. CTELockHandle TCBHandle;
  1786. IPAddr SrcAddr;
  1787. ushort MSS;
  1788. TCP_TIME *Timeout;
  1789. // First, get and validate the remote address.
  1790. if (RequestAddr == NULL || RequestAddr->RemoteAddress == NULL ||
  1791. !GetAddress((PTRANSPORT_ADDRESS) RequestAddr->RemoteAddress, &DestAddr,
  1792. &DestPort))
  1793. return TDI_BAD_ADDR;
  1794. AddrType = (*LocalNetInfo.ipi_getaddrtype) (DestAddr);
  1795. if (AddrType == DEST_INVALID || IS_BCAST_DEST(AddrType) || DestPort == 0)
  1796. return TDI_BAD_ADDR;
  1797. // Now get a connection request. If we can't, bail out now.
  1798. ConnReq = GetConnReq();
  1799. if (ConnReq == NULL)
  1800. return TDI_NO_RESOURCES;
  1801. // Get a TCB, assuming we'll need one.
  1802. NewTCB = AllocTCB();
  1803. if (NewTCB == NULL) {
  1804. // Couldn't get a TCB.
  1805. FreeConnReq(ConnReq);
  1806. return TDI_NO_RESOURCES;
  1807. }
  1808. Timeout = (TCP_TIME *) TO;
  1809. if (Timeout != NULL && !INFINITE_CONN_TO(*Timeout)) {
  1810. ulong Ticks = TCP_TIME_TO_TICKS(*Timeout);
  1811. if (Ticks > MAX_CONN_TO_TICKS)
  1812. Ticks = MAX_CONN_TO_TICKS;
  1813. else
  1814. Ticks++;
  1815. ConnReq->tcr_timeout = (ushort) Ticks;
  1816. } else
  1817. ConnReq->tcr_timeout = 0;
  1818. ConnReq->tcr_conninfo = ReturnAddr;
  1819. ConnReq->tcr_addrinfo = NULL;
  1820. ConnReq->tcr_req.tr_rtn = Request->RequestNotifyObject;
  1821. ConnReq->tcr_req.tr_context = Request->RequestContext;
  1822. NewTCB->tcb_daddr = DestAddr;
  1823. NewTCB->tcb_dport = DestPort;
  1824. // Now find the real connection. If we find it, we'll make sure it's
  1825. // associated.
  1826. CTEGetLock(&AddrObjTableLock.Lock, &AOTableHandle);
  1827. Conn = GetConnFromConnID(ConnID, &ConnTableHandle);
  1828. if (Conn != NULL) {
  1829. uint Inserted;
  1830. CTEStructAssert(Conn, tc);
  1831. AO = Conn->tc_ao;
  1832. if (AO != NULL) {
  1833. CTEGetLock(&AO->ao_lock, &AOHandle);
  1834. CTEStructAssert(AO, ao);
  1835. Status = InitTCBFromConn(Conn, NewTCB, RequestAddr, TRUE);
  1836. NewTCB->tcb_numdelacks = 1;
  1837. NewTCB->tcb_rcvdsegs = 0;
  1838. if (Status == TDI_SUCCESS) {
  1839. // We've processed the options, and we know the destination
  1840. // address is good, and we have all the resources we need,
  1841. // so we can go ahead and open an RCE. If this works we'll
  1842. // put the TCB into the Connection and send a SYN.
  1843. // We're done with the AddrObjTable now, so we can free it's
  1844. // lock.
  1845. NewTCB->tcb_flags |= ACTIVE_OPEN;
  1846. CTEFreeLock(&AddrObjTableLock.Lock, AOHandle);
  1847. SrcAddr = (*LocalNetInfo.ipi_openrce)(DestAddr,
  1848. NewTCB->tcb_saddr,
  1849. &NewTCB->tcb_rce,
  1850. &AddrType, &MSS,
  1851. &NewTCB->tcb_opt);
  1852. if (IP_ADDR_EQUAL(SrcAddr, NULL_IP_ADDR)) {
  1853. // The request failed. We know the destination is good
  1854. // (we verified it above), so it must be unreachable.
  1855. CTEFreeLock(&AO->ao_lock, ConnTableHandle);
  1856. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), AOTableHandle);
  1857. Status = TDI_DEST_UNREACHABLE;
  1858. goto error;
  1859. }
  1860. if (AddrType == DEST_LOCAL) {
  1861. NewTCB->tcb_flags &= ~NAGLING;
  1862. // Ack every segment for loopback
  1863. NewTCB->tcb_numdelacks = 0;
  1864. }
  1865. //Check if we have per adapter specific window size.
  1866. if (NewTCB->tcb_rce->rce_TcpWindowSize) {
  1867. if (NewTCB->tcb_rce->rce_TcpWindowSize <= GlobalMaxRcvWin) {
  1868. NewTCB->tcb_defaultwin =
  1869. NewTCB->tcb_rce->rce_TcpWindowSize;
  1870. } else {
  1871. NewTCB->tcb_defaultwin = GlobalMaxRcvWin;
  1872. }
  1873. NewTCB->tcb_rcvwin = NewTCB->tcb_defaultwin;
  1874. // Compute *new* rcv window scale based on the rcvwin
  1875. // note that we had already done this in initTcbfromConn
  1876. // But it is not based on per adapter window size.
  1877. // From RFC 1323 - TCP_MAX_WINSHIFT is set to 14
  1878. NewTCB->tcb_rcvwinscale = 0;
  1879. if (TcpHostOpts & TCP_FLAG_WS) {
  1880. while ((NewTCB->tcb_rcvwinscale < TCP_MAX_WINSHIFT) &&
  1881. ((TCP_MAXWIN << NewTCB->tcb_rcvwinscale) <
  1882. (int)NewTCB->tcb_defaultwin)) {
  1883. NewTCB->tcb_rcvwinscale++;
  1884. }
  1885. }
  1886. }
  1887. AdjustAckParameters(NewTCB);
  1888. // OK, the RCE open worked. Enter the TCB into the connection.
  1889. CTEGetLock(&NewTCB->tcb_lock, &TCBHandle);
  1890. Conn->tc_tcb = NewTCB;
  1891. NewTCB->tcb_connid = Conn->tc_connid;
  1892. Conn->tc_refcnt++;
  1893. NewTCB->tcb_conn = Conn;
  1894. REMOVEQ(&Conn->tc_q);
  1895. ENQUEUE(&AO->ao_activeq, &Conn->tc_q);
  1896. // This is outgoing connect request
  1897. // ISN will not be grabbed twice
  1898. #if MILLEN
  1899. //just use tcb_sendnext to hold hash value
  1900. //for randisn
  1901. NewTCB->tcb_sendnext =
  1902. TCB_HASH(NewTCB->tcb_daddr, NewTCB->tcb_dport,
  1903. NewTCB->tcb_saddr, NewTCB->tcb_sport);
  1904. #endif
  1905. GetRandomISN(&NewTCB->tcb_sendnext);
  1906. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), TCBHandle);
  1907. CTEFreeLock(&AO->ao_lock, ConnTableHandle);
  1908. // If the caller didn't specify a local address, use what
  1909. // IP provided.
  1910. if (IP_ADDR_EQUAL(NewTCB->tcb_saddr, NULL_IP_ADDR))
  1911. NewTCB->tcb_saddr = SrcAddr;
  1912. // Until we have MTU discovery in place, hold the MSS down
  1913. // to 536 if we're going off net.
  1914. MSS -= sizeof(TCPHeader);
  1915. if (!PMTUDiscovery && IS_OFFNET_DEST(AddrType)) {
  1916. NewTCB->tcb_mss = MIN(MSS, MAX_REMOTE_MSS) -
  1917. NewTCB->tcb_opt.ioi_optlength;
  1918. ASSERT(NewTCB->tcb_mss > 0);
  1919. } else {
  1920. if (PMTUDiscovery)
  1921. NewTCB->tcb_opt.ioi_flags = IP_FLAG_DF;
  1922. NewTCB->tcb_mss = MSS - NewTCB->tcb_opt.ioi_optlength;
  1923. ASSERT(NewTCB->tcb_mss > 0);
  1924. }
  1925. ValidateMSS(NewTCB);
  1926. //
  1927. // Initialize the remote mss in case we receive an MTU change
  1928. // from IP before the remote SYN arrives. The remmms will
  1929. // be replaced when the remote SYN is processed.
  1930. //
  1931. NewTCB->tcb_remmss = NewTCB->tcb_mss;
  1932. // Now initialize our send state.
  1933. InitSendState(NewTCB);
  1934. NewTCB->tcb_refcnt = 0;
  1935. REFERENCE_TCB(NewTCB);
  1936. NewTCB->tcb_state = TCB_SYN_SENT;
  1937. TStats.ts_activeopens++;
  1938. #if TRACE_EVENT
  1939. NewTCB->tcb_cpcontext = HandleToUlong(PsGetCurrentProcessId());
  1940. #endif
  1941. // Need to put the ConnReq on the TCB now,
  1942. // in case the timer fires after we've inserted.
  1943. NewTCB->tcb_connreq = ConnReq;
  1944. CTEFreeLock(&NewTCB->tcb_lock, AOTableHandle);
  1945. Inserted = InsertTCB(NewTCB);
  1946. CTEGetLock(&NewTCB->tcb_lock, &TCBHandle);
  1947. if (!Inserted) {
  1948. // Insert failed. We must already have a connection. Pull
  1949. // the connreq from the TCB first, so we can return the
  1950. // correct error code for it.
  1951. NewTCB->tcb_connreq = NULL;
  1952. DEREFERENCE_TCB(NewTCB);
  1953. TryToCloseTCB(NewTCB, TCB_CLOSE_ABORTED, TCBHandle);
  1954. FreeConnReq(ConnReq);
  1955. return TDI_ADDR_IN_USE;
  1956. }
  1957. // If it's closing somehow, stop now. It can't have gone to
  1958. // closed, as we hold a reference on it. It could have gone
  1959. // to some other state (for example SYN-RCVD) so we need to
  1960. // check that now too.
  1961. if (!CLOSING(NewTCB) && NewTCB->tcb_state == TCB_SYN_SENT) {
  1962. if (ConnReq->tcr_timeout > 0) {
  1963. START_TCB_TIMER_R(NewTCB, CONN_TIMER, ConnReq->tcr_timeout);
  1964. }
  1965. SendSYN(NewTCB, TCBHandle);
  1966. CTEGetLock(&NewTCB->tcb_lock, &TCBHandle);
  1967. }
  1968. DerefTCB(NewTCB, TCBHandle);
  1969. return TDI_PENDING;
  1970. } else
  1971. CTEFreeLock(&AO->ao_lock, AOHandle);
  1972. } else
  1973. Status = TDI_NOT_ASSOCIATED;
  1974. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), ConnTableHandle);
  1975. } else
  1976. Status = TDI_INVALID_CONNECTION;
  1977. CTEFreeLock(&AddrObjTableLock.Lock, AOTableHandle);
  1978. error:
  1979. //CTEFreeLock(&ConnTableLock, AOTableHandle);
  1980. FreeConnReq(ConnReq);
  1981. FreeTCB(NewTCB);
  1982. return Status;
  1983. }
  1984. //* TdiListen - Listen for a connection.
  1985. //
  1986. // The TDI listen handling routine. Called when the client wants to
  1987. // post a listen, we validate his incoming parameters, allocate a TCB
  1988. // and return.
  1989. //
  1990. // Input: Request - The request structure for this command.
  1991. // Flags - Listen flags for the listen.
  1992. // AcceptableAddr - Pointer to a TDI_CONNECTION_INFORMATION
  1993. // structure describing acceptable remote
  1994. // addresses.
  1995. // ConnectedAddr - Pointer to where to return information
  1996. // about the address we connected to.
  1997. //
  1998. // Returns: Status of attempt to connect.
  1999. //
  2000. TDI_STATUS
  2001. TdiListen(PTDI_REQUEST Request, ushort Flags,
  2002. PTDI_CONNECTION_INFORMATION AcceptableAddr,
  2003. PTDI_CONNECTION_INFORMATION ConnectedAddr)
  2004. {
  2005. TCPConnReq *ConnReq; // Connection request to use.
  2006. IPAddr RemoteAddr; // Remote address to take conn. from.
  2007. ushort RemotePort; // Acceptable remote port.
  2008. uchar AddrType; // Type of remote address.
  2009. TCPConn *Conn; // Pointer to the Connection being
  2010. // listened upon.
  2011. TCB *NewTCB; // Pointer to the new TCB we'll use.
  2012. uint ConnID = PtrToUlong(Request->Handle.ConnectionContext);
  2013. CTELockHandle AOTableHandle, ConnTableHandle;
  2014. TDI_STATUS Status;
  2015. // If we've been given remote addressing criteria, check it out.
  2016. if (AcceptableAddr != NULL && AcceptableAddr->RemoteAddress != NULL) {
  2017. if (!GetAddress((PTRANSPORT_ADDRESS) AcceptableAddr->RemoteAddress,
  2018. &RemoteAddr, &RemotePort))
  2019. return TDI_BAD_ADDR;
  2020. if (!IP_ADDR_EQUAL(RemoteAddr, NULL_IP_ADDR)) {
  2021. AddrType = (*LocalNetInfo.ipi_getaddrtype) (RemoteAddr);
  2022. if (AddrType == DEST_INVALID || IS_BCAST_DEST(AddrType))
  2023. return TDI_BAD_ADDR;
  2024. }
  2025. } else {
  2026. RemoteAddr = NULL_IP_ADDR;
  2027. RemotePort = 0;
  2028. }
  2029. // The remote address is valid. Get a ConnReq, and maybe a TCB.
  2030. ConnReq = GetConnReq();
  2031. if (ConnReq == NULL)
  2032. return TDI_NO_RESOURCES; // Couldn't get one.
  2033. // Now try to get a TCB.
  2034. NewTCB = AllocTCB();
  2035. if (NewTCB == NULL) {
  2036. // Couldn't get a TCB. Return an error.
  2037. FreeConnReq(ConnReq);
  2038. return TDI_NO_RESOURCES;
  2039. }
  2040. // We have the resources we need. Initialize them, and then check the
  2041. // state of the connection.
  2042. ConnReq->tcr_flags =
  2043. (Flags & TDI_QUERY_ACCEPT) ? TCR_FLAG_QUERY_ACCEPT : 0;
  2044. ConnReq->tcr_conninfo = ConnectedAddr;
  2045. ConnReq->tcr_addrinfo = NULL;
  2046. ConnReq->tcr_req.tr_rtn = Request->RequestNotifyObject;
  2047. ConnReq->tcr_req.tr_context = Request->RequestContext;
  2048. NewTCB->tcb_connreq = ConnReq;
  2049. NewTCB->tcb_daddr = RemoteAddr;
  2050. NewTCB->tcb_dport = RemotePort;
  2051. NewTCB->tcb_state = TCB_LISTEN;
  2052. // Now find the real connection. If we find it, we'll make sure it's
  2053. // associated.
  2054. //CTEGetLock(&ConnTableLock, &ConnTableHandle);
  2055. Conn = GetConnFromConnID(ConnID, &ConnTableHandle);
  2056. if (Conn != NULL) {
  2057. CTELockHandle AddrHandle;
  2058. AddrObj *ConnAO;
  2059. CTEStructAssert(Conn, tc);
  2060. // We have a connection. Make sure it's associated with an address and
  2061. // doesn't already have a TCB attached.
  2062. ConnAO = Conn->tc_ao;
  2063. if (ConnAO != NULL) {
  2064. CTEStructAssert(ConnAO, ao);
  2065. CTEGetLockAtDPC(&ConnAO->ao_lock, &AddrHandle);
  2066. if (AO_VALID(ConnAO)) {
  2067. Status = InitTCBFromConn(Conn, NewTCB, AcceptableAddr, TRUE);
  2068. } else {
  2069. Status = TDI_ADDR_INVALID;
  2070. }
  2071. if (Status == TDI_SUCCESS) {
  2072. // The initialization worked. Assign the new TCB to the connection,
  2073. // and return.
  2074. REMOVEQ(&Conn->tc_q);
  2075. //ENQUEUE(&ConnAO->ao_listenq, &Conn->tc_q);
  2076. PUSHQ(&ConnAO->ao_listenq, &Conn->tc_q);
  2077. Conn->tc_tcb = NewTCB;
  2078. NewTCB->tcb_conn = Conn;
  2079. NewTCB->tcb_connid = Conn->tc_connid;
  2080. Conn->tc_refcnt++;
  2081. ConnAO->ao_listencnt++;
  2082. CTEFreeLockFromDPC(&ConnAO->ao_lock, AddrHandle);
  2083. Status = TDI_PENDING;
  2084. } else {
  2085. FreeTCB(NewTCB);
  2086. CTEFreeLockFromDPC(&ConnAO->ao_lock, AddrHandle);
  2087. }
  2088. } else {
  2089. FreeTCB(NewTCB);
  2090. Status = TDI_NOT_ASSOCIATED;
  2091. }
  2092. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), ConnTableHandle);
  2093. } else {
  2094. FreeTCB(NewTCB);
  2095. Status = TDI_INVALID_CONNECTION;
  2096. }
  2097. // We're all done. Free the locks and get out.
  2098. //CTEFreeLock(&ConnTableLock, ConnTableHandle);
  2099. return Status;
  2100. }
  2101. //* InitRCE - Initialize an RCE.
  2102. //
  2103. // A utility routine to open and RCE and determine the maximum segment size
  2104. // for a connections. This function is called with the TCB lock held
  2105. // when transitioning out of the SYN_SENT or LISTEN states.
  2106. //
  2107. // Input: NewTCB - TCB for which an RCE is to be opened.
  2108. //
  2109. // Returns: Nothing.
  2110. //
  2111. void
  2112. InitRCE(TCB * NewTCB)
  2113. {
  2114. uchar DType;
  2115. ushort MSS;
  2116. // Open an RCE for this connection.
  2117. // postpone getting an RCE for this until gotpoestab,
  2118. // if in synattackprotect mode.
  2119. if (SynAttackProtect && NewTCB->tcb_state == TCB_SYN_RCVD &&
  2120. TCPHalfOpen > TCPMaxHalfOpen) {
  2121. (*LocalNetInfo.ipi_openrce)(NewTCB->tcb_daddr, NewTCB->tcb_saddr,
  2122. NULL, &DType, &MSS, &NewTCB->tcb_opt);
  2123. } else {
  2124. (*LocalNetInfo.ipi_openrce)(NewTCB->tcb_daddr, NewTCB->tcb_saddr,
  2125. &NewTCB->tcb_rce, &DType, &MSS,
  2126. &NewTCB->tcb_opt);
  2127. }
  2128. NewTCB->tcb_numdelacks = 1;
  2129. NewTCB->tcb_rcvdsegs = 0;
  2130. if (NewTCB->tcb_rce) {
  2131. if (NewTCB->tcb_rce->rce_TcpWindowSize) {
  2132. if (NewTCB->tcb_rce->rce_TcpWindowSize <= GlobalMaxRcvWin) {
  2133. NewTCB->tcb_defaultwin = NewTCB->tcb_rce->rce_TcpWindowSize;
  2134. } else if (NewTCB->tcb_defaultwin > GlobalMaxRcvWin) {
  2135. NewTCB->tcb_defaultwin = GlobalMaxRcvWin;
  2136. }
  2137. NewTCB->tcb_rcvwin = NewTCB->tcb_defaultwin;
  2138. // Compute *new* rcv window scale based on the rcvwin
  2139. // note that we had already done this in initTcbfromConn
  2140. // But it is not based on per adapter window size.
  2141. // From RFC 1323 - TCP_MAX_WINSHIFT is set to 14
  2142. NewTCB->tcb_rcvwinscale = 0;
  2143. if (TcpHostOpts & TCP_FLAG_WS) {
  2144. while ((NewTCB->tcb_rcvwinscale < TCP_MAX_WINSHIFT) &&
  2145. ((TCP_MAXWIN << NewTCB->tcb_rcvwinscale) <
  2146. (int)NewTCB->tcb_defaultwin)) {
  2147. NewTCB->tcb_rcvwinscale++;
  2148. }
  2149. }
  2150. }
  2151. AdjustAckParameters(NewTCB);
  2152. } //if rce != NULL
  2153. if (DType == DEST_LOCAL) {
  2154. // Ack every segment for loopback
  2155. NewTCB->tcb_numdelacks = 0;
  2156. NewTCB->tcb_flags &= ~NAGLING;
  2157. }
  2158. // Until we have Dynamic MTU discovery in place, force MTU down.
  2159. MSS -= sizeof(TCPHeader);
  2160. if (!PMTUDiscovery && (DType & DEST_OFFNET_BIT)) {
  2161. NewTCB->tcb_mss = MIN(NewTCB->tcb_remmss, MIN(MSS, MAX_REMOTE_MSS)
  2162. - NewTCB->tcb_opt.ioi_optlength);
  2163. ASSERT(NewTCB->tcb_mss > 0);
  2164. } else {
  2165. if (PMTUDiscovery)
  2166. NewTCB->tcb_opt.ioi_flags = IP_FLAG_DF;
  2167. MSS -= NewTCB->tcb_opt.ioi_optlength;
  2168. NewTCB->tcb_mss = MIN(NewTCB->tcb_remmss, MSS);
  2169. ASSERT(NewTCB->tcb_mss > 0);
  2170. }
  2171. ValidateMSS(NewTCB);
  2172. }
  2173. //* ValidateMSS - Enforce restrictions on the MSS selected for a TCB.
  2174. //
  2175. // Called to enforce the minimum acceptable value of the MSS for a TCB.
  2176. // In the case where an MSS has been selected which drops below the minimum,
  2177. // the minimum is chosen and the dont-fragment flag is cleared to allow
  2178. // fragmentation. Assumes the TCB is locked by the caller.
  2179. //
  2180. // Input: MssTCB - TCB to be validated.
  2181. //
  2182. // Returns: Nothing.
  2183. //
  2184. void
  2185. ValidateMSS(TCB* MssTCB)
  2186. {
  2187. if ((MssTCB->tcb_mss + MssTCB->tcb_opt.ioi_optlength) < MIN_LOCAL_MSS) {
  2188. MssTCB->tcb_mss = MIN_LOCAL_MSS - MssTCB->tcb_opt.ioi_optlength;
  2189. MssTCB->tcb_opt.ioi_flags &= ~IP_FLAG_DF;
  2190. }
  2191. }
  2192. //* AcceptConn - Accept a connection on a TCB.
  2193. //
  2194. // Called to accept a connection on a TCB, either from an incoming
  2195. // receive segment or via a user's accept. We initialize the RCE
  2196. // and the send state, and send out a SYN. We assume the TCB is locked
  2197. // and referenced when we get it.
  2198. //
  2199. // Input: AcceptTCB - TCB to accept on.
  2200. // Handle - Lock handle for TCB.
  2201. //
  2202. // Returns: Nothing.
  2203. //
  2204. void
  2205. AcceptConn(TCB * AcceptTCB, CTELockHandle Handle)
  2206. {
  2207. CTEStructAssert(AcceptTCB, tcb);
  2208. ASSERT(AcceptTCB->tcb_refcnt != 0);
  2209. InitRCE(AcceptTCB);
  2210. InitSendState(AcceptTCB);
  2211. AdjustRcvWin(AcceptTCB);
  2212. SendSYN(AcceptTCB, Handle);
  2213. CTEGetLock(&AcceptTCB->tcb_lock, &Handle);
  2214. DerefTCB(AcceptTCB, Handle);
  2215. }
  2216. //* TdiAccept - Accept a connection.
  2217. //
  2218. // The TDI accept routine. Called when the client wants to
  2219. // accept a connection for which a listen had previously completed. We
  2220. // examine the state of the connection - it has to be in SYN-RCVD, with
  2221. // a TCB, with no pending connreq, etc.
  2222. //
  2223. // Input: Request - The request structure for this command.
  2224. // AcceptInfo - Pointer to a TDI_CONNECTION_INFORMATION
  2225. // structure describing option information
  2226. // for this accept.
  2227. // ConnectedIndo - Pointer to where to return information
  2228. // about the address we connected to.
  2229. //
  2230. // Returns: Status of attempt to connect.
  2231. //
  2232. TDI_STATUS
  2233. TdiAccept(PTDI_REQUEST Request, PTDI_CONNECTION_INFORMATION AcceptInfo,
  2234. PTDI_CONNECTION_INFORMATION ConnectedInfo)
  2235. {
  2236. TCPConnReq *ConnReq; // ConnReq for this connection.
  2237. uint ConnID = PtrToUlong(Request->Handle.ConnectionContext);
  2238. TCPConn *Conn; // Connection being accepted upon.
  2239. TCB *AcceptTCB; // TCB for Conn.
  2240. CTELockHandle ConnTableHandle;// Lock handle for connection table.
  2241. CTELockHandle TCBHandle; // Lock handle for TCB.
  2242. TDI_STATUS Status;
  2243. // First, get the ConnReq we'll need.
  2244. ConnReq = GetConnReq();
  2245. if (ConnReq == NULL)
  2246. return TDI_NO_RESOURCES;
  2247. ConnReq->tcr_conninfo = ConnectedInfo;
  2248. ConnReq->tcr_addrinfo = NULL;
  2249. ConnReq->tcr_req.tr_rtn = Request->RequestNotifyObject;
  2250. ConnReq->tcr_req.tr_context = Request->RequestContext;
  2251. ConnReq->tcr_flags = 0;
  2252. // Now look up the connection.
  2253. //CTEGetLock(&ConnTableLock, &ConnTableHandle);
  2254. Conn = GetConnFromConnID(ConnID, &ConnTableHandle);
  2255. if (Conn != NULL) {
  2256. CTEStructAssert(Conn, tc);
  2257. // We have the connection. Make sure is has a TCB, and that the
  2258. // TCB is in the SYN-RCVD state, etc.
  2259. AcceptTCB = Conn->tc_tcb;
  2260. if (AcceptTCB != NULL) {
  2261. CTEStructAssert(AcceptTCB, tcb);
  2262. // Grab random ISN
  2263. // Note that if CONN was pre accepted we would'nt be here
  2264. // So, we are not getting ISN twice.
  2265. #if MILLEN
  2266. //just use tcb_sendnext to hold hash value
  2267. //for randisn
  2268. AcceptTCB->tcb_sendnext = TCB_HASH(AcceptTCB->tcb_daddr, AcceptTCB->tcb_dport, AcceptTCB->tcb_saddr, AcceptTCB->tcb_sport);
  2269. #endif
  2270. GetRandomISN(&AcceptTCB->tcb_sendnext);
  2271. CTEGetLock(&AcceptTCB->tcb_lock, &TCBHandle);
  2272. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), TCBHandle);
  2273. if (!CLOSING(AcceptTCB) && AcceptTCB->tcb_state == TCB_SYN_RCVD) {
  2274. // State is valid. Make sure this TCB had a delayed accept on
  2275. // it, and that there is currently no connect request pending.
  2276. if (!(AcceptTCB->tcb_flags & CONN_ACCEPTED) &&
  2277. AcceptTCB->tcb_connreq == NULL) {
  2278. // If the caller gave us options, they'll override any
  2279. // that are already present, if they're valid.
  2280. if (AcceptInfo != NULL) {
  2281. if (AcceptInfo->Options != NULL) {
  2282. IPOptInfo TempOptInfo;
  2283. // We have options. Copy them to make sure they're
  2284. // valid.
  2285. Status = ProcessUserOptions(AcceptInfo,
  2286. &TempOptInfo);
  2287. if (Status == TDI_SUCCESS) {
  2288. (*LocalNetInfo.ipi_freeopts) (&AcceptTCB->tcb_opt);
  2289. AcceptTCB->tcb_opt = TempOptInfo;
  2290. AcceptTCB->tcb_flags |= CLIENT_OPTIONS;
  2291. } else
  2292. goto connerror;
  2293. }
  2294. if (AcceptInfo->RemoteAddress) {
  2295. ConnReq->tcr_addrinfo = AcceptInfo;
  2296. }
  2297. }
  2298. AcceptTCB->tcb_connreq = ConnReq;
  2299. AcceptTCB->tcb_flags |= CONN_ACCEPTED;
  2300. REFERENCE_TCB(AcceptTCB);
  2301. // Everything's set. Accept the connection now.
  2302. AcceptConn(AcceptTCB, ConnTableHandle);
  2303. #if TRACE_EVENT
  2304. AcceptTCB->tcb_cpcontext = HandleToUlong(PsGetCurrentProcessId());
  2305. #endif
  2306. return TDI_PENDING;
  2307. }
  2308. }
  2309. connerror:
  2310. CTEFreeLock(&AcceptTCB->tcb_lock, ConnTableHandle);
  2311. Status = TDI_INVALID_CONNECTION;
  2312. goto error;
  2313. }
  2314. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), ConnTableHandle);
  2315. }
  2316. Status = TDI_INVALID_CONNECTION;
  2317. //CTEFreeLock(&ConnTableLock, ConnTableHandle);
  2318. error:
  2319. FreeConnReq(ConnReq);
  2320. return Status;
  2321. }
  2322. //* TdiDisConnect - Disconnect a connection.
  2323. //
  2324. // The TDI disconnection routine. Called when the client wants to disconnect
  2325. // a connection. There are two types of disconnection we support, graceful
  2326. // and abortive. A graceful close will cause us to send a FIN and not complete
  2327. // the request until we get the ACK back. An abortive close causes us to send
  2328. // a RST. In that case we'll just get things going and return immediately.
  2329. //
  2330. // Input: Request - The request structure for this command.
  2331. // Timeout - How long to wait for the request. The format
  2332. // of this time is system specific - we use
  2333. // a macro to convert to ticks.
  2334. // Flags - Flags indicating type of disconnect.
  2335. // DiscConnInfo - Pointer to a TDI_CONNECTION_INFORMATION
  2336. // structure giving disconnection info. Ignored
  2337. // for this request.
  2338. // ReturnInfo - Pointer to where to return information.
  2339. // Ignored for this request.
  2340. //
  2341. // Returns: Status of attempt to disconnect.
  2342. //
  2343. TDI_STATUS
  2344. TdiDisconnect(PTDI_REQUEST Request, void *TO, ushort Flags,
  2345. PTDI_CONNECTION_INFORMATION DiscConnInfo,
  2346. PTDI_CONNECTION_INFORMATION ReturnInfo)
  2347. {
  2348. TCPConnReq *ConnReq; // Connection request to use.
  2349. TCPConn *Conn;
  2350. TCB *DiscTCB;
  2351. CTELockHandle ConnTableHandle, TCBHandle;
  2352. TDI_STATUS Status;
  2353. TCP_TIME *Timeout;
  2354. //CTEGetLock(&ConnTableLock, &ConnTableHandle);
  2355. Conn = GetConnFromConnID(PtrToUlong(Request->Handle.ConnectionContext), &ConnTableHandle);
  2356. if (Conn != NULL) {
  2357. CTEStructAssert(Conn, tc);
  2358. DiscTCB = Conn->tc_tcb;
  2359. if (DiscTCB != NULL) {
  2360. CTEStructAssert(DiscTCB, tcb);
  2361. CTEGetLock(&DiscTCB->tcb_lock, &TCBHandle);
  2362. // We have the TCB. See what kind of disconnect this is.
  2363. if (Flags & TDI_DISCONNECT_ABORT) {
  2364. // This is an abortive disconnect. If we're not already
  2365. // closed or closing, blow the connection away.
  2366. if (DiscTCB->tcb_state != TCB_CLOSED) {
  2367. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), TCBHandle);
  2368. if (!CLOSING(DiscTCB)) {
  2369. DiscTCB->tcb_flags |= NEED_RST;
  2370. TryToCloseTCB(DiscTCB, TCB_CLOSE_ABORTED,
  2371. ConnTableHandle);
  2372. } else
  2373. CTEFreeLock(&DiscTCB->tcb_lock, ConnTableHandle);
  2374. return TDI_SUCCESS;
  2375. } else {
  2376. // The TCB isn't connected.
  2377. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), TCBHandle);
  2378. CTEFreeLock(&DiscTCB->tcb_lock, ConnTableHandle);
  2379. return TDI_INVALID_STATE;
  2380. }
  2381. } else {
  2382. // This is not an abortive close. For graceful close we'll need
  2383. // a ConnReq.
  2384. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), TCBHandle);
  2385. // Make sure we aren't in the middle of an abortive close.
  2386. if (CLOSING(DiscTCB)) {
  2387. CTEFreeLock(&DiscTCB->tcb_lock, ConnTableHandle);
  2388. return TDI_INVALID_CONNECTION;
  2389. }
  2390. ConnReq = GetConnReq();
  2391. if (ConnReq != NULL) {
  2392. // Got the ConnReq. See if this is a DISCONNECT_WAIT
  2393. // primitive or not.
  2394. ConnReq->tcr_flags = 0;
  2395. ConnReq->tcr_conninfo = NULL;
  2396. ConnReq->tcr_addrinfo = NULL;
  2397. ConnReq->tcr_req.tr_rtn = Request->RequestNotifyObject;
  2398. ConnReq->tcr_req.tr_context = Request->RequestContext;
  2399. if (!(Flags & TDI_DISCONNECT_WAIT)) {
  2400. Timeout = (TCP_TIME *) TO;
  2401. if (Timeout != NULL && !INFINITE_CONN_TO(*Timeout)) {
  2402. ulong Ticks = TCP_TIME_TO_TICKS(*Timeout);
  2403. if (Ticks > MAX_CONN_TO_TICKS)
  2404. Ticks = MAX_CONN_TO_TICKS;
  2405. else
  2406. Ticks++;
  2407. ConnReq->tcr_timeout = (ushort) Ticks;
  2408. } else
  2409. ConnReq->tcr_timeout = 0;
  2410. // OK, we're just about set. We need to update the TCB
  2411. // state, and send the FIN.
  2412. if (DiscTCB->tcb_state == TCB_ESTAB) {
  2413. DiscTCB->tcb_state = TCB_FIN_WAIT1;
  2414. // Since we left established, we're off the fast
  2415. // receive path.
  2416. DiscTCB->tcb_slowcount++;
  2417. DiscTCB->tcb_fastchk |= TCP_FLAG_SLOW;
  2418. } else if (DiscTCB->tcb_state == TCB_CLOSE_WAIT)
  2419. DiscTCB->tcb_state = TCB_LAST_ACK;
  2420. else {
  2421. CTEFreeLock(&DiscTCB->tcb_lock, ConnTableHandle);
  2422. FreeConnReq(ConnReq);
  2423. return TDI_INVALID_STATE;
  2424. }
  2425. TStats.ts_currestab--; // Update SNMP info.
  2426. ASSERT(DiscTCB->tcb_connreq == NULL);
  2427. DiscTCB->tcb_connreq = ConnReq;
  2428. if (ConnReq->tcr_timeout > 0) {
  2429. START_TCB_TIMER_R(DiscTCB, CONN_TIMER, ConnReq->tcr_timeout);
  2430. }
  2431. DiscTCB->tcb_flags |= FIN_NEEDED;
  2432. REFERENCE_TCB(DiscTCB);
  2433. TCPSend(DiscTCB, ConnTableHandle);
  2434. return TDI_PENDING;
  2435. } else {
  2436. // This is a DISC_WAIT request.
  2437. ConnReq->tcr_timeout = 0;
  2438. if (DiscTCB->tcb_discwait == NULL) {
  2439. DiscTCB->tcb_discwait = ConnReq;
  2440. Status = TDI_PENDING;
  2441. } else
  2442. Status = TDI_INVALID_STATE;
  2443. CTEFreeLock(&DiscTCB->tcb_lock, ConnTableHandle);
  2444. return Status;
  2445. }
  2446. } else {
  2447. // Couldn't get a ConnReq.
  2448. CTEFreeLock(&DiscTCB->tcb_lock, ConnTableHandle);
  2449. return TDI_NO_RESOURCES;
  2450. }
  2451. }
  2452. } else
  2453. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), ConnTableHandle);
  2454. }
  2455. // No Conn, or no TCB on conn. Return an error.
  2456. //CTEFreeLock(&ConnTableLock, ConnTableHandle);
  2457. return TDI_INVALID_CONNECTION;
  2458. }
  2459. //* OKToNotify - See if it's OK to notify about a DISC.
  2460. //
  2461. // A little utility function, called to see it it's OK to notify the client
  2462. // of an incoming FIN.
  2463. //
  2464. // Input: NotifyTCB - TCB to check.
  2465. //
  2466. // Returns: TRUE if it's OK, False otherwise.
  2467. //
  2468. uint
  2469. OKToNotify(TCB * NotifyTCB)
  2470. {
  2471. CTEStructAssert(NotifyTCB, tcb);
  2472. if (NotifyTCB->tcb_pendingcnt == 0 && NotifyTCB->tcb_urgcnt == 0 &&
  2473. NotifyTCB->tcb_rcvhead == NULL && NotifyTCB->tcb_exprcv == NULL)
  2474. return TRUE;
  2475. else
  2476. return FALSE;
  2477. }
  2478. //* NotifyOfDisc - Notify a client that a TCB is being disconnected.
  2479. //
  2480. // Called when we're disconnecting a TCB because we've received a FIN or
  2481. // RST from the remote peer, or because we're aborting for some reason.
  2482. // We'll complete a DISCONNECT_WAIT request if we have one, or try and
  2483. // issue an indication otherwise. This is only done if we're in a synchronized
  2484. // state and not in TIMED-WAIT.
  2485. //
  2486. // Input: DiscTCB - Pointer to TCB we're notifying.
  2487. // Status - Status code for notification.
  2488. //
  2489. // Returns: Nothing.
  2490. //
  2491. void
  2492. NotifyOfDisc(TCB * DiscTCB, IPOptInfo * DiscInfo, TDI_STATUS Status)
  2493. {
  2494. CTELockHandle TCBHandle, AOTHandle, ConnTHandle;
  2495. TCPConnReq *DiscReq;
  2496. TCPConn *Conn;
  2497. AddrObj *DiscAO;
  2498. PVOID ConnContext;
  2499. CTEStructAssert(DiscTCB, tcb);
  2500. ASSERT(DiscTCB->tcb_refcnt != 0);
  2501. CTEGetLock(&DiscTCB->tcb_lock, &TCBHandle);
  2502. if (SYNC_STATE(DiscTCB->tcb_state) &&
  2503. !(DiscTCB->tcb_flags & DISC_NOTIFIED)) {
  2504. // We can't notify him if there's still data to be taken.
  2505. if (Status == TDI_GRACEFUL_DISC && !OKToNotify(DiscTCB)) {
  2506. DiscTCB->tcb_flags |= DISC_PENDING;
  2507. CTEFreeLock(&DiscTCB->tcb_lock, TCBHandle);
  2508. return;
  2509. }
  2510. DiscTCB->tcb_flags |= DISC_NOTIFIED;
  2511. DiscTCB->tcb_flags &= ~DISC_PENDING;
  2512. // We're in a state where a disconnect is meaningful, and we haven't
  2513. // already notified the client.
  2514. // See if we have a DISC-WAIT request pending.
  2515. if ((DiscReq = DiscTCB->tcb_discwait) != NULL) {
  2516. // We have a disconnect wait request. Complete it and we're done.
  2517. DiscTCB->tcb_discwait = NULL;
  2518. CTEFreeLock(&DiscTCB->tcb_lock, TCBHandle);
  2519. (*DiscReq->tcr_req.tr_rtn) (DiscReq->tcr_req.tr_context, Status, 0);
  2520. FreeConnReq(DiscReq);
  2521. return;
  2522. }
  2523. // No DISC-WAIT. Find the AddrObj for the connection, and see if there
  2524. // is a disconnect handler registered.
  2525. ConnContext = DiscTCB->tcb_conncontext;
  2526. CTEFreeLock(&DiscTCB->tcb_lock, TCBHandle);
  2527. CTEGetLock(&AddrObjTableLock.Lock, &AOTHandle);
  2528. //CTEGetLock(&ConnTableLock, &ConnTHandle);
  2529. if ((Conn = DiscTCB->tcb_conn) != NULL) {
  2530. CTEGetLock(&(Conn->tc_ConnBlock->cb_lock), &ConnTHandle);
  2531. #if DBG
  2532. Conn->tc_ConnBlock->line = (uint) __LINE__;
  2533. Conn->tc_ConnBlock->module = (uchar *) __FILE__;
  2534. #endif
  2535. CTEStructAssert(Conn, tc);
  2536. DiscAO = Conn->tc_ao;
  2537. if (DiscAO != NULL) {
  2538. CTELockHandle AOHandle;
  2539. PDisconnectEvent DiscEvent;
  2540. PVOID DiscContext;
  2541. CTEStructAssert(DiscAO, ao);
  2542. CTEGetLock(&DiscAO->ao_lock, &AOHandle);
  2543. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), AOHandle);
  2544. CTEFreeLock(&AddrObjTableLock.Lock, ConnTHandle);
  2545. DiscEvent = DiscAO->ao_disconnect;
  2546. DiscContext = DiscAO->ao_disconncontext;
  2547. if (DiscEvent != NULL) {
  2548. uint InfoLength;
  2549. PVOID Info;
  2550. REF_AO(DiscAO);
  2551. CTEFreeLock(&DiscAO->ao_lock, AOTHandle);
  2552. if (DiscInfo != NULL) {
  2553. InfoLength = (uint) DiscInfo->ioi_optlength;
  2554. Info = DiscInfo->ioi_options;
  2555. } else {
  2556. InfoLength = 0;
  2557. Info = NULL;
  2558. }
  2559. IF_TCPDBG(TCP_DEBUG_CLOSE) {
  2560. TCPTRACE(("TCP: indicating %s disconnect\n",
  2561. (Status == TDI_GRACEFUL_DISC) ? "graceful" :
  2562. "abortive"
  2563. ));
  2564. }
  2565. (*DiscEvent) (DiscContext,
  2566. ConnContext, 0,
  2567. NULL, InfoLength, Info, (Status == TDI_GRACEFUL_DISC) ?
  2568. TDI_DISCONNECT_RELEASE : TDI_DISCONNECT_ABORT);
  2569. DELAY_DEREF_AO(DiscAO);
  2570. return;
  2571. } else {
  2572. CTEFreeLock(&DiscAO->ao_lock, AOTHandle);
  2573. return;
  2574. }
  2575. }
  2576. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), ConnTHandle);
  2577. }
  2578. CTEFreeLock(&AddrObjTableLock.Lock, AOTHandle);
  2579. return;
  2580. }
  2581. CTEFreeLock(&DiscTCB->tcb_lock, TCBHandle);
  2582. }
  2583. //* GracefulClose - Complete the transition to a gracefully closed state.
  2584. //
  2585. // Called when we need to complete the transition to a gracefully closed
  2586. // state, either TIME_WAIT or CLOSED. This completion involves removing
  2587. // the TCB from it's associated connection (if it has one), notifying the
  2588. // upper layer client either via completing a request or calling a disc.
  2589. // notification handler, and actually doing the transition.
  2590. //
  2591. // The tricky part here is if we need to notify him (instead of completing
  2592. // a graceful disconnect request). We can't notify him if there is pending
  2593. // data on the connection, so in that case we have to pend the disconnect
  2594. // notification until we deliver the data.
  2595. //
  2596. // Input: CloseTCB - TCB to transition.
  2597. // ToTimeWait - True if we're going to TIME_WAIT, False if
  2598. // we're going to close the TCB.
  2599. // Notify - True if we're going to transition via notification,
  2600. // False if we're going to transition by completing
  2601. // a disconnect request.
  2602. // Handle - Lock handle for TCB.
  2603. //
  2604. // Returns: Nothing.
  2605. //
  2606. void
  2607. GracefulClose(TCB * CloseTCB, uint ToTimeWait, uint Notify, CTELockHandle Handle)
  2608. {
  2609. CTEStructAssert(CloseTCB, tcb);
  2610. ASSERT(CloseTCB->tcb_refcnt != 0);
  2611. // First, see if we need to notify the client of a FIN.
  2612. if (Notify) {
  2613. #if DBG
  2614. if (CloseTCB->tcb_fastchk & TCP_FLAG_SEND_AND_DISC) {
  2615. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Notifying on S&D %x\n", CloseTCB));
  2616. DbgBreakPoint();
  2617. }
  2618. #endif
  2619. // We do need to notify him. See if it's OK to do so.
  2620. if (OKToNotify(CloseTCB)) {
  2621. // We can notify him. Change his state, pull him from the conn.,
  2622. // and notify him.
  2623. if (ToTimeWait) {
  2624. // Save the time we went into time wait, in case we need to
  2625. // scavenge.
  2626. //CloseTCB->tcb_alive = CTESystemUpTime();
  2627. CloseTCB->tcb_state = TCB_TIME_WAIT;
  2628. //take care rcvind if this is on delay q.
  2629. CloseTCB->tcb_rcvind = NULL;
  2630. CTEFreeLock(&CloseTCB->tcb_lock, Handle);
  2631. } else {
  2632. // He's going to close. Mark him as closing with TryToCloseTCB
  2633. // (he won't actually close since we have a ref. on him). We
  2634. // do this so that anyone touching him after we free the
  2635. // lock will fail.
  2636. TryToCloseTCB(CloseTCB, TDI_SUCCESS, Handle);
  2637. }
  2638. RemoveTCBFromConn(CloseTCB);
  2639. NotifyOfDisc(CloseTCB, NULL, TDI_GRACEFUL_DISC);
  2640. } else {
  2641. // Can't notify him now. Set the appropriate flags, and return.
  2642. CloseTCB->tcb_flags |= (GC_PENDING | (ToTimeWait ? TW_PENDING : 0));
  2643. DerefTCB(CloseTCB, Handle);
  2644. return;
  2645. }
  2646. } else {
  2647. // We're not notifying this guy, we just need to complete a conn. req.
  2648. // We need to check and see if he's been notified, and if not
  2649. // we'll complete the request and notify him later.
  2650. if ((CloseTCB->tcb_flags & DISC_NOTIFIED)
  2651. || (CloseTCB->tcb_fastchk & TCP_FLAG_SEND_AND_DISC)) {
  2652. // He's been notified.
  2653. if (ToTimeWait) {
  2654. // Save the time we went into time wait, in case we need to
  2655. // scavenge.
  2656. //CloseTCB->tcb_alive = CTESystemUpTime();
  2657. CloseTCB->tcb_state = TCB_TIME_WAIT;
  2658. CloseTCB->tcb_rcvind = NULL;
  2659. CTEFreeLock(&CloseTCB->tcb_lock, Handle);
  2660. } else {
  2661. // Mark him as closed. See comments above.
  2662. TryToCloseTCB(CloseTCB, TDI_SUCCESS, Handle);
  2663. }
  2664. RemoveTCBFromConn(CloseTCB);
  2665. CTEGetLock(&CloseTCB->tcb_lock, &Handle);
  2666. if (CloseTCB->tcb_fastchk & TCP_FLAG_SEND_AND_DISC) {
  2667. if (!EMPTYQ(&CloseTCB->tcb_sendq)) {
  2668. TCPReq *Req;
  2669. TCPSendReq *SendReq;
  2670. uint Result;
  2671. DEQUEUE(&CloseTCB->tcb_sendq, Req, TCPReq, tr_q);
  2672. CTEStructAssert(Req, tr);
  2673. SendReq = (TCPSendReq *) Req;
  2674. CTEStructAssert(SendReq, tsr);
  2675. ASSERT(SendReq->tsr_flags & TSR_FLAG_SEND_AND_DISC);
  2676. CTEFreeLock(&CloseTCB->tcb_lock, Handle);
  2677. // Decrement the initial reference put on the buffer when it was
  2678. // allocated. This reference would have been decremented if the
  2679. // send had been acknowledged, but then the send would not still
  2680. // be on the tcb_sendq.
  2681. SendReq->tsr_req.tr_status = TDI_SUCCESS;
  2682. Result = CTEInterlockedDecrementLong(&(SendReq->tsr_refcnt));
  2683. if (Result <= 1) {
  2684. // If we've sent directly from this send, NULL out the next
  2685. // pointer for the last buffer in the chain.
  2686. CloseTCB->tcb_flags |= DISC_NOTIFIED;
  2687. if (SendReq->tsr_lastbuf != NULL) {
  2688. NDIS_BUFFER_LINKAGE(SendReq->tsr_lastbuf) = NULL;
  2689. SendReq->tsr_lastbuf = NULL;
  2690. }
  2691. //KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"GC: Completing %x %x %x\n",
  2692. // SendReq, Req->tr_context, CloseTCB));
  2693. (*Req->tr_rtn) (Req->tr_context, TDI_SUCCESS, SendReq->tsr_size);
  2694. FreeSendReq(SendReq);
  2695. }
  2696. } else {
  2697. CTEFreeLock(&CloseTCB->tcb_lock, Handle);
  2698. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"S&D empty sendq %x\n", CloseTCB));
  2699. ASSERT(FALSE);
  2700. }
  2701. } else {
  2702. CompleteConnReq(CloseTCB, NULL, TDI_SUCCESS);
  2703. CTEFreeLock(&CloseTCB->tcb_lock, Handle);
  2704. }
  2705. } else {
  2706. // He hasn't been notified. He should be pending already.
  2707. ASSERT(CloseTCB->tcb_flags & DISC_PENDING);
  2708. CloseTCB->tcb_flags |= (GC_PENDING | (ToTimeWait ? TW_PENDING : 0));
  2709. CompleteConnReq(CloseTCB, NULL, TDI_SUCCESS);
  2710. DerefTCB(CloseTCB, Handle);
  2711. return;
  2712. }
  2713. }
  2714. // If we're going to TIME_WAIT, start the TIME_WAIT timer now.
  2715. // Otherwise close the TCB.
  2716. CTEGetLock(&CloseTCB->tcb_lock, &Handle);
  2717. if (!CLOSING(CloseTCB) && ToTimeWait) {
  2718. CTEFreeLock(&CloseTCB->tcb_lock, Handle);
  2719. RemoveConnFromTCB(CloseTCB);
  2720. //at this point ref_cnt should be 1
  2721. //tcb_pending should be 0
  2722. if (!RemoveAndInsert(CloseTCB)) {
  2723. ASSERT(0);
  2724. }
  2725. return;
  2726. }
  2727. DerefTCB(CloseTCB, Handle);
  2728. }
  2729. //* ConnCheckPassed - Check to see if we have exceeded the connect limit
  2730. //
  2731. // Called when a SYN is received to determine whether we will accept
  2732. // the incoming connection. If the is an empty slot or if the IPAddr
  2733. // is already in the table, we accept it.
  2734. //
  2735. // Input: Source Address of incoming connection
  2736. // Destination port of incoming connection
  2737. //
  2738. // Returns: TRUE is connect is to be accepted
  2739. // FALSE if connection is rejected
  2740. //
  2741. int
  2742. ConnCheckPassed(IPAddr Src, ulong Prt)
  2743. {
  2744. UNREFERENCED_PARAMETER(Src);
  2745. UNREFERENCED_PARAMETER(Prt);
  2746. return TRUE;
  2747. }
  2748. void
  2749. InitAddrChecks()
  2750. {
  2751. return;
  2752. }
  2753. //* EnumerateConnectionList - Enumerate Connection List database.
  2754. //
  2755. // This routine enumerates the contents of the connection limit database
  2756. //
  2757. // Input:
  2758. //
  2759. // Buffer - A pointer to a buffer into which to put
  2760. // the returned connection list entries.
  2761. //
  2762. // BufferSize - On input, the size in bytes of Buffer.
  2763. // On output, the number of bytes written.
  2764. //
  2765. // EntriesAvailable - On output, the total number of connection entries
  2766. // available in the database.
  2767. //
  2768. // Returns: A TDI status code:
  2769. //
  2770. // TDI_SUCCESS otherwise.
  2771. //
  2772. // NOTES:
  2773. //
  2774. // This routine acquires AddrObjTableLock.
  2775. //
  2776. // Entries written to output buffer are in host byte order.
  2777. //
  2778. void
  2779. EnumerateConnectionList(uchar * Buffer, ulong BufferSize,
  2780. ulong * EntriesReturned, ulong * EntriesAvailable)
  2781. {
  2782. UNREFERENCED_PARAMETER(Buffer);
  2783. UNREFERENCED_PARAMETER(BufferSize);
  2784. *EntriesAvailable = 0;
  2785. *EntriesReturned = 0;
  2786. return;
  2787. }
  2788. #pragma BEGIN_INIT
  2789. //* InitTCPConn - Initialize TCP connection management code.
  2790. //
  2791. // Called during init time to initialize our TCP connection mgmt..
  2792. //
  2793. // Input: Nothing.
  2794. //
  2795. // Returns: TRUE.
  2796. //
  2797. int
  2798. InitTCPConn(void)
  2799. {
  2800. TcpConnPool = PplCreatePool(
  2801. TcpConnAllocate,
  2802. TcpConnFree,
  2803. 0,
  2804. sizeof(TCPConn),
  2805. 'CPCT',
  2806. 0);
  2807. if (!TcpConnPool) {
  2808. return FALSE;
  2809. }
  2810. CTEInitLock(&ConnTableLock);
  2811. return TRUE;
  2812. }
  2813. //* UnInitTCPConn - Uninitialize our connection management code.
  2814. //
  2815. // Called if initialization fails to uninitialize our conn mgmet.
  2816. //
  2817. //
  2818. // Input: Nothing.
  2819. //
  2820. // Returns: Nothing.
  2821. //
  2822. void
  2823. UnInitTCPConn(void)
  2824. {
  2825. PplDestroyPool(TcpConnPool);
  2826. }
  2827. #pragma END_INIT