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.

976 lines
36 KiB

  1. // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil -*- (for GNU Emacs)
  2. //
  3. // Copyright (c) 1985-2000 Microsoft Corporation
  4. //
  5. // This file is part of the Microsoft Research IPv6 Network Protocol Stack.
  6. // You should have received a copy of the Microsoft End-User License Agreement
  7. // for this software along with this release; see the file "license.txt".
  8. // If not, please see http://www.research.microsoft.com/msripv6/license.htm,
  9. // or write to Microsoft Research, One Microsoft Way, Redmond, WA 98052-6399.
  10. //
  11. // Abstract:
  12. //
  13. // This file contains the code for dealing with TDI Query/Set
  14. // information calls.
  15. //
  16. #include "oscfg.h"
  17. #include "ndis.h"
  18. #include "ip6imp.h"
  19. #include "ip6def.h"
  20. #include "tdi.h"
  21. #include "tdint.h"
  22. #include "tdistat.h"
  23. #include "queue.h"
  24. #include "transprt.h"
  25. #include "addr.h"
  26. #include "tcp.h"
  27. #include "tcb.h"
  28. #include "tcpconn.h"
  29. #include "tdiinfo.h"
  30. #include "ndis.h"
  31. #include "info.h"
  32. #include "tdiinfo.h"
  33. #include "tcpcfg.h"
  34. #include "udp.h"
  35. #include "tcpsend.h"
  36. extern long
  37. IPv6QueryInfo(TDIObjectID * ID, PNDIS_BUFFER Buffer, uint * Size,
  38. void *Context, uint ContextSize);
  39. #ifndef UDP_ONLY
  40. #define MY_SERVICE_FLAGS (TDI_SERVICE_CONNECTION_MODE | \
  41. TDI_SERVICE_ORDERLY_RELEASE | \
  42. TDI_SERVICE_CONNECTIONLESS_MODE | \
  43. TDI_SERVICE_ERROR_FREE_DELIVERY | \
  44. TDI_SERVICE_BROADCAST_SUPPORTED | \
  45. TDI_SERVICE_DELAYED_ACCEPTANCE | \
  46. TDI_SERVICE_EXPEDITED_DATA | \
  47. TDI_SERVICE_FORCE_ACCESS_CHECK | \
  48. TDI_SERVICE_ACCEPT_LOCAL_ADDR | \
  49. TDI_SERVICE_NO_ZERO_LENGTH | \
  50. TDI_SERVICE_ADDRESS_SECURITY)
  51. #else
  52. #define MY_SERVICE_FLAGS (TDI_SERVICE_CONNECTIONLESS_MODE | \
  53. TDI_SERVICE_BROADCAST_SUPPORTED)
  54. #endif
  55. extern LARGE_INTEGER StartTime;
  56. extern KSPIN_LOCK AddrObjTableLock;
  57. #ifndef UDP_ONLY
  58. TCPStats TStats;
  59. #endif
  60. UDPStats UStats;
  61. struct ReadTableStruct {
  62. uint (*rts_validate)(void *Context, uint *Valid);
  63. uint (*rts_readnext)(void *Context, void *OutBuf);
  64. };
  65. struct ReadTableStruct ReadAOTable = {ValidateAOContext, ReadNextAO};
  66. #ifndef UDP_ONLY
  67. struct ReadTableStruct ReadTCBTable = {ValidateTCBContext, ReadNextTCB};
  68. extern KSPIN_LOCK TCBTableLock;
  69. #endif
  70. extern KSPIN_LOCK AddrObjTableLock;
  71. struct TDIEntityID *EntityList;
  72. uint EntityCount;
  73. //* TdiQueryInformation - Query Information handler.
  74. //
  75. // The TDI QueryInformation routine. Called when the client wants to
  76. // query information on a connection, the provider as a whole, or to
  77. // get statistics.
  78. //
  79. TDI_STATUS // Returns: Status of attempt to query information.
  80. TdiQueryInformation(
  81. PTDI_REQUEST Request, // Request structure for this command.
  82. uint QueryType, // Type of query to be performed.
  83. PNDIS_BUFFER Buffer, // Buffer to place data info.
  84. uint *BufferSize, // Pointer to size in bytes of buffer.
  85. // On return, filled in with number of bytes copied.
  86. uint IsConn) // Valid only for TDI_QUERY_ADDRESS_INFO. TRUE if
  87. // we are querying the address info on a connection.
  88. {
  89. union {
  90. TDI_CONNECTION_INFO ConnInfo;
  91. TDI_ADDRESS_INFO AddrInfo;
  92. TDI_PROVIDER_INFO ProviderInfo;
  93. TDI_PROVIDER_STATISTICS ProviderStats;
  94. } InfoBuf;
  95. uint InfoSize;
  96. KIRQL Irql0, Irql1, Irql2; // One per lock nesting level.
  97. #ifndef UDP_ONLY
  98. TCPConn *Conn;
  99. TCB *InfoTCB;
  100. #endif
  101. AddrObj *InfoAO;
  102. void *InfoPtr = NULL;
  103. uint Offset;
  104. uint Size;
  105. uint BytesCopied;
  106. switch (QueryType) {
  107. case TDI_QUERY_BROADCAST_ADDRESS:
  108. return TDI_INVALID_QUERY;
  109. break;
  110. case TDI_QUERY_PROVIDER_INFO:
  111. InfoBuf.ProviderInfo.Version = 0x100;
  112. #ifndef UDP_ONLY
  113. InfoBuf.ProviderInfo.MaxSendSize = 0xffffffff;
  114. #else
  115. InfoBuf.ProviderInfo.MaxSendSize = 0;
  116. #endif
  117. InfoBuf.ProviderInfo.MaxConnectionUserData = 0;
  118. InfoBuf.ProviderInfo.MaxDatagramSize = 0xffff - sizeof(UDPHeader);
  119. InfoBuf.ProviderInfo.ServiceFlags = MY_SERVICE_FLAGS;
  120. InfoBuf.ProviderInfo.MinimumLookaheadData = 1;
  121. InfoBuf.ProviderInfo.MaximumLookaheadData = 0xffff;
  122. InfoBuf.ProviderInfo.NumberOfResources = 0;
  123. InfoBuf.ProviderInfo.StartTime = StartTime;
  124. InfoSize = sizeof(TDI_PROVIDER_INFO);
  125. InfoPtr = &InfoBuf.ProviderInfo;
  126. break;
  127. case TDI_QUERY_ADDRESS_INFO:
  128. InfoSize = sizeof(TDI_ADDRESS_INFO) - sizeof(TRANSPORT_ADDRESS) +
  129. TCP_TA_SIZE;
  130. RtlZeroMemory(&InfoBuf.AddrInfo, TCP_TA_SIZE);
  131. //
  132. // Since noone knows what this means, we'll set it to one.
  133. //
  134. InfoBuf.AddrInfo.ActivityCount = 1;
  135. if (IsConn) {
  136. #ifdef UDP_ONLY
  137. return TDI_INVALID_QUERY;
  138. #else
  139. KeAcquireSpinLock(&AddrObjTableLock, &Irql0);
  140. Conn = GetConnFromConnID(
  141. PtrToUlong(Request->Handle.ConnectionContext), &Irql1);
  142. if (Conn != NULL) {
  143. CHECK_STRUCT(Conn, tc);
  144. InfoTCB = Conn->tc_tcb;
  145. // If we have a TCB we'll return information about that TCB.
  146. // Otherwise we'll return info about the address object.
  147. if (InfoTCB != NULL) {
  148. CHECK_STRUCT(InfoTCB, tcb);
  149. KeAcquireSpinLock(&InfoTCB->tcb_lock, &Irql2);
  150. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql2);
  151. KeReleaseSpinLock(&AddrObjTableLock, Irql1);
  152. BuildTDIAddress((uchar *)&InfoBuf.AddrInfo.Address,
  153. &InfoTCB->tcb_saddr,
  154. InfoTCB->tcb_sscope_id,
  155. InfoTCB->tcb_sport);
  156. KeReleaseSpinLock(&InfoTCB->tcb_lock, Irql0);
  157. InfoPtr = &InfoBuf.AddrInfo;
  158. break;
  159. } else {
  160. // No TCB, return info on the AddrObj.
  161. InfoAO = Conn->tc_ao;
  162. if (InfoAO != NULL) {
  163. // We have an AddrObj.
  164. CHECK_STRUCT(InfoAO, ao);
  165. KeAcquireSpinLock(&InfoAO->ao_lock, &Irql2);
  166. BuildTDIAddress((uchar *)&InfoBuf.AddrInfo.Address,
  167. &InfoAO->ao_addr,
  168. InfoAO->ao_scope_id,
  169. InfoAO->ao_port);
  170. KeReleaseSpinLock(&InfoAO->ao_lock, Irql2);
  171. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql1);
  172. KeReleaseSpinLock(&AddrObjTableLock, Irql0);
  173. InfoPtr = &InfoBuf.AddrInfo;
  174. break;
  175. } else
  176. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql1);
  177. }
  178. }
  179. //
  180. // Fall through to here when we can't find the connection, or
  181. // the connection isn't associated.
  182. //
  183. KeReleaseSpinLock(&AddrObjTableLock, Irql0);
  184. return TDI_INVALID_CONNECTION;
  185. break;
  186. #endif
  187. } else {
  188. // Asking for information on an addr. object.
  189. InfoAO = Request->Handle.AddressHandle;
  190. if (InfoAO == NULL)
  191. return TDI_ADDR_INVALID;
  192. CHECK_STRUCT(InfoAO, ao);
  193. KeAcquireSpinLock(&InfoAO->ao_lock, &Irql0);
  194. if (!AO_VALID(InfoAO)) {
  195. KeReleaseSpinLock(&InfoAO->ao_lock, Irql0);
  196. return TDI_ADDR_INVALID;
  197. }
  198. BuildTDIAddress((uchar *)&InfoBuf.AddrInfo.Address,
  199. &InfoAO->ao_addr, InfoAO->ao_scope_id,
  200. InfoAO->ao_port);
  201. KeReleaseSpinLock(&InfoAO->ao_lock, Irql0);
  202. InfoPtr = &InfoBuf.AddrInfo;
  203. break;
  204. }
  205. break;
  206. case TDI_QUERY_CONNECTION_INFO:
  207. #ifndef UDP_ONLY
  208. InfoSize = sizeof(TDI_CONNECTION_INFO);
  209. Conn = GetConnFromConnID(PtrToUlong(Request->Handle.ConnectionContext),
  210. &Irql0);
  211. if (Conn != NULL) {
  212. CHECK_STRUCT(Conn, tc);
  213. InfoTCB = Conn->tc_tcb;
  214. // If we have a TCB we'll return the information.
  215. // Otherwise we'll error out.
  216. if (InfoTCB != NULL) {
  217. CHECK_STRUCT(InfoTCB, tcb);
  218. KeAcquireSpinLock(&InfoTCB->tcb_lock, &Irql1);
  219. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql1);
  220. RtlZeroMemory(&InfoBuf.ConnInfo, sizeof(TDI_CONNECTION_INFO));
  221. InfoBuf.ConnInfo.State = (ulong)InfoTCB->tcb_state;
  222. // IPv4 code called down into IP here to get PathBPS
  223. // for InfoTCB's saddr, daddr pair.
  224. InfoBuf.ConnInfo.Throughput.LowPart = 0xFFFFFFFF;
  225. InfoBuf.ConnInfo.Throughput.HighPart = 0xFFFFFFFF;
  226. // To figure the delay we use the rexmit timeout. Our
  227. // rexmit timeout is roughly the round trip time plus
  228. // some slop, so we use half of that as the one way delay.
  229. InfoBuf.ConnInfo.Delay.LowPart =
  230. (REXMIT_TO(InfoTCB) * MS_PER_TICK) / 2;
  231. InfoBuf.ConnInfo.Delay.HighPart = 0;
  232. //
  233. // Convert milliseconds to 100ns and negate for relative
  234. // time.
  235. //
  236. InfoBuf.ConnInfo.Delay = RtlExtendedIntegerMultiply(
  237. InfoBuf.ConnInfo.Delay, 10000);
  238. ASSERT(InfoBuf.ConnInfo.Delay.HighPart == 0);
  239. InfoBuf.ConnInfo.Delay.QuadPart =
  240. -InfoBuf.ConnInfo.Delay.QuadPart;
  241. KeReleaseSpinLock(&InfoTCB->tcb_lock, Irql0);
  242. InfoPtr = &InfoBuf.ConnInfo;
  243. break;
  244. } else
  245. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql0);
  246. }
  247. //
  248. // Come through here if we can't find the connection
  249. // or it has no TCB.
  250. //
  251. return TDI_INVALID_CONNECTION;
  252. break;
  253. #else // UDP_ONLY
  254. return TDI_INVALID_QUERY;
  255. break;
  256. #endif // UDP_ONLY
  257. case TDI_QUERY_PROVIDER_STATISTICS:
  258. RtlZeroMemory(&InfoBuf.ProviderStats, sizeof(TDI_PROVIDER_STATISTICS));
  259. InfoBuf.ProviderStats.Version = 0x100;
  260. InfoSize = sizeof(TDI_PROVIDER_STATISTICS);
  261. InfoPtr = &InfoBuf.ProviderStats;
  262. break;
  263. default:
  264. return TDI_INVALID_QUERY;
  265. break;
  266. }
  267. // When we get here, we've got the pointers set up and the information
  268. // filled in.
  269. ASSERT(InfoPtr != NULL);
  270. Offset = 0;
  271. Size = *BufferSize;
  272. (void)CopyFlatToNdis(Buffer, InfoPtr, MIN(InfoSize, Size), &Offset,
  273. &BytesCopied);
  274. if (Size < InfoSize)
  275. return TDI_BUFFER_OVERFLOW;
  276. else {
  277. *BufferSize = InfoSize;
  278. return TDI_SUCCESS;
  279. }
  280. }
  281. //* TdiSetInformation - Set Information handler.
  282. //
  283. // The TDI SetInformation routine. Currently we don't allow anything to be
  284. // set.
  285. //
  286. TDI_STATUS // Returns: Status of attempt to set information.
  287. TdiSetInformation(
  288. PTDI_REQUEST Request, // Request structure for this command.
  289. uint SetType, // Type of set to be performed.
  290. PNDIS_BUFFER Buffer, // Buffer to set from.
  291. uint BufferSize, // Size in bytes of buffer.
  292. uint IsConn) // Valid only for TDI_QUERY_ADDRESS_INFO. TRUE if
  293. // we are setting the address info on a connection.
  294. {
  295. UNREFERENCED_PARAMETER(Request);
  296. UNREFERENCED_PARAMETER(SetType);
  297. UNREFERENCED_PARAMETER(Buffer);
  298. UNREFERENCED_PARAMETER(BufferSize);
  299. UNREFERENCED_PARAMETER(IsConn);
  300. return TDI_INVALID_REQUEST;
  301. }
  302. //* TdiAction - Action handler.
  303. //
  304. // The TDI Action routine. Currently we don't support any actions.
  305. //
  306. TDI_STATUS // Returns: Status of attempt to perform action.
  307. TdiAction(
  308. PTDI_REQUEST Request, // Request structure for this command.
  309. uint ActionType, // Type of action to be performed.
  310. PNDIS_BUFFER Buffer, // Buffer of action info.
  311. uint BufferSize) // Size in bytes of buffer.
  312. {
  313. UNREFERENCED_PARAMETER(Request);
  314. UNREFERENCED_PARAMETER(ActionType);
  315. UNREFERENCED_PARAMETER(Buffer);
  316. UNREFERENCED_PARAMETER(BufferSize);
  317. return TDI_INVALID_REQUEST;
  318. }
  319. //* CopyAO_TCPConn - Copy listening endpoints into connection table.
  320. //
  321. int
  322. CopyAO_TCPConn(
  323. const AddrObj *AO, // Address object to possibly copy.
  324. TCP6ConnTableEntry *Buffer) // Output buffer to fill in.
  325. {
  326. if (AO == NULL)
  327. return 0;
  328. if ((!AO->ao_listencnt) && (AO->ao_prot == IP_PROTOCOL_TCP)) {
  329. Buffer->tct_state = TCP_CONN_LISTEN;
  330. // else if .. other cases can be added here ...
  331. } else {
  332. return 0;
  333. }
  334. Buffer->tct_localaddr = AO->ao_addr;
  335. Buffer->tct_localscopeid = AO->ao_scope_id;
  336. Buffer->tct_localport = AO->ao_port;
  337. RtlZeroMemory(&Buffer->tct_remoteaddr, sizeof(Buffer->tct_remoteaddr));
  338. Buffer->tct_remoteport = (ULONG) ((ULONG_PTR) AO & 0x0000ffff);
  339. Buffer->tct_remotescopeid = 0;
  340. Buffer->tct_owningpid = AO->ao_owningpid;
  341. return 1;
  342. }
  343. //* TdiQueryInformationEx - Extended TDI query information.
  344. //
  345. // This is the new TDI query information handler. We take in a TDIObjectID
  346. // structure, a buffer and length, and some context information, and return
  347. // the requested information if possible.
  348. //
  349. TDI_STATUS // Returns: Status of attempt to get information.
  350. TdiQueryInformationEx(
  351. PTDI_REQUEST Request, // Request structure for this command.
  352. TDIObjectID *ID, // Object ID.
  353. PNDIS_BUFFER Buffer, // Buffer to be filled in.
  354. uint *Size, // Pointer to size in bytes of Buffer.
  355. // On return, filled with number of bytes written.
  356. void *Context, // Context buffer.
  357. uint ContextSize) // Size of context buffer.
  358. {
  359. uint BufferSize = *Size;
  360. uint InfoSize;
  361. void *InfoPtr;
  362. uint Fixed;
  363. KIRQL Irql0 = 0, Irql1;
  364. KSPIN_LOCK *AOLockPtr = NULL;
  365. uint Offset = 0;
  366. uchar InfoBuffer[sizeof(TCP6ConnTableEntry)];
  367. uint BytesRead;
  368. uint Valid;
  369. uint Entity;
  370. uint BytesCopied;
  371. TCPStats TCPStatsListen;
  372. BOOLEAN TABLELOCK = FALSE;
  373. int lcount;
  374. AddrObj *pAO;
  375. TCP6ConnTableEntry tcp_ce;
  376. uint Index;
  377. int InfoTcpConn = 0; // true if tcp conn info needed.
  378. // First check to see if he's querying for list of entities.
  379. Entity = ID->toi_entity.tei_entity;
  380. if (Entity == GENERIC_ENTITY) {
  381. *Size = 0;
  382. if (ID->toi_class != INFO_CLASS_GENERIC ||
  383. ID->toi_type != INFO_TYPE_PROVIDER ||
  384. ID->toi_id != ENTITY_LIST_ID) {
  385. return TDI_INVALID_PARAMETER;
  386. }
  387. // Make sure we have room for it the list in the buffer.
  388. InfoSize = EntityCount * sizeof(TDIEntityID);
  389. if (BufferSize < InfoSize) {
  390. // Not enough room.
  391. return TDI_BUFFER_TOO_SMALL;
  392. }
  393. *Size = InfoSize;
  394. // Copy it in, free our temp. buffer, and return success.
  395. (void)CopyFlatToNdis(Buffer, (uchar *)EntityList, InfoSize, &Offset,
  396. &BytesCopied);
  397. return TDI_SUCCESS;
  398. }
  399. //* Check the level. If it can't be for us, pass it down.
  400. #ifndef UDP_ONLY
  401. if (Entity != CO_TL_ENTITY && Entity != CL_TL_ENTITY) {
  402. #else
  403. if (Entity != CL_TL_ENTITY) {
  404. #endif
  405. // When we support multiple lower entities at this layer we'll have
  406. // to figure out which one to dispatch to. For now, just pass it
  407. // straight down.
  408. return IPv6QueryInfo(ID, Buffer, Size, Context, ContextSize);
  409. }
  410. if (ID->toi_entity.tei_instance != TL_INSTANCE) {
  411. // We only support a single instance.
  412. return TDI_INVALID_REQUEST;
  413. }
  414. // Zero returned parameters in case of an error below.
  415. *Size = 0;
  416. if (ID->toi_class == INFO_CLASS_GENERIC) {
  417. // This is a generic request.
  418. if (ID->toi_type == INFO_TYPE_PROVIDER &&
  419. ID->toi_id == ENTITY_TYPE_ID) {
  420. if (BufferSize >= sizeof(uint)) {
  421. *(uint *)&InfoBuffer[0] = (Entity == CO_TL_ENTITY) ? CO_TL_TCP
  422. : CL_TL_UDP;
  423. (void)CopyFlatToNdis(Buffer, InfoBuffer, sizeof(uint), &Offset,
  424. &BytesCopied);
  425. return TDI_SUCCESS;
  426. } else
  427. return TDI_BUFFER_TOO_SMALL;
  428. }
  429. return TDI_INVALID_PARAMETER;
  430. }
  431. if (ID->toi_class == INFO_CLASS_PROTOCOL) {
  432. // Handle protocol specific class of information. For us, this is
  433. // the MIB-2 stuff or the minimal stuff we do for oob_inline support.
  434. #ifndef UDP_ONLY
  435. if (ID->toi_type == INFO_TYPE_CONNECTION) {
  436. TCPConn *Conn;
  437. TCB *QueryTCB;
  438. TCPSocketAMInfo *AMInfo;
  439. if (BufferSize < sizeof(TCPSocketAMInfo) ||
  440. ID->toi_id != TCP_SOCKET_ATMARK)
  441. return TDI_INVALID_PARAMETER;
  442. AMInfo = (TCPSocketAMInfo *)InfoBuffer;
  443. Conn = GetConnFromConnID(
  444. PtrToUlong(Request->Handle.ConnectionContext), &Irql0);
  445. if (Conn != NULL) {
  446. CHECK_STRUCT(Conn, tc);
  447. QueryTCB = Conn->tc_tcb;
  448. if (QueryTCB != NULL) {
  449. CHECK_STRUCT(QueryTCB, tcb);
  450. KeAcquireSpinLock(&QueryTCB->tcb_lock, &Irql1);
  451. if ((QueryTCB->tcb_flags & (URG_INLINE | URG_VALID)) ==
  452. (URG_INLINE | URG_VALID)) {
  453. // We're in inline mode, and the urgent data fields are
  454. // valid.
  455. AMInfo->tsa_size = QueryTCB->tcb_urgend -
  456. QueryTCB->tcb_urgstart + 1;
  457. // Rcvnext - pendingcnt is the sequence number of the
  458. // next byte of data that will be delivered to the
  459. // client. Urgend - that value is the offset in the
  460. // data stream of the end of urgent data.
  461. AMInfo->tsa_offset = QueryTCB->tcb_urgend -
  462. (QueryTCB->tcb_rcvnext - QueryTCB->tcb_pendingcnt);
  463. } else {
  464. AMInfo->tsa_size = 0;
  465. AMInfo->tsa_offset = 0;
  466. }
  467. KeReleaseSpinLock(&QueryTCB->tcb_lock, Irql1);
  468. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql0);
  469. *Size = sizeof(TCPSocketAMInfo);
  470. CopyFlatToNdis(Buffer, InfoBuffer, sizeof(TCPSocketAMInfo),
  471. &Offset, &BytesCopied);
  472. return TDI_SUCCESS;
  473. } else
  474. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql0);
  475. }
  476. return TDI_INVALID_PARAMETER;
  477. }
  478. #endif
  479. if (ID->toi_type != INFO_TYPE_PROVIDER)
  480. return TDI_INVALID_PARAMETER;
  481. switch (ID->toi_id) {
  482. case UDP_MIB_STAT_ID:
  483. #if UDP_MIB_STAT_ID != TCP_MIB_STAT_ID
  484. case TCP_MIB_STAT_ID:
  485. #endif
  486. Fixed = TRUE;
  487. if (Entity == CL_TL_ENTITY) {
  488. InfoSize = sizeof(UDPStats);
  489. InfoPtr = &UStats;
  490. } else {
  491. #ifndef UDP_ONLY
  492. TCPStatsListen = TStats;
  493. InfoSize = sizeof(TCPStatsListen);
  494. InfoPtr = &TCPStatsListen;
  495. lcount = 0;
  496. KeAcquireSpinLock(&AddrObjTableLock, &Irql0);
  497. for (Index = 0; Index < AddrObjTableSize; Index++) {
  498. pAO = AddrObjTable[Index];
  499. while (pAO) {
  500. lcount += CopyAO_TCPConn(pAO,
  501. &tcp_ce);
  502. pAO = pAO->ao_next;
  503. }
  504. }
  505. KeReleaseSpinLock(&AddrObjTableLock, Irql0);
  506. TCPStatsListen.ts_numconns += lcount;
  507. #else
  508. return TDI_INVALID_PARAMETER;
  509. #endif
  510. }
  511. break;
  512. case UDP_EX_TABLE_ID:
  513. #if UDP_EX_TABLE_ID != TCP_EX_TABLE_ID
  514. case TCP_EX_TABLE_ID:
  515. #endif
  516. Fixed = FALSE;
  517. if (Entity == CL_TL_ENTITY) {
  518. InfoSize = sizeof(UDP6ListenerEntry);
  519. InfoPtr = &ReadAOTable;
  520. KeAcquireSpinLock(&AddrObjTableLock, &Irql0);
  521. AOLockPtr = &AddrObjTableLock;
  522. } else {
  523. #ifndef UDP_ONLY
  524. InfoSize = sizeof(TCP6ConnTableEntry);
  525. InfoTcpConn = 1;
  526. InfoPtr = &ReadTCBTable;
  527. TABLELOCK = TRUE;
  528. KeAcquireSpinLock(&TCBTableLock, &Irql0);
  529. #else
  530. return TDI_INVALID_PARAMETER;
  531. #endif
  532. }
  533. break;
  534. default:
  535. return TDI_INVALID_PARAMETER;
  536. break;
  537. }
  538. if (Fixed) {
  539. if (BufferSize < InfoSize)
  540. return TDI_BUFFER_TOO_SMALL;
  541. *Size = InfoSize;
  542. (void)CopyFlatToNdis(Buffer, InfoPtr, InfoSize, &Offset,
  543. &BytesCopied);
  544. return TDI_SUCCESS;
  545. } else {
  546. struct ReadTableStruct *RTSPtr;
  547. uint ReadStatus;
  548. // Have a variable length (or mult-instance) structure to copy.
  549. // InfoPtr points to the structure describing the routines to
  550. // call to read the table.
  551. // Loop through up to CountWanted times, calling the routine
  552. // each time.
  553. BytesRead = 0;
  554. RTSPtr = InfoPtr;
  555. ReadStatus = (*(RTSPtr->rts_validate))(Context, &Valid);
  556. // If we successfully read something we'll continue. Otherwise
  557. // we'll bail out.
  558. if (!Valid) {
  559. if (TABLELOCK)
  560. KeReleaseSpinLock(&TCBTableLock, Irql0);
  561. if (AOLockPtr)
  562. KeReleaseSpinLock(AOLockPtr, Irql0);
  563. return TDI_INVALID_PARAMETER;
  564. }
  565. while (ReadStatus) {
  566. // The invariant here is that there is data in the table to
  567. // read. We may or may not have room for it. So ReadStatus
  568. // is TRUE, and BufferSize - BytesRead is the room left
  569. // in the buffer.
  570. if ((int)(BufferSize - BytesRead) >= (int)InfoSize) {
  571. ReadStatus = (*(RTSPtr->rts_readnext))(Context,
  572. InfoBuffer);
  573. BytesRead += InfoSize;
  574. Buffer = CopyFlatToNdis(Buffer, InfoBuffer, InfoSize,
  575. &Offset, &BytesCopied);
  576. } else
  577. break;
  578. }
  579. if (TABLELOCK)
  580. KeReleaseSpinLock(&TCBTableLock, Irql0);
  581. if ((!ReadStatus) && InfoTcpConn) {
  582. if (!AOLockPtr) {
  583. KeAcquireSpinLock(&AddrObjTableLock, &Irql0);
  584. AOLockPtr = &AddrObjTableLock;
  585. }
  586. for (Index = 0; Index < AddrObjTableSize; Index++) {
  587. pAO = AddrObjTable[Index];
  588. while (pAO) {
  589. if (BufferSize < (BytesRead + InfoSize)) {
  590. goto no_more_ao;
  591. }
  592. if (CopyAO_TCPConn(pAO, &tcp_ce)) {
  593. ASSERT(BufferSize >= BytesRead);
  594. Buffer = CopyFlatToNdis(Buffer, (void *)&tcp_ce,
  595. InfoSize,
  596. &Offset, &BytesCopied);
  597. BytesRead += InfoSize;
  598. ASSERT(BufferSize >= BytesRead);
  599. }
  600. pAO = pAO->ao_next;
  601. }
  602. }
  603. no_more_ao:;
  604. }
  605. if (AOLockPtr)
  606. KeReleaseSpinLock(AOLockPtr, Irql0);
  607. *Size = BytesRead;
  608. return (!ReadStatus ? TDI_SUCCESS : TDI_BUFFER_OVERFLOW);
  609. }
  610. }
  611. if (ID->toi_class == INFO_CLASS_IMPLEMENTATION) {
  612. // We want to return implementation specific info. For now, error out.
  613. return TDI_INVALID_PARAMETER;
  614. }
  615. return TDI_INVALID_PARAMETER;
  616. }
  617. //* TdiSetInfoEx - Extended TDI set information.
  618. //
  619. // This is the new TDI set information handler. We take in a TDIObjectID
  620. // structure, a buffer and length. We set the object specifed by the ID
  621. // (and possibly by the Request) to the value specified in the buffer.
  622. //
  623. TDI_STATUS // Returns: Status of attempt to get information.
  624. TdiSetInformationEx(
  625. PTDI_REQUEST Request, // Request structure for this command.
  626. TDIObjectID *ID, // Object ID.
  627. void *Buffer, // Buffer containing value to set.
  628. uint Size) // Size in bytes of Buffer.
  629. {
  630. TCP6ConnTableEntry *TCPEntry;
  631. KIRQL Irql0, Irql1; // One per lock nesting level.
  632. #ifndef UDP_ONLY
  633. TCB *SetTCB;
  634. TCPConn *Conn;
  635. #endif
  636. uint Entity;
  637. TDI_STATUS Status;
  638. // Check the level. If it can't be for us, pass it down.
  639. Entity = ID->toi_entity.tei_entity;
  640. if (Entity != CO_TL_ENTITY && Entity != CL_TL_ENTITY) {
  641. // Someday we'll have to figure out how to dispatch.
  642. // For now, just pass it down.
  643. // IPv4 code passed the set info request down to IP here.
  644. // Our IPv6 code is not configured this way.
  645. return TDI_INVALID_REQUEST;
  646. }
  647. if (ID->toi_entity.tei_instance != TL_INSTANCE)
  648. return TDI_INVALID_REQUEST;
  649. if (ID->toi_class == INFO_CLASS_GENERIC) {
  650. // Fill this in when we have generic class defines.
  651. return TDI_INVALID_PARAMETER;
  652. }
  653. // Now look at the rest of it.
  654. if (ID->toi_class == INFO_CLASS_PROTOCOL) {
  655. // Handle protocol specific class of information. For us, this is
  656. // the MIB-2 stuff, as well as common sockets options,
  657. // and in particular the setting of the state of a TCP connection.
  658. if (ID->toi_type == INFO_TYPE_CONNECTION) {
  659. TCPSocketOption *Option;
  660. uint Flag;
  661. uint Value;
  662. #ifndef UDP_ONLY
  663. // A connection type. Get the connection, and then figure out
  664. // what to do with it.
  665. Status = TDI_INVALID_PARAMETER;
  666. if (Size < sizeof(TCPSocketOption))
  667. return Status;
  668. Conn = GetConnFromConnID(
  669. PtrToUlong(Request->Handle.ConnectionContext), &Irql0);
  670. if (Conn != NULL) {
  671. CHECK_STRUCT(Conn, tc);
  672. Status = TDI_SUCCESS;
  673. if (ID->toi_id == TCP_SOCKET_WINDOW) {
  674. // This is a funny option, because it doesn't involve
  675. // flags. Handle this specially.
  676. Option = (TCPSocketOption *)Buffer;
  677. // We don't allow anyone to shrink the window, as this
  678. // gets too weird from a protocol point of view. Also,
  679. // make sure they don't try and set anything too big.
  680. if (Option->tso_value > 0xffff)
  681. Status = TDI_INVALID_PARAMETER;
  682. else if (Option->tso_value > Conn->tc_window ||
  683. Conn->tc_tcb == NULL) {
  684. Conn->tc_flags |= CONN_WINSET;
  685. Conn->tc_window = Option->tso_value;
  686. SetTCB = Conn->tc_tcb;
  687. if (SetTCB != NULL) {
  688. CHECK_STRUCT(SetTCB, tcb);
  689. KeAcquireSpinLock(&SetTCB->tcb_lock, &Irql1);
  690. ASSERT(Option->tso_value > SetTCB->tcb_defaultwin);
  691. if (DATA_RCV_STATE(SetTCB->tcb_state) &&
  692. !CLOSING(SetTCB)) {
  693. SetTCB->tcb_flags |= WINDOW_SET;
  694. SetTCB->tcb_defaultwin = Option->tso_value;
  695. SetTCB->tcb_refcnt++;
  696. KeReleaseSpinLock(&SetTCB->tcb_lock, Irql1);
  697. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock,
  698. Irql0);
  699. SendACK(SetTCB);
  700. KeAcquireSpinLock(&SetTCB->tcb_lock, &Irql1);
  701. DerefTCB(SetTCB, Irql1);
  702. return Status;
  703. } else {
  704. KeReleaseSpinLock(&SetTCB->tcb_lock, Irql1);
  705. }
  706. }
  707. }
  708. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql0);
  709. return Status;
  710. }
  711. Flag = 0;
  712. if (ID->toi_id == TCP_SOCKET_KEEPALIVE_VALS) {
  713. TCPKeepalive *KAOption;
  714. // treat it as separate as it takes a structure instead of integer
  715. if (Size < sizeof(TCPKeepalive)) {
  716. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql0);
  717. // The IPv4 code returns success here.
  718. return TDI_INVALID_PARAMETER;
  719. }
  720. KAOption = (TCPKeepalive *) Buffer;
  721. Value = KAOption->onoff;
  722. if (Value) {
  723. Conn->tc_tcbkatime = MS_TO_TICKS(KAOption->keepalivetime);
  724. Conn->tc_tcbkainterval = MS_TO_TICKS(KAOption->keepaliveinterval);
  725. }
  726. Flag = KEEPALIVE;
  727. } else {
  728. Option = (TCPSocketOption *)Buffer;
  729. Value = Option->tso_value;
  730. // We have the connection, so figure out which flag to set.
  731. switch (ID->toi_id) {
  732. case TCP_SOCKET_NODELAY:
  733. Value = !Value;
  734. Flag = NAGLING;
  735. break;
  736. case TCP_SOCKET_KEEPALIVE:
  737. Flag = KEEPALIVE;
  738. Conn->tc_tcbkatime = KeepAliveTime;
  739. Conn->tc_tcbkainterval = KAInterval;
  740. break;
  741. case TCP_SOCKET_BSDURGENT:
  742. Flag = BSD_URGENT;
  743. break;
  744. case TCP_SOCKET_OOBINLINE:
  745. Flag = URG_INLINE;
  746. break;
  747. default:
  748. Status = TDI_INVALID_PARAMETER;
  749. break;
  750. }
  751. }
  752. if (Status == TDI_SUCCESS) {
  753. if (Value)
  754. Conn->tc_tcbflags |= Flag;
  755. else
  756. Conn->tc_tcbflags &= ~Flag;
  757. SetTCB = Conn->tc_tcb;
  758. if (SetTCB != NULL) {
  759. CHECK_STRUCT(SetTCB, tcb);
  760. KeAcquireSpinLock(&SetTCB->tcb_lock, &Irql1);
  761. if ((ID->toi_id == TCP_SOCKET_OOBINLINE ||
  762. ID->toi_id == TCP_SOCKET_BSDURGENT) &&
  763. ((SetTCB->tcb_flags & URG_VALID) ||
  764. (SetTCB->tcb_fastchk & TCP_FLAG_IN_RCV))) {
  765. // Don't allow switching to and from inline mode
  766. // while we have urgent data outstanding or
  767. // while we're processing receives.
  768. Status = TDI_INVALID_STATE;
  769. } else if (Value)
  770. SetTCB->tcb_flags |= Flag;
  771. else
  772. SetTCB->tcb_flags &= ~Flag;
  773. if ((ID->toi_id == TCP_SOCKET_KEEPALIVE) ||
  774. (ID->toi_id == TCP_SOCKET_KEEPALIVE_VALS)) {
  775. SetTCB->tcb_alive = TCPTime;
  776. SetTCB->tcb_kacount = 0;
  777. }
  778. KeReleaseSpinLock(&SetTCB->tcb_lock, Irql1);
  779. }
  780. }
  781. KeReleaseSpinLock(&Conn->tc_ConnBlock->cb_lock, Irql0);
  782. }
  783. return Status;
  784. #else
  785. return TDI_INVALID_PARAMETER;
  786. #endif
  787. }
  788. if (ID->toi_type == INFO_TYPE_ADDRESS_OBJECT) {
  789. // We're setting information on an address object. This is
  790. // pretty simple.
  791. return SetAddrOptions(Request, ID->toi_id, Size, Buffer);
  792. }
  793. if (ID->toi_type != INFO_TYPE_PROVIDER)
  794. return TDI_INVALID_PARAMETER;
  795. #ifndef UDP_ONLY
  796. if (ID->toi_id == TCP_MIB_TABLE_ID) {
  797. if (Size != sizeof(TCP6ConnTableEntry))
  798. return TDI_INVALID_PARAMETER;
  799. TCPEntry = (TCP6ConnTableEntry *)Buffer;
  800. if (TCPEntry->tct_state != TCP_DELETE_TCB)
  801. return TDI_INVALID_PARAMETER;
  802. // We have an apparently valid request. Look up the TCB.
  803. KeAcquireSpinLock(&TCBTableLock, &Irql0);
  804. SetTCB = FindTCB(&TCPEntry->tct_localaddr,
  805. &TCPEntry->tct_remoteaddr,
  806. TCPEntry->tct_localscopeid,
  807. TCPEntry->tct_remotescopeid,
  808. (ushort)TCPEntry->tct_localport,
  809. (ushort)TCPEntry->tct_remoteport);
  810. // We found him. If he's not closing or closed, close him.
  811. if (SetTCB != NULL) {
  812. KeAcquireSpinLock(&SetTCB->tcb_lock, &Irql1);
  813. KeReleaseSpinLock(&TCBTableLock, Irql1);
  814. // We've got him. Bump his ref. count, and call TryToCloseTCB
  815. // to mark him as closing. Then notify the upper layer client
  816. // of the disconnect.
  817. SetTCB->tcb_refcnt++;
  818. if (SetTCB->tcb_state != TCB_CLOSED && !CLOSING(SetTCB)) {
  819. SetTCB->tcb_flags |= NEED_RST;
  820. TryToCloseTCB(SetTCB, TCB_CLOSE_ABORTED, Irql0);
  821. KeAcquireSpinLock(&SetTCB->tcb_lock, &Irql0);
  822. if (SetTCB->tcb_state != TCB_TIME_WAIT) {
  823. // Remove him from the TCB, and notify the client.
  824. KeReleaseSpinLock(&SetTCB->tcb_lock, Irql0);
  825. RemoveTCBFromConn(SetTCB);
  826. NotifyOfDisc(SetTCB, TDI_CONNECTION_RESET, NULL);
  827. KeAcquireSpinLock(&SetTCB->tcb_lock, &Irql0);
  828. }
  829. }
  830. DerefTCB(SetTCB, Irql0);
  831. return TDI_SUCCESS;
  832. } else {
  833. KeReleaseSpinLock(&TCBTableLock, Irql0);
  834. return TDI_INVALID_PARAMETER;
  835. }
  836. } else
  837. return TDI_INVALID_PARAMETER;
  838. #else
  839. return TDI_INVALID_PARAMETER;
  840. #endif
  841. }
  842. if (ID->toi_class == INFO_CLASS_IMPLEMENTATION) {
  843. // We want to return implementation specific info. For now, error out.
  844. return TDI_INVALID_REQUEST;
  845. }
  846. return TDI_INVALID_REQUEST;
  847. }