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

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