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

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