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.

1343 lines
52 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. #include "ipfilter.h"
  23. TCPInternalStats TStats;
  24. TCPInternalPerCpuStats TPerCpuStats[TCPS_MAX_PROCESSOR_BUCKETS];
  25. UDPStats UStats;
  26. extern uint NumTcbTablePartitions;
  27. extern ulong DisableUserTOSSetting;
  28. extern uint StartTime;
  29. #define MY_SERVICE_FLAGS (TDI_SERVICE_CONNECTION_MODE | \
  30. TDI_SERVICE_ORDERLY_RELEASE | \
  31. TDI_SERVICE_CONNECTIONLESS_MODE | \
  32. TDI_SERVICE_ERROR_FREE_DELIVERY | \
  33. TDI_SERVICE_BROADCAST_SUPPORTED | \
  34. TDI_SERVICE_DELAYED_ACCEPTANCE | \
  35. TDI_SERVICE_EXPEDITED_DATA | \
  36. TDI_SERVICE_DGRAM_CONNECTION | \
  37. TDI_SERVICE_FORCE_ACCESS_CHECK | \
  38. TDI_SERVICE_SEND_AND_DISCONNECT | \
  39. TDI_SERVICE_ACCEPT_LOCAL_ADDR | \
  40. TDI_SERVICE_NO_ZERO_LENGTH | \
  41. TDI_SERVICE_ADDRESS_SECURITY)
  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. #define ROUTING_INFO_ADDR_1_SIZE \
  55. FIELD_OFFSET(TDI_ROUTING_INFO, Address) + \
  56. FIELD_OFFSET(TRANSPORT_ADDRESS, Address) + \
  57. FIELD_OFFSET(TA_ADDRESS, Address) + sizeof(TDI_ADDRESS_IP)
  58. #define ROUTING_INFO_ADDR_2_SIZE ROUTING_INFO_ADDR_1_SIZE + \
  59. FIELD_OFFSET(TA_ADDRESS, Address) + sizeof(TDI_ADDRESS_IP)
  60. #ifdef ALLOC_PRAGMA
  61. #pragma alloc_text(INIT, TcpInitCcb)
  62. #endif
  63. PCALLBACK_OBJECT TcpCcbObject;
  64. //* TdiQueryInformation - Query Information handler.
  65. //
  66. // The TDI QueryInformation routine. Called when the client wants to
  67. // query information on a connection, the provider as a whole, or to
  68. // get statistics.
  69. //
  70. // Input: Request - The request structure for this command.
  71. // QueryInformation - The Query passed in by the client.
  72. // Buffer - Buffer to place data into.
  73. // BufferSize - Pointer to size in bytes of buffer. On return,
  74. // filled in with bytes copied.
  75. // IsConn - Valid only for TDI_QUERY_ADDRESS_INFO. TRUE
  76. // if we are querying the address info on
  77. // a connection.
  78. //
  79. // Returns: Status of attempt to query information.
  80. //
  81. TDI_STATUS
  82. TdiQueryInformation(PTDI_REQUEST Request,
  83. PTDI_REQUEST_KERNEL_QUERY_INFORMATION QueryInformation,
  84. PNDIS_BUFFER Buffer, uint * BufferSize, uint IsConn)
  85. {
  86. union {
  87. TDI_CONNECTION_INFO ConnInfo;
  88. TDI_ADDRESS_INFO AddrInfo;
  89. TDI_PROVIDER_INFO ProviderInfo;
  90. TDI_PROVIDER_STATISTICS ProviderStats;
  91. UCHAR RoutingInfo[ROUTING_INFO_ADDR_2_SIZE];
  92. } InfoBuf;
  93. uint InfoSize;
  94. CTELockHandle ConnTableHandle, TCBHandle, AddrHandle, AOHandle;
  95. TCPConn *Conn;
  96. TCB *InfoTCB;
  97. AddrObj *InfoAO;
  98. void *InfoPtr = NULL;
  99. uint Offset;
  100. uint Size;
  101. uint BytesCopied;
  102. uint QueryType = QueryInformation->QueryType;
  103. switch (QueryType) {
  104. case TDI_QUERY_BROADCAST_ADDRESS:
  105. return TDI_INVALID_QUERY;
  106. break;
  107. case TDI_QUERY_PROVIDER_INFO:
  108. InfoBuf.ProviderInfo.Version = 0x100;
  109. InfoBuf.ProviderInfo.MaxSendSize = 0xffffffff;
  110. InfoBuf.ProviderInfo.MaxConnectionUserData = 0;
  111. InfoBuf.ProviderInfo.MaxDatagramSize =
  112. 0xffff - (sizeof(IPHeader) + sizeof(UDPHeader));
  113. InfoBuf.ProviderInfo.ServiceFlags = MY_SERVICE_FLAGS;
  114. InfoBuf.ProviderInfo.MinimumLookaheadData = 1;
  115. InfoBuf.ProviderInfo.MaximumLookaheadData = 0xffff;
  116. InfoBuf.ProviderInfo.NumberOfResources = 0;
  117. InfoBuf.ProviderInfo.StartTime.LowPart = StartTime;
  118. InfoBuf.ProviderInfo.StartTime.HighPart = 0;
  119. InfoSize = sizeof(TDI_PROVIDER_INFO);
  120. InfoPtr = &InfoBuf.ProviderInfo;
  121. break;
  122. case TDI_QUERY_ADDRESS_INFO:
  123. InfoSize = sizeof(TDI_ADDRESS_INFO) - sizeof(TRANSPORT_ADDRESS) +
  124. TCP_TA_SIZE;
  125. NdisZeroMemory(&InfoBuf.AddrInfo, TCP_TA_SIZE);
  126. InfoBuf.AddrInfo.ActivityCount = 1; // Since noone knows what
  127. // this means, we'll set
  128. // it to one.
  129. if (IsConn) {
  130. CTEGetLock(&AddrObjTableLock.Lock, &AddrHandle);
  131. //CTEGetLock(&ConnTableLock, &ConnTableHandle);
  132. Conn = GetConnFromConnID(PtrToUlong(Request->Handle.ConnectionContext), &ConnTableHandle);
  133. if (Conn != NULL) {
  134. CTEStructAssert(Conn, tc);
  135. InfoTCB = Conn->tc_tcb;
  136. // If we have a TCB we'll
  137. // return information about that TCB. Otherwise we'll return
  138. // info about the address object.
  139. if (InfoTCB != NULL) {
  140. CTEStructAssert(InfoTCB, tcb);
  141. CTEGetLock(&InfoTCB->tcb_lock, &TCBHandle);
  142. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), TCBHandle);
  143. CTEFreeLock(&AddrObjTableLock.Lock, ConnTableHandle);
  144. BuildTDIAddress((uchar *) & InfoBuf.AddrInfo.Address,
  145. InfoTCB->tcb_saddr, InfoTCB->tcb_sport);
  146. CTEFreeLock(&InfoTCB->tcb_lock, AddrHandle);
  147. InfoPtr = &InfoBuf.AddrInfo;
  148. break;
  149. } else {
  150. // No TCB, return info on the AddrObj.
  151. InfoAO = Conn->tc_ao;
  152. if (InfoAO != NULL) {
  153. // We have an AddrObj.
  154. CTEStructAssert(InfoAO, ao);
  155. CTEGetLock(&InfoAO->ao_lock, &AOHandle);
  156. BuildTDIAddress((uchar *) & InfoBuf.AddrInfo.Address,
  157. InfoAO->ao_addr, InfoAO->ao_port);
  158. CTEFreeLock(&InfoAO->ao_lock, AOHandle);
  159. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), ConnTableHandle);
  160. CTEFreeLock(&AddrObjTableLock.Lock, AddrHandle);
  161. InfoPtr = &InfoBuf.AddrInfo;
  162. break;
  163. } else
  164. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), ConnTableHandle);
  165. }
  166. }
  167. // Fall through to here when we can't find the connection, or
  168. // the connection isn't associated.
  169. //CTEFreeLock(&ConnTableLock, ConnTableHandle);
  170. CTEFreeLock(&AddrObjTableLock.Lock, AddrHandle);
  171. return TDI_INVALID_CONNECTION;
  172. break;
  173. } else {
  174. // Asking for information on an addr. object.
  175. InfoAO = Request->Handle.AddressHandle;
  176. if (InfoAO == NULL)
  177. return TDI_ADDR_INVALID;
  178. CTEStructAssert(InfoAO, ao);
  179. CTEGetLock(&InfoAO->ao_lock, &AOHandle);
  180. if (!AO_VALID(InfoAO)) {
  181. CTEFreeLock(&InfoAO->ao_lock, AOHandle);
  182. return TDI_ADDR_INVALID;
  183. } else if (AO_CONNUDP(InfoAO) &&
  184. IP_ADDR_EQUAL(InfoAO->ao_addr, NULL_IP_ADDR) &&
  185. InfoAO->ao_rce &&
  186. (InfoAO->ao_rce->rce_flags & RCE_VALID)) {
  187. BuildTDIAddress((uchar *) & InfoBuf.AddrInfo.Address,
  188. InfoAO->ao_rcesrc, InfoAO->ao_port);
  189. CTEFreeLock(&InfoAO->ao_lock, AOHandle);
  190. InfoPtr = &InfoBuf.AddrInfo;
  191. break;
  192. }
  193. BuildTDIAddress((uchar *) & InfoBuf.AddrInfo.Address,
  194. InfoAO->ao_addr, InfoAO->ao_port);
  195. CTEFreeLock(&InfoAO->ao_lock, AOHandle);
  196. InfoPtr = &InfoBuf.AddrInfo;
  197. break;
  198. }
  199. break;
  200. case TDI_QUERY_CONNECTION_INFO:
  201. InfoSize = sizeof(TDI_CONNECTION_INFO);
  202. //CTEGetLock(&ConnTableLock, &ConnTableHandle);
  203. Conn = GetConnFromConnID(PtrToUlong(Request->Handle.ConnectionContext), &ConnTableHandle);
  204. if (Conn != NULL) {
  205. CTEStructAssert(Conn, tc);
  206. InfoTCB = Conn->tc_tcb;
  207. // If we have a TCB we'll return the information. Otherwise
  208. // we'll error out.
  209. if (InfoTCB != NULL) {
  210. ulong TotalTime;
  211. ulong BPS, PathBPS;
  212. IP_STATUS IPStatus;
  213. CTEULargeInt TempULargeInt;
  214. CTEStructAssert(InfoTCB, tcb);
  215. CTEGetLock(&InfoTCB->tcb_lock, &TCBHandle);
  216. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), TCBHandle);
  217. NdisZeroMemory(&InfoBuf.ConnInfo, sizeof(TDI_CONNECTION_INFO));
  218. InfoBuf.ConnInfo.State = (ulong) InfoTCB->tcb_state;
  219. IPStatus = (*LocalNetInfo.ipi_getpinfo) (InfoTCB->tcb_daddr,
  220. InfoTCB->tcb_saddr, NULL, (uint*)&PathBPS, InfoTCB->tcb_rce);
  221. if (IPStatus != IP_SUCCESS) {
  222. InfoBuf.ConnInfo.Throughput.LowPart = 0xFFFFFFFF;
  223. InfoBuf.ConnInfo.Throughput.HighPart = 0xFFFFFFFF;
  224. } else {
  225. InfoBuf.ConnInfo.Throughput.HighPart = 0;
  226. TotalTime = InfoTCB->tcb_totaltime /
  227. (1000 / MS_PER_TICK);
  228. if (TotalTime != 0 && (TotalTime > InfoTCB->tcb_bcounthi)) {
  229. TempULargeInt.LowPart = InfoTCB->tcb_bcountlow;
  230. TempULargeInt.HighPart = InfoTCB->tcb_bcounthi;
  231. BPS = CTEEnlargedUnsignedDivide(TempULargeInt,
  232. TotalTime, NULL);
  233. InfoBuf.ConnInfo.Throughput.LowPart =
  234. MIN(BPS, PathBPS);
  235. } else
  236. InfoBuf.ConnInfo.Throughput.LowPart = PathBPS;
  237. }
  238. // To figure the delay we use the rexmit timeout. Our
  239. // rexmit timeout is roughly the round trip time plus
  240. // some slop, so we use half of that as the one way delay.
  241. InfoBuf.ConnInfo.Delay.LowPart =
  242. (REXMIT_TO(InfoTCB) * MS_PER_TICK) / 2;
  243. InfoBuf.ConnInfo.Delay.HighPart = 0;
  244. //
  245. // Convert milliseconds to 100ns and negate for relative
  246. // time.
  247. //
  248. InfoBuf.ConnInfo.Delay =
  249. RtlExtendedIntegerMultiply(
  250. InfoBuf.ConnInfo.Delay,
  251. 10000
  252. );
  253. ASSERT(InfoBuf.ConnInfo.Delay.HighPart == 0);
  254. InfoBuf.ConnInfo.Delay.QuadPart =
  255. -InfoBuf.ConnInfo.Delay.QuadPart;
  256. CTEFreeLock(&InfoTCB->tcb_lock, ConnTableHandle);
  257. InfoPtr = &InfoBuf.ConnInfo;
  258. break;
  259. }
  260. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), ConnTableHandle);
  261. }
  262. // Come through here if we can't find the connection or it has
  263. // no TCB.
  264. //CTEFreeLock(&ConnTableLock, ConnTableHandle);
  265. return TDI_INVALID_CONNECTION;
  266. break;
  267. case TDI_QUERY_PROVIDER_STATISTICS:
  268. NdisZeroMemory(&InfoBuf.ProviderStats, sizeof(TDI_PROVIDER_STATISTICS));
  269. InfoBuf.ProviderStats.Version = 0x100;
  270. InfoSize = sizeof(TDI_PROVIDER_STATISTICS);
  271. InfoPtr = &InfoBuf.ProviderStats;
  272. break;
  273. case TDI_QUERY_ROUTING_INFO:
  274. InfoSize = 0;
  275. if (IsConn) {
  276. NTSTATUS Status;
  277. PTRANSPORT_ADDRESS TransportAddress;
  278. PTDI_ROUTING_INFO RoutingInfo;
  279. PVOID NextAddress;
  280. // Get a hold of the TCB, return the {invariants, outgoing-if,
  281. // outgoing-link}
  282. Conn = GetConnFromConnID(PtrToUlong(
  283. Request->Handle.ConnectionContext),
  284. &ConnTableHandle);
  285. if (Conn == NULL) {
  286. return TDI_INVALID_CONNECTION;
  287. }
  288. CTEStructAssert(Conn, tc);
  289. InfoTCB = Conn->tc_tcb;
  290. // If we have a TCB we'll return information about that TCB.
  291. // Otherwise we'll return info about the address object.
  292. if (InfoTCB == NULL) {
  293. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), ConnTableHandle);
  294. return TDI_INVALID_CONNECTION;
  295. }
  296. CTEGetLockAtDPC(&InfoTCB->tcb_lock);
  297. // Release the semi-global conn-table lock as soon as TCB lock is
  298. // acquired. Note that we set the IRQL back to what we got in
  299. // TCBHandle.
  300. CTEFreeLockFromDPC(&(Conn->tc_ConnBlock->cb_lock));
  301. CTEStructAssert(InfoTCB, tcb);
  302. NdisZeroMemory(&InfoBuf.RoutingInfo, ROUTING_INFO_ADDR_2_SIZE);
  303. RoutingInfo = (PTDI_ROUTING_INFO)(&InfoBuf.RoutingInfo);
  304. TransportAddress =
  305. (PTRANSPORT_ADDRESS)&(RoutingInfo->Address);
  306. Status = GetIFAndLink(InfoTCB->tcb_rce, &RoutingInfo->InterfaceId,
  307. &RoutingInfo->LinkId);
  308. if (Status != IP_SUCCESS) {
  309. CTEFreeLock(&InfoTCB->tcb_lock, ConnTableHandle);
  310. return TDI_INVALID_CONNECTION;
  311. }
  312. // Collect the information from the connection. For TCP, both the
  313. // local and remote address/port information are supplied.
  314. RoutingInfo->Protocol = PROTOCOL_TCP;
  315. NextAddress = BuildTDIAddress((uchar*)TransportAddress,
  316. InfoTCB->tcb_saddr,
  317. InfoTCB->tcb_sport);
  318. AppendTDIAddress((uchar*)TransportAddress, NextAddress,
  319. InfoTCB->tcb_daddr, InfoTCB->tcb_dport);
  320. CTEFreeLock(&InfoTCB->tcb_lock, ConnTableHandle);
  321. InfoSize = ROUTING_INFO_ADDR_2_SIZE;
  322. InfoPtr = &InfoBuf.RoutingInfo;
  323. } else {
  324. IPAddr RemoteAddress;
  325. ushort RemotePort;
  326. IPAddr SrcAddr;
  327. RouteCacheEntry* Rce;
  328. uchar DestType;
  329. ushort MSS;
  330. PTDI_ROUTING_INFO RoutingInfo;
  331. NTSTATUS Status;
  332. PTRANSPORT_ADDRESS TransportAddress;
  333. BOOLEAN NeedToCloseRce = FALSE;
  334. if (QueryInformation->RequestConnectionInformation == NULL) {
  335. return STATUS_INVALID_PARAMETER;
  336. }
  337. // Get the Addresses here. The user should have passed in a valid
  338. // TRANSPORT_ADDR structure here.
  339. GetAddress((PTRANSPORT_ADDRESS)QueryInformation->
  340. RequestConnectionInformation->RemoteAddress,
  341. &RemoteAddress, &RemotePort);
  342. InfoAO = Request->Handle.AddressHandle;
  343. if (InfoAO == NULL) {
  344. return TDI_ADDR_INVALID;
  345. }
  346. CTEGetLock(&InfoAO->ao_lock, &AOHandle);
  347. CTEStructAssert(InfoAO, ao);
  348. // Query on Address Object is allowed for any protocol other than
  349. // TCP.
  350. if (!AO_VALID(InfoAO) || (InfoAO->ao_prot == PROTOCOL_TCP)) {
  351. CTEFreeLock(&InfoAO->ao_lock, AOHandle);
  352. return TDI_ADDR_INVALID;
  353. }
  354. if (AO_CONNUDP(InfoAO) &&
  355. InfoAO->ao_rce &&
  356. (InfoAO->ao_rce->rce_flags & RCE_VALID) &&
  357. IP_ADDR_EQUAL(RemoteAddress, InfoAO->ao_rce->rce_dest)) {
  358. Rce = InfoAO->ao_rce;
  359. SrcAddr = Rce->rce_src;
  360. } else {
  361. SrcAddr = (*LocalNetInfo.ipi_openrce)(RemoteAddress,
  362. InfoAO->ao_addr, &Rce, &DestType, &MSS,
  363. CLASSD_ADDR(RemoteAddress) ?
  364. &InfoAO->ao_mcastopt :
  365. &InfoAO->ao_opt);
  366. NeedToCloseRce = TRUE;
  367. }
  368. // If SrcAddr returned is NULL_IP_ADDR, there is no Rce created,
  369. // so, there is no need to close it either.
  370. if (IP_ADDR_EQUAL(SrcAddr, NULL_IP_ADDR)) {
  371. CTEFreeLock(&InfoAO->ao_lock, AOHandle);
  372. return TDI_ADDR_INVALID;
  373. }
  374. NdisZeroMemory(&InfoBuf.RoutingInfo, ROUTING_INFO_ADDR_1_SIZE);
  375. RoutingInfo = (PTDI_ROUTING_INFO)(&InfoBuf.RoutingInfo);
  376. TransportAddress =
  377. (PTRANSPORT_ADDRESS)&(RoutingInfo->Address);
  378. Status = GetIFAndLink(Rce, &RoutingInfo->InterfaceId,
  379. &RoutingInfo->LinkId);
  380. if (NeedToCloseRce) {
  381. (*LocalNetInfo.ipi_closerce) (Rce);
  382. }
  383. if (Status != IP_SUCCESS) {
  384. CTEFreeLock(&InfoAO->ao_lock, AOHandle);
  385. return TDI_INVALID_CONNECTION;
  386. }
  387. // Gather the relevant information. In case of UDP, only the local
  388. // address/port information is provided.
  389. RoutingInfo->Protocol = PROTOCOL_UDP;
  390. BuildTDIAddress((uchar*)TransportAddress, SrcAddr, InfoAO->ao_port);
  391. CTEFreeLock(&InfoAO->ao_lock, AOHandle);
  392. InfoSize = ROUTING_INFO_ADDR_1_SIZE;
  393. InfoPtr = &InfoBuf.RoutingInfo;
  394. }
  395. break;
  396. default:
  397. return TDI_INVALID_QUERY;
  398. break;
  399. }
  400. // When we get here, we've got the pointers set up and the information
  401. // filled in.
  402. ASSERT(InfoPtr != NULL);
  403. Offset = 0;
  404. Size = *BufferSize;
  405. (void)CopyFlatToNdis(Buffer, InfoPtr, MIN(InfoSize, Size), &Offset,
  406. &BytesCopied);
  407. if (Size < InfoSize)
  408. return TDI_BUFFER_OVERFLOW;
  409. else {
  410. *BufferSize = InfoSize;
  411. return TDI_SUCCESS;
  412. }
  413. }
  414. //* TdiSetInformation - Set Information handler.
  415. //
  416. // The TDI SetInformation routine. Currently we don't allow anything to be
  417. // set.
  418. //
  419. // Input: Request - The request structure for this command.
  420. // SetType - The type of set to be performed.
  421. // Buffer - Buffer to set from.
  422. // BufferSize - Size in bytes of buffer.
  423. // IsConn - Valid only for TDI_QUERY_ADDRESS_INFO. TRUE
  424. // if we are setting the address info on
  425. // a connection.
  426. //
  427. // Returns: Status of attempt to set information.
  428. //
  429. TDI_STATUS
  430. TdiSetInformation(PTDI_REQUEST Request, uint SetType, PNDIS_BUFFER Buffer,
  431. uint BufferSize, uint IsConn)
  432. {
  433. return TDI_INVALID_REQUEST;
  434. }
  435. //* TdiAction - Action handler.
  436. //
  437. // The TDI Action routine. Currently we don't support any actions.
  438. //
  439. // Input: Request - The request structure for this command.
  440. // ActionType - The type of action to be performed.
  441. // Buffer - Buffer of action info.
  442. // BufferSize - Size in bytes of buffer.
  443. //
  444. // Returns: Status of attempt to perform action.
  445. //
  446. TDI_STATUS
  447. TdiAction(PTDI_REQUEST Request, uint ActionType, PNDIS_BUFFER Buffer,
  448. uint BufferSize)
  449. {
  450. return TDI_INVALID_REQUEST;
  451. }
  452. // We are looking only for missing TCPConnTableEntry ies,
  453. // ie. listen.
  454. int
  455. CopyAO_TCPConn(const AddrObj *AO, uint InfoSize, TCPConnTableEntryEx *Buffer)
  456. {
  457. if (AO == NULL)
  458. return 0;
  459. ASSERT(InfoSize == sizeof(TCPConnTableEntry) ||
  460. InfoSize == sizeof(TCPConnTableEntryEx));
  461. if ((!AO->ao_listencnt) && (AO->ao_prot == PROTOCOL_TCP) &&
  462. (AO->ao_connect)) {
  463. Buffer->tcte_basic.tct_state = TCP_CONN_LISTEN;
  464. // else if .. other cases can be added here ...
  465. } else {
  466. return 0;
  467. }
  468. Buffer->tcte_basic.tct_localaddr = AO->ao_addr;
  469. Buffer->tcte_basic.tct_localport = AO->ao_port;
  470. Buffer->tcte_basic.tct_remoteaddr = 0;
  471. Buffer->tcte_basic.tct_remoteport = (ULONG) ((ULONG_PTR) AO & 0x0000ffff);
  472. if (InfoSize > sizeof(TCPConnTableEntry)) {
  473. ((TCPConnTableEntryEx*)Buffer)->tcte_owningpid = AO->ao_owningpid;
  474. }
  475. return 1;
  476. }
  477. //* TdiQueryInfoEx - Extended TDI query information.
  478. //
  479. // This is the new TDI query information handler. We take in a TDIObjectID
  480. // structure, a buffer and length, and some context information, and return
  481. // the requested information if possible.
  482. //
  483. // Input: Request - The request structure for this command.
  484. // ID - The object ID
  485. // Buffer - Pointer to buffer to be filled in.
  486. // Size - Pointer to size in bytes of Buffer. On exit,
  487. // filled in with bytes written.
  488. // Context - Pointer to context buffer.
  489. //
  490. // Returns: Status of attempt to get information.
  491. //
  492. TDI_STATUS
  493. TdiQueryInformationEx(PTDI_REQUEST Request, TDIObjectID * ID,
  494. PNDIS_BUFFER Buffer, uint * Size, void *Context)
  495. {
  496. uint BufferSize = *Size;
  497. uint InfoSize;
  498. void *InfoPtr;
  499. uint Fixed;
  500. CTELockHandle Handle = 0, DpcHandle = 0, TableHandle;
  501. CTELock *AOLockPtr = NULL;
  502. uint Offset = 0;
  503. uchar InfoBuffer[sizeof(TCPConnTableEntryEx)];
  504. uint BytesRead;
  505. uint Valid;
  506. uint Entity;
  507. uint BytesCopied;
  508. TCPStats TCPStatsListen;
  509. CTELockHandle EntityHandle;
  510. CTELockHandle TWHandle = 0, TWDpcHandle = 0;
  511. BOOLEAN TWTABLELOCK = FALSE;
  512. BOOLEAN TABLELOCK = FALSE;
  513. int lcount;
  514. AddrObj *pAO;
  515. TCPConnTableEntryEx tcp_ce;
  516. uint Index, i;
  517. int InfoTcpConn = 0; // true if tcp conn info needed.
  518. // First check to see if he's querying for list of entities.
  519. Entity = ID->toi_entity.tei_entity;
  520. if (Entity == GENERIC_ENTITY) {
  521. *Size = 0;
  522. if (ID->toi_class != INFO_CLASS_GENERIC ||
  523. ID->toi_type != INFO_TYPE_PROVIDER ||
  524. ID->toi_id != ENTITY_LIST_ID) {
  525. return TDI_INVALID_PARAMETER;
  526. }
  527. CTEGetLock(&EntityLock, &EntityHandle);
  528. // Make sure we have room for it the list in the buffer.
  529. InfoSize = EntityCount * sizeof(TDIEntityID);
  530. if (BufferSize < InfoSize) {
  531. // Not enough room.
  532. CTEFreeLock(&EntityLock, EntityHandle);
  533. return TDI_BUFFER_TOO_SMALL;
  534. }
  535. // Copy it in, free our temp. buffer, and return success.
  536. (void)CopyFlatToNdis(Buffer, (uchar *) EntityList, InfoSize, &Offset,
  537. &BytesCopied);
  538. *Size = BytesCopied;
  539. CTEFreeLock(&EntityLock, EntityHandle);
  540. return TDI_SUCCESS;
  541. }
  542. //* Check the level. If it can't be for us, pass it down.
  543. if (Entity != CO_TL_ENTITY && Entity != CL_TL_ENTITY)
  544. {
  545. // When we support multiple lower entities at this layer we'll have
  546. // to figure out which one to dispatch to. For now, just pass it
  547. // straight down.
  548. return (*LocalNetInfo.ipi_qinfo) (ID, Buffer, Size, Context);
  549. }
  550. if (ID->toi_entity.tei_instance != TL_INSTANCE) {
  551. // We only support a single instance.
  552. return TDI_INVALID_REQUEST;
  553. }
  554. // Zero returned parameters in case of an error below.
  555. *Size = 0;
  556. if (ID->toi_class == INFO_CLASS_GENERIC) {
  557. // This is a generic request.
  558. if (ID->toi_type == INFO_TYPE_PROVIDER && ID->toi_id == ENTITY_TYPE_ID) {
  559. if (BufferSize >= sizeof(uint)) {
  560. *(uint *) & InfoBuffer[0] = (Entity == CO_TL_ENTITY) ? CO_TL_TCP
  561. : CL_TL_UDP;
  562. (void)CopyFlatToNdis(Buffer, InfoBuffer, sizeof(uint), &Offset,
  563. &BytesCopied);
  564. return TDI_SUCCESS;
  565. } else
  566. return TDI_BUFFER_TOO_SMALL;
  567. }
  568. return TDI_INVALID_PARAMETER;
  569. }
  570. if (ID->toi_class == INFO_CLASS_PROTOCOL) {
  571. // Handle protocol specific class of information. For us, this is
  572. // the MIB-2 stuff or the minimal stuff we do for oob_inline support.
  573. if (ID->toi_type == INFO_TYPE_CONNECTION) {
  574. TCPConn *Conn;
  575. TCB *QueryTCB;
  576. TCPSocketAMInfo *AMInfo;
  577. CTELockHandle TCBHandle;
  578. if (BufferSize < sizeof(TCPSocketAMInfo) ||
  579. ID->toi_id != TCP_SOCKET_ATMARK)
  580. return TDI_INVALID_PARAMETER;
  581. AMInfo = (TCPSocketAMInfo *) InfoBuffer;
  582. //CTEGetLock(&ConnTableLock, &Handle);
  583. Conn = GetConnFromConnID(PtrToUlong(Request->Handle.ConnectionContext), &Handle);
  584. if (Conn != NULL) {
  585. CTEStructAssert(Conn, tc);
  586. QueryTCB = Conn->tc_tcb;
  587. if (QueryTCB != NULL) {
  588. CTEStructAssert(QueryTCB, tcb);
  589. CTEGetLock(&QueryTCB->tcb_lock, &TCBHandle);
  590. if ((QueryTCB->tcb_flags & (URG_INLINE | URG_VALID)) ==
  591. (URG_INLINE | URG_VALID)) {
  592. // We're in inline mode, and the urgent data fields are
  593. // valid.
  594. AMInfo->tsa_size = QueryTCB->tcb_urgend -
  595. QueryTCB->tcb_urgstart + 1;
  596. // Rcvnext - pendingcnt is the sequence number of the
  597. // next byte of data that will be delivered to the
  598. // client. Urgend - that value is the offset in the
  599. // data stream of the end of urgent data.
  600. AMInfo->tsa_offset = QueryTCB->tcb_urgend -
  601. (QueryTCB->tcb_rcvnext - QueryTCB->tcb_pendingcnt);
  602. } else {
  603. AMInfo->tsa_size = 0;
  604. AMInfo->tsa_offset = 0;
  605. }
  606. CTEFreeLock(&QueryTCB->tcb_lock, TCBHandle);
  607. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), Handle);
  608. CopyFlatToNdis(Buffer, InfoBuffer, sizeof(TCPSocketAMInfo),
  609. &Offset, &BytesCopied);
  610. *Size = BytesCopied;
  611. return TDI_SUCCESS;
  612. }
  613. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), Handle);
  614. }
  615. return TDI_INVALID_PARAMETER;
  616. }
  617. if (ID->toi_type == INFO_TYPE_ADDRESS_OBJECT) {
  618. // We're getting information on an address object. This is
  619. // pretty simple.
  620. return GetAddrOptionsEx(Request, ID->toi_id, BufferSize, Buffer,
  621. Size, Context);
  622. }
  623. if (ID->toi_type != INFO_TYPE_PROVIDER)
  624. return TDI_INVALID_PARAMETER;
  625. switch (ID->toi_id) {
  626. case UDP_MIB_STAT_ID:
  627. #if UDP_MIB_STAT_ID != TCP_MIB_STAT_ID
  628. case TCP_MIB_STAT_ID:
  629. #endif
  630. Fixed = TRUE;
  631. if (Entity == CL_TL_ENTITY) {
  632. InfoSize = sizeof(UDPStats);
  633. InfoPtr = &UStats;
  634. } else {
  635. TCPInternalPerCpuStats SumCpuStats;
  636. TCPStatsListen.ts_rtoalgorithm = TStats.ts_rtoalgorithm;
  637. TCPStatsListen.ts_rtomin = TStats.ts_rtomin;
  638. TCPStatsListen.ts_rtomax = TStats.ts_rtomax;
  639. TCPStatsListen.ts_maxconn = TStats.ts_maxconn;
  640. TCPStatsListen.ts_activeopens = TStats.ts_activeopens;
  641. TCPStatsListen.ts_passiveopens = TStats.ts_passiveopens;
  642. TCPStatsListen.ts_attemptfails = TStats.ts_attemptfails;
  643. TCPStatsListen.ts_estabresets = TStats.ts_estabresets;
  644. TCPStatsListen.ts_currestab = TStats.ts_currestab;
  645. TCPStatsListen.ts_retranssegs = TStats.ts_retranssegs;
  646. TCPStatsListen.ts_inerrs = TStats.ts_inerrs;
  647. TCPStatsListen.ts_outrsts = TStats.ts_outrsts;
  648. TCPStatsListen.ts_numconns = TStats.ts_numconns;
  649. #if !MILLEN
  650. TCPSGetTotalCounts(&SumCpuStats);
  651. TCPStatsListen.ts_insegs = SumCpuStats.tcs_insegs;
  652. TCPStatsListen.ts_outsegs = SumCpuStats.tcs_outsegs;
  653. #else
  654. TCPStatsListen.ts_insegs = TStats.ts_insegs;
  655. TCPStatsListen.ts_outsegs = TStats.ts_outsegs;
  656. #endif
  657. InfoSize = sizeof(TCPStatsListen);
  658. InfoPtr = &TCPStatsListen;
  659. lcount = 0;
  660. CTEGetLock(&AddrObjTableLock.Lock, &TableHandle);
  661. for (Index = 0; Index < AddrObjTableSize; Index++) {
  662. pAO = AddrObjTable[Index];
  663. while (pAO) {
  664. lcount += CopyAO_TCPConn(pAO,
  665. sizeof(TCPConnTableEntry),
  666. &tcp_ce);
  667. pAO = pAO->ao_next;
  668. }
  669. }
  670. CTEFreeLock(&AddrObjTableLock.Lock, TableHandle);
  671. TCPStatsListen.ts_numconns += lcount;
  672. }
  673. break;
  674. case UDP_MIB_TABLE_ID:
  675. #if UDP_MIB_STAT_ID != TCP_MIB_STAT_ID
  676. case TCP_MIB_TABLE_ID:
  677. #endif
  678. case UDP_EX_TABLE_ID:
  679. #if UDP_EX_STAT_ID != TCP_EX_STAT_ID
  680. case TCP_EX_TABLE_ID:
  681. #endif
  682. Fixed = FALSE;
  683. if (Entity == CL_TL_ENTITY) {
  684. InfoSize = (UDP_MIB_TABLE_ID == ID->toi_id)
  685. ? sizeof(UDPEntry)
  686. : sizeof(UDPEntryEx);
  687. ((UDPContext*)Context)->uc_infosize = InfoSize;
  688. InfoPtr = &ReadAOTable;
  689. CTEGetLock(&AddrObjTableLock.Lock, &Handle);
  690. AOLockPtr = &AddrObjTableLock.Lock;
  691. } else {
  692. InfoSize = (TCP_MIB_TABLE_ID == ID->toi_id)
  693. ? sizeof(TCPConnTableEntry)
  694. : sizeof(TCPConnTableEntryEx);
  695. ((TCPConnContext*)Context)->tcc_infosize = InfoSize;
  696. InfoTcpConn = 1;
  697. InfoPtr = &ReadTCBTable;
  698. TABLELOCK = TRUE;
  699. CTEGetLock(&pTCBTableLock[0], &Handle);
  700. for (i = 1; i < NumTcbTablePartitions; i++) {
  701. CTEGetLock(&pTCBTableLock[i], &DpcHandle);
  702. }
  703. CTEGetLock(&pTWTCBTableLock[0], &TWHandle);
  704. for (i = 1; i < NumTcbTablePartitions; i++) {
  705. CTEGetLock(&pTWTCBTableLock[i], &TWDpcHandle);
  706. }
  707. TWTABLELOCK = TRUE;
  708. }
  709. break;
  710. default:
  711. return TDI_INVALID_PARAMETER;
  712. break;
  713. }
  714. if (Fixed) {
  715. if (BufferSize < InfoSize)
  716. return TDI_BUFFER_TOO_SMALL;
  717. (void)CopyFlatToNdis(Buffer, InfoPtr, InfoSize, &Offset,
  718. &BytesCopied);
  719. *Size = BytesCopied;
  720. return TDI_SUCCESS;
  721. } else {
  722. struct ReadTableStruct *RTSPtr;
  723. uint ReadStatus;
  724. // Have a variable length (or mult-instance) structure to copy.
  725. // InfoPtr points to the structure describing the routines to
  726. // call to read the table.
  727. // Loop through up to CountWanted times, calling the routine
  728. // each time.
  729. BytesRead = 0;
  730. RTSPtr = InfoPtr;
  731. ReadStatus = (*(RTSPtr->rts_validate)) (Context, &Valid);
  732. // If we successfully read something we'll continue. Otherwise
  733. // we'll bail out.
  734. if (!Valid) {
  735. if (TWTABLELOCK) {
  736. for (i = NumTcbTablePartitions - 1; i > 0; i--) {
  737. CTEFreeLock(&pTWTCBTableLock[i], TWDpcHandle);
  738. }
  739. CTEFreeLock(&pTWTCBTableLock[0], TWHandle);
  740. }
  741. if (TABLELOCK) {
  742. for (i = NumTcbTablePartitions - 1; i > 0; i--) {
  743. CTEFreeLock(&pTCBTableLock[i], DpcHandle);
  744. }
  745. CTEFreeLock(&pTCBTableLock[0], Handle);
  746. }
  747. if (AOLockPtr)
  748. CTEFreeLock(AOLockPtr, Handle);
  749. return TDI_INVALID_PARAMETER;
  750. }
  751. while (ReadStatus) {
  752. // The invariant here is that there is data in the table to
  753. // read. We may or may not have room for it. So ReadStatus
  754. // is TRUE, and BufferSize - BytesRead is the room left
  755. // in the buffer.
  756. if ((int)(BufferSize - BytesRead) >= (int)InfoSize) {
  757. ReadStatus = (*(RTSPtr->rts_readnext)) (Context,
  758. InfoBuffer);
  759. BytesRead += InfoSize;
  760. Buffer = CopyFlatToNdis(Buffer, InfoBuffer, InfoSize,
  761. &Offset, &BytesCopied);
  762. } else
  763. break;
  764. }
  765. if (TWTABLELOCK) {
  766. for (i = NumTcbTablePartitions - 1; i > 0; i--) {
  767. CTEFreeLock(&pTWTCBTableLock[i], TWDpcHandle);
  768. }
  769. CTEFreeLock(&pTWTCBTableLock[0], TWHandle);
  770. }
  771. if (TABLELOCK) {
  772. for (i = NumTcbTablePartitions - 1; i > 0; i--) {
  773. CTEFreeLock(&pTCBTableLock[i], DpcHandle);
  774. }
  775. CTEFreeLock(&pTCBTableLock[0], Handle);
  776. }
  777. if ((!ReadStatus) && InfoTcpConn) {
  778. if (!AOLockPtr) {
  779. CTEGetLock(&AddrObjTableLock.Lock, &TableHandle);
  780. AOLockPtr = &AddrObjTableLock.Lock;
  781. }
  782. for (Index = 0; Index < AddrObjTableSize; Index++) {
  783. pAO = AddrObjTable[Index];
  784. while (pAO) {
  785. if (CopyAO_TCPConn(pAO, InfoSize, &tcp_ce)) {
  786. if (BufferSize < (BytesRead + InfoSize)) {
  787. goto no_more_ao;
  788. }
  789. Buffer = CopyFlatToNdis(Buffer, (void *)&tcp_ce,
  790. InfoSize,
  791. &Offset, &BytesCopied);
  792. BytesRead += InfoSize;
  793. ASSERT(BufferSize >= BytesRead);
  794. }
  795. pAO = pAO->ao_next;
  796. }
  797. }
  798. no_more_ao:;
  799. }
  800. if (AOLockPtr)
  801. CTEFreeLock(AOLockPtr, Handle);
  802. *Size = BytesRead;
  803. return (!ReadStatus ? TDI_SUCCESS : TDI_BUFFER_OVERFLOW);
  804. }
  805. }
  806. if (ID->toi_class == INFO_CLASS_IMPLEMENTATION) {
  807. // We want to return implementation specific info. For now, error out.
  808. return TDI_INVALID_PARAMETER;
  809. }
  810. return TDI_INVALID_PARAMETER;
  811. }
  812. //* TdiSetInfoEx - Extended TDI set information.
  813. //
  814. // This is the new TDI set information handler. We take in a TDIObjectID
  815. // structure, a buffer and length. We set the object specifed by the ID
  816. // (and possibly by the Request) to the value specified in the buffer.
  817. //
  818. // Input: Request - The request structure for this command.
  819. // ID - The object ID
  820. // Buffer - Pointer to buffer containing value to set.
  821. // Size - Size in bytes of Buffer.
  822. //
  823. // Returns: Status of attempt to get information.
  824. //
  825. TDI_STATUS
  826. TdiSetInformationEx(PTDI_REQUEST Request, TDIObjectID * ID, void *Buffer,
  827. uint Size)
  828. {
  829. TCPConnTableEntry *TCPEntry;
  830. CTELockHandle TableHandle, TCBHandle;
  831. TCB *SetTCB;
  832. uint Entity;
  833. TCPConn *Conn;
  834. TDI_STATUS Status;
  835. uint index;
  836. DEBUGMSG(DBG_TRACE && DBG_SETINFO,
  837. (DTEXT("+TdiSetInformationEx(%x, %x, %x, %d)\n"),
  838. Request, ID, Buffer, Size));
  839. //* Check the level. If it can't be for us, pass it down.
  840. Entity = ID->toi_entity.tei_entity;
  841. if (Entity != CO_TL_ENTITY && Entity != CL_TL_ENTITY) {
  842. Status = (*LocalNetInfo.ipi_setinfo) (ID, Buffer, Size);
  843. DEBUGMSG(Status != TDI_SUCCESS && DBG_ERROR && DBG_SETINFO,
  844. (DTEXT("TdiSetInformationEx: ipi_setinfo failure %x\n"),
  845. Status));
  846. // Someday we'll have to figure out how to dispatch. For now, just pass
  847. // it down.
  848. return Status;
  849. }
  850. if (ID->toi_entity.tei_instance != TL_INSTANCE)
  851. return TDI_INVALID_REQUEST;
  852. if (ID->toi_class == INFO_CLASS_GENERIC) {
  853. // Fill this in when we have generic class defines.
  854. return TDI_INVALID_PARAMETER;
  855. }
  856. //* Now look at the rest of it.
  857. if (ID->toi_class == INFO_CLASS_PROTOCOL) {
  858. // Handle protocol specific class of information. For us, this is
  859. // the MIB-2 stuff, as well as common sockets options,
  860. // and in particular the setting of the state of a TCP connection.
  861. if (ID->toi_type == INFO_TYPE_CONNECTION) {
  862. TCPSocketOption *Option;
  863. uint Flag;
  864. uint Value;
  865. // A connection type. Get the connection, and then figure out
  866. // what to do with it.
  867. Status = TDI_INVALID_PARAMETER;
  868. if (Size < sizeof(TCPSocketOption))
  869. return Status;
  870. //CTEGetLock(&ConnTableLock, &TableHandle);
  871. Conn = GetConnFromConnID(PtrToUlong(Request->Handle.ConnectionContext), &TableHandle);
  872. if (Conn != NULL) {
  873. CTEStructAssert(Conn, tc);
  874. Status = TDI_SUCCESS;
  875. Option = (TCPSocketOption *) Buffer;
  876. if (ID->toi_id == TCP_SOCKET_WINDOW) {
  877. // This is a funny option, because it doesn't involve
  878. // flags. Handle this specially.
  879. // We don't allow anyone to shrink the window, as this
  880. // gets too weird from a protocol point of view. Also,
  881. // make sure they don't try and set anything too big.
  882. if (Option->tso_value > TCP_MAX_SCALED_WIN)
  883. Status = TDI_INVALID_PARAMETER;
  884. else if ((Option->tso_value > Conn->tc_window) ||
  885. (Conn->tc_tcb == NULL) ||
  886. (Conn->tc_tcb && Option->tso_value >
  887. Conn->tc_tcb->tcb_defaultwin)) {
  888. Conn->tc_flags |= CONN_WINSET;
  889. Conn->tc_window = Option->tso_value;
  890. SetTCB = Conn->tc_tcb;
  891. if (SetTCB != NULL) {
  892. CTEStructAssert(SetTCB, tcb);
  893. CTEGetLock(&SetTCB->tcb_lock, &TCBHandle);
  894. //ASSERT(Option->tso_value > SetTCB->tcb_defaultwin);
  895. if (DATA_RCV_STATE(SetTCB->tcb_state) &&
  896. !CLOSING(SetTCB)) {
  897. // If we are setting the window size
  898. // when scaling is enabled, make sure that the
  899. // scale factor remains same as the one
  900. // which was used in SYN
  901. int rcvwinscale = 0;
  902. if (Option->tso_value >= SetTCB->tcb_defaultwin) {
  903. while ((rcvwinscale < TCP_MAX_WINSHIFT) &&
  904. ((TCP_MAXWIN << rcvwinscale) < (int)Conn->tc_window)) {
  905. rcvwinscale++;
  906. }
  907. if (SetTCB->tcb_rcvwinscale != rcvwinscale) {
  908. CTEFreeLock(&SetTCB->tcb_lock, TCBHandle);
  909. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), TableHandle);
  910. return TDI_INVALID_PARAMETER;
  911. }
  912. SetTCB->tcb_flags |= WINDOW_SET;
  913. SetTCB->tcb_defaultwin = Option->tso_value;
  914. REFERENCE_TCB(SetTCB);
  915. CTEFreeLock(&SetTCB->tcb_lock, TCBHandle);
  916. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), TableHandle);
  917. SendACK(SetTCB);
  918. CTEGetLock(&SetTCB->tcb_lock, &TCBHandle);
  919. DerefTCB(SetTCB, TCBHandle);
  920. return Status;
  921. } else {
  922. CTEFreeLock(&SetTCB->tcb_lock, TCBHandle);
  923. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), TableHandle);
  924. return TDI_INVALID_PARAMETER;
  925. }
  926. } else {
  927. CTEFreeLock(&SetTCB->tcb_lock, TCBHandle);
  928. }
  929. }
  930. //CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), TableHandle);
  931. }
  932. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), TableHandle);
  933. //CTEFreeLock(&ConnTableLock, TableHandle);
  934. return Status;
  935. }
  936. if ((ID->toi_id == TCP_SOCKET_TOS) && !DisableUserTOSSetting) {
  937. SetTCB = Conn->tc_tcb;
  938. if (SetTCB) {
  939. CTEGetLock(&SetTCB->tcb_lock, &TCBHandle);
  940. KdPrintEx((DPFLTR_TCPIP_ID, DPFLTR_INFO_LEVEL,"Setting tos %x %d\n", SetTCB, Option->tso_value));
  941. if (Option->tso_value) {
  942. SetTCB->tcb_opt.ioi_tos = (uchar) Option->tso_value;
  943. Status = TDI_SUCCESS;
  944. }
  945. CTEFreeLock(&SetTCB->tcb_lock, TCBHandle);
  946. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), TableHandle);
  947. return Status;
  948. }
  949. }
  950. Flag = 0;
  951. if (ID->toi_id == TCP_SOCKET_KEEPALIVE_VALS) {
  952. TCPKeepalive *Option;
  953. // treat it as separate as it takes a structure instead of integer
  954. if (Size < sizeof(TCPKeepalive)) {
  955. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), TableHandle);
  956. return Status;
  957. }
  958. Option = (TCPKeepalive *) Buffer;
  959. Value = Option->onoff;
  960. if (Value) {
  961. Conn->tc_tcbkatime = MS_TO_TICKS(Option->keepalivetime);
  962. Conn->tc_tcbkainterval = MS_TO_TICKS(Option->keepaliveinterval);
  963. }
  964. Flag = KEEPALIVE;
  965. } else {
  966. Option = (TCPSocketOption *) Buffer;
  967. Value = Option->tso_value;
  968. // We have the connection, so figure out which flag to set.
  969. switch (ID->toi_id) {
  970. case TCP_SOCKET_NODELAY:
  971. Value = !Value;
  972. Flag = NAGLING;
  973. break;
  974. case TCP_SOCKET_KEEPALIVE:
  975. Flag = KEEPALIVE;
  976. Conn->tc_tcbkatime = KeepAliveTime;
  977. Conn->tc_tcbkainterval = KAInterval;
  978. break;
  979. case TCP_SOCKET_BSDURGENT:
  980. Flag = BSD_URGENT;
  981. break;
  982. case TCP_SOCKET_OOBINLINE:
  983. Flag = URG_INLINE;
  984. break;
  985. case TCP_SOCKET_SCALE_CWIN:
  986. Flag = SCALE_CWIN;
  987. break;
  988. default:
  989. Status = TDI_INVALID_PARAMETER;
  990. break;
  991. }
  992. }
  993. if (Status == TDI_SUCCESS) {
  994. if (Value)
  995. Conn->tc_tcbflags |= Flag;
  996. else
  997. Conn->tc_tcbflags &= ~Flag;
  998. SetTCB = Conn->tc_tcb;
  999. if (SetTCB != NULL) {
  1000. CTEStructAssert(SetTCB, tcb);
  1001. CTEGetLock(&SetTCB->tcb_lock, &TCBHandle);
  1002. if ((ID->toi_id == TCP_SOCKET_OOBINLINE ||
  1003. ID->toi_id == TCP_SOCKET_BSDURGENT) &&
  1004. ((SetTCB->tcb_flags & URG_VALID) ||
  1005. (SetTCB->tcb_fastchk & TCP_FLAG_IN_RCV))) {
  1006. // Don't allow switching to and from inline mode
  1007. // while we have urgent data outstanding or
  1008. // while we're processing receives.
  1009. Status = TDI_INVALID_STATE;
  1010. } else if (Value)
  1011. SetTCB->tcb_flags |= Flag;
  1012. else
  1013. SetTCB->tcb_flags &= ~Flag;
  1014. if ((ID->toi_id == TCP_SOCKET_KEEPALIVE) ||
  1015. (ID->toi_id == TCP_SOCKET_KEEPALIVE_VALS)) {
  1016. START_TCB_TIMER_R(SetTCB, KA_TIMER,
  1017. Conn->tc_tcbkatime);
  1018. SetTCB->tcb_kacount = 0;
  1019. }
  1020. CTEFreeLock(&SetTCB->tcb_lock, TCBHandle);
  1021. }
  1022. }
  1023. CTEFreeLock(&(Conn->tc_ConnBlock->cb_lock), TableHandle);
  1024. }
  1025. return Status;
  1026. }
  1027. if (ID->toi_type == INFO_TYPE_ADDRESS_OBJECT) {
  1028. // We're setting information on an address object. This is
  1029. // pretty simple.
  1030. return SetAddrOptions(Request, ID->toi_id, Size, Buffer);
  1031. }
  1032. if (ID->toi_type != INFO_TYPE_PROVIDER)
  1033. return TDI_INVALID_PARAMETER;
  1034. if (ID->toi_id == TCP_MIB_TABLE_ID) {
  1035. if (Size != sizeof(TCPConnTableEntry))
  1036. return TDI_INVALID_PARAMETER;
  1037. TCPEntry = (TCPConnTableEntry *) Buffer;
  1038. if (TCPEntry->tct_state != TCP_DELETE_TCB)
  1039. return TDI_INVALID_PARAMETER;
  1040. // We have an apparently valid request. Look up the TCB.
  1041. SetTCB = FindTCB(TCPEntry->tct_localaddr,
  1042. TCPEntry->tct_remoteaddr, (ushort) TCPEntry->tct_remoteport,
  1043. (ushort) TCPEntry->tct_localport, &TCBHandle, FALSE, &index);
  1044. // We found him. If he's not closing or closed, close him.
  1045. if (SetTCB != NULL) {
  1046. // We've got him. Bump his ref. count, and call TryToCloseTCB
  1047. // to mark him as closing. Then notify the upper layer client
  1048. // of the disconnect.
  1049. REFERENCE_TCB(SetTCB);
  1050. if (SetTCB->tcb_state != TCB_CLOSED && !CLOSING(SetTCB)) {
  1051. SetTCB->tcb_flags |= NEED_RST;
  1052. TryToCloseTCB(SetTCB, TCB_CLOSE_ABORTED, TCBHandle);
  1053. CTEGetLock(&SetTCB->tcb_lock, &TCBHandle);
  1054. if (SetTCB->tcb_state != TCB_TIME_WAIT) {
  1055. // Remove him from the TCB, and notify the client.
  1056. CTEFreeLock(&SetTCB->tcb_lock, TCBHandle);
  1057. RemoveTCBFromConn(SetTCB);
  1058. NotifyOfDisc(SetTCB, NULL, TDI_CONNECTION_RESET, NULL);
  1059. CTEGetLock(&SetTCB->tcb_lock, &TCBHandle);
  1060. }
  1061. }
  1062. DerefTCB(SetTCB, TCBHandle);
  1063. return TDI_SUCCESS;
  1064. } else {
  1065. return TDI_INVALID_PARAMETER;
  1066. }
  1067. } else
  1068. return TDI_INVALID_PARAMETER;
  1069. }
  1070. if (ID->toi_class == INFO_CLASS_IMPLEMENTATION) {
  1071. // We want to return implementation specific info. For now, error out.
  1072. return TDI_INVALID_REQUEST;
  1073. }
  1074. return TDI_INVALID_REQUEST;
  1075. }
  1076. //* TcpInvokeCcb - Called to post an event on a Connection callback.
  1077. //
  1078. // Various modules in TCP call this to post events to notify interested
  1079. // clients. The information that is communicated along with this is based upon
  1080. // the needs of the current clients.
  1081. //
  1082. // Input: PreviousState - Previous state of the TCP connection.
  1083. // CurrentState - Current state of the TCP connection.
  1084. // TcpAddrBytes - The address information for the connection.
  1085. // InterfaceId - Index of the Interface on which the segment that
  1086. // caused this state transition was received.
  1087. //
  1088. // Returns: Status of attempt to get information.
  1089. //
  1090. void
  1091. TcpInvokeCcb(uint PreviousState, uint CurrentState, TCPAddrInfo *TcpAddrBytes,
  1092. uint InterfaceId)
  1093. {
  1094. TCPCcbInfo CallbackInfo;
  1095. CallbackInfo.tci_prevstate = PreviousState;
  1096. CallbackInfo.tci_currstate = CurrentState;
  1097. CallbackInfo.tci_incomingif = InterfaceId;
  1098. CallbackInfo.tci_connaddr = TcpAddrBytes;
  1099. ExNotifyCallback(TcpCcbObject, (PVOID)&CallbackInfo, 0);
  1100. }
  1101. //* TcpInitCcb - Initilize Connection callback for TCP.
  1102. //
  1103. // TCP calls this function to create a callback object to notify clients
  1104. // interested in knowing when connections get created and destroyed.
  1105. //
  1106. // Input: None.
  1107. //
  1108. // Returns: Status indicating the result of callback creation.
  1109. //
  1110. NTSTATUS
  1111. TcpInitCcb()
  1112. {
  1113. OBJECT_ATTRIBUTES ObjectAttr;
  1114. UNICODE_STRING CallBackObjectName;
  1115. NTSTATUS Status;
  1116. RtlInitUnicodeString(&CallBackObjectName, TCP_CCB_NAME);
  1117. InitializeObjectAttributes(&ObjectAttr, &CallBackObjectName,
  1118. OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
  1119. NULL, NULL);
  1120. Status = ExCreateCallback(&TcpCcbObject, &ObjectAttr, TRUE, TRUE);
  1121. return Status;
  1122. }
  1123. //* TcpUnInitCcb - Deinitilize Connection callback for TCP.
  1124. //
  1125. // This routine is called to remove a reference made by TCP on the callback
  1126. // object.
  1127. //
  1128. // Input: None.
  1129. //
  1130. // Returns: None.
  1131. //
  1132. VOID
  1133. TcpUnInitCcb()
  1134. {
  1135. if (TcpCcbObject) {
  1136. ObDereferenceObject(TcpCcbObject);
  1137. }
  1138. }