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

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