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.

3022 lines
98 KiB

  1. /*++
  2. Copyright (c) 2000-2000 Microsoft Corporation
  3. Module Name:
  4. Address.c
  5. Abstract:
  6. This module implements Address handling routines
  7. for the PGM Transport
  8. Author:
  9. Mohammad Shabbir Alam (MAlam) 3-30-2000
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #include <ipinfo.h> // for IPInterfaceInfo
  14. #include <tcpinfo.h> // for AO_OPTION_xxx, TCPSocketOption
  15. #include <tdiinfo.h> // for CL_TL_ENTITY, TCP_REQUEST_SET_INFORMATION_EX
  16. #ifdef FILE_LOGGING
  17. #include "address.tmh"
  18. #endif // FILE_LOGGING
  19. //******************* Pageable Routine Declarations ****************
  20. #ifdef ALLOC_PRAGMA
  21. #endif
  22. //******************* Pageable Routine Declarations ****************
  23. #if(WINVER <= 0x0500)
  24. extern POBJECT_TYPE *IoFileObjectType;
  25. #endif // WINVER
  26. //----------------------------------------------------------------------------
  27. BOOLEAN
  28. GetIpAddress(
  29. IN TRANSPORT_ADDRESS UNALIGNED *pTransportAddr,
  30. IN ULONG BufferLength, // Total Buffer length
  31. OUT tIPADDRESS *pIpAddress,
  32. OUT USHORT *pPort
  33. )
  34. /*++
  35. Routine Description:
  36. This routine extracts the IP address from the TDI address block
  37. Arguments:
  38. IN pTransportAddr -- the block of TDI address(es)
  39. IN BufferLength -- length of the block
  40. OUT pIpAddress -- contains the IpAddress if we succeeded
  41. OUT pPort -- contains the port if we succeeded
  42. Return Value:
  43. TRUE if we succeeded in extracting the IP address, FALSE otherwise
  44. --*/
  45. {
  46. ULONG MinBufferLength; // Minimun reqd to read next AddressType and AddressLength
  47. TA_ADDRESS *pAddress;
  48. TDI_ADDRESS_IP UNALIGNED *pValidAddr;
  49. INT i;
  50. BOOLEAN fAddressFound = FALSE;
  51. if (BufferLength < sizeof(TA_IP_ADDRESS))
  52. {
  53. PgmTrace (LogError, ("GetIpAddress: ERROR -- " \
  54. "Rejecting Open Address request -- BufferLength<%d> < Min<%d>\n",
  55. BufferLength, sizeof(TA_IP_ADDRESS)));
  56. return (FALSE);
  57. }
  58. try
  59. {
  60. MinBufferLength = FIELD_OFFSET(TRANSPORT_ADDRESS,Address) + FIELD_OFFSET(TA_ADDRESS,Address);
  61. pAddress = (TA_ADDRESS *) &pTransportAddr->Address[0]; // address type + the actual address
  62. for (i=0; i<pTransportAddr->TAAddressCount; i++)
  63. {
  64. //
  65. // We support only IP address types:
  66. //
  67. if ((pAddress->AddressType == TDI_ADDRESS_TYPE_IP) &&
  68. (pAddress->AddressLength >= TDI_ADDRESS_LENGTH_IP)) // sizeof (TDI_ADDRESS_IP)
  69. {
  70. pValidAddr = (TDI_ADDRESS_IP UNALIGNED *) pAddress->Address;
  71. *pIpAddress = pValidAddr->in_addr;
  72. *pPort = pValidAddr->sin_port;
  73. fAddressFound = TRUE;
  74. break;
  75. }
  76. //
  77. // Verify that we have enough Buffer space to read in next Address if IP address
  78. //
  79. MinBufferLength += pAddress->AddressLength + FIELD_OFFSET(TA_ADDRESS,Address);
  80. if (BufferLength < (MinBufferLength + sizeof(TDI_ADDRESS_IP)))
  81. {
  82. break;
  83. }
  84. //
  85. // Set pAddress to point to the next address
  86. //
  87. pAddress = (TA_ADDRESS *) (((PUCHAR) pAddress->Address) + pAddress->AddressLength);
  88. }
  89. }
  90. except(EXCEPTION_EXECUTE_HANDLER)
  91. {
  92. PgmTrace (LogError, ("GetIpAddress: ERROR -- " \
  93. "Exception <0x%x> trying to access Addr info\n", GetExceptionCode()));
  94. }
  95. PgmTrace (LogAllFuncs, ("GetIpAddress: " \
  96. "%s!\n", (fAddressFound ? "SUCCEEDED" : "FAILED")));
  97. return (fAddressFound);
  98. }
  99. //----------------------------------------------------------------------------
  100. NTSTATUS
  101. SetSenderMCastOutIf(
  102. IN tADDRESS_CONTEXT *pAddress,
  103. IN tIPADDRESS IpAddress // Net format
  104. )
  105. /*++
  106. Routine Description:
  107. This routine sets the outgoing interface for multicast traffic
  108. Arguments:
  109. IN pAddress -- Pgm's Address object (contains file handle over IP)
  110. IN IpAddress -- interface address
  111. Return Value:
  112. NTSTATUS - Final status of the set Interface operation
  113. --*/
  114. {
  115. NTSTATUS status;
  116. PGMLockHandle OldIrq;
  117. ULONG BufferLength = 50;
  118. IPInterfaceInfo *pIpIfInfo = NULL;
  119. status = PgmSetTcpInfo (pAddress->FileHandle,
  120. AO_OPTION_MCASTIF,
  121. &IpAddress,
  122. sizeof (tIPADDRESS));
  123. if (!NT_SUCCESS (status))
  124. {
  125. PgmTrace (LogError, ("SetSenderMCastOutIf: ERROR -- " \
  126. "AO_OPTION_MCASTIF for <%x> (RouterAlert) returned <%x>\n", IpAddress, status));
  127. return (status);
  128. }
  129. status = PgmSetTcpInfo (pAddress->RAlertFileHandle,
  130. AO_OPTION_MCASTIF,
  131. &IpAddress,
  132. sizeof (tIPADDRESS));
  133. if (!NT_SUCCESS (status))
  134. {
  135. PgmTrace (LogError, ("SetSenderMCastOutIf: ERROR -- " \
  136. "AO_OPTION_MCASTIF for <%x> (RouterAlert) returned <%x>\n", IpAddress, status));
  137. return (status);
  138. }
  139. //
  140. // Now, determine the MTU
  141. //
  142. status = PgmQueryTcpInfo (pAddress->RAlertFileHandle,
  143. IP_INTFC_INFO_ID,
  144. &IpAddress,
  145. sizeof (tIPADDRESS),
  146. &pIpIfInfo,
  147. &BufferLength);
  148. if (!NT_SUCCESS (status))
  149. {
  150. PgmTrace (LogError, ("SetSenderMCastOutIf: ERROR -- " \
  151. "IP_INTFC_INFO_ID for <%x> returned <%x>\n", IpAddress, status));
  152. return (status);
  153. }
  154. if (pIpIfInfo->iii_mtu <= (sizeof(IPV4Header) +
  155. ROUTER_ALERT_SIZE +
  156. PGM_MAX_FEC_DATA_HEADER_LENGTH))
  157. {
  158. PgmTrace (LogError, ("SetSenderMCastOutIf: ERROR -- " \
  159. "MTU=<%d> for Ip=<%x> is too small, <= <%d>\n",
  160. pIpIfInfo->iii_mtu, IpAddress,
  161. (sizeof(IPV4Header) + ROUTER_ALERT_SIZE + PGM_MAX_FEC_DATA_HEADER_LENGTH)));
  162. PgmFreeMem (pIpIfInfo);
  163. return (STATUS_UNSUCCESSFUL);
  164. }
  165. PgmLock (pAddress, OldIrq);
  166. //
  167. // get the length of the mac address in case is is less than 6 bytes
  168. //
  169. BufferLength = pIpIfInfo->iii_addrlength < sizeof(tMAC_ADDRESS) ?
  170. pIpIfInfo->iii_addrlength : sizeof(tMAC_ADDRESS);
  171. PgmZeroMemory (pAddress->OutIfMacAddress.Address, sizeof(tMAC_ADDRESS));
  172. PgmCopyMemory (&pAddress->OutIfMacAddress, pIpIfInfo->iii_addr, BufferLength);
  173. pAddress->OutIfMTU = pIpIfInfo->iii_mtu - (sizeof(IPV4Header) + ROUTER_ALERT_SIZE);
  174. pAddress->OutIfFlags = pIpIfInfo->iii_flags;
  175. pAddress->SenderMCastOutIf = ntohl (IpAddress);
  176. PgmUnlock (pAddress, OldIrq);
  177. PgmTrace (LogStatus, ("SetSenderMCastOutIf: " \
  178. "OutIf=<%x>, MTU=<%d>==><%d>\n",
  179. pAddress->SenderMCastOutIf, pIpIfInfo->iii_mtu, pAddress->OutIfMTU));
  180. PgmFreeMem (pIpIfInfo);
  181. return (status);
  182. }
  183. //----------------------------------------------------------------------------
  184. VOID
  185. PgmDestroyAddress(
  186. IN tADDRESS_CONTEXT *pAddress,
  187. IN PVOID Unused1,
  188. IN PVOID Unused2
  189. )
  190. /*++
  191. Routine Description:
  192. This routine closes the Files handles opened earlier and free's the memory
  193. It should only be called if there is no Reference on the Address Context
  194. Arguments:
  195. IN pAddress -- Pgm's Address object
  196. Return Value:
  197. NONE
  198. --*/
  199. {
  200. if (pAddress->RAlertFileHandle)
  201. {
  202. CloseAddressHandles (pAddress->RAlertFileHandle, pAddress->pRAlertFileObject);
  203. pAddress->RAlertFileHandle = NULL;
  204. }
  205. if (pAddress->FileHandle)
  206. {
  207. CloseAddressHandles (pAddress->FileHandle, pAddress->pFileObject);
  208. pAddress->FileHandle = NULL;
  209. }
  210. else
  211. {
  212. ASSERT (0);
  213. }
  214. if (pAddress->pUserId)
  215. {
  216. PgmFreeMem (pAddress->pUserId);
  217. pAddress->pUserId = NULL;
  218. }
  219. PgmFreeMem (pAddress);
  220. }
  221. //----------------------------------------------------------------------------
  222. NTSTATUS
  223. PgmCreateAddress(
  224. IN tPGM_DEVICE *pPgmDevice,
  225. IN PIRP pIrp,
  226. IN PIO_STACK_LOCATION pIrpSp,
  227. IN PFILE_FULL_EA_INFORMATION TargetEA
  228. )
  229. /*++
  230. Routine Description:
  231. This routine is called to create an address context for the client
  232. It's main task is to allocate the memory, open handles on IP, and
  233. set the initial IP options
  234. Arguments:
  235. IN pPgmDevice -- Pgm's Device object context
  236. IN pIrp -- Client's request Irp
  237. IN pIrpSp -- current request's stack pointer
  238. IN TargetEA -- contains the MCast address info (determines whether
  239. the client is a sender or receiver)
  240. Return Value:
  241. NTSTATUS - Final status of the CreateAddress operation
  242. --*/
  243. {
  244. tADDRESS_CONTEXT *pAddress = NULL;
  245. PADDRESS_CONTEXT pOldAddress, pOldAddressToDeref;
  246. TRANSPORT_ADDRESS UNALIGNED *pTransportAddr;
  247. tMCAST_INFO MCastInfo;
  248. NTSTATUS status;
  249. tIPADDRESS IpAddress;
  250. LIST_ENTRY *pEntry;
  251. USHORT Port;
  252. PGMLockHandle OldIrq;
  253. ULONG NumUserStreams;
  254. TOKEN_USER *pUserId = NULL;
  255. BOOLEAN fUserIsAdmin = FALSE;
  256. status = PgmGetUserInfo (pIrp, pIrpSp, &pUserId, &fUserIsAdmin);
  257. if (!NT_SUCCESS (status))
  258. {
  259. PgmTrace (LogError, ("PgmCreateAddress: ERROR -- " \
  260. "GetUserInfo FAILed status=<%x>!\n", status));
  261. }
  262. //
  263. // Verify Minimum Buffer length!
  264. //
  265. pTransportAddr = (TRANSPORT_ADDRESS UNALIGNED *) &(TargetEA->EaName[TargetEA->EaNameLength+1]);
  266. if (!GetIpAddress (pTransportAddr, TargetEA->EaValueLength, &IpAddress, &Port))
  267. {
  268. PgmTrace (LogError, ("PgmCreateAddress: ERROR -- " \
  269. "GetIpAddress FAILed to return valid Address!\n"));
  270. PgmFreeMem (pUserId);
  271. return (STATUS_INVALID_ADDRESS_COMPONENT);
  272. }
  273. //
  274. // Convert the parameters to host format
  275. //
  276. IpAddress = ntohl (IpAddress);
  277. Port = ntohs (Port);
  278. //
  279. // If we have been supplied an address at bind time, it has to
  280. // be a Multicast address
  281. //
  282. if ((IpAddress) &&
  283. (!IS_MCAST_ADDRESS (IpAddress)))
  284. {
  285. PgmTrace (LogError, ("PgmCreateAddress: ERROR -- " \
  286. "IP=<%x> is not MCast addr!\n", IpAddress));
  287. PgmFreeMem (pUserId);
  288. return (STATUS_UNSUCCESSFUL);
  289. }
  290. else if ((!IpAddress) &&
  291. (!fUserIsAdmin))
  292. {
  293. PgmTrace (LogError, ("PgmCreateAddress: ERROR -- " \
  294. "Sender MUST be Admin!\n"));
  295. PgmFreeMem (pUserId);
  296. return (STATUS_ACCESS_DENIED);
  297. }
  298. //
  299. // So, we found a valid address -- now, open it!
  300. //
  301. if (!(pAddress = PgmAllocMem (sizeof(tADDRESS_CONTEXT), PGM_TAG('0'))))
  302. {
  303. PgmTrace (LogError, ("PgmCreateAddress: ERROR -- " \
  304. "STATUS_INSUFFICIENT_RESOURCES!\n"));
  305. PgmFreeMem (pUserId);
  306. return (STATUS_INSUFFICIENT_RESOURCES);
  307. }
  308. PgmZeroMemory (pAddress, sizeof (tADDRESS_CONTEXT));
  309. InitializeListHead (&pAddress->Linkage);
  310. InitializeListHead (&pAddress->AssociatedConnections); // List of associated connections
  311. InitializeListHead (&pAddress->ListenHead); // List of Clients listening on this address
  312. PgmInitLock (pAddress, ADDRESS_LOCK);
  313. pAddress->Verify = PGM_VERIFY_ADDRESS;
  314. PGM_REFERENCE_ADDRESS (pAddress, REF_ADDRESS_CREATE, TRUE); // Set Locked to TRUE since it not in use
  315. pAddress->Process = (PEPROCESS) PsGetCurrentProcess();
  316. pAddress->pUserId = pUserId;
  317. //
  318. // Now open a handle on IP
  319. //
  320. status = TdiOpenAddressHandle (pgPgmDevice,
  321. (PVOID) pAddress,
  322. 0, // Open any Src address
  323. IPPROTO_RM, // PGM port
  324. &pAddress->FileHandle,
  325. &pAddress->pFileObject,
  326. &pAddress->pDeviceObject);
  327. if (!NT_SUCCESS (status))
  328. {
  329. PgmTrace (LogError, ("PgmCreateAddress: ERROR -- " \
  330. "TdiOpenAddressHandle returned <%x>, Destroying pAddress=<%p>\n",
  331. status, pAddress));
  332. PgmFreeMem (pUserId);
  333. PgmFreeMem (pAddress);
  334. return (status);
  335. }
  336. if (IpAddress)
  337. {
  338. //
  339. // We are now ready to start receiving data (if we have been designated an MCast receiver)
  340. // Save the MCast addresses (if any were provided)
  341. //
  342. pAddress->ReceiverMCastAddr = IpAddress; // Saved in Host format
  343. pAddress->ReceiverMCastPort = Port;
  344. pAddress->pUserId = pUserId;
  345. PgmLock (&PgmDynamicConfig, OldIrq);
  346. //
  347. // Verify that Non-Admin user has < MAX_STREAMS_PER_NONADMIN_RECEIVER Sessions for this IP and Port #
  348. //
  349. NumUserStreams = 0;
  350. pOldAddress = pOldAddressToDeref = NULL;
  351. if (!fUserIsAdmin)
  352. {
  353. pEntry = PgmDynamicConfig.ReceiverAddressHead.Flink;
  354. while (pEntry != &PgmDynamicConfig.ReceiverAddressHead)
  355. {
  356. pOldAddress = CONTAINING_RECORD (pEntry, tADDRESS_CONTEXT, Linkage);
  357. if ((IpAddress == pOldAddress->ReceiverMCastAddr) &&
  358. (Port == pOldAddress->ReceiverMCastPort))
  359. {
  360. PGM_REFERENCE_ADDRESS (pOldAddress, REF_ADDRESS_VERIFY_USER, FALSE);
  361. PgmUnlock (&PgmDynamicConfig, OldIrq);
  362. if (pOldAddressToDeref)
  363. {
  364. PGM_DEREFERENCE_ADDRESS (pOldAddressToDeref, REF_ADDRESS_VERIFY_USER);
  365. }
  366. pOldAddressToDeref = pOldAddress;
  367. if (RtlEqualSid (pUserId->User.Sid, pOldAddress->pUserId->User.Sid))
  368. {
  369. NumUserStreams++;
  370. }
  371. PgmLock (&PgmDynamicConfig, OldIrq);
  372. }
  373. pEntry = pOldAddress->Linkage.Flink;
  374. }
  375. if (NumUserStreams >= MAX_STREAMS_PER_NONADMIN_RECEIVER)
  376. {
  377. PgmUnlock (&PgmDynamicConfig, OldIrq);
  378. if (pOldAddressToDeref)
  379. {
  380. PGM_DEREFERENCE_ADDRESS (pOldAddressToDeref, REF_ADDRESS_VERIFY_USER);
  381. pOldAddressToDeref = NULL;
  382. }
  383. PgmTrace (LogError, ("PgmCreateAddress: ERROR -- " \
  384. "Non-admin user trying to open %d+1 handle for IP:Port=<%x:%x>\n",
  385. NumUserStreams, IpAddress, Port));
  386. PgmDestroyAddress (pAddress, NULL, NULL);
  387. return (STATUS_ACCESS_DENIED);
  388. }
  389. }
  390. InsertTailList (&PgmDynamicConfig.ReceiverAddressHead, &pAddress->Linkage);
  391. PgmUnlock (&PgmDynamicConfig, OldIrq);
  392. if (pOldAddressToDeref)
  393. {
  394. PGM_DEREFERENCE_ADDRESS (pOldAddressToDeref, REF_ADDRESS_VERIFY_USER);
  395. pOldAddressToDeref = NULL;
  396. }
  397. }
  398. else
  399. {
  400. //
  401. // This is an address for sending mcast packets, so
  402. // Open another FileObject for sending packets with RouterAlert option
  403. //
  404. status = TdiOpenAddressHandle (pgPgmDevice,
  405. NULL,
  406. 0, // Open any Src address
  407. IPPROTO_RM, // PGM port
  408. &pAddress->RAlertFileHandle,
  409. &pAddress->pRAlertFileObject,
  410. &pAddress->pRAlertDeviceObject);
  411. if (!NT_SUCCESS (status))
  412. {
  413. PgmTrace (LogError, ("PgmCreateAddress: ERROR -- " \
  414. "AO_OPTION_IPOPTIONS for Router Alert returned <%x>, Destroying pAddress=<%p>\n",
  415. status, pAddress));
  416. PgmDestroyAddress (pAddress, NULL, NULL);
  417. return (status);
  418. }
  419. PgmLock (&PgmDynamicConfig, OldIrq);
  420. //
  421. // Set the default sender parameters
  422. // Since we don't know the MTU at this time, we
  423. // will assume 1.4K window size for Ethernet
  424. //
  425. pAddress->RateKbitsPerSec = SENDER_DEFAULT_RATE_KBITS_PER_SEC;
  426. pAddress->WindowSizeInBytes = SENDER_DEFAULT_WINDOW_SIZE_BYTES;
  427. pAddress->MaxWindowSizeBytes = SENDER_MAX_WINDOW_SIZE_PACKETS;
  428. pAddress->MaxWindowSizeBytes *= 1400;
  429. ASSERT (pAddress->MaxWindowSizeBytes >= SENDER_DEFAULT_WINDOW_SIZE_BYTES);
  430. pAddress->WindowSizeInMSecs = (BITS_PER_BYTE * pAddress->WindowSizeInBytes) /
  431. SENDER_DEFAULT_RATE_KBITS_PER_SEC;
  432. pAddress->WindowAdvancePercentage = SENDER_DEFAULT_WINDOW_ADV_PERCENTAGE;
  433. pAddress->LateJoinerPercentage = SENDER_DEFAULT_LATE_JOINER_PERCENTAGE;
  434. pAddress->FECGroupSize = 1; // ==> No FEC packets!
  435. pAddress->MCastPacketTtl = MAX_MCAST_TTL;
  436. InsertTailList (&PgmDynamicConfig.SenderAddressHead, &pAddress->Linkage);
  437. PgmUnlock (&PgmDynamicConfig, OldIrq);
  438. }
  439. PgmTrace (LogStatus, ("PgmCreateAddress: " \
  440. "%s -- pAddress=<%p>, IP:Port=<%x:%x>\n", (IpAddress ? "Receiver" : "Sender"),
  441. pAddress, IpAddress, Port));
  442. pIrpSp->FileObject->FsContext = pAddress;
  443. pIrpSp->FileObject->FsContext2 = (PVOID) TDI_TRANSPORT_ADDRESS_FILE;
  444. return (STATUS_SUCCESS);
  445. }
  446. //----------------------------------------------------------------------------
  447. VOID
  448. PgmDereferenceAddress(
  449. IN tADDRESS_CONTEXT *pAddress,
  450. IN ULONG RefContext
  451. )
  452. /*++
  453. Routine Description:
  454. This routine decrements the RefCount on the address object
  455. and causes a cleanup to occur if the RefCount went to 0
  456. Arguments:
  457. IN pAddress -- Pgm's address object
  458. IN RefContext -- context for which this address object
  459. was referenced earlier
  460. Return Value:
  461. NONE
  462. --*/
  463. {
  464. NTSTATUS status;
  465. PGMLockHandle OldIrq, OldIrq1;
  466. PIRP pIrpClose;
  467. PIO_STACK_LOCATION pIrpSp;
  468. PgmLock (pAddress, OldIrq);
  469. ASSERT (PGM_VERIFY_HANDLE2 (pAddress,PGM_VERIFY_ADDRESS, PGM_VERIFY_ADDRESS_DOWN));
  470. ASSERT (pAddress->RefCount); // Check for too many derefs
  471. ASSERT (pAddress->ReferenceContexts[RefContext]--);
  472. if (--pAddress->RefCount)
  473. {
  474. PgmUnlock (pAddress, OldIrq);
  475. return;
  476. }
  477. ASSERT (IsListEmpty (&pAddress->AssociatedConnections));
  478. PgmUnlock (pAddress, OldIrq);
  479. //
  480. // Just Remove from the ClosedAddresses list
  481. //
  482. PgmLock (&PgmDynamicConfig, OldIrq);
  483. PgmLock (pAddress, OldIrq1);
  484. pIrpClose = pAddress->pIrpClose;
  485. pAddress->pIrpClose = NULL;
  486. RemoveEntryList (&pAddress->Linkage);
  487. PgmUnlock (pAddress, OldIrq1);
  488. PgmUnlock (&PgmDynamicConfig, OldIrq);
  489. PgmTrace (LogStatus, ("PgmDereferenceAddress: " \
  490. "Destroying Address=<%p>\n", pAddress));
  491. if (PgmGetCurrentIrql())
  492. {
  493. status = PgmQueueForDelayedExecution (PgmDestroyAddress, pAddress, NULL, NULL, FALSE);
  494. if (!NT_SUCCESS (status))
  495. {
  496. PgmInterlockedInsertTailList (&PgmDynamicConfig.DestroyedAddresses, &pAddress->Linkage, &PgmDynamicConfig);
  497. }
  498. }
  499. else
  500. {
  501. PgmDestroyAddress (pAddress, NULL, NULL);
  502. }
  503. //
  504. // pIrpClose will be NULL if we dereferencing the address
  505. // as a result of an error during the Create
  506. //
  507. if (pIrpClose)
  508. {
  509. pIrpSp = IoGetCurrentIrpStackLocation (pIrpClose);
  510. pIrpSp->FileObject->FsContext = NULL;
  511. PgmIoComplete (pIrpClose, STATUS_SUCCESS, 0);
  512. }
  513. }
  514. //----------------------------------------------------------------------------
  515. NTSTATUS
  516. PgmCleanupAddress(
  517. IN tADDRESS_CONTEXT *pAddress,
  518. IN PIRP pIrp
  519. )
  520. /*++
  521. Routine Description:
  522. This routine is called as a result of a close on the client's
  523. address handle. Our main job here is to mark the address
  524. as being cleaned up (so it that subsequent operations will
  525. fail) and complete the request only when the last RefCount
  526. has been dereferenced.
  527. Arguments:
  528. IN pAddress -- Pgm's address object
  529. IN pIrp -- Client's request Irp
  530. Return Value:
  531. NTSTATUS - Final status of the set event operation (STATUS_PENDING)
  532. --*/
  533. {
  534. NTSTATUS status;
  535. PGMLockHandle OldIrq, OldIrq1;
  536. PgmTrace (LogStatus, ("PgmCleanupAddress: " \
  537. "Address=<%p> FileHandle=<%p>, FileObject=<%p>\n",
  538. pAddress, pAddress->FileHandle, pAddress->pFileObject));
  539. PgmLock (&PgmDynamicConfig, OldIrq);
  540. PgmLock (pAddress, OldIrq1);
  541. ASSERT (PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS));
  542. pAddress->Verify = PGM_VERIFY_ADDRESS_DOWN;
  543. PgmUnlock (pAddress, OldIrq1);
  544. PgmUnlock (&PgmDynamicConfig, OldIrq);
  545. return (STATUS_SUCCESS);
  546. }
  547. //----------------------------------------------------------------------------
  548. NTSTATUS
  549. PgmCloseAddress(
  550. IN PIRP pIrp,
  551. IN PIO_STACK_LOCATION pIrpSp
  552. )
  553. /*++
  554. Routine Description:
  555. This routine is the final dispatch operation to be performed
  556. after the cleanup, which should result in the address being
  557. completely destroyed -- our RefCount must have already
  558. been set to 0 when we completed the Cleanup request.
  559. Arguments:
  560. IN pIrp -- Client's request Irp
  561. IN pIrpSp -- Current request stack location
  562. Return Value:
  563. NTSTATUS - Final status of the operation (STATUS_SUCCESS)
  564. --*/
  565. {
  566. PGMLockHandle OldIrq, OldIrq1;
  567. tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
  568. PgmTrace (LogAllFuncs, ("PgmCloseAddress: " \
  569. "Address=<%p>, RefCount=<%d>\n", pAddress, pAddress->RefCount));
  570. //
  571. // Remove from the global list and Put it on the Closed list!
  572. //
  573. PgmLock (&PgmDynamicConfig, OldIrq);
  574. PgmLock (pAddress, OldIrq1);
  575. RemoveEntryList (&pAddress->Linkage);
  576. InsertTailList (&PgmDynamicConfig.ClosedAddresses, &pAddress->Linkage);
  577. pAddress->pIrpClose = pIrp;
  578. PgmUnlock (pAddress, OldIrq1);
  579. PgmUnlock (&PgmDynamicConfig, OldIrq);
  580. PGM_DEREFERENCE_ADDRESS (pAddress, REF_ADDRESS_CREATE);
  581. //
  582. // The final Dereference will complete the Irp!
  583. //
  584. return (STATUS_PENDING);
  585. }
  586. //----------------------------------------------------------------------------
  587. NTSTATUS
  588. PgmAssociateAddress(
  589. IN tPGM_DEVICE *pPgmDevice,
  590. IN PIRP pIrp,
  591. IN PIO_STACK_LOCATION pIrpSp
  592. )
  593. /*++
  594. Routine Description:
  595. This routine associates a connection with an address object
  596. Arguments:
  597. IN pPgmDevice -- Pgm's Device object context
  598. IN pIrp -- Client's request Irp
  599. IN pIrpSp -- current request's stack pointer
  600. Return Value:
  601. NTSTATUS - Final status of the set event operation
  602. --*/
  603. {
  604. tADDRESS_CONTEXT *pAddress = NULL;
  605. tCOMMON_SESSION_CONTEXT *pSession = pIrpSp->FileObject->FsContext;
  606. PTDI_REQUEST_KERNEL_ASSOCIATE pParameters = (PTDI_REQUEST_KERNEL_ASSOCIATE) &pIrpSp->Parameters;
  607. PFILE_OBJECT pFileObject = NULL;
  608. NTSTATUS status;
  609. PGMLockHandle OldIrq, OldIrq1, OldIrq2;
  610. ULONG i;
  611. UCHAR pRandomData[SOURCE_ID_LENGTH];
  612. //
  613. // Get a pointer to the file object, which points to the address
  614. // element by calling a kernel routine to convert the filehandle into
  615. // a file object pointer.
  616. //
  617. status = ObReferenceObjectByHandle (pParameters->AddressHandle,
  618. FILE_READ_DATA,
  619. *IoFileObjectType,
  620. pIrp->RequestorMode,
  621. (PVOID *) &pFileObject,
  622. NULL);
  623. if (!NT_SUCCESS(status))
  624. {
  625. PgmTrace (LogError, ("PgmAssociateAddress: ERROR -- " \
  626. "Invalid Address Handle=<%p>\n", pParameters->AddressHandle));
  627. return (STATUS_INVALID_HANDLE);
  628. }
  629. //
  630. // Acquire the DynamicConfig lock so as to ensure that the Address
  631. // and Connection cannot get removed while we are processing it!
  632. //
  633. PgmLock (&PgmDynamicConfig, OldIrq);
  634. //
  635. // Verify the Connection handle
  636. //
  637. if ((!PGM_VERIFY_HANDLE (pSession, PGM_VERIFY_SESSION_UNASSOCIATED)) ||
  638. (pSession->pAssociatedAddress)) // Ensure the connection is not already associated!
  639. {
  640. PgmTrace (LogError, ("PgmAssociateAddress: ERROR -- " \
  641. "Invalid Session Handle=<%p>\n", pSession));
  642. PgmUnlock (&PgmDynamicConfig, OldIrq);
  643. ObDereferenceObject ((PVOID) pFileObject);
  644. return (STATUS_INVALID_HANDLE);
  645. }
  646. //
  647. // Verify the Address handle
  648. //
  649. pAddress = pFileObject->FsContext;
  650. if ((pFileObject->DeviceObject->DriverObject != PgmStaticConfig.DriverObject) ||
  651. (PtrToUlong (pFileObject->FsContext2) != TDI_TRANSPORT_ADDRESS_FILE) ||
  652. (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS)))
  653. {
  654. PgmTrace (LogError, ("PgmAssociateAddress: ERROR -- " \
  655. "Invalid Address Context=<%p>\n", pAddress));
  656. PgmUnlock (&PgmDynamicConfig, OldIrq);
  657. ObDereferenceObject ((PVOID) pFileObject);
  658. return (STATUS_INVALID_HANDLE);
  659. }
  660. PgmLock (pAddress, OldIrq1);
  661. PgmLock (pSession, OldIrq2);
  662. ASSERT (!pSession->pReceiver && !pSession->pSender);
  663. //
  664. // Now try to allocate the send / receive context
  665. //
  666. status = STATUS_INSUFFICIENT_RESOURCES;
  667. if (pAddress->ReceiverMCastAddr)
  668. {
  669. if (pSession->pReceiver = PgmAllocMem (sizeof(tRECEIVE_CONTEXT), PGM_TAG('0')))
  670. {
  671. //
  672. // We are a receiver
  673. //
  674. PgmZeroMemory (pSession->pReceiver, sizeof(tRECEIVE_CONTEXT));
  675. InitializeListHead (&pSession->pReceiver->Linkage);
  676. InitializeListHead (&pSession->pReceiver->NaksForwardDataList);
  677. InitializeListHead (&pSession->pReceiver->ReceiveIrpsList);
  678. InitializeListHead (&pSession->pReceiver->BufferedDataList);
  679. InitializeListHead (&pSession->pReceiver->PendingNaksList);
  680. pSession->Verify = PGM_VERIFY_SESSION_RECEIVE;
  681. PGM_REFERENCE_SESSION_RECEIVE (pSession, REF_SESSION_ASSOCIATED, TRUE);
  682. pSession->pReceiver->ListenMCastIpAddress = pAddress->ReceiverMCastAddr;
  683. pSession->pReceiver->ListenMCastPort = pAddress->ReceiverMCastPort;
  684. pSession->pReceiver->pReceive = pSession;
  685. status = STATUS_SUCCESS;
  686. }
  687. }
  688. else if (pSession->pSender = PgmAllocMem (sizeof(tSEND_CONTEXT), PGM_TAG('0')))
  689. {
  690. //
  691. // We are a sender
  692. //
  693. PgmZeroMemory (pSession->pSender, sizeof(tSEND_CONTEXT));
  694. InitializeListHead (&pSession->pSender->Linkage);
  695. InitializeListHead (&pSession->pSender->PendingSends);
  696. InitializeListHead (&pSession->pSender->CompletedSendsInWindow);
  697. ExInitializeResourceLite (&pSession->pSender->Resource);
  698. pSession->Verify = PGM_VERIFY_SESSION_SEND;
  699. GetRandomData (pRandomData, SOURCE_ID_LENGTH);
  700. for (i=0; i<SOURCE_ID_LENGTH; i++)
  701. {
  702. pSession->TSI.GSI[i] = pRandomData[i] ^ pAddress->OutIfMacAddress.Address[i];
  703. }
  704. PGM_REFERENCE_SESSION_SEND (pSession, REF_SESSION_ASSOCIATED, TRUE);
  705. status = STATUS_SUCCESS;
  706. }
  707. if (!NT_SUCCESS (status))
  708. {
  709. PgmUnlock (pSession, OldIrq2);
  710. PgmUnlock (pAddress, OldIrq1);
  711. PgmUnlock (&PgmDynamicConfig, OldIrq);
  712. ObDereferenceObject ((PVOID) pFileObject);
  713. PgmTrace (LogError, ("PgmAssociateAddress: ERROR -- " \
  714. "STATUS_INSUFFICIENT_RESOURCES allocating context for %s, pAddress=<%p>, pSession=<%p>\n",
  715. (pAddress->ReceiverMCastAddr ? "pReceiver" : "pSender"), pAddress, pSession));
  716. return (STATUS_INSUFFICIENT_RESOURCES);
  717. }
  718. //
  719. // Now associate the connection with the address!
  720. // Unlink from the ConnectionsCreated list which was linked
  721. // when the connection was created, and put on the AssociatedConnections list
  722. //
  723. pSession->pAssociatedAddress = pAddress;
  724. RemoveEntryList (&pSession->Linkage);
  725. InsertTailList (&pAddress->AssociatedConnections, &pSession->Linkage);
  726. PGM_REFERENCE_ADDRESS (pAddress, REF_ADDRESS_ASSOCIATED, TRUE);
  727. PgmUnlock (pSession, OldIrq2);
  728. PgmUnlock (pAddress, OldIrq1);
  729. PgmUnlock (&PgmDynamicConfig, OldIrq);
  730. ObDereferenceObject ((PVOID) pFileObject);
  731. PgmTrace (LogStatus, ("PgmAssociateAddress: " \
  732. "Associated pSession=<%p> with pAddress=<%p>\n", pSession, pAddress));
  733. return (STATUS_SUCCESS);
  734. }
  735. //----------------------------------------------------------------------------
  736. NTSTATUS
  737. PgmDisassociateAddress(
  738. IN PIRP pIrp,
  739. IN PIO_STACK_LOCATION pIrpSp
  740. )
  741. /*++
  742. Routine Description:
  743. This routine disassociates a connection from an address object
  744. Arguments:
  745. IN pIrp -- Client's request Irp
  746. IN pIrpSp -- current request's stack pointer
  747. Return Value:
  748. NTSTATUS - Final status of the set event operation
  749. --*/
  750. {
  751. PGMLockHandle OldIrq, OldIrq1, OldIrq2;
  752. ULONG CheckFlags;
  753. NTSTATUS status;
  754. tADDRESS_CONTEXT *pAddress = NULL;
  755. tCOMMON_SESSION_CONTEXT *pSession = pIrpSp->FileObject->FsContext;
  756. //
  757. // Acquire the DynamicConfig lock so as to ensure that the Address
  758. // and Connection Linkages cannot change while we are processing it!
  759. //
  760. PgmLock (&PgmDynamicConfig, OldIrq);
  761. //
  762. // First verify all the handles
  763. //
  764. if (!PGM_VERIFY_HANDLE3 (pSession, PGM_VERIFY_SESSION_SEND,
  765. PGM_VERIFY_SESSION_RECEIVE,
  766. PGM_VERIFY_SESSION_DOWN))
  767. {
  768. PgmTrace (LogError, ("PgmDisassociateAddress: ERROR -- " \
  769. "Invalid Session Handle=<%p>, Verify=<%x>\n",
  770. pSession, (pSession ? pSession->Verify : 0)));
  771. PgmUnlock (&PgmDynamicConfig, OldIrq);
  772. return (STATUS_INVALID_HANDLE);
  773. }
  774. pAddress = pSession->pAssociatedAddress;
  775. if (!PGM_VERIFY_HANDLE2 (pAddress, PGM_VERIFY_ADDRESS, PGM_VERIFY_ADDRESS_DOWN))
  776. {
  777. PgmTrace (LogError, ("PgmDisassociateAddress: ERROR -- " \
  778. "pSession=<%p>, Invalid Address Context=<%p>\n", pSession, pSession->pAssociatedAddress));
  779. PgmUnlock (&PgmDynamicConfig, OldIrq);
  780. return (STATUS_INVALID_HANDLE);
  781. }
  782. PgmTrace (LogStatus, ("PgmDisassociateAddress: " \
  783. "Disassociating pSession=<%p:%p> from pAddress=<%p>\n",
  784. pSession, pSession->ClientSessionContext, pSession->pAssociatedAddress));
  785. PgmLock (pAddress, OldIrq1);
  786. PgmLock (pSession, OldIrq2);
  787. //
  788. // Unlink from the AssociatedConnections list, which was linked
  789. // when the connection was created.
  790. //
  791. pSession->pAssociatedAddress = NULL; // Disassociated!
  792. RemoveEntryList (&pSession->Linkage);
  793. if (PGM_VERIFY_HANDLE2 (pSession, PGM_VERIFY_SESSION_SEND, PGM_VERIFY_SESSION_RECEIVE))
  794. {
  795. //
  796. // The connection is still active, so just put it on the CreatedConnections list
  797. //
  798. InsertTailList (&PgmDynamicConfig.ConnectionsCreated, &pSession->Linkage);
  799. }
  800. else // PGM_VERIFY_SESSION_DOWN
  801. {
  802. //
  803. // The Connection was CleanedUp and may even be closed,
  804. // so put it on the CleanedUp list!
  805. //
  806. InsertTailList (&PgmDynamicConfig.CleanedUpConnections, &pSession->Linkage);
  807. }
  808. CheckFlags = PGM_SESSION_FLAG_IN_INDICATE | PGM_SESSION_CLIENT_DISCONNECTED;
  809. if (CheckFlags == (pSession->SessionFlags & CheckFlags))
  810. {
  811. pSession->pIrpDisassociate = pIrp;
  812. status = STATUS_PENDING;
  813. }
  814. else
  815. {
  816. pSession->SessionFlags |= PGM_SESSION_CLIENT_DISCONNECTED;
  817. status = STATUS_SUCCESS;
  818. }
  819. PgmUnlock (pSession, OldIrq2);
  820. PgmUnlock (pAddress, OldIrq1);
  821. PgmUnlock (&PgmDynamicConfig, OldIrq);
  822. if (PGM_VERIFY_HANDLE (pSession, PGM_VERIFY_SESSION_RECEIVE))
  823. {
  824. PGM_DEREFERENCE_SESSION_RECEIVE (pSession, REF_SESSION_ASSOCIATED);
  825. }
  826. else if (PGM_VERIFY_HANDLE (pSession, PGM_VERIFY_SESSION_SEND))
  827. {
  828. PGM_DEREFERENCE_SESSION_SEND (pSession, REF_SESSION_ASSOCIATED);
  829. }
  830. else // we have already been cleaned up, so just do unassociated!
  831. {
  832. PGM_DEREFERENCE_SESSION_UNASSOCIATED (pSession, REF_SESSION_ASSOCIATED);
  833. }
  834. PGM_DEREFERENCE_ADDRESS (pAddress, REF_ADDRESS_ASSOCIATED);
  835. return (status);
  836. }
  837. //----------------------------------------------------------------------------
  838. NTSTATUS
  839. PgmSetMCastOutIf(
  840. IN PIRP pIrp,
  841. IN PIO_STACK_LOCATION pIrpSp
  842. )
  843. /*++
  844. Routine Description:
  845. This routine is called as a result of the client attempting
  846. to set the outgoing interface for MCast traffic
  847. Arguments:
  848. IN pIrp -- Client's request Irp
  849. IN pIrpSp -- current request's stack pointer
  850. Return Value:
  851. NTSTATUS - Final status of the set outgoing interface operation
  852. --*/
  853. {
  854. NTSTATUS status;
  855. PGMLockHandle OldIrq;
  856. ULONG Length;
  857. ULONG BufferLength = 50;
  858. UCHAR pBuffer[50];
  859. IPInterfaceInfo *pIpIfInfo = (IPInterfaceInfo *) pBuffer;
  860. tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
  861. tPGM_MCAST_REQUEST *pInputBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
  862. ULONG *pInfoBuffer = (PULONG) pIrp->AssociatedIrp.SystemBuffer;
  863. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (tPGM_MCAST_REQUEST))
  864. {
  865. PgmTrace (LogError, ("PgmSetMCastOutIf: ERROR -- " \
  866. "Invalid BufferLength, <%d> < <%d>\n",
  867. pIrpSp->Parameters.DeviceIoControl.InputBufferLength, sizeof (tPGM_MCAST_REQUEST)));
  868. return (STATUS_INVALID_PARAMETER);
  869. }
  870. PgmLock (&PgmDynamicConfig, OldIrq);
  871. if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
  872. {
  873. PgmTrace (LogError, ("PgmSetMCastOutIf: ERROR -- " \
  874. "Invalid Handle pAddress=<%p>\n", pAddress));
  875. PgmUnlock (&PgmDynamicConfig, OldIrq);
  876. return (STATUS_INVALID_HANDLE);
  877. }
  878. if (pAddress->ReceiverMCastAddr) // Cannot set OutIf on Receiver!
  879. {
  880. PgmTrace (LogError, ("PgmSetMCastOutIf: ERROR -- " \
  881. "Invalid Option for Receiver, pAddress=<%p>\n", pAddress));
  882. PgmUnlock (&PgmDynamicConfig, OldIrq);
  883. return (STATUS_NOT_SUPPORTED);
  884. }
  885. PGM_REFERENCE_ADDRESS (pAddress, REF_ADDRESS_SET_INFO, FALSE);
  886. PgmUnlock (&PgmDynamicConfig, OldIrq);
  887. status = SetSenderMCastOutIf (pAddress, pInputBuffer->MCastOutIf);
  888. PGM_DEREFERENCE_ADDRESS (pAddress, REF_ADDRESS_SET_INFO);
  889. PgmTrace (LogStatus, ("PgmSetMCastOutIf: " \
  890. "OutIf = <%x>\n", pAddress->SenderMCastOutIf));
  891. return (status);
  892. }
  893. //----------------------------------------------------------------------------
  894. NTSTATUS
  895. ReceiverAddMCastIf(
  896. IN tADDRESS_CONTEXT *pAddress,
  897. IN tIPADDRESS IpAddress, // In host format
  898. IN PGMLockHandle *pOldIrqDynamicConfig,
  899. IN PGMLockHandle *pOldIrqAddress
  900. )
  901. /*++
  902. Routine Description:
  903. This routine is called as a result of the client attempting
  904. to add an interface to the list of interfaces listening for
  905. MCast traffic
  906. Arguments:
  907. IN pIrp -- Client's request Irp
  908. IN pIrpSp -- current request's stack pointer
  909. Return Value:
  910. NTSTATUS - Final status of the add interface operation
  911. --*/
  912. {
  913. NTSTATUS status;
  914. tMCAST_INFO MCastInfo;
  915. ULONG IpInterfaceIndex;
  916. USHORT i;
  917. if (!pAddress->ReceiverMCastAddr) // Cannot set ReceiveIf on Sender!
  918. {
  919. PgmTrace (LogError, ("ReceiverAddMCastIf: ERROR -- " \
  920. "Invalid Option for Sender, pAddress=<%p>\n", pAddress));
  921. return (STATUS_NOT_SUPPORTED);
  922. }
  923. status = GetIpInterfaceIndexFromAddress (IpAddress, &IpInterfaceIndex);
  924. if (!NT_SUCCESS (status))
  925. {
  926. PgmTrace (LogError, ("ReceiverAddMCastIf: ERROR -- " \
  927. "GetIpInterfaceIndexFromAddress returned <%x> for Address=<%x>\n",
  928. status, IpAddress));
  929. return (STATUS_SUCCESS);
  930. }
  931. //
  932. // If we are already listening on this interface, return success
  933. //
  934. for (i=0; i <pAddress->NumReceiveInterfaces; i++)
  935. {
  936. #ifdef IP_FIX
  937. if (pAddress->ReceiverInterfaceList[i] == IpInterfaceIndex)
  938. #else
  939. if (pAddress->ReceiverInterfaceList[i] == IpAddress)
  940. #endif // IP_FIX
  941. {
  942. PgmTrace (LogStatus, ("ReceiverAddMCastIf: " \
  943. "InAddress=<%x> -- Already listening on IfContext=<%x>\n",
  944. IpAddress, IpInterfaceIndex));
  945. return (STATUS_SUCCESS);
  946. }
  947. }
  948. //
  949. // If we have reached the limit on the interfaces we can listen on,
  950. // return error
  951. //
  952. if (pAddress->NumReceiveInterfaces >= MAX_RECEIVE_INTERFACES)
  953. {
  954. PgmTrace (LogError, ("ReceiverAddMCastIf: ERROR -- " \
  955. "Listening on too many interfaces!, pAddress=<%p>\n", pAddress));
  956. return (STATUS_NOT_SUPPORTED);
  957. }
  958. PgmUnlock (pAddress, *pOldIrqAddress);
  959. PgmUnlock (&PgmDynamicConfig, *pOldIrqDynamicConfig);
  960. //
  961. // This is the interface for receiving mcast packets on, so do JoinLeaf
  962. //
  963. MCastInfo.MCastIpAddr = htonl (pAddress->ReceiverMCastAddr);
  964. #ifdef IP_FIX
  965. MCastInfo.MCastInIf = IpInterfaceIndex;
  966. status = PgmSetTcpInfo (pAddress->FileHandle,
  967. AO_OPTION_INDEX_ADD_MCAST,
  968. &MCastInfo,
  969. sizeof (tMCAST_INFO));
  970. #else
  971. MCastInfo.MCastInIf = ntohl (IpAddress);
  972. status = PgmSetTcpInfo (pAddress->FileHandle,
  973. AO_OPTION_ADD_MCAST,
  974. &MCastInfo,
  975. sizeof (tMCAST_INFO));
  976. #endif // IP_FIX
  977. PgmLock (&PgmDynamicConfig, *pOldIrqDynamicConfig);
  978. PgmLock (pAddress, *pOldIrqAddress);
  979. if (!NT_SUCCESS (status))
  980. {
  981. PgmTrace (LogError, ("ReceiverAddMCastIf: ERROR -- " \
  982. "PgmSetTcpInfo returned: <%x>, If=<%x>\n", status, IpAddress));
  983. return (status);
  984. }
  985. #ifdef IP_FIX
  986. pAddress->ReceiverInterfaceList[pAddress->NumReceiveInterfaces++] = IpInterfaceIndex;
  987. #else
  988. pAddress->ReceiverInterfaceList[pAddress->NumReceiveInterfaces++] = IpAddress;
  989. #endif // IP_FIX
  990. PgmTrace (LogStatus, ("ReceiverAddMCastIf: " \
  991. "Added Ip=<%x>, IfContext=<%x>\n", IpAddress, IpInterfaceIndex));
  992. return (status);
  993. }
  994. //----------------------------------------------------------------------------
  995. NTSTATUS
  996. PgmSetEventHandler(
  997. IN tPGM_DEVICE *pPgmDevice,
  998. IN PIRP pIrp,
  999. IN PIO_STACK_LOCATION pIrpSp
  1000. )
  1001. /*++
  1002. Routine Description:
  1003. This routine sets the client's Event Handlers wrt its address context
  1004. Arguments:
  1005. IN pPgmDevice -- Pgm's Device object context
  1006. IN pIrp -- Client's request Irp
  1007. IN pIrpSp -- current request's stack pointer
  1008. Return Value:
  1009. NTSTATUS - Final status of the set event operation
  1010. --*/
  1011. {
  1012. NTSTATUS status = STATUS_SUCCESS;
  1013. tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
  1014. PTDI_REQUEST_KERNEL_SET_EVENT pKeSetEvent = (PTDI_REQUEST_KERNEL_SET_EVENT) &pIrpSp->Parameters;
  1015. PVOID pEventHandler = pKeSetEvent->EventHandler;
  1016. PVOID pEventContext = pKeSetEvent->EventContext;
  1017. PGMLockHandle OldIrq, OldIrq1;
  1018. PgmLock (&PgmDynamicConfig, OldIrq);
  1019. if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
  1020. {
  1021. PgmTrace (LogError, ("PgmSetEventHandler: ERROR -- " \
  1022. "Invalid Address Handle=<%p>\n", pAddress));
  1023. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1024. return (STATUS_INVALID_HANDLE);
  1025. }
  1026. PgmTrace (LogAllFuncs, ("PgmSetEventHandler: " \
  1027. "Type=<%x>, Handler=<%p>, Context=<%p>\n", pKeSetEvent->EventType, pEventHandler, pEventContext));
  1028. if (!pEventHandler)
  1029. {
  1030. //
  1031. // We will set it to use the default Tdi Handler!
  1032. //
  1033. pEventContext = NULL;
  1034. }
  1035. PgmLock (pAddress, OldIrq1);
  1036. PGM_REFERENCE_ADDRESS (pAddress, REF_ADDRESS_SET_INFO, TRUE);
  1037. switch (pKeSetEvent->EventType)
  1038. {
  1039. case TDI_EVENT_CONNECT:
  1040. {
  1041. if (!pAddress->ReceiverMCastAddr)
  1042. {
  1043. PgmUnlock (pAddress, OldIrq1);
  1044. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1045. PgmTrace (LogError, ("PgmSetEventHandler: ERROR -- " \
  1046. "TDI_EVENT_CONNECT: pAddress=<%p> is not a Receiver\n", pAddress));
  1047. return (STATUS_UNSUCCESSFUL);
  1048. }
  1049. pAddress->evConnect = (pEventHandler ? pEventHandler : TdiDefaultConnectHandler);
  1050. pAddress->ConEvContext = pEventContext;
  1051. //
  1052. // If no default interface was specified, we need to set one now
  1053. //
  1054. if (!pAddress->NumReceiveInterfaces)
  1055. {
  1056. if (!IsListEmpty (&PgmDynamicConfig.LocalInterfacesList))
  1057. {
  1058. status = ListenOnAllInterfaces (pAddress, &OldIrq, &OldIrq1);
  1059. if (NT_SUCCESS (status))
  1060. {
  1061. PgmTrace (LogAllFuncs, ("PgmSetEventHandler: " \
  1062. "CONNECT: ListenOnAllInterfaces for pAddress=<%p> succeeded\n", pAddress));
  1063. }
  1064. else
  1065. {
  1066. PgmTrace (LogError, ("PgmSetEventHandler: ERROR -- " \
  1067. "CONNECT: ListenOnAllInterfaces for pAddress=<%p> returned <%x>\n",
  1068. pAddress, status));
  1069. }
  1070. }
  1071. pAddress->Flags |= (PGM_ADDRESS_WAITING_FOR_NEW_INTERFACE |
  1072. PGM_ADDRESS_LISTEN_ON_ALL_INTERFACES);
  1073. }
  1074. break;
  1075. }
  1076. case TDI_EVENT_DISCONNECT:
  1077. {
  1078. pAddress->evDisconnect = (pEventHandler ? pEventHandler : TdiDefaultDisconnectHandler);
  1079. pAddress->DiscEvContext = pEventContext;
  1080. break;
  1081. }
  1082. case TDI_EVENT_ERROR:
  1083. {
  1084. pAddress->evError = (pEventHandler ? pEventHandler : TdiDefaultErrorHandler);
  1085. pAddress->ErrorEvContext = pEventContext;
  1086. break;
  1087. }
  1088. case TDI_EVENT_RECEIVE:
  1089. {
  1090. pAddress->evReceive = (pEventHandler ? pEventHandler : TdiDefaultReceiveHandler);
  1091. pAddress->RcvEvContext = pEventContext;
  1092. break;
  1093. }
  1094. case TDI_EVENT_RECEIVE_DATAGRAM:
  1095. {
  1096. pAddress->evRcvDgram = (pEventHandler ? pEventHandler : TdiDefaultRcvDatagramHandler);
  1097. pAddress->RcvDgramEvContext = pEventContext;
  1098. break;
  1099. }
  1100. case TDI_EVENT_RECEIVE_EXPEDITED:
  1101. {
  1102. pAddress->evRcvExpedited = (pEventHandler ? pEventHandler : TdiDefaultRcvExpeditedHandler);
  1103. pAddress->RcvExpedEvContext = pEventContext;
  1104. break;
  1105. }
  1106. case TDI_EVENT_SEND_POSSIBLE:
  1107. {
  1108. pAddress->evSendPossible = (pEventHandler ? pEventHandler : TdiDefaultSendPossibleHandler);
  1109. pAddress->SendPossEvContext = pEventContext;
  1110. break;
  1111. }
  1112. case TDI_EVENT_CHAINED_RECEIVE:
  1113. case TDI_EVENT_CHAINED_RECEIVE_DATAGRAM:
  1114. case TDI_EVENT_CHAINED_RECEIVE_EXPEDITED:
  1115. case TDI_EVENT_ERROR_EX:
  1116. {
  1117. status = STATUS_NOT_SUPPORTED;
  1118. break;
  1119. }
  1120. default:
  1121. {
  1122. PgmTrace (LogError, ("PgmSetEventHandler: ERROR -- " \
  1123. "Invalid Event Type = <%x>\n", pKeSetEvent->EventType));
  1124. status = STATUS_UNSUCCESSFUL;
  1125. break;
  1126. }
  1127. }
  1128. PgmUnlock (pAddress, OldIrq1);
  1129. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1130. PGM_DEREFERENCE_ADDRESS (pAddress, REF_ADDRESS_SET_INFO);
  1131. return (status);
  1132. }
  1133. //----------------------------------------------------------------------------
  1134. NTSTATUS
  1135. PgmAddMCastReceiveIf(
  1136. IN PIRP pIrp,
  1137. IN PIO_STACK_LOCATION pIrpSp
  1138. )
  1139. /*++
  1140. Routine Description:
  1141. This routine is called as a result of the client attempting
  1142. to add an interface to the list of interfaces listening for
  1143. MCast traffic
  1144. Arguments:
  1145. IN pIrp -- Client's request Irp
  1146. IN pIrpSp -- current request's stack pointer
  1147. Return Value:
  1148. NTSTATUS - Final status of the add interface operation
  1149. --*/
  1150. {
  1151. NTSTATUS status;
  1152. PGMLockHandle OldIrq, OldIrq1;
  1153. tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
  1154. tPGM_MCAST_REQUEST *pInputBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
  1155. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (tPGM_MCAST_REQUEST))
  1156. {
  1157. PgmTrace (LogError, ("PgmAddMCastReceiveIf: ERROR -- " \
  1158. "Invalid BufferLength, <%d> < <%d>\n",
  1159. pIrpSp->Parameters.DeviceIoControl.InputBufferLength, sizeof (tPGM_MCAST_REQUEST)));
  1160. return (STATUS_INVALID_PARAMETER);
  1161. }
  1162. PgmLock (&PgmDynamicConfig, OldIrq);
  1163. if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
  1164. {
  1165. PgmTrace (LogError, ("PgmAddMCastReceiveIf: ERROR -- " \
  1166. "Invalid Handle pAddress=<%p>\n", pAddress));
  1167. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1168. return (STATUS_INVALID_HANDLE);
  1169. }
  1170. PgmLock (pAddress, OldIrq1);
  1171. if (!pInputBuffer->MCastInfo.MCastInIf)
  1172. {
  1173. //
  1174. // We will use default behavior
  1175. //
  1176. pAddress->Flags |= PGM_ADDRESS_LISTEN_ON_ALL_INTERFACES;
  1177. PgmUnlock (pAddress, OldIrq1);
  1178. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1179. PgmTrace (LogPath, ("PgmAddMCastReceiveIf: " \
  1180. "Application requested bind to IP=<%x>\n", pInputBuffer->MCastInfo.MCastInIf));
  1181. return (STATUS_SUCCESS);
  1182. }
  1183. PGM_REFERENCE_ADDRESS (pAddress, REF_ADDRESS_SET_INFO, TRUE);
  1184. status = ReceiverAddMCastIf (pAddress, ntohl (pInputBuffer->MCastInfo.MCastInIf), &OldIrq, &OldIrq1);
  1185. PgmUnlock (pAddress, OldIrq1);
  1186. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1187. PGM_DEREFERENCE_ADDRESS (pAddress, REF_ADDRESS_SET_INFO);
  1188. if (NT_SUCCESS (status))
  1189. {
  1190. PgmTrace (LogPath, ("PgmAddMCastReceiveIf: " \
  1191. "Added Address=<%x>\n", pInputBuffer->MCastInfo.MCastInIf));
  1192. }
  1193. else
  1194. {
  1195. PgmTrace (LogError, ("PgmAddMCastReceiveIf: ERROR -- " \
  1196. "ReceiverAddMCastIf returned <%x>, Address=<%x>\n", status, pInputBuffer->MCastInfo.MCastInIf));
  1197. }
  1198. return (status);
  1199. }
  1200. //----------------------------------------------------------------------------
  1201. NTSTATUS
  1202. PgmDelMCastReceiveIf(
  1203. IN PIRP pIrp,
  1204. IN PIO_STACK_LOCATION pIrpSp
  1205. )
  1206. /*++
  1207. Routine Description:
  1208. This routine is called by the client to remove an interface from the list
  1209. of interfaces we are currently listening on
  1210. Arguments:
  1211. IN pIrp -- Client's request Irp
  1212. IN pIrpSp -- current request's stack pointer
  1213. Return Value:
  1214. NTSTATUS - Final status of the delete interface operation
  1215. --*/
  1216. {
  1217. NTSTATUS status;
  1218. PGMLockHandle OldIrq, OldIrq1;
  1219. tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
  1220. tPGM_MCAST_REQUEST *pInputBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
  1221. tMCAST_INFO MCastInfo;
  1222. ULONG IpInterfaceIndex;
  1223. USHORT i;
  1224. BOOLEAN fFound;
  1225. #ifndef IP_FIX
  1226. tIPADDRESS IpAddress;
  1227. #endif // !IP_FIX
  1228. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (tPGM_MCAST_REQUEST))
  1229. {
  1230. PgmTrace (LogError, ("PgmDelMCastReceiveIf: ERROR -- " \
  1231. "Invalid BufferLength, <%d> < <%d>\n",
  1232. pIrpSp->Parameters.DeviceIoControl.InputBufferLength, sizeof (tPGM_MCAST_REQUEST)));
  1233. return (STATUS_INVALID_PARAMETER);
  1234. }
  1235. PgmLock (&PgmDynamicConfig, OldIrq);
  1236. if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
  1237. {
  1238. PgmTrace (LogError, ("PgmDelMCastReceiveIf: ERROR -- " \
  1239. "Invalid Handles pAddress=<%p>\n", pAddress));
  1240. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1241. return (STATUS_INVALID_HANDLE);
  1242. }
  1243. if (!pAddress->ReceiverMCastAddr) // Cannot set ReceiveIf on Sender!
  1244. {
  1245. PgmTrace (LogError, ("PgmDelMCastReceiveIf: ERROR -- " \
  1246. "Invalid Option for Sender, pAddress=<%p>\n", pAddress));
  1247. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1248. return (STATUS_NOT_SUPPORTED);
  1249. }
  1250. status = GetIpInterfaceIndexFromAddress (ntohl(pInputBuffer->MCastInfo.MCastInIf), &IpInterfaceIndex);
  1251. if (!NT_SUCCESS (status))
  1252. {
  1253. PgmTrace (LogError, ("PgmDelMCastReceiveIf: ERROR -- " \
  1254. "GetIpInterfaceIndexFromAddress returned <%x> for Address=<%x>\n",
  1255. status, pInputBuffer->MCastInfo.MCastInIf));
  1256. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1257. return (STATUS_INVALID_ADDRESS);
  1258. }
  1259. PgmLock (pAddress, OldIrq1);
  1260. //
  1261. // Now see if we are even listening on this interface
  1262. //
  1263. fFound = FALSE;
  1264. #ifndef IP_FIX
  1265. IpAddress = ntohl(pInputBuffer->MCastInfo.MCastInIf);
  1266. #endif // !IP_FIX
  1267. for (i=0; i <pAddress->NumReceiveInterfaces; i++)
  1268. {
  1269. #ifdef IP_FIX
  1270. if (pAddress->ReceiverInterfaceList[i] == IpInterfaceIndex)
  1271. #else
  1272. if (pAddress->ReceiverInterfaceList[i] == IpAddress)
  1273. #endif // IP_FIX
  1274. {
  1275. fFound = TRUE;
  1276. break;
  1277. }
  1278. }
  1279. if (!fFound)
  1280. {
  1281. PgmTrace (LogStatus, ("PgmDelMCastReceiveIf: " \
  1282. "Receiver is no longer listening on InAddress=<%x>, IfContext=<%x>\n",
  1283. pInputBuffer->MCastInfo.MCastInIf, IpInterfaceIndex));
  1284. PgmUnlock (pAddress, OldIrq1);
  1285. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1286. return (STATUS_SUCCESS);
  1287. }
  1288. pAddress->NumReceiveInterfaces--;
  1289. while (i < pAddress->NumReceiveInterfaces)
  1290. {
  1291. pAddress->ReceiverInterfaceList[i] = pAddress->ReceiverInterfaceList[i+1];
  1292. i++;
  1293. }
  1294. PGM_REFERENCE_ADDRESS (pAddress, REF_ADDRESS_SET_INFO, TRUE);
  1295. PgmUnlock (pAddress, OldIrq1);
  1296. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1297. MCastInfo.MCastIpAddr = htonl (pAddress->ReceiverMCastAddr);
  1298. #ifdef IP_FIX
  1299. MCastInfo.MCastInIf = IpInterfaceIndex;
  1300. status = PgmSetTcpInfo (pAddress->FileHandle,
  1301. AO_OPTION_INDEX_DEL_MCAST,
  1302. &MCastInfo,
  1303. sizeof (tMCAST_INFO));
  1304. #else
  1305. MCastInfo.MCastInIf = pInputBuffer->MCastInfo.MCastInIf;
  1306. status = PgmSetTcpInfo (pAddress->FileHandle,
  1307. AO_OPTION_DEL_MCAST,
  1308. &MCastInfo,
  1309. sizeof (tMCAST_INFO));
  1310. #endif // IP_FIX
  1311. if (NT_SUCCESS (status))
  1312. {
  1313. PgmTrace (LogStatus, ("PgmDelMCastReceiveIf: " \
  1314. "MCast Addr:Port=<%x:%x>, OutIf=<%x>\n",
  1315. pAddress->ReceiverMCastAddr, pAddress->ReceiverMCastPort,
  1316. pInputBuffer->MCastInfo.MCastInIf));
  1317. }
  1318. else
  1319. {
  1320. PgmTrace (LogError, ("PgmDelMCastReceiveIf: ERROR -- " \
  1321. "PgmSetTcpInfo returned: <%x> for IP=<%x>, IfContext=<%x>\n",
  1322. status, pInputBuffer->MCastInfo.MCastInIf, IpInterfaceIndex));
  1323. return (status);
  1324. }
  1325. PGM_DEREFERENCE_ADDRESS (pAddress, REF_ADDRESS_SET_INFO);
  1326. return (status);
  1327. }
  1328. //----------------------------------------------------------------------------
  1329. NTSTATUS
  1330. PgmSetWindowSizeAndSendRate(
  1331. IN PIRP pIrp,
  1332. IN PIO_STACK_LOCATION pIrpSp
  1333. )
  1334. /*++
  1335. Routine Description:
  1336. This routine is called by the client via setopt to override the default
  1337. Send Rate and Window size specifications
  1338. Arguments:
  1339. IN pIrp -- Client's request Irp
  1340. IN pIrpSp -- current request's stack pointer
  1341. Return Value:
  1342. NTSTATUS - Final status of the set operation
  1343. --*/
  1344. {
  1345. NTSTATUS status;
  1346. PGMLockHandle OldIrq;
  1347. tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
  1348. tPGM_MCAST_REQUEST *pInputBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
  1349. ULONGLONG RateKbitsPerSec; // Send rate
  1350. ULONGLONG WindowSizeInBytes;
  1351. ULONGLONG WindowSizeInMSecs;
  1352. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (tPGM_MCAST_REQUEST))
  1353. {
  1354. PgmTrace (LogError, ("PgmSetWindowSizeAndSendRate: ERROR -- " \
  1355. "Invalid BufferLength, <%d> < <%d>\n",
  1356. pIrpSp->Parameters.DeviceIoControl.InputBufferLength, sizeof (tPGM_MCAST_REQUEST)));
  1357. return (STATUS_INVALID_PARAMETER);
  1358. }
  1359. PgmLock (&PgmDynamicConfig, OldIrq);
  1360. if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
  1361. {
  1362. PgmTrace (LogError, ("PgmSetWindowSizeAndSendRate: ERROR -- " \
  1363. "Invalid Handle pAddress=<%p>\n", pAddress));
  1364. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1365. return (STATUS_INVALID_HANDLE);
  1366. }
  1367. if ((pAddress->ReceiverMCastAddr) || // Cannot set OutIf on Receiver!
  1368. (!IsListEmpty (&pAddress->AssociatedConnections))) // Cannot set options on active sender
  1369. {
  1370. PgmTrace (LogError, ("PgmSetWindowSizeAndSendRate: ERROR -- " \
  1371. "Invalid Option, pAddress=<%p>\n", pAddress));
  1372. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1373. return (STATUS_NOT_SUPPORTED);
  1374. }
  1375. RateKbitsPerSec = pInputBuffer->TransmitWindowInfo.RateKbitsPerSec;
  1376. WindowSizeInBytes = pInputBuffer->TransmitWindowInfo.WindowSizeInBytes;
  1377. WindowSizeInMSecs = pInputBuffer->TransmitWindowInfo.WindowSizeInMSecs;
  1378. //
  1379. // Now, fill in missing info
  1380. //
  1381. if ((RateKbitsPerSec || WindowSizeInMSecs || WindowSizeInBytes) && // no paramter specified -- error
  1382. (!(RateKbitsPerSec && WindowSizeInMSecs && WindowSizeInBytes))) // all parameters specified
  1383. {
  1384. //
  1385. // If 2 parameters have been specified, we only need to compute the third one
  1386. //
  1387. if (RateKbitsPerSec && WindowSizeInMSecs)
  1388. {
  1389. ASSERT (WindowSizeInMSecs >= MIN_RECOMMENDED_WINDOW_MSECS);
  1390. WindowSizeInBytes = (WindowSizeInMSecs * RateKbitsPerSec) / BITS_PER_BYTE;
  1391. }
  1392. else if (RateKbitsPerSec && WindowSizeInBytes)
  1393. {
  1394. WindowSizeInMSecs = (BITS_PER_BYTE * WindowSizeInBytes) / RateKbitsPerSec;
  1395. }
  1396. else if (WindowSizeInBytes && WindowSizeInMSecs)
  1397. {
  1398. RateKbitsPerSec = (WindowSizeInBytes * BITS_PER_BYTE) / WindowSizeInMSecs;
  1399. ASSERT (WindowSizeInMSecs >= MIN_RECOMMENDED_WINDOW_MSECS);
  1400. }
  1401. // for the remainder of the scenarios only 1 parameter has been specified
  1402. // Since WindowSizeInMSecs does not really affect our boundaries,
  1403. // it is the easiest to ignore while picking the defaults
  1404. else if (RateKbitsPerSec)
  1405. {
  1406. if (RateKbitsPerSec <= 500) // If the requested rate <= 0.5MB/sec, use a larger window
  1407. {
  1408. WindowSizeInMSecs = MAX_RECOMMENDED_WINDOW_MSECS;
  1409. }
  1410. else if (RateKbitsPerSec > 10000) // If the requested rate is very high, use the Min window
  1411. {
  1412. WindowSizeInMSecs = MIN_RECOMMENDED_WINDOW_MSECS;
  1413. }
  1414. else
  1415. {
  1416. WindowSizeInMSecs = MID_RECOMMENDED_WINDOW_MSECS;
  1417. }
  1418. WindowSizeInBytes = (WindowSizeInMSecs * RateKbitsPerSec) / BITS_PER_BYTE;
  1419. }
  1420. else if ((WindowSizeInBytes) &&
  1421. (WindowSizeInBytes >= pAddress->OutIfMTU)) // Necessary so that Win Adv rate!=0
  1422. {
  1423. RateKbitsPerSec = SENDER_DEFAULT_RATE_KBITS_PER_SEC;
  1424. WindowSizeInMSecs = (BITS_PER_BYTE * WindowSizeInBytes) / RateKbitsPerSec;
  1425. ASSERT (WindowSizeInMSecs >= MIN_RECOMMENDED_WINDOW_MSECS);
  1426. }
  1427. else if ((WindowSizeInMSecs < pAddress->MaxWindowSizeBytes) && // Necessary so that Rate >= 1
  1428. (WindowSizeInMSecs >= MIN_RECOMMENDED_WINDOW_MSECS) &&
  1429. (WindowSizeInMSecs >= pAddress->OutIfMTU)) // Necessary so that Win Adv rate!=0
  1430. {
  1431. // This is trickier -- we will first try to determine our constraints
  1432. // and try to use default settings, otherwise attempt to use the median value.
  1433. if (WindowSizeInMSecs <= (BITS_PER_BYTE * (pAddress->MaxWindowSizeBytes /
  1434. SENDER_DEFAULT_RATE_KBITS_PER_SEC)))
  1435. {
  1436. RateKbitsPerSec = SENDER_DEFAULT_RATE_KBITS_PER_SEC;
  1437. WindowSizeInBytes = (WindowSizeInMSecs * RateKbitsPerSec) / BITS_PER_BYTE;
  1438. }
  1439. // Hmm, we have to drop below out preferred rate -- try to pick the median range
  1440. else if (RateKbitsPerSec = BITS_PER_BYTE * (pAddress->MaxWindowSizeBytes /
  1441. (WindowSizeInMSecs * 2)))
  1442. {
  1443. WindowSizeInBytes = (WindowSizeInMSecs * RateKbitsPerSec) / BITS_PER_BYTE;
  1444. }
  1445. else
  1446. {
  1447. //
  1448. // Darn, we have to go with a huge file size and the min. rate!
  1449. //
  1450. RateKbitsPerSec = 1;
  1451. WindowSizeInBytes = WindowSizeInMSecs;
  1452. }
  1453. }
  1454. }
  1455. //
  1456. // Check validity of requested settings
  1457. //
  1458. if ((!(RateKbitsPerSec && WindowSizeInMSecs && WindowSizeInBytes)) || // all 3 must be specified from above
  1459. (RateKbitsPerSec != (WindowSizeInBytes * BITS_PER_BYTE / WindowSizeInMSecs)) ||
  1460. (WindowSizeInBytes > pAddress->MaxWindowSizeBytes) ||
  1461. (WindowSizeInBytes < pAddress->OutIfMTU))
  1462. {
  1463. PgmTrace (LogError, ("PgmSetWindowSizeAndSendRate: ERROR -- " \
  1464. "Invalid settings for pAddress=<%p>, Rate=<%d>, WSizeBytes=<%d>, WSizeMS=<%d>, MaxWSize=<%I64d>\n",
  1465. pAddress,
  1466. pInputBuffer->TransmitWindowInfo.RateKbitsPerSec,
  1467. pInputBuffer->TransmitWindowInfo.WindowSizeInBytes,
  1468. pInputBuffer->TransmitWindowInfo.WindowSizeInMSecs,
  1469. pAddress->MaxWindowSizeBytes));
  1470. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1471. return (STATUS_INVALID_PARAMETER);
  1472. }
  1473. pAddress->RateKbitsPerSec = (ULONG) RateKbitsPerSec;
  1474. pAddress->WindowSizeInBytes = (ULONG) WindowSizeInBytes;
  1475. pAddress->WindowSizeInMSecs = (ULONG) WindowSizeInMSecs;
  1476. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1477. PgmTrace (LogStatus, ("PgmSetWindowSizeAndSendRate: " \
  1478. "Settings for pAddress=<%p>: Rate=<%I64d>, WSizeBytes=<%I64d>, WSizeMS=<%I64d>\n",
  1479. pAddress, RateKbitsPerSec, WindowSizeInBytes, WindowSizeInMSecs));
  1480. return (STATUS_SUCCESS);
  1481. }
  1482. //----------------------------------------------------------------------------
  1483. NTSTATUS
  1484. PgmQueryWindowSizeAndSendRate(
  1485. IN PIRP pIrp,
  1486. IN PIO_STACK_LOCATION pIrpSp
  1487. )
  1488. /*++
  1489. Routine Description:
  1490. This routine is called by the client via setopt to query the current
  1491. Send Rate and Window size specifications
  1492. Arguments:
  1493. IN pIrp -- Client's request Irp
  1494. IN pIrpSp -- current request's stack pointer
  1495. Return Value:
  1496. NTSTATUS - Final status of the query operation
  1497. --*/
  1498. {
  1499. NTSTATUS status;
  1500. PGMLockHandle OldIrq;
  1501. tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
  1502. tPGM_MCAST_REQUEST *pBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
  1503. if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof (tPGM_MCAST_REQUEST))
  1504. {
  1505. PgmTrace (LogError, ("PgmQueryWindowSizeAndSendRate: ERROR -- " \
  1506. "Invalid BufferLength, <%d> < <%d>\n",
  1507. pIrpSp->Parameters.DeviceIoControl.OutputBufferLength, sizeof (tPGM_MCAST_REQUEST)));
  1508. return (STATUS_INVALID_PARAMETER);
  1509. }
  1510. PgmLock (&PgmDynamicConfig, OldIrq);
  1511. if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
  1512. {
  1513. PgmTrace (LogError, ("PgmQueryWindowSizeAndSendRate: ERROR -- " \
  1514. "Invalid Handle pAddress=<%p>\n", pAddress));
  1515. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1516. return (STATUS_INVALID_HANDLE);
  1517. }
  1518. if (pAddress->ReceiverMCastAddr) // Invalid option for Receiver!
  1519. {
  1520. PgmTrace (LogError, ("PgmQueryWindowSizeAndSendRate: ERROR -- " \
  1521. "Invalid option ofr receiver pAddress=<%p>\n", pAddress));
  1522. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1523. return (STATUS_NOT_SUPPORTED);
  1524. }
  1525. PgmZeroMemory (pBuffer, sizeof (tPGM_MCAST_REQUEST));
  1526. pBuffer->TransmitWindowInfo.RateKbitsPerSec = (ULONG) pAddress->RateKbitsPerSec;
  1527. pBuffer->TransmitWindowInfo.WindowSizeInBytes = (ULONG) pAddress->WindowSizeInBytes;
  1528. pBuffer->TransmitWindowInfo.WindowSizeInMSecs = (ULONG) pAddress->WindowSizeInMSecs;
  1529. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1530. pIrp->IoStatus.Information = sizeof (tPGM_MCAST_REQUEST);
  1531. return (STATUS_SUCCESS);
  1532. }
  1533. //----------------------------------------------------------------------------
  1534. NTSTATUS
  1535. PgmSetWindowAdvanceRate(
  1536. IN PIRP pIrp,
  1537. IN PIO_STACK_LOCATION pIrpSp
  1538. )
  1539. /*++
  1540. Routine Description:
  1541. This routine is called by the client via setopt to override the default
  1542. Window Advance rate
  1543. Arguments:
  1544. IN pIrp -- Client's request Irp
  1545. IN pIrpSp -- current request's stack pointer
  1546. Return Value:
  1547. NTSTATUS - Final status of the set event operation
  1548. --*/
  1549. {
  1550. NTSTATUS status;
  1551. PGMLockHandle OldIrq;
  1552. tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
  1553. tPGM_MCAST_REQUEST *pInputBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
  1554. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (tPGM_MCAST_REQUEST))
  1555. {
  1556. PgmTrace (LogError, ("PgmSetWindowAdvanceRate: ERROR -- " \
  1557. "Invalid BufferLength, <%d> < <%d>\n",
  1558. pIrpSp->Parameters.DeviceIoControl.InputBufferLength, sizeof (tPGM_MCAST_REQUEST)));
  1559. return (STATUS_INVALID_PARAMETER);
  1560. }
  1561. PgmLock (&PgmDynamicConfig, OldIrq);
  1562. status = STATUS_SUCCESS;
  1563. if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
  1564. {
  1565. PgmTrace (LogError, ("PgmSetWindowAdvanceRate: ERROR -- " \
  1566. "Invalid Handle pAddress=<%p>\n", pAddress));
  1567. status = STATUS_INVALID_HANDLE;
  1568. }
  1569. else if ((pAddress->ReceiverMCastAddr) || // Cannot set OutIf on Receiver!
  1570. (!IsListEmpty (&pAddress->AssociatedConnections))) // Cannot set options on active sender
  1571. {
  1572. PgmTrace (LogError, ("PgmSetWindowAdvanceRate: ERROR -- " \
  1573. "Invalid pAddress type or state <%p>\n", pAddress));
  1574. status = STATUS_NOT_SUPPORTED;
  1575. }
  1576. if (!NT_SUCCESS (status))
  1577. {
  1578. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1579. return (status);
  1580. }
  1581. if ((pInputBuffer->WindowAdvancePercentage) &&
  1582. (pInputBuffer->WindowAdvancePercentage <= MAX_WINDOW_INCREMENT_PERCENTAGE))
  1583. {
  1584. pAddress->WindowAdvancePercentage = pInputBuffer->WindowAdvancePercentage;
  1585. status = STATUS_SUCCESS;
  1586. }
  1587. else
  1588. {
  1589. status = STATUS_INVALID_PARAMETER;
  1590. }
  1591. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1592. return (status);
  1593. }
  1594. //----------------------------------------------------------------------------
  1595. NTSTATUS
  1596. PgmQueryWindowAdvanceRate(
  1597. IN PIRP pIrp,
  1598. IN PIO_STACK_LOCATION pIrpSp
  1599. )
  1600. /*++
  1601. Routine Description:
  1602. This routine is called by the client via setopt to query the current
  1603. Send Window advance rate
  1604. Arguments:
  1605. IN pIrp -- Client's request Irp
  1606. IN pIrpSp -- current request's stack pointer
  1607. Return Value:
  1608. NTSTATUS - Final status of the query operation
  1609. --*/
  1610. {
  1611. NTSTATUS status;
  1612. PGMLockHandle OldIrq;
  1613. tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
  1614. tPGM_MCAST_REQUEST *pBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
  1615. if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof (tPGM_MCAST_REQUEST))
  1616. {
  1617. PgmTrace (LogError, ("PgmQueryWindowAdvanceRate: ERROR -- " \
  1618. "Invalid BufferLength, <%d> < <%d>\n",
  1619. pIrpSp->Parameters.DeviceIoControl.OutputBufferLength, sizeof (tPGM_MCAST_REQUEST)));
  1620. return (STATUS_INVALID_PARAMETER);
  1621. }
  1622. PgmLock (&PgmDynamicConfig, OldIrq);
  1623. if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
  1624. {
  1625. PgmTrace (LogError, ("PgmQueryWindowAdvanceRate: ERROR -- " \
  1626. "Invalid Handle pAddress=<%p>\n", pAddress));
  1627. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1628. return (STATUS_INVALID_HANDLE);
  1629. }
  1630. if (pAddress->ReceiverMCastAddr) // Invalid option for Receiver!
  1631. {
  1632. PgmTrace (LogError, ("PgmQueryWindowAdvanceRate: ERROR -- " \
  1633. "Invalid option for receiver, pAddress=<%p>\n", pAddress));
  1634. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1635. return (STATUS_NOT_SUPPORTED);
  1636. }
  1637. PgmZeroMemory (pBuffer, sizeof (tPGM_MCAST_REQUEST));
  1638. pBuffer->WindowAdvancePercentage = pAddress->WindowAdvancePercentage;
  1639. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1640. pIrp->IoStatus.Information = sizeof (tPGM_MCAST_REQUEST);
  1641. return (STATUS_SUCCESS);
  1642. }
  1643. //----------------------------------------------------------------------------
  1644. NTSTATUS
  1645. PgmSetLateJoinerPercentage(
  1646. IN PIRP pIrp,
  1647. IN PIO_STACK_LOCATION pIrpSp
  1648. )
  1649. /*++
  1650. Routine Description:
  1651. This routine is called by the client via setopt to override the default
  1652. Late Joiner percentage (i.e. % of Window late joiner can request)
  1653. Arguments:
  1654. IN pIrp -- Client's request Irp
  1655. IN pIrpSp -- current request's stack pointer
  1656. Return Value:
  1657. NTSTATUS - Final status of the set operation
  1658. --*/
  1659. {
  1660. NTSTATUS status;
  1661. PGMLockHandle OldIrq;
  1662. tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
  1663. tPGM_MCAST_REQUEST *pInputBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
  1664. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (tPGM_MCAST_REQUEST))
  1665. {
  1666. PgmTrace (LogError, ("PgmSetLateJoinerPercentage: ERROR -- " \
  1667. "Invalid BufferLength, <%d> < <%d>\n",
  1668. pIrpSp->Parameters.DeviceIoControl.InputBufferLength, sizeof (tPGM_MCAST_REQUEST)));
  1669. return (STATUS_INVALID_PARAMETER);
  1670. }
  1671. PgmLock (&PgmDynamicConfig, OldIrq);
  1672. status = STATUS_SUCCESS;
  1673. if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
  1674. {
  1675. PgmTrace (LogError, ("PgmSetLateJoinerPercentage: ERROR -- " \
  1676. "Invalid Handle pAddress=<%p>\n", pAddress));
  1677. status = STATUS_INVALID_HANDLE;
  1678. }
  1679. else if ((pAddress->ReceiverMCastAddr) || // Cannot set LateJoin % on Receiver!
  1680. (!IsListEmpty (&pAddress->AssociatedConnections))) // Cannot set options on active sender
  1681. {
  1682. PgmTrace (LogError, ("PgmSetLateJoinerPercentage: ERROR -- " \
  1683. "Invalid pAddress type or state <%p>\n", pAddress));
  1684. status = STATUS_NOT_SUPPORTED;
  1685. }
  1686. if (!NT_SUCCESS (status))
  1687. {
  1688. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1689. return (status);
  1690. }
  1691. if (pInputBuffer->LateJoinerPercentage <= SENDER_MAX_LATE_JOINER_PERCENTAGE)
  1692. {
  1693. pAddress->LateJoinerPercentage = pInputBuffer->LateJoinerPercentage;
  1694. }
  1695. else
  1696. {
  1697. status = STATUS_INVALID_PARAMETER;
  1698. }
  1699. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1700. return (status);
  1701. }
  1702. //----------------------------------------------------------------------------
  1703. NTSTATUS
  1704. PgmQueryLateJoinerPercentage(
  1705. IN PIRP pIrp,
  1706. IN PIO_STACK_LOCATION pIrpSp
  1707. )
  1708. /*++
  1709. Routine Description:
  1710. This routine is called by the client via setopt to query the current
  1711. Late Joiner percentage
  1712. Arguments:
  1713. IN pIrp -- Client's request Irp
  1714. IN pIrpSp -- current request's stack pointer
  1715. Return Value:
  1716. NTSTATUS - Final status of the query operation
  1717. --*/
  1718. {
  1719. NTSTATUS status;
  1720. PGMLockHandle OldIrq;
  1721. tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
  1722. tPGM_MCAST_REQUEST *pBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
  1723. if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof (tPGM_MCAST_REQUEST))
  1724. {
  1725. PgmTrace (LogError, ("PgmQueryLateJoinerPercentage: ERROR -- " \
  1726. "Invalid BufferLength, <%d> < <%d>\n",
  1727. pIrpSp->Parameters.DeviceIoControl.OutputBufferLength, sizeof (tPGM_MCAST_REQUEST)));
  1728. return (STATUS_INVALID_PARAMETER);
  1729. }
  1730. PgmLock (&PgmDynamicConfig, OldIrq);
  1731. if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
  1732. {
  1733. PgmTrace (LogError, ("PgmQueryLateJoinerPercentage: ERROR -- " \
  1734. "Invalid Handle pAddress=<%p>\n", pAddress));
  1735. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1736. return (STATUS_INVALID_HANDLE);
  1737. }
  1738. if (pAddress->ReceiverMCastAddr) // Cannot query LateJoin % on Receiver!
  1739. {
  1740. PgmTrace (LogError, ("PgmQueryLateJoinerPercentage: ERROR -- " \
  1741. "Invalid option for receiver, pAddress=<%p>\n", pAddress));
  1742. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1743. return (STATUS_NOT_SUPPORTED);
  1744. }
  1745. pBuffer->LateJoinerPercentage = pAddress->LateJoinerPercentage;
  1746. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1747. pIrp->IoStatus.Information = sizeof (tPGM_MCAST_REQUEST);
  1748. return (STATUS_SUCCESS);
  1749. }
  1750. //----------------------------------------------------------------------------
  1751. NTSTATUS
  1752. PgmSetWindowAdvanceMethod(
  1753. IN PIRP pIrp,
  1754. IN PIO_STACK_LOCATION pIrpSp
  1755. )
  1756. /*++
  1757. Routine Description:
  1758. This routine is called by the client via setopt to override the default
  1759. Late Joiner percentage (i.e. % of Window late joiner can request)
  1760. Arguments:
  1761. IN pIrp -- Client's request Irp
  1762. IN pIrpSp -- current request's stack pointer
  1763. Return Value:
  1764. NTSTATUS - Final status of the set operation
  1765. --*/
  1766. {
  1767. NTSTATUS status;
  1768. PGMLockHandle OldIrq;
  1769. tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
  1770. tPGM_MCAST_REQUEST *pInputBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
  1771. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (tPGM_MCAST_REQUEST))
  1772. {
  1773. PgmTrace (LogError, ("PgmSetWindowAdvanceMethod: ERROR -- " \
  1774. "Invalid BufferLength, <%d> < <%d>\n",
  1775. pIrpSp->Parameters.DeviceIoControl.InputBufferLength, sizeof (tPGM_MCAST_REQUEST)));
  1776. return (STATUS_INVALID_PARAMETER);
  1777. }
  1778. PgmLock (&PgmDynamicConfig, OldIrq);
  1779. status = STATUS_SUCCESS;
  1780. if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
  1781. {
  1782. PgmTrace (LogError, ("PgmSetWindowAdvanceMethod: ERROR -- " \
  1783. "Invalid Handle pAddress=<%p>\n", pAddress));
  1784. status = STATUS_INVALID_HANDLE;
  1785. }
  1786. else if (pAddress->ReceiverMCastAddr) // Cannot set WindowAdvanceMethod on Receiver!
  1787. {
  1788. PgmTrace (LogError, ("PgmSetWindowAdvanceMethod: ERROR -- " \
  1789. "Invalid pAddress type or state <%p>\n", pAddress));
  1790. status = STATUS_NOT_SUPPORTED;
  1791. }
  1792. if (!NT_SUCCESS (status))
  1793. {
  1794. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1795. return (status);
  1796. }
  1797. if (pInputBuffer->WindowAdvanceMethod == E_WINDOW_ADVANCE_BY_TIME)
  1798. {
  1799. pAddress->Flags &= ~PGM_ADDRESS_USE_WINDOW_AS_DATA_CACHE;
  1800. }
  1801. else if (pInputBuffer->WindowAdvanceMethod == E_WINDOW_USE_AS_DATA_CACHE)
  1802. {
  1803. // pAddress->Flags |= PGM_ADDRESS_USE_WINDOW_AS_DATA_CACHE;
  1804. status = STATUS_NOT_SUPPORTED; // Not supported for now!
  1805. }
  1806. else
  1807. {
  1808. status = STATUS_INVALID_PARAMETER;
  1809. }
  1810. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1811. return (status);
  1812. }
  1813. //----------------------------------------------------------------------------
  1814. NTSTATUS
  1815. PgmQueryWindowAdvanceMethod(
  1816. IN PIRP pIrp,
  1817. IN PIO_STACK_LOCATION pIrpSp
  1818. )
  1819. /*++
  1820. Routine Description:
  1821. This routine is called by the client via setopt to query the current
  1822. Window Advance Method
  1823. Arguments:
  1824. IN pIrp -- Client's request Irp
  1825. IN pIrpSp -- current request's stack pointer
  1826. Return Value:
  1827. NTSTATUS - Final status of the query operation
  1828. --*/
  1829. {
  1830. NTSTATUS status;
  1831. PGMLockHandle OldIrq;
  1832. tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
  1833. tPGM_MCAST_REQUEST *pBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
  1834. if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof (tPGM_MCAST_REQUEST))
  1835. {
  1836. PgmTrace (LogError, ("PgmQueryWindowAdvanceMethod: ERROR -- " \
  1837. "Invalid BufferLength, <%d> < <%d>\n",
  1838. pIrpSp->Parameters.DeviceIoControl.OutputBufferLength, sizeof (tPGM_MCAST_REQUEST)));
  1839. return (STATUS_INVALID_PARAMETER);
  1840. }
  1841. PgmLock (&PgmDynamicConfig, OldIrq);
  1842. if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
  1843. {
  1844. PgmTrace (LogError, ("PgmQueryWindowAdvanceMethod: ERROR -- " \
  1845. "Invalid Handle pAddress=<%p>\n", pAddress));
  1846. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1847. return (STATUS_INVALID_HANDLE);
  1848. }
  1849. if (pAddress->ReceiverMCastAddr) // Cannot query WindowAdvanceMethod on Receiver!
  1850. {
  1851. PgmTrace (LogError, ("PgmQueryWindowAdvanceMethod: ERROR -- " \
  1852. "Invalid option for receiver, pAddress=<%p>\n", pAddress));
  1853. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1854. return (STATUS_NOT_SUPPORTED);
  1855. }
  1856. PgmZeroMemory (pBuffer, sizeof (tPGM_MCAST_REQUEST));
  1857. if (pAddress->Flags & PGM_ADDRESS_USE_WINDOW_AS_DATA_CACHE)
  1858. {
  1859. pBuffer->WindowAdvanceMethod = E_WINDOW_USE_AS_DATA_CACHE;
  1860. }
  1861. else
  1862. {
  1863. pBuffer->WindowAdvanceMethod = E_WINDOW_ADVANCE_BY_TIME;
  1864. }
  1865. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1866. pIrp->IoStatus.Information = sizeof (tPGM_MCAST_REQUEST);
  1867. return (STATUS_SUCCESS);
  1868. }
  1869. //----------------------------------------------------------------------------
  1870. NTSTATUS
  1871. PgmSetNextMessageBoundary(
  1872. IN PIRP pIrp,
  1873. IN PIO_STACK_LOCATION pIrpSp
  1874. )
  1875. /*++
  1876. Routine Description:
  1877. This routine is called by the client via setopt to set the Message length
  1878. for the next set of messages (typically, 1 send is sent as 1 Message).
  1879. Arguments:
  1880. IN pIrp -- Client's request Irp
  1881. IN pIrpSp -- current request's stack pointer
  1882. Return Value:
  1883. NTSTATUS - Final status of the set operation
  1884. --*/
  1885. {
  1886. NTSTATUS status;
  1887. PGMLockHandle OldIrq, OldIrq1;
  1888. tSEND_SESSION *pSend = (tSEND_SESSION *) pIrpSp->FileObject->FsContext;
  1889. tPGM_MCAST_REQUEST *pInputBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
  1890. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (tPGM_MCAST_REQUEST))
  1891. {
  1892. PgmTrace (LogError, ("PgmSetNextMessageBoundary: ERROR -- " \
  1893. "Invalid BufferLength, <%d> < <%d>\n",
  1894. pIrpSp->Parameters.DeviceIoControl.InputBufferLength, sizeof (tPGM_MCAST_REQUEST)));
  1895. return (STATUS_INVALID_PARAMETER);
  1896. }
  1897. PgmLock (&PgmDynamicConfig, OldIrq);
  1898. if ((!PGM_VERIFY_HANDLE (pSend, PGM_VERIFY_SESSION_SEND)) ||
  1899. (!pSend->pAssociatedAddress))
  1900. {
  1901. PgmTrace (LogError, ("PgmSetNextMessageBoundary: ERROR -- " \
  1902. "Invalid Handle pSend=<%p>\n", pSend));
  1903. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1904. return (STATUS_INVALID_HANDLE);
  1905. }
  1906. if (!pSend->pSender)
  1907. {
  1908. PgmTrace (LogError, ("PgmSetNextMessageBoundary: ERROR -- " \
  1909. "Invalid Option for Receiver, pSend=<%p>\n", pSend));
  1910. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1911. return (STATUS_NOT_SUPPORTED);
  1912. }
  1913. PgmLock (pSend, OldIrq1);
  1914. if ((pInputBuffer->NextMessageBoundary) &&
  1915. (!pSend->pSender->ThisSendMessageLength))
  1916. {
  1917. pSend->pSender->ThisSendMessageLength = pInputBuffer->NextMessageBoundary;
  1918. status = STATUS_SUCCESS;
  1919. }
  1920. else
  1921. {
  1922. PgmTrace (LogError, ("PgmSetNextMessageBoundary: ERROR -- " \
  1923. "Invalid parameter = <%d>\n", pInputBuffer->NextMessageBoundary));
  1924. status = STATUS_INVALID_PARAMETER;
  1925. }
  1926. PgmUnlock (pSend, OldIrq1);
  1927. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1928. return (status);
  1929. }
  1930. //----------------------------------------------------------------------------
  1931. NTSTATUS
  1932. PgmSetFECInfo(
  1933. IN PIRP pIrp,
  1934. IN PIO_STACK_LOCATION pIrpSp
  1935. )
  1936. /*++
  1937. Routine Description:
  1938. This routine is called by the client via setopt to set the parameters
  1939. for using FEC
  1940. Arguments:
  1941. IN pIrp -- Client's request Irp
  1942. IN pIrpSp -- current request's stack pointer
  1943. Return Value:
  1944. NTSTATUS - Final status of the set operation
  1945. --*/
  1946. {
  1947. NTSTATUS status;
  1948. PGMLockHandle OldIrq, OldIrq1;
  1949. tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
  1950. tPGM_MCAST_REQUEST *pInputBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
  1951. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (tPGM_MCAST_REQUEST))
  1952. {
  1953. PgmTrace (LogError, ("PgmSetFECInfo: ERROR -- " \
  1954. "Invalid BufferLength, <%d> < <%d>\n",
  1955. pIrpSp->Parameters.DeviceIoControl.InputBufferLength, sizeof (tPGM_MCAST_REQUEST)));
  1956. return (STATUS_INVALID_PARAMETER);
  1957. }
  1958. PgmLock (&PgmDynamicConfig, OldIrq);
  1959. status = STATUS_SUCCESS;
  1960. if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
  1961. {
  1962. PgmTrace (LogError, ("PgmSetFECInfo: ERROR -- " \
  1963. "Invalid Handle pAddress=<%p>\n", pAddress));
  1964. status = STATUS_INVALID_HANDLE;
  1965. }
  1966. else if ((pAddress->ReceiverMCastAddr) || // Cannot set FEC on Receiver!
  1967. (!IsListEmpty (&pAddress->AssociatedConnections))) // Cannot set options on active sender
  1968. {
  1969. PgmTrace (LogError, ("PgmSetFECInfo: ERROR -- " \
  1970. "Invalid pAddress type or state <%p>\n", pAddress));
  1971. status = STATUS_NOT_SUPPORTED;
  1972. }
  1973. if (!NT_SUCCESS (status))
  1974. {
  1975. PgmUnlock (&PgmDynamicConfig, OldIrq);
  1976. return (status);
  1977. }
  1978. PgmLock (pAddress, OldIrq1);
  1979. if (!(pInputBuffer->FECInfo.FECProActivePackets || pInputBuffer->FECInfo.fFECOnDemandParityEnabled) ||
  1980. !(pInputBuffer->FECInfo.FECBlockSize && pInputBuffer->FECInfo.FECGroupSize) ||
  1981. (pInputBuffer->FECInfo.FECBlockSize > FEC_MAX_BLOCK_SIZE) ||
  1982. (pInputBuffer->FECInfo.FECBlockSize <= pInputBuffer->FECInfo.FECGroupSize) ||
  1983. (!gFECLog2[pInputBuffer->FECInfo.FECGroupSize])) // FECGroup size has to be power of 2
  1984. {
  1985. PgmTrace (LogError, ("PgmSetFECInfo: ERROR -- " \
  1986. "Invalid parameters, FECBlockSize= <%d>, FECGroupSize=<%d>\n",
  1987. pInputBuffer->FECInfo.FECBlockSize, pInputBuffer->FECInfo.FECGroupSize));
  1988. status = STATUS_INVALID_PARAMETER;
  1989. }
  1990. else
  1991. {
  1992. status = STATUS_SUCCESS;
  1993. pAddress->FECBlockSize = pInputBuffer->FECInfo.FECBlockSize;
  1994. pAddress->FECGroupSize = pInputBuffer->FECInfo.FECGroupSize;
  1995. pAddress->FECOptions = 0; // Init
  1996. if (pInputBuffer->FECInfo.FECProActivePackets)
  1997. {
  1998. pAddress->FECProActivePackets = pInputBuffer->FECInfo.FECProActivePackets;
  1999. pAddress->FECOptions |= PACKET_OPTION_SPECIFIC_FEC_PRO_BIT;
  2000. }
  2001. if (pInputBuffer->FECInfo.fFECOnDemandParityEnabled)
  2002. {
  2003. pAddress->FECOptions |= PACKET_OPTION_SPECIFIC_FEC_OND_BIT;
  2004. }
  2005. }
  2006. PgmUnlock (pAddress, OldIrq1);
  2007. PgmUnlock (&PgmDynamicConfig, OldIrq);
  2008. return (status);
  2009. }
  2010. //----------------------------------------------------------------------------
  2011. NTSTATUS
  2012. PgmQueryFecInfo(
  2013. IN PIRP pIrp,
  2014. IN PIO_STACK_LOCATION pIrpSp
  2015. )
  2016. /*++
  2017. Routine Description:
  2018. This routine is called by the client via setopt to query the current
  2019. Send Window advance rate
  2020. Arguments:
  2021. IN pIrp -- Client's request Irp
  2022. IN pIrpSp -- current request's stack pointer
  2023. Return Value:
  2024. NTSTATUS - Final status of the query operation
  2025. --*/
  2026. {
  2027. NTSTATUS status;
  2028. PGMLockHandle OldIrq;
  2029. tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
  2030. tPGM_MCAST_REQUEST *pBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
  2031. if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof (tPGM_MCAST_REQUEST))
  2032. {
  2033. PgmTrace (LogError, ("PgmQueryFecInfo: ERROR -- " \
  2034. "Invalid BufferLength, <%d> < <%d>\n",
  2035. pIrpSp->Parameters.DeviceIoControl.OutputBufferLength, sizeof (tPGM_MCAST_REQUEST)));
  2036. return (STATUS_INVALID_PARAMETER);
  2037. }
  2038. PgmLock (&PgmDynamicConfig, OldIrq);
  2039. if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
  2040. {
  2041. PgmTrace (LogError, ("PgmQueryFecInfo: ERROR -- " \
  2042. "Invalid Handle pAddress=<%p>\n", pAddress));
  2043. PgmUnlock (&PgmDynamicConfig, OldIrq);
  2044. return (STATUS_INVALID_HANDLE);
  2045. }
  2046. if ((pAddress->ReceiverMCastAddr) || // Cannot query Fec on Receiver!
  2047. (!IsListEmpty (&pAddress->AssociatedConnections))) // Cannot query options on active sender
  2048. {
  2049. PgmTrace (LogError, ("PgmQueryFecInfo: ERROR -- " \
  2050. "Invalid Option for receiver, pAddress=<%p>\n", pAddress));
  2051. PgmUnlock (&PgmDynamicConfig, OldIrq);
  2052. return (STATUS_NOT_SUPPORTED);
  2053. }
  2054. PgmZeroMemory (pBuffer, sizeof (tPGM_MCAST_REQUEST));
  2055. pBuffer->FECInfo.FECBlockSize = pAddress->FECBlockSize;
  2056. pBuffer->FECInfo.FECGroupSize = pAddress->FECGroupSize;
  2057. pBuffer->FECInfo.FECProActivePackets = pAddress->FECProActivePackets;
  2058. if (pAddress->FECOptions & PACKET_OPTION_SPECIFIC_FEC_OND_BIT)
  2059. {
  2060. pBuffer->FECInfo.fFECOnDemandParityEnabled = TRUE;
  2061. }
  2062. else
  2063. {
  2064. pBuffer->FECInfo.fFECOnDemandParityEnabled = FALSE;
  2065. }
  2066. PgmUnlock (&PgmDynamicConfig, OldIrq);
  2067. pIrp->IoStatus.Information = sizeof (tPGM_MCAST_REQUEST);
  2068. return (STATUS_SUCCESS);
  2069. }
  2070. //----------------------------------------------------------------------------
  2071. NTSTATUS
  2072. PgmSetMCastTtl(
  2073. IN PIRP pIrp,
  2074. IN PIO_STACK_LOCATION pIrpSp
  2075. )
  2076. /*++
  2077. Routine Description:
  2078. This routine is called by the client via setopt to set the Message length
  2079. for the next set of messages (typically, 1 send is sent as 1 Message).
  2080. Arguments:
  2081. IN pIrp -- Client's request Irp
  2082. IN pIrpSp -- current request's stack pointer
  2083. Return Value:
  2084. NTSTATUS - Final status of the set operation
  2085. --*/
  2086. {
  2087. NTSTATUS status;
  2088. PGMLockHandle OldIrq, OldIrq1;
  2089. tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
  2090. tPGM_MCAST_REQUEST *pInputBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
  2091. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (tPGM_MCAST_REQUEST))
  2092. {
  2093. PgmTrace (LogError, ("PgmSetMCastTtl: ERROR -- " \
  2094. "Invalid BufferLength, <%d> < <%d>\n",
  2095. pIrpSp->Parameters.DeviceIoControl.InputBufferLength, sizeof (tPGM_MCAST_REQUEST)));
  2096. return (STATUS_INVALID_PARAMETER);
  2097. }
  2098. PgmLock (&PgmDynamicConfig, OldIrq);
  2099. if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
  2100. {
  2101. PgmTrace (LogError, ("PgmSetMCastTtl: ERROR -- " \
  2102. "Invalid Handle pAddress=<%p>\n", pAddress));
  2103. PgmUnlock (&PgmDynamicConfig, OldIrq);
  2104. return (STATUS_INVALID_HANDLE);
  2105. }
  2106. if (pAddress->ReceiverMCastAddr) // Cannot set MCast Ttl on Receiver!
  2107. {
  2108. PgmTrace (LogError, ("PgmSetMCastTtl: ERROR -- " \
  2109. "Invalid Options for Receiver, pAddress=<%p>\n", pAddress));
  2110. PgmUnlock (&PgmDynamicConfig, OldIrq);
  2111. return (STATUS_NOT_SUPPORTED);
  2112. }
  2113. PgmLock (pAddress, OldIrq1);
  2114. if ((pInputBuffer->MCastTtl) &&
  2115. (pInputBuffer->MCastTtl <= MAX_MCAST_TTL))
  2116. {
  2117. pAddress->MCastPacketTtl = pInputBuffer->MCastTtl;
  2118. status = STATUS_SUCCESS;
  2119. }
  2120. else
  2121. {
  2122. PgmTrace (LogError, ("PgmSetMCastTtl: ERROR -- " \
  2123. "Invalid parameter = <%d>\n", pInputBuffer->MCastTtl));
  2124. status = STATUS_INVALID_PARAMETER;
  2125. }
  2126. PgmUnlock (pAddress, OldIrq1);
  2127. PgmUnlock (&PgmDynamicConfig, OldIrq);
  2128. return (status);
  2129. }
  2130. //----------------------------------------------------------------------------
  2131. NTSTATUS
  2132. PgmQueryHighSpeedOptimization(
  2133. IN PIRP pIrp,
  2134. IN PIO_STACK_LOCATION pIrpSp
  2135. )
  2136. /*++
  2137. Routine Description:
  2138. This routine is called by the client via setopt to query the
  2139. Address is optimized for High Speed Intranet scenario
  2140. Arguments:
  2141. IN pIrp -- Client's request Irp
  2142. IN pIrpSp -- current request's stack pointer
  2143. Return Value:
  2144. NTSTATUS - Final status of the query operation
  2145. --*/
  2146. {
  2147. NTSTATUS status;
  2148. PGMLockHandle OldIrq;
  2149. tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
  2150. tPGM_MCAST_REQUEST *pBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
  2151. if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof (tPGM_MCAST_REQUEST))
  2152. {
  2153. PgmTrace (LogError, ("PgmQueryHighSpeedOptimization: ERROR -- " \
  2154. "Invalid BufferLength, <%d> < <%d>\n",
  2155. pIrpSp->Parameters.DeviceIoControl.OutputBufferLength, sizeof (tPGM_MCAST_REQUEST)));
  2156. return (STATUS_INVALID_PARAMETER);
  2157. }
  2158. PgmLock (&PgmDynamicConfig, OldIrq);
  2159. if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
  2160. {
  2161. PgmTrace (LogError, ("PgmQueryHighSpeedOptimization: ERROR -- " \
  2162. "Invalid Handle pAddress=<%p>\n", pAddress));
  2163. PgmUnlock (&PgmDynamicConfig, OldIrq);
  2164. return (STATUS_INVALID_HANDLE);
  2165. }
  2166. PgmZeroMemory (pBuffer, sizeof (tPGM_MCAST_REQUEST));
  2167. if (pAddress->Flags & PGM_ADDRESS_HIGH_SPEED_OPTIMIZED)
  2168. {
  2169. pBuffer->HighSpeedIntranetOptimization = 1;
  2170. }
  2171. else
  2172. {
  2173. pBuffer->HighSpeedIntranetOptimization = 0;
  2174. }
  2175. PgmUnlock (&PgmDynamicConfig, OldIrq);
  2176. pIrp->IoStatus.Information = sizeof (tPGM_MCAST_REQUEST);
  2177. return (STATUS_SUCCESS);
  2178. }
  2179. //----------------------------------------------------------------------------
  2180. NTSTATUS
  2181. PgmSetHighSpeedOptimization(
  2182. IN PIRP pIrp,
  2183. IN PIO_STACK_LOCATION pIrpSp
  2184. )
  2185. /*++
  2186. Routine Description:
  2187. This routine is called by the client via setopt to optimize
  2188. this address for High Speed Intranet scenario.
  2189. Arguments:
  2190. IN pIrp -- Client's request Irp
  2191. IN pIrpSp -- current request's stack pointer
  2192. Return Value:
  2193. NTSTATUS - Final status of the set operation
  2194. --*/
  2195. {
  2196. NTSTATUS status;
  2197. PGMLockHandle OldIrq, OldIrq1;
  2198. tADDRESS_CONTEXT *pAddress = (tADDRESS_CONTEXT *) pIrpSp->FileObject->FsContext;
  2199. tPGM_MCAST_REQUEST *pInputBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
  2200. if (pIrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof (tPGM_MCAST_REQUEST))
  2201. {
  2202. PgmTrace (LogError, ("PgmSetHighSpeedOptimization: ERROR -- " \
  2203. "Invalid BufferLength, <%d> < <%d>\n",
  2204. pIrpSp->Parameters.DeviceIoControl.InputBufferLength, sizeof (tPGM_MCAST_REQUEST)));
  2205. return (STATUS_INVALID_PARAMETER);
  2206. }
  2207. PgmLock (&PgmDynamicConfig, OldIrq);
  2208. if (!PGM_VERIFY_HANDLE (pAddress, PGM_VERIFY_ADDRESS))
  2209. {
  2210. PgmTrace (LogError, ("PgmSetHighSpeedOptimization: ERROR -- " \
  2211. "Invalid Handle pAddress=<%p>\n", pAddress));
  2212. PgmUnlock (&PgmDynamicConfig, OldIrq);
  2213. return (STATUS_INVALID_HANDLE);
  2214. }
  2215. PgmLock (pAddress, OldIrq1);
  2216. PgmTrace (LogStatus, ("PgmSetHighSpeedOptimization: " \
  2217. "HighSpeedIntranetOptimization = %sSet ==> %sSet\n",
  2218. ((pAddress->Flags & PGM_ADDRESS_HIGH_SPEED_OPTIMIZED) ? "" : "Not "),
  2219. (pInputBuffer->HighSpeedIntranetOptimization ? "" : "Not ")));
  2220. if (pInputBuffer->HighSpeedIntranetOptimization)
  2221. {
  2222. pAddress->Flags |= PGM_ADDRESS_HIGH_SPEED_OPTIMIZED;
  2223. }
  2224. else
  2225. {
  2226. pAddress->Flags &= ~PGM_ADDRESS_HIGH_SPEED_OPTIMIZED;
  2227. }
  2228. PgmUnlock (pAddress, OldIrq1);
  2229. PgmUnlock (&PgmDynamicConfig, OldIrq);
  2230. return (STATUS_SUCCESS);
  2231. }
  2232. //----------------------------------------------------------------------------
  2233. NTSTATUS
  2234. PgmQuerySenderStats(
  2235. IN PIRP pIrp,
  2236. IN PIO_STACK_LOCATION pIrpSp
  2237. )
  2238. /*++
  2239. Routine Description:
  2240. This routine is called by the client via setopt to query the current
  2241. Sender-side statistics
  2242. Arguments:
  2243. IN pIrp -- Client's request Irp
  2244. IN pIrpSp -- current request's stack pointer
  2245. Return Value:
  2246. NTSTATUS - Final status of the query operation
  2247. --*/
  2248. {
  2249. NTSTATUS status;
  2250. PGMLockHandle OldIrq, OldIrq1;
  2251. tSEND_SESSION *pSend = (tSEND_SESSION *) pIrpSp->FileObject->FsContext;
  2252. tPGM_MCAST_REQUEST *pBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
  2253. if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof (tPGM_MCAST_REQUEST))
  2254. {
  2255. PgmTrace (LogError, ("PgmQuerySenderStats: ERROR -- " \
  2256. "Invalid BufferLength, <%d> < <%d>\n",
  2257. pIrpSp->Parameters.DeviceIoControl.OutputBufferLength, sizeof (tPGM_MCAST_REQUEST)));
  2258. return (STATUS_INVALID_PARAMETER);
  2259. }
  2260. PgmLock (&PgmDynamicConfig, OldIrq);
  2261. if ((!PGM_VERIFY_HANDLE (pSend, PGM_VERIFY_SESSION_SEND)) ||
  2262. (!pSend->pSender) ||
  2263. (!pSend->pAssociatedAddress))
  2264. {
  2265. PgmTrace (LogError, ("PgmQuerySenderStats: ERROR -- " \
  2266. "Invalid Handle pSend=<%p>\n", pSend));
  2267. PgmUnlock (&PgmDynamicConfig, OldIrq);
  2268. return (STATUS_INVALID_HANDLE);
  2269. }
  2270. PgmLock (pSend, OldIrq1);
  2271. PgmZeroMemory (pBuffer, sizeof (tPGM_MCAST_REQUEST));
  2272. pBuffer->SenderStats.DataBytesSent = pSend->DataBytes;
  2273. pBuffer->SenderStats.TotalBytesSent = pSend->TotalBytes;
  2274. pBuffer->SenderStats.RateKBitsPerSecLast = pSend->RateKBitsPerSecLast;
  2275. pBuffer->SenderStats.RateKBitsPerSecOverall = pSend->RateKBitsPerSecOverall;
  2276. pBuffer->SenderStats.NaksReceived = pSend->pSender->NaksReceived;
  2277. pBuffer->SenderStats.NaksReceivedTooLate = pSend->pSender->NaksReceivedTooLate;
  2278. pBuffer->SenderStats.NumOutstandingNaks = pSend->pSender->NumOutstandingNaks;
  2279. pBuffer->SenderStats.NumNaksAfterRData = pSend->pSender->NumNaksAfterRData;
  2280. pBuffer->SenderStats.RepairPacketsSent = pSend->pSender->TotalRDataPacketsSent;
  2281. pBuffer->SenderStats.TotalODataPacketsSent = pSend->pSender->TotalODataPacketsSent;
  2282. pBuffer->SenderStats.BufferSpaceAvailable = pSend->pSender->BufferSizeAvailable;
  2283. pBuffer->SenderStats.TrailingEdgeSeqId = (SEQ_TYPE) pSend->pSender->TrailingEdgeSequenceNumber;
  2284. pBuffer->SenderStats.LeadingEdgeSeqId = (SEQ_TYPE) pSend->pSender->LastODataSentSequenceNumber;
  2285. PgmUnlock (pSend, OldIrq1);
  2286. PgmUnlock (&PgmDynamicConfig, OldIrq);
  2287. pIrp->IoStatus.Information = sizeof (tPGM_MCAST_REQUEST);
  2288. return (STATUS_SUCCESS);
  2289. }
  2290. //----------------------------------------------------------------------------
  2291. NTSTATUS
  2292. PgmQueryReceiverStats(
  2293. IN PIRP pIrp,
  2294. IN PIO_STACK_LOCATION pIrpSp
  2295. )
  2296. /*++
  2297. Routine Description:
  2298. This routine is called by the client via setopt to query the current
  2299. Sender-side statistics
  2300. Arguments:
  2301. IN pIrp -- Client's request Irp
  2302. IN pIrpSp -- current request's stack pointer
  2303. Return Value:
  2304. NTSTATUS - Final status of the query operation
  2305. --*/
  2306. {
  2307. NTSTATUS status;
  2308. PGMLockHandle OldIrq, OldIrq1;
  2309. tRECEIVE_SESSION *pReceive = (tRECEIVE_SESSION *) pIrpSp->FileObject->FsContext;
  2310. tPGM_MCAST_REQUEST *pBuffer = (tPGM_MCAST_REQUEST *) pIrp->AssociatedIrp.SystemBuffer;
  2311. if (pIrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof (tPGM_MCAST_REQUEST))
  2312. {
  2313. PgmTrace (LogError, ("PgmQueryReceiverStats: ERROR -- " \
  2314. "Invalid BufferLength, <%d> < <%d>\n",
  2315. pIrpSp->Parameters.DeviceIoControl.OutputBufferLength, sizeof (tPGM_MCAST_REQUEST)));
  2316. return (STATUS_INVALID_PARAMETER);
  2317. }
  2318. PgmLock (&PgmDynamicConfig, OldIrq);
  2319. if ((!PGM_VERIFY_HANDLE (pReceive, PGM_VERIFY_SESSION_RECEIVE)) ||
  2320. (!pReceive->pReceiver) ||
  2321. (!pReceive->pAssociatedAddress))
  2322. {
  2323. PgmTrace (LogError, ("PgmQueryReceiverStats: ERROR -- " \
  2324. "Invalid Handle pReceive=<%p>\n", pReceive));
  2325. PgmUnlock (&PgmDynamicConfig, OldIrq);
  2326. return (STATUS_INVALID_HANDLE);
  2327. }
  2328. PgmLock (pReceive, OldIrq1);
  2329. PgmZeroMemory (pBuffer, sizeof (tPGM_MCAST_REQUEST));
  2330. pBuffer->ReceiverStats.NumODataPacketsReceived = pReceive->pReceiver->NumODataPacketsReceived;
  2331. pBuffer->ReceiverStats.NumRDataPacketsReceived = pReceive->pReceiver->NumRDataPacketsReceived;
  2332. pBuffer->ReceiverStats.NumDuplicateDataPackets = pReceive->pReceiver->NumDupPacketsOlderThanWindow +
  2333. pReceive->pReceiver->NumDupPacketsBuffered;
  2334. pBuffer->ReceiverStats.DataBytesReceived = pReceive->DataBytes;
  2335. pBuffer->ReceiverStats.TotalBytesReceived = pReceive->TotalBytes;
  2336. pBuffer->ReceiverStats.RateKBitsPerSecLast = pReceive->RateKBitsPerSecLast;
  2337. pBuffer->ReceiverStats.RateKBitsPerSecOverall = pReceive->RateKBitsPerSecOverall;
  2338. pBuffer->ReceiverStats.TrailingEdgeSeqId = (SEQ_TYPE) pReceive->pReceiver->LastTrailingEdgeSeqNum;
  2339. pBuffer->ReceiverStats.LeadingEdgeSeqId = (SEQ_TYPE) pReceive->pReceiver->FurthestKnownGroupSequenceNumber;
  2340. pBuffer->ReceiverStats.AverageSequencesInWindow = pReceive->pReceiver->AverageSequencesInWindow;
  2341. pBuffer->ReceiverStats.MinSequencesInWindow = pReceive->pReceiver->MinSequencesInWindow;
  2342. pBuffer->ReceiverStats.MaxSequencesInWindow = pReceive->pReceiver->MaxSequencesInWindow;
  2343. pBuffer->ReceiverStats.FirstNakSequenceNumber = pReceive->pReceiver->FirstNakSequenceNumber;
  2344. pBuffer->ReceiverStats.NumPendingNaks = pReceive->pReceiver->NumPendingNaks;
  2345. pBuffer->ReceiverStats.NumOutstandingNaks = pReceive->pReceiver->NumOutstandingNaks;
  2346. pBuffer->ReceiverStats.NumDataPacketsBuffered = pReceive->pReceiver->TotalDataPacketsBuffered;
  2347. pBuffer->ReceiverStats.TotalSelectiveNaksSent = pReceive->pReceiver->TotalSelectiveNaksSent;
  2348. pBuffer->ReceiverStats.TotalParityNaksSent = pReceive->pReceiver->TotalParityNaksSent;
  2349. PgmUnlock (pReceive, OldIrq1);
  2350. PgmUnlock (&PgmDynamicConfig, OldIrq);
  2351. pIrp->IoStatus.Information = sizeof (tPGM_MCAST_REQUEST);
  2352. return (STATUS_SUCCESS);
  2353. }
  2354. //----------------------------------------------------------------------------