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.

1089 lines
42 KiB

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