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.

1295 lines
28 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. qos.c
  5. Abstract:
  6. Quality Of Service support routines. These are a collection of
  7. heuristics that allow configuration of different types of VCs
  8. between two IP endstations.
  9. Revision History:
  10. Who When What
  11. -------- -------- ----------------------------------------------
  12. arvindm 09-27-96 Created
  13. Notes:
  14. --*/
  15. #include <precomp.h>
  16. #define _FILENUMBER ' SOQ'
  17. #ifdef QOS_HEURISTICS
  18. VOID
  19. AtmArpQosGetPacketSpecs(
  20. IN PVOID Context,
  21. IN PNDIS_PACKET pNdisPacket,
  22. OUT PATMARP_FLOW_INFO *ppFlowInfo,
  23. OUT PATMARP_FLOW_SPEC *ppFlowSpec,
  24. OUT PATMARP_FILTER_SPEC *ppFilterSpec
  25. )
  26. /*++
  27. Routine Description:
  28. Given a packet to be transmitted over an Interface, return the
  29. flow and filter specs for the packet.
  30. We go through the list of configured Flow Info structures on the
  31. specified interface, and find the Flow Info that comes closest
  32. to matching this packet.
  33. For now, the algorithm is: search thru the list of Flow Info structures
  34. configured on the interface -- a match is found when we find a Flow
  35. Info structure that has a PacketSizeLimit greater than or equal to the
  36. packet size (the flow info list is arranged in ascending order of
  37. PacketSizeLimit).
  38. GPC enhancement: if we couldn't find a matching flow on the Interface,
  39. ask the GPC to classify the packet for us.
  40. NOTE: This packet must not have any headers (LLC/SNAP) pre-pended to it.
  41. Arguments:
  42. Context - Actually a pointer to an Interface structure
  43. pNdisPacket - Pointer to the packet to be classified
  44. ppFlowInfo - where we return a pointer to the packet's flow info
  45. ppFlowSpec - where we return a pointer to the packet's flow spec
  46. ppFilterSpec - where we return a pointer to the packet's filter spec
  47. Return Value:
  48. None. See Arguments above.
  49. --*/
  50. {
  51. PATMARP_INTERFACE pInterface;
  52. PATMARP_FLOW_INFO pFlowInfo;
  53. UINT TotalLength;
  54. #if DBG
  55. AA_IRQL EntryIrq, ExitIrq;
  56. #endif
  57. AA_GET_ENTRY_IRQL(EntryIrq);
  58. pInterface = (PATMARP_INTERFACE)Context;
  59. //
  60. // Get the packet's total length.
  61. //
  62. NdisQueryPacket(
  63. pNdisPacket,
  64. NULL, // Phys buffer count
  65. NULL, // Buffer count
  66. NULL, // First Buffer
  67. &TotalLength
  68. );
  69. //
  70. // Note that we test for pInterface->pFlowInfoList BEFORE grabbing
  71. // the interface lock -- this so that for the most common case of not
  72. // having these preconfigured flows, we don't take the drastic action
  73. // of taking the interface lock for each send packet! There is
  74. // no harm in doing this check, as long as the pFlowInfo pointer we actually
  75. // use is got AFTER taking the lock.
  76. //
  77. // TODO: perhaps get rid of this code altogether -- along with other code
  78. // dealing with preconfigured flows.
  79. //
  80. pFlowInfo = pInterface->pFlowInfoList;
  81. if (pFlowInfo)
  82. {
  83. AA_ACQUIRE_IF_LOCK(pInterface);
  84. //
  85. // Remember to reload pFlowInfo once we have the the lock.
  86. //
  87. for (pFlowInfo = pInterface->pFlowInfoList;
  88. pFlowInfo != (PATMARP_FLOW_INFO)NULL;
  89. pFlowInfo = pFlowInfo->pNextFlow)
  90. {
  91. if (TotalLength <= pFlowInfo->PacketSizeLimit)
  92. {
  93. break;
  94. }
  95. }
  96. AA_RELEASE_IF_LOCK(pInterface);
  97. }
  98. if (pFlowInfo != (PATMARP_FLOW_INFO)NULL)
  99. {
  100. *ppFlowInfo = pFlowInfo;
  101. *ppFlowSpec = &(pFlowInfo->FlowSpec);
  102. *ppFilterSpec = &(pFlowInfo->FilterSpec);
  103. }
  104. else
  105. {
  106. #ifdef GPC
  107. CLASSIFICATION_HANDLE ClassificationHandle;
  108. ClassificationHandle = (CLASSIFICATION_HANDLE)
  109. PtrToUlong(
  110. NDIS_PER_PACKET_INFO_FROM_PACKET(pNdisPacket,
  111. ClassificationHandlePacketInfo));
  112. *ppFlowInfo = NULL;
  113. if (ClassificationHandle){
  114. GPC_STATUS GpcStatus;
  115. AA_ASSERT(GpcGetCfInfoClientContext);
  116. GpcStatus = GpcGetCfInfoClientContext(pAtmArpGlobalInfo->GpcClientHandle,
  117. ClassificationHandle,
  118. ppFlowInfo);
  119. }
  120. else{
  121. #if 0
  122. //
  123. // THIS CODE HAS BEEN COMMENTED OUT SINCE
  124. // WE ASSUME THAT CLASSIFICATION IS DONE IN
  125. // TCP. IF WE DON'T GET A CH - THERE'S NOT MUCH POINT
  126. // IN CALLING THE GPC AGAIN...
  127. //
  128. GPC_STATUS GpcStatus;
  129. TC_INTERFACE_ID InterfaceId;
  130. InterfaceId.InterfaceId = 0;
  131. InterfaceId.LinkId = 0;
  132. AA_ASSERT(GpcClassifyPacket);
  133. GpcStatus = GpcClassifyPacket(
  134. pAtmArpGlobalInfo->GpcClientHandle,
  135. GPC_PROTOCOL_TEMPLATE_IP,
  136. pNdisPacket,
  137. 0, // TransportHeaderOffset
  138. &InterfaceId,
  139. (PGPC_CLIENT_HANDLE)ppFlowInfo,
  140. &ClassificationHandle
  141. );
  142. #endif
  143. }
  144. AA_CHECK_EXIT_IRQL(EntryIrq, ExitIrq);
  145. if (*ppFlowInfo != NULL)
  146. {
  147. AA_ASSERT(*ppFlowInfo != NULL);
  148. *ppFlowSpec = &((*ppFlowInfo)->FlowSpec);
  149. *ppFilterSpec = &((*ppFlowInfo)->FilterSpec);
  150. AADEBUGP(AAD_LOUD,
  151. ("ClassifyPacket: Pkt %x: pFlowInfo %x, pFlowSpec %x, SendBW %d, ServType %d\n",
  152. pNdisPacket,
  153. *ppFlowInfo,
  154. *ppFlowSpec,
  155. (*ppFlowSpec)->SendAvgBandwidth,
  156. (*ppFlowSpec)->SendServiceType));
  157. }
  158. else
  159. {
  160. //*ppFlowInfo = NULL;
  161. *ppFlowSpec = &(pInterface->DefaultFlowSpec);
  162. *ppFilterSpec = &(pInterface->DefaultFilterSpec);
  163. }
  164. #else
  165. *ppFlowInfo = NULL;
  166. *ppFlowSpec = &(pInterface->DefaultFlowSpec);
  167. *ppFilterSpec = &(pInterface->DefaultFilterSpec);
  168. #endif // GPC
  169. }
  170. return;
  171. }
  172. BOOLEAN
  173. AtmArpQosDoFlowsMatch(
  174. IN PVOID Context,
  175. IN PATMARP_FLOW_SPEC pFlowSpec,
  176. IN PATMARP_FLOW_SPEC pTargetFlowSpec
  177. )
  178. /*++
  179. Routine Description:
  180. Check if a target flow spec supports the given flow spec. Currently,
  181. we check only the bandwidth: if the target flow spec has a send bandwidth
  182. greater than or equal to that of the given flow spec, we declare a match.
  183. Arguments:
  184. Context - Actually a pointer to an Interface structure
  185. pFlowSpec - The given flow spec which we are trying to satisfy
  186. pTargetFlowSpec - The candidate flow spec
  187. Return Value:
  188. TRUE iff the target flow spec matches the given flow spec.
  189. --*/
  190. {
  191. return (
  192. (pFlowSpec->SendServiceType == pTargetFlowSpec->SendServiceType)
  193. &&
  194. (pFlowSpec->SendPeakBandwidth <= pTargetFlowSpec->SendPeakBandwidth)
  195. );
  196. }
  197. BOOLEAN
  198. AtmArpQosDoFiltersMatch(
  199. IN PVOID Context,
  200. IN PATMARP_FILTER_SPEC pFilterSpec,
  201. IN PATMARP_FILTER_SPEC pTargetFilterSpec
  202. )
  203. /*++
  204. Routine Description:
  205. Check if a target filter spec matches the given filter spec. Currently,
  206. we always return TRUE.
  207. Arguments:
  208. Context - Actually a pointer to an Interface structure
  209. pFilterSpec - The given filter spec which we are trying to satisfy
  210. pTargetFilterSpec - The candidate filter spec
  211. Return Value:
  212. TRUE always.
  213. --*/
  214. {
  215. return (TRUE);
  216. }
  217. #endif // QOS_HEURISTICS
  218. #ifdef GPC
  219. #define AA_GPC_COPY_FLOW_PARAMS(_pFlowInfo, _pQosInfo) \
  220. { \
  221. (_pFlowInfo)->FlowSpec.SendAvgBandwidth = \
  222. (_pQosInfo)->GenFlow.SendingFlowspec.TokenRate; \
  223. (_pFlowInfo)->FlowSpec.SendPeakBandwidth = \
  224. (_pQosInfo)->GenFlow.SendingFlowspec.PeakBandwidth; \
  225. (_pFlowInfo)->FlowSpec.SendMaxSize = \
  226. MAX((_pQosInfo)->GenFlow.SendingFlowspec.TokenBucketSize, \
  227. (_pQosInfo)->GenFlow.SendingFlowspec.MaxSduSize); \
  228. (_pFlowInfo)->PacketSizeLimit = (_pFlowInfo)->FlowSpec.SendMaxSize; \
  229. (_pFlowInfo)->FlowSpec.ReceiveAvgBandwidth = \
  230. (_pQosInfo)->GenFlow.ReceivingFlowspec.TokenRate; \
  231. (_pFlowInfo)->FlowSpec.ReceivePeakBandwidth = \
  232. (_pQosInfo)->GenFlow.ReceivingFlowspec.PeakBandwidth; \
  233. (_pFlowInfo)->FlowSpec.ReceiveMaxSize = \
  234. MAX((_pQosInfo)->GenFlow.ReceivingFlowspec.TokenBucketSize, \
  235. (_pQosInfo)->GenFlow.ReceivingFlowspec.MaxSduSize); \
  236. (_pFlowInfo)->FlowSpec.Encapsulation = ENCAPSULATION_TYPE_LLCSNAP; \
  237. (_pFlowInfo)->FlowSpec.AgingTime = 0; \
  238. (_pFlowInfo)->FlowSpec.SendServiceType = \
  239. (_pQosInfo)->GenFlow.SendingFlowspec.ServiceType; \
  240. (_pFlowInfo)->FlowSpec.ReceiveServiceType = \
  241. (_pQosInfo)->GenFlow.ReceivingFlowspec.ServiceType; \
  242. }
  243. VOID
  244. AtmArpGpcInitialize(
  245. VOID
  246. )
  247. /*++
  248. Routine Description:
  249. Initialize with the Generic Packet Classifier. The GPC informs us of
  250. newly created flows (e.g. via RSVP) and of flows being torn down.
  251. For each flow, we keep context (ATMARP_FLOW_INFO) that keeps track of
  252. the QoS needed for the flow. Each IP packet given to us for transmission
  253. is classified into a flow, and we use this flow info to make VCs with
  254. the appropriate characteristics.
  255. Arguments:
  256. None
  257. Return Value:
  258. None
  259. --*/
  260. {
  261. GPC_STATUS GpcStatus;
  262. ULONG ClassificationFamilyId;
  263. ULONG Flags;
  264. ULONG ProtocolTemplate;
  265. ULONG MaxPriorities;
  266. GPC_CLIENT_FUNC_LIST AtmArpFuncList;
  267. GPC_CLIENT_HANDLE ClientContext;
  268. //
  269. // Initialize the GPC.
  270. //
  271. GpcStatus = GpcInitialize(&pAtmArpGlobalInfo->GpcCalls);
  272. if (GpcStatus != GPC_STATUS_SUCCESS)
  273. {
  274. AADEBUGP(AAD_WARNING, ("GpcInitialize failed, status 0x%x\n", GpcStatus));
  275. pAtmArpGlobalInfo->bGpcInitialized = FALSE;
  276. return;
  277. }
  278. pAtmArpGlobalInfo->bGpcInitialized = TRUE;
  279. AtmArpGpcClassifyPacketHandler = pAtmArpGlobalInfo->GpcCalls.GpcClassifyPacketHandler;
  280. AtmArpGpcGetCfInfoClientContextHandler = pAtmArpGlobalInfo->GpcCalls.GpcGetCfInfoClientContextHandler;
  281. ClassificationFamilyId = GPC_CF_QOS;
  282. Flags = 0;
  283. ProtocolTemplate = GPC_PROTOCOL_TEMPLATE_IP;
  284. MaxPriorities = 1;
  285. AA_SET_MEM(&AtmArpFuncList, 0, sizeof(AtmArpFuncList));
  286. AtmArpFuncList.ClAddCfInfoCompleteHandler = AtmArpGpcAddCfInfoComplete;
  287. AtmArpFuncList.ClAddCfInfoNotifyHandler = AtmArpGpcAddCfInfoNotify;
  288. AtmArpFuncList.ClModifyCfInfoCompleteHandler = AtmArpGpcModifyCfInfoComplete;
  289. AtmArpFuncList.ClModifyCfInfoNotifyHandler = AtmArpGpcModifyCfInfoNotify;
  290. AtmArpFuncList.ClRemoveCfInfoCompleteHandler = AtmArpGpcRemoveCfInfoComplete;
  291. AtmArpFuncList.ClGetCfInfoName = AtmArpGpcGetCfInfoName;
  292. AtmArpFuncList.ClRemoveCfInfoNotifyHandler = AtmArpGpcRemoveCfInfoNotify;
  293. ClientContext = (GPC_CLIENT_HANDLE)pAtmArpGlobalInfo;
  294. GpcStatus = GpcRegisterClient(
  295. ClassificationFamilyId,
  296. Flags,
  297. MaxPriorities,
  298. &AtmArpFuncList,
  299. ClientContext,
  300. &(pAtmArpGlobalInfo->GpcClientHandle)
  301. );
  302. AADEBUGP(AAD_INFO,
  303. ("GpcRegisterClient status 0x%x, GpcClientHandle 0x%x\n",
  304. GpcStatus, pAtmArpGlobalInfo->GpcClientHandle));
  305. if(GpcStatus != GPC_STATUS_SUCCESS)
  306. {
  307. AA_ASSERT(FALSE);
  308. pAtmArpGlobalInfo->bGpcInitialized = FALSE;
  309. }
  310. }
  311. VOID
  312. AtmArpGpcShutdown(
  313. VOID
  314. )
  315. /*++
  316. Routine Description:
  317. Shuts down our GPC interface.
  318. Arguments:
  319. None
  320. Return Value:
  321. None
  322. --*/
  323. {
  324. GPC_STATUS GpcStatus;
  325. if (pAtmArpGlobalInfo->bGpcInitialized)
  326. {
  327. GpcStatus = GpcDeregisterClient(pAtmArpGlobalInfo->GpcClientHandle);
  328. AA_ASSERT(GpcStatus == GPC_STATUS_SUCCESS);
  329. }
  330. }
  331. VOID
  332. AtmArpGpcAddCfInfoComplete(
  333. IN GPC_CLIENT_HANDLE ClientContext,
  334. IN GPC_CLIENT_HANDLE ClientCfInfoContext,
  335. IN GPC_STATUS GpcStatus
  336. )
  337. /*++
  338. Routine Description:
  339. This is the entry point called by GPC when a pended call to
  340. GpcAddCfInfo() has completed. Since we never call GpcAddCfInfo,
  341. we should never be called here.
  342. Arguments:
  343. <Not used>
  344. Return Value:
  345. None
  346. --*/
  347. {
  348. AA_ASSERT(FALSE);
  349. }
  350. GPC_STATUS
  351. AtmArpGpcAddCfInfoNotify(
  352. IN GPC_CLIENT_HANDLE ClientContext,
  353. IN GPC_HANDLE GpcCfInfoHandle,
  354. IN ULONG CfInfoSize,
  355. IN PVOID pCfInfo,
  356. OUT PGPC_CLIENT_HANDLE pClientCfInfoContext
  357. )
  358. /*++
  359. Routine Description:
  360. This is the entry point called by GPC to notify us of creation of
  361. a new INFO block of type QOS. We allocate a FLOW_INFO structure,
  362. fill it with what we need, and return a pointer to it as our context.
  363. Arguments:
  364. ClientContext - Pointer to our global info struct
  365. GpcCfInfoHandle - GPC Handle to use in all GPC APIs for this INFO block
  366. CfInfoSize - Length of the following block
  367. pCfInfo - Pointer to the newly created INFO block
  368. pClientCfInfoContext- Place where we return our context for this block
  369. Return Value:
  370. GPC_STATUS_SUCCESS if we were able to allocate a new FLOW_INFO structure,
  371. GPC_STATUS_RESOURCES otherwise.
  372. --*/
  373. {
  374. PATMARP_FLOW_INFO pFlowInfo;
  375. GPC_STATUS GpcStatus;
  376. PCF_INFO_QOS pQosInfo;
  377. pQosInfo = (PCF_INFO_QOS)pCfInfo;
  378. //
  379. // Initialize.
  380. //
  381. *pClientCfInfoContext = NULL;
  382. do
  383. {
  384. GpcStatus = AtmArpGpcValidateCfInfo(pCfInfo, CfInfoSize);
  385. if (GpcStatus != GPC_STATUS_SUCCESS)
  386. {
  387. break;
  388. }
  389. AA_ALLOC_MEM(pFlowInfo, ATMARP_FLOW_INFO, sizeof(ATMARP_FLOW_INFO));
  390. if (pFlowInfo == NULL)
  391. {
  392. GpcStatus = GPC_STATUS_RESOURCES;
  393. break;
  394. }
  395. AA_SET_MEM(pFlowInfo, 0, sizeof(ATMARP_FLOW_INFO));
  396. pFlowInfo->CfInfoHandle = GpcCfInfoHandle;
  397. //
  398. // Copy in flow parameters
  399. //
  400. AA_GPC_COPY_FLOW_PARAMS(pFlowInfo, pQosInfo);
  401. //
  402. // Generate Unique Name for this flow.
  403. // This name is based on the template, AA_FLOW_INSTANCE_TEMPLATE.
  404. // The flow number part is based on a static variable which is
  405. // InterlockIncremented each time a flowinfo is created.
  406. //
  407. {
  408. static ULONG FlowCount = 0;
  409. ULONG ThisFlow = NdisInterlockedIncrement(&FlowCount);
  410. WCHAR *pwc;
  411. AA_ASSERT(sizeof(pFlowInfo->FlowInstanceName)
  412. == sizeof(AA_FLOW_INSTANCE_NAME_TEMPLATE)-sizeof(WCHAR));
  413. AA_COPY_MEM(
  414. pFlowInfo->FlowInstanceName,
  415. AA_FLOW_INSTANCE_NAME_TEMPLATE,
  416. sizeof(pFlowInfo->FlowInstanceName)
  417. );
  418. //
  419. // We fill in the "flow number" field of the template, which
  420. // is the 1st 8 characters, with the hex representation of
  421. // ThisFlow. The LS digit is at offset 7.
  422. //
  423. pwc = pFlowInfo->FlowInstanceName+7;
  424. AA_ASSERT(2*sizeof(ThisFlow) == 8);
  425. while (ThisFlow)
  426. {
  427. ULONG u = ThisFlow & 0xf;
  428. *pwc-- = (WCHAR) ((u < 10) ? (u + '0') : u + 'A' - 10);
  429. ThisFlow >>= 4;
  430. }
  431. }
  432. //
  433. // Link it to the global flow list.
  434. //
  435. AA_ACQUIRE_GLOBAL_LOCK(pAtmArpGlobalInfo);
  436. pFlowInfo->pPrevFlow = NULL;
  437. pFlowInfo->pNextFlow = pAtmArpGlobalInfo->pFlowInfoList;
  438. if (pAtmArpGlobalInfo->pFlowInfoList != NULL)
  439. {
  440. pAtmArpGlobalInfo->pFlowInfoList->pPrevFlow = pFlowInfo;
  441. }
  442. pAtmArpGlobalInfo->pFlowInfoList = pFlowInfo;
  443. AA_RELEASE_GLOBAL_LOCK(pAtmArpGlobalInfo);
  444. //
  445. // Return our context for this flow.
  446. //
  447. *pClientCfInfoContext = (GPC_CLIENT_HANDLE)pFlowInfo;
  448. GpcStatus = GPC_STATUS_SUCCESS;
  449. break;
  450. }
  451. while (FALSE);
  452. AADEBUGP(AAD_INFO, ("AddCfInfoNotify: pCfInfo x%x, ClientCtx x%x, ret x%x\n",
  453. pCfInfo, *pClientCfInfoContext, GpcStatus));
  454. #if DBG
  455. if (GpcStatus == GPC_STATUS_SUCCESS)
  456. {
  457. AADEBUGP(AAD_INFO, (" : SendPeak %d, SendAvg %d, SendPktSize %d, ServType %d\n",
  458. pFlowInfo->FlowSpec.SendPeakBandwidth,
  459. pFlowInfo->FlowSpec.SendAvgBandwidth,
  460. pFlowInfo->FlowSpec.SendMaxSize,
  461. pFlowInfo->FlowSpec.SendServiceType));
  462. AADEBUGP(AAD_INFO, (" : RecvPeak %d, RecvAvg %d, RecvPktSize %d, ServType %d\n",
  463. pFlowInfo->FlowSpec.ReceivePeakBandwidth,
  464. pFlowInfo->FlowSpec.ReceiveAvgBandwidth,
  465. pFlowInfo->FlowSpec.ReceiveMaxSize,
  466. pFlowInfo->FlowSpec.ReceiveServiceType));
  467. }
  468. #endif
  469. return (GpcStatus);
  470. }
  471. VOID
  472. AtmArpGpcModifyCfInfoComplete(
  473. IN GPC_CLIENT_HANDLE ClientContext,
  474. IN GPC_CLIENT_HANDLE ClientCfInfoContext,
  475. IN GPC_STATUS GpcStatus
  476. )
  477. /*++
  478. Routine Description:
  479. This is the entry point called by GPC when a pended call to
  480. GpcModifyCfInfo() has completed. Since we never call GpcModifyCfInfo,
  481. we should never be called here.
  482. Addendum: Apparently this is called even if another client calls
  483. GpcModifyCfInfo, just to notify this client that the modify operation
  484. finished.
  485. Arguments:
  486. <Not used>
  487. Return Value:
  488. None
  489. --*/
  490. {
  491. return;
  492. }
  493. GPC_STATUS
  494. AtmArpGpcModifyCfInfoNotify(
  495. IN GPC_CLIENT_HANDLE ClientContext,
  496. IN GPC_CLIENT_HANDLE ClientCfInfoContext,
  497. IN ULONG CfInfoSize,
  498. IN PVOID pNewCfInfo
  499. )
  500. /*++
  501. Routine Description:
  502. This is the entry point called by GPC when an existing flow has
  503. been modified.
  504. If the flow info for this flow is linked with a VC, we unlink it,
  505. and start an aging timeout on the VC. We update the flow info structure
  506. with this new information. The next packet that falls into this
  507. classification will cause a new VC with updated QoS to be created.
  508. Arguments:
  509. ClientContext - Pointer to our global context
  510. ClientCfInfoContext - Pointer to our FLOW INFO structure
  511. CfInfoSize - Length of the following
  512. pNewCfInfo - Updated flow info
  513. Return Value:
  514. GPC_STATUS_SUCCESS always.
  515. --*/
  516. {
  517. PATMARP_FLOW_INFO pFlowInfo;
  518. PATMARP_VC pVc;
  519. GPC_STATUS GpcStatus;
  520. PCF_INFO_QOS pQosInfo;
  521. ULONG rc;
  522. pQosInfo = (PCF_INFO_QOS)pNewCfInfo;
  523. pFlowInfo = (PATMARP_FLOW_INFO)ClientCfInfoContext;
  524. GpcStatus = GPC_STATUS_SUCCESS;
  525. do
  526. {
  527. GpcStatus = AtmArpGpcValidateCfInfo(pNewCfInfo, CfInfoSize);
  528. if (GpcStatus != GPC_STATUS_SUCCESS)
  529. {
  530. break;
  531. }
  532. pVc = (PATMARP_VC) InterlockedExchangePointer(
  533. &(pFlowInfo->VcContext),
  534. NULL
  535. );
  536. if (pVc == NULL_PATMARP_VC)
  537. {
  538. //
  539. // This flow isn't associated with a VC.
  540. //
  541. break;
  542. }
  543. //
  544. // Unlink the flow from the VC.
  545. //
  546. AA_ACQUIRE_VC_LOCK(pVc);
  547. AA_ASSERT(pVc->FlowHandle == (PVOID)pFlowInfo);
  548. pVc->FlowHandle = NULL;
  549. rc = AtmArpDereferenceVc(pVc); // GPC Unlink flow info (modify)
  550. if (rc != 0)
  551. {
  552. AA_SET_FLAG(pVc->Flags,
  553. AA_VC_GPC_MASK,
  554. AA_VC_GPC_IS_UNLINKED_FROM_FLOW);
  555. //
  556. // Age out this VC if it isn't aging out yet.
  557. //
  558. if (!AA_IS_TIMER_ACTIVE(&(pVc->Timer)))
  559. {
  560. AtmArpStartTimer(
  561. pVc->pInterface,
  562. &(pVc->Timer),
  563. AtmArpVcAgingTimeout,
  564. 1, // Age out in 1 second
  565. (PVOID)pVc
  566. );
  567. AtmArpReferenceVc(pVc); // GPC Flow remove decay timer ref
  568. }
  569. AA_RELEASE_VC_LOCK(pVc);
  570. }
  571. //
  572. // else the VC is gone.
  573. //
  574. //
  575. // Update the flow info.
  576. //
  577. AA_GPC_COPY_FLOW_PARAMS(pFlowInfo, pQosInfo);
  578. break;
  579. }
  580. while (FALSE);
  581. AADEBUGP(AAD_INFO, ("ModCfInfo: pFlowInfo x%x, VC x%x, New SendBW %d, SendPktSz %d\n",
  582. pFlowInfo,
  583. pFlowInfo->VcContext,
  584. pFlowInfo->FlowSpec.SendAvgBandwidth,
  585. pFlowInfo->FlowSpec.SendMaxSize));
  586. return (GpcStatus);
  587. }
  588. VOID
  589. AtmArpGpcRemoveCfInfoComplete(
  590. IN GPC_CLIENT_HANDLE ClientContext,
  591. IN GPC_CLIENT_HANDLE ClientCfInfoContext,
  592. IN GPC_STATUS GpcStatus
  593. )
  594. /*++
  595. Routine Description:
  596. This is the entry point called by GPC when a pended call to
  597. GpcRemoveCfInfo() has completed. Since we never call GpcRemoveCfInfo,
  598. we should never be called here.
  599. Arguments:
  600. <Not used>
  601. Return Value:
  602. None
  603. --*/
  604. {
  605. AA_ASSERT(FALSE);
  606. }
  607. GPC_STATUS
  608. AtmArpGpcRemoveCfInfoNotify(
  609. IN GPC_CLIENT_HANDLE ClientContext,
  610. IN GPC_CLIENT_HANDLE ClientCfInfoContext
  611. )
  612. /*++
  613. Routine Description:
  614. This is the entry point called by GPC to notify us that a flow
  615. is being removed. We locate our context for the flow, unlink
  616. it from the ATM VC that carries the flow, and start aging
  617. Arguments:
  618. ClientContext - Pointer to our global context
  619. ClientCfInfoContext - Pointer to our FLOW INFO structure
  620. Return Value:
  621. GPC_STATUS_SUCCESS always.
  622. --*/
  623. {
  624. PATMARP_FLOW_INFO pFlowInfo;
  625. PATMARP_VC pVc;
  626. GPC_STATUS GpcStatus;
  627. ULONG rc;
  628. pFlowInfo = (PATMARP_FLOW_INFO)ClientCfInfoContext;
  629. AADEBUGP(AAD_INFO, ("RemCfInfo: pFlowInfo x%x, VC x%x, SendBW %d, SendPktSz %d\n",
  630. pFlowInfo,
  631. pFlowInfo->VcContext,
  632. pFlowInfo->FlowSpec.SendAvgBandwidth,
  633. pFlowInfo->FlowSpec.SendMaxSize));
  634. GpcStatus = GPC_STATUS_SUCCESS;
  635. do
  636. {
  637. pVc = (PATMARP_VC) InterlockedExchangePointer(
  638. &(pFlowInfo->VcContext),
  639. NULL
  640. );
  641. if (pVc == NULL_PATMARP_VC)
  642. {
  643. //
  644. // This flow isn't associated with a VC.
  645. //
  646. break;
  647. }
  648. //
  649. // Unlink the flow from the VC.
  650. //
  651. AA_ACQUIRE_VC_LOCK(pVc);
  652. AA_ASSERT(pVc->FlowHandle == (PVOID)pFlowInfo);
  653. pVc->FlowHandle = NULL;
  654. rc = AtmArpDereferenceVc(pVc); // GPC Unlink flow info (modify)
  655. if (rc != 0)
  656. {
  657. AA_SET_FLAG(pVc->Flags,
  658. AA_VC_GPC_MASK,
  659. AA_VC_GPC_IS_UNLINKED_FROM_FLOW);
  660. //
  661. // Age out this VC if it isn't aging out yet.
  662. //
  663. if (!AA_IS_TIMER_ACTIVE(&(pVc->Timer)))
  664. {
  665. AtmArpStartTimer(
  666. pVc->pInterface,
  667. &(pVc->Timer),
  668. AtmArpVcAgingTimeout,
  669. 1, // Age out in 1 second
  670. (PVOID)pVc
  671. );
  672. AtmArpReferenceVc(pVc); // GPC Flow remove decay timer ref
  673. }
  674. AA_RELEASE_VC_LOCK(pVc);
  675. }
  676. //
  677. // else the VC is gone.
  678. //
  679. break;
  680. }
  681. while (FALSE);
  682. //
  683. // Unlink this flow from the global list.
  684. //
  685. AA_ACQUIRE_GLOBAL_LOCK(pAtmArpGlobalInfo);
  686. if (pFlowInfo->pNextFlow != NULL)
  687. {
  688. pFlowInfo->pNextFlow->pPrevFlow = pFlowInfo->pPrevFlow;
  689. }
  690. if (pFlowInfo->pPrevFlow != NULL)
  691. {
  692. pFlowInfo->pPrevFlow->pNextFlow = pFlowInfo->pNextFlow;
  693. }
  694. else
  695. {
  696. pAtmArpGlobalInfo->pFlowInfoList = pFlowInfo->pNextFlow;
  697. }
  698. AA_RELEASE_GLOBAL_LOCK(pAtmArpGlobalInfo);
  699. //
  700. // Delete this flow info structure.
  701. //
  702. AA_FREE_MEM(pFlowInfo);
  703. return (GpcStatus);
  704. }
  705. GPC_STATUS
  706. AtmArpValidateFlowSpec(
  707. IN PATMARP_INTERFACE pInterface, LOCKIN LOCKOUT
  708. IN FLOWSPEC * pFS,
  709. IN BOOLEAN fSending
  710. )
  711. /*++
  712. Routine Description:
  713. Check the contents of a CF INFO structure that's been given to us.
  714. Arguments:
  715. pFS - The FLOWSPEC struct to check.
  716. pInterface - Pointer to the interface (assumed to be locked).
  717. fSending - if TRUE this is a sending flow otherwise it is a receiving
  718. flow.
  719. Return Value:
  720. GPC_STATUS_SUCCESS if the structure is OK, error code otherwise.
  721. --*/
  722. {
  723. /*
  724. Here is the validation plan for the
  725. fields of FLOWSPEC:
  726. Ignored fields:
  727. Latency
  728. DelayVariation
  729. If ServiceType == NO_TRAFFIC, we ignore all other fields.
  730. Default handling
  731. MinimumPolicedSize: ignored
  732. TokenRate: BE:line-rate; GS:invalid CLS: invalid
  733. TokenBucketSize: MTU
  734. PeakBandwidth: line-rate
  735. ServiceType:BE
  736. MaxSduSize: MTU
  737. Valid ranges
  738. MinimumPolicedSize <= MTU
  739. 0<TokenRate <= LineRate
  740. 0<TokenBucketSize
  741. 0<TokenRate <= PeakBandwidth
  742. ServiceType: valid type
  743. 0<MaxSduSize <= MTU
  744. MaxSduSize <= TokenBucketSize
  745. */
  746. GPC_STATUS Status = GPC_STATUS_SUCCESS;
  747. do
  748. {
  749. ULONG MTU = pInterface->pAdapter->MaxPacketSize;
  750. UINT LineRate = (fSending)
  751. ? pInterface->pAdapter->LineRate.Outbound
  752. : pInterface->pAdapter->LineRate.Inbound;
  753. //
  754. // Check service types.
  755. //
  756. switch(pFS->ServiceType)
  757. {
  758. case SERVICETYPE_GUARANTEED: // fall through
  759. case SERVICETYPE_CONTROLLEDLOAD:
  760. if (pFS->TokenRate == QOS_NOT_SPECIFIED)
  761. {
  762. AADEBUGP(AAD_INFO,
  763. ("GpcValidateCfInfo: FAIL: Token rate U for ST G/CL. ST=0x%lx\n",
  764. pFS->ServiceType));
  765. Status = QOS_STATUS_INVALID_TOKEN_RATE;
  766. // Status = GPC_STATUS_INVALID_PARAMETER;
  767. }
  768. break;
  769. case SERVICETYPE_NOTRAFFIC: // fall through
  770. case SERVICETYPE_BESTEFFORT: // fall through
  771. case QOS_NOT_SPECIFIED:
  772. break;
  773. default:
  774. // Status = GPC_STATUS_INVALID_PARAMETER;
  775. Status = QOS_STATUS_INVALID_SERVICE_TYPE;
  776. AADEBUGP(AAD_INFO,
  777. ("GpcValidateCfInfo: FAIL: Unknown ST 0x%lx\n", pFS->ServiceType));
  778. break;
  779. }
  780. if (Status != GPC_STATUS_SUCCESS)
  781. {
  782. break;
  783. }
  784. //
  785. // If service type is notraffic, we ignore all other parameters...
  786. //
  787. if (pFS->ServiceType == SERVICETYPE_NOTRAFFIC)
  788. {
  789. break;
  790. }
  791. //
  792. // Check that non-default values fall into valid ranges...
  793. //
  794. #define EXCEEDSMAX(_value,_max) \
  795. ((_value) != QOS_NOT_SPECIFIED && (_value) > (_max))
  796. if (EXCEEDSMAX(pFS->MinimumPolicedSize, MTU))
  797. {
  798. AADEBUGP(AAD_INFO,
  799. ("GpcValidateCfInfo: FAIL: MinPolSz(%lu)>MTU(%lu)\n",
  800. pFS->MinimumPolicedSize,
  801. MTU));
  802. Status = GPC_STATUS_RESOURCES;
  803. break;
  804. }
  805. if (EXCEEDSMAX(pFS->TokenRate, LineRate))
  806. {
  807. AADEBUGP(AAD_INFO,
  808. ("GpcValidateCfInfo: FAIL: TokRt(%lu)>LineRt(%lu)\n",
  809. pFS->TokenRate,
  810. LineRate));
  811. Status = QOS_STATUS_INVALID_TOKEN_RATE;
  812. // Status = GPC_STATUS_RESOURCES;
  813. break;
  814. }
  815. if (EXCEEDSMAX(pFS->TokenRate, pFS->PeakBandwidth))
  816. {
  817. AADEBUGP(AAD_INFO,
  818. ("GpcValidateCfInfo: FAIL: TokRt(%lu)>PkBw(%lu)\n",
  819. pFS->TokenRate,
  820. pFS->PeakBandwidth));
  821. //
  822. // 3/15/1999 JosephJ: According to EricEil, in this condition
  823. // we should return INVALID_PEAK_RATE, not
  824. // INVALID_TOKEN_RATE
  825. //
  826. Status = QOS_STATUS_INVALID_PEAK_RATE;
  827. break;
  828. }
  829. if (EXCEEDSMAX(pFS->MaxSduSize, MTU))
  830. {
  831. AADEBUGP(AAD_INFO,
  832. ("GpcValidateCfInfo: FAIL: MaxSduSz(%lu)>MTU(%lu)\n",
  833. pFS->MaxSduSize,
  834. MTU));
  835. Status = GPC_STATUS_RESOURCES;
  836. break;
  837. }
  838. if (EXCEEDSMAX(pFS->MaxSduSize, pFS->TokenBucketSize))
  839. {
  840. AADEBUGP(AAD_INFO,
  841. ("GpcValidateCfInfo: FAIL: MaxSduSz(%lu)>TokBktSz(%lu)\n",
  842. pFS->MaxSduSize,
  843. pFS->TokenBucketSize));
  844. Status = GPC_STATUS_INVALID_PARAMETER;
  845. break;
  846. }
  847. if (
  848. pFS->TokenRate==0
  849. || pFS->TokenBucketSize==0
  850. || pFS->MaxSduSize==0)
  851. {
  852. AADEBUGP(AAD_INFO,
  853. ("GpcValidateCfInfo: FAIL: !TokRt || !TokBktSz || !MaxSduSz\n"));
  854. if (pFS->TokenRate == 0)
  855. {
  856. Status = QOS_STATUS_INVALID_TOKEN_RATE;
  857. }
  858. else
  859. {
  860. Status = GPC_STATUS_INVALID_PARAMETER;
  861. }
  862. break;
  863. }
  864. } while (FALSE);
  865. return Status;
  866. }
  867. GPC_STATUS
  868. AtmArpGpcValidateCfInfo(
  869. IN PVOID pCfInfo,
  870. IN ULONG CfInfoSize
  871. )
  872. /*++
  873. Routine Description:
  874. Check the contents of a CF INFO structure that's been given to us.
  875. Arguments:
  876. pCfInfo - Pointer to the newly created INFO block
  877. CfInfoSize - Length of the above
  878. Return Value:
  879. GPC_STATUS_SUCCESS if the structure is OK, error code otherwise.
  880. --*/
  881. {
  882. GPC_STATUS GpcStatus;
  883. PCF_INFO_QOS pQosInfo;
  884. PATMARP_INTERFACE pInterface;
  885. pQosInfo = (PCF_INFO_QOS)pCfInfo;
  886. GpcStatus = GPC_STATUS_SUCCESS;
  887. do
  888. {
  889. if(CfInfoSize < (FIELD_OFFSET(CF_INFO_QOS, GenFlow) +
  890. FIELD_OFFSET(TC_GEN_FLOW, TcObjects)))
  891. {
  892. GpcStatus = GPC_STATUS_INVALID_PARAMETER;
  893. break;
  894. }
  895. #ifdef ATMARP_WMI
  896. //
  897. // Check that both recv and send servicetypes are not both notraffic
  898. //
  899. if ( pQosInfo->GenFlow.ReceivingFlowspec.ServiceType==SERVICETYPE_NOTRAFFIC
  900. && pQosInfo->GenFlow.SendingFlowspec.ServiceType==SERVICETYPE_NOTRAFFIC)
  901. {
  902. GpcStatus = GPC_STATUS_INVALID_PARAMETER;
  903. break;
  904. }
  905. //
  906. // Check if this notification is actually for us.
  907. //
  908. pInterface = AtmArpWmiGetIfByName(
  909. (PWSTR)&pQosInfo->InstanceName[0],
  910. pQosInfo->InstanceNameLength
  911. );
  912. if (pInterface != NULL_PATMARP_INTERFACE)
  913. {
  914. AA_ACQUIRE_IF_LOCK(pInterface);
  915. if (pInterface->AdminState != IF_STATUS_UP)
  916. {
  917. //
  918. // Oh oh -- interface is not up and about....
  919. //
  920. AtmArpDereferenceInterface(pInterface); // WMI: Tmp ref.
  921. AA_RELEASE_IF_LOCK(pInterface);
  922. pInterface = NULL;
  923. }
  924. }
  925. if (pInterface == NULL_PATMARP_INTERFACE)
  926. {
  927. AADEBUGP(AAD_WARNING,
  928. ("GpcValidateCfInfo: pQosInfo 0x%x, unknown instance name %ws\n",
  929. pQosInfo, pQosInfo->InstanceName));
  930. GpcStatus = GPC_STATUS_IGNORED;
  931. break;
  932. }
  933. //
  934. // We have the interface lock -- don't break without releasing it first!
  935. //
  936. GpcStatus = AtmArpValidateFlowSpec(
  937. pInterface,
  938. &(pQosInfo->GenFlow.ReceivingFlowspec),
  939. FALSE
  940. );
  941. if (GpcStatus == GPC_STATUS_SUCCESS)
  942. {
  943. GpcStatus = AtmArpValidateFlowSpec(
  944. pInterface,
  945. &(pQosInfo->GenFlow.SendingFlowspec),
  946. TRUE
  947. );
  948. }
  949. AtmArpDereferenceInterface(pInterface); // WMI: Tmp ref.
  950. AA_RELEASE_IF_LOCK(pInterface);
  951. #endif // ATMARP_WMI
  952. break;
  953. }
  954. while (FALSE);
  955. return (GpcStatus);
  956. }
  957. EXTERN
  958. GPC_STATUS
  959. AtmArpGpcGetCfInfoName(
  960. IN GPC_CLIENT_HANDLE ClientContext,
  961. IN GPC_CLIENT_HANDLE ClientCfInfoContext,
  962. OUT PNDIS_STRING InstanceName
  963. )
  964. /*++
  965. Routine Description:
  966. The GPC can issue this call to get from us the WMI manageable
  967. InstanceName which Ndis created for the flow associated with
  968. the CfInfo struct.
  969. We guarantee to keep the string buffer around until the CfInfo
  970. structure is removed.
  971. Arguments:
  972. ClientContext - Client context supplied to GpcRegisterClient
  973. ClientCfInfoContext - Client's CfInfo context
  974. InstanceName - We return a pointer to our string.
  975. Return Value:
  976. Status
  977. --*/
  978. {
  979. PATMARP_FLOW_INFO pFlowInfo = (PATMARP_FLOW_INFO)ClientCfInfoContext;
  980. InstanceName->Buffer = pFlowInfo->FlowInstanceName;
  981. InstanceName->Length = sizeof(pFlowInfo->FlowInstanceName);
  982. InstanceName->MaximumLength = sizeof(pFlowInfo->FlowInstanceName);
  983. return NDIS_STATUS_SUCCESS;
  984. }
  985. #endif // GPC