Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1297 lines
30 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 PTC_INTERFACE_ID InterfaceInfo,
  355. IN ULONG CfInfoSize,
  356. IN PVOID pCfInfo,
  357. OUT PGPC_CLIENT_HANDLE pClientCfInfoContext
  358. )
  359. /*++
  360. Routine Description:
  361. This is the entry point called by GPC to notify us of creation of
  362. a new INFO block of type QOS. We allocate a FLOW_INFO structure,
  363. fill it with what we need, and return a pointer to it as our context.
  364. Arguments:
  365. ClientContext - Pointer to our global info struct
  366. GpcCfInfoHandle - GPC Handle to use in all GPC APIs for this INFO block
  367. InterfaceInfo - Some information about the interface (ignored)
  368. CfInfoSize - Length of the following block
  369. pCfInfo - Pointer to the newly created INFO block
  370. pClientCfInfoContext- Place where we return our context for this block
  371. Return Value:
  372. GPC_STATUS_SUCCESS if we were able to allocate a new FLOW_INFO structure,
  373. GPC_STATUS_RESOURCES otherwise.
  374. --*/
  375. {
  376. PATMARP_FLOW_INFO pFlowInfo;
  377. GPC_STATUS GpcStatus;
  378. PCF_INFO_QOS pQosInfo;
  379. pQosInfo = (PCF_INFO_QOS)pCfInfo;
  380. //
  381. // Initialize.
  382. //
  383. *pClientCfInfoContext = NULL;
  384. do
  385. {
  386. GpcStatus = AtmArpGpcValidateCfInfo(pCfInfo, CfInfoSize);
  387. if (GpcStatus != GPC_STATUS_SUCCESS)
  388. {
  389. break;
  390. }
  391. AA_ALLOC_MEM(pFlowInfo, ATMARP_FLOW_INFO, sizeof(ATMARP_FLOW_INFO));
  392. if (pFlowInfo == NULL)
  393. {
  394. GpcStatus = GPC_STATUS_RESOURCES;
  395. break;
  396. }
  397. AA_SET_MEM(pFlowInfo, 0, sizeof(ATMARP_FLOW_INFO));
  398. pFlowInfo->CfInfoHandle = GpcCfInfoHandle;
  399. //
  400. // Copy in flow parameters
  401. //
  402. AA_GPC_COPY_FLOW_PARAMS(pFlowInfo, pQosInfo);
  403. //
  404. // Generate Unique Name for this flow.
  405. // This name is based on the template, AA_FLOW_INSTANCE_TEMPLATE.
  406. // The flow number part is based on a static variable which is
  407. // InterlockIncremented each time a flowinfo is created.
  408. //
  409. {
  410. static ULONG FlowCount = 0;
  411. ULONG ThisFlow = NdisInterlockedIncrement(&FlowCount);
  412. WCHAR *pwc;
  413. AA_ASSERT(sizeof(pFlowInfo->FlowInstanceName)
  414. == sizeof(AA_FLOW_INSTANCE_NAME_TEMPLATE)-sizeof(WCHAR));
  415. AA_COPY_MEM(
  416. pFlowInfo->FlowInstanceName,
  417. AA_FLOW_INSTANCE_NAME_TEMPLATE,
  418. sizeof(pFlowInfo->FlowInstanceName)
  419. );
  420. //
  421. // We fill in the "flow number" field of the template, which
  422. // is the 1st 8 characters, with the hex representation of
  423. // ThisFlow. The LS digit is at offset 7.
  424. //
  425. pwc = pFlowInfo->FlowInstanceName+7;
  426. AA_ASSERT(2*sizeof(ThisFlow) == 8);
  427. while (ThisFlow)
  428. {
  429. ULONG u = ThisFlow & 0xf;
  430. *pwc-- = (WCHAR) ((u < 10) ? (u + '0') : u + 'A' - 10);
  431. ThisFlow >>= 4;
  432. }
  433. }
  434. //
  435. // Link it to the global flow list.
  436. //
  437. AA_ACQUIRE_GLOBAL_LOCK(pAtmArpGlobalInfo);
  438. pFlowInfo->pPrevFlow = NULL;
  439. pFlowInfo->pNextFlow = pAtmArpGlobalInfo->pFlowInfoList;
  440. if (pAtmArpGlobalInfo->pFlowInfoList != NULL)
  441. {
  442. pAtmArpGlobalInfo->pFlowInfoList->pPrevFlow = pFlowInfo;
  443. }
  444. pAtmArpGlobalInfo->pFlowInfoList = pFlowInfo;
  445. AA_RELEASE_GLOBAL_LOCK(pAtmArpGlobalInfo);
  446. //
  447. // Return our context for this flow.
  448. //
  449. *pClientCfInfoContext = (GPC_CLIENT_HANDLE)pFlowInfo;
  450. GpcStatus = GPC_STATUS_SUCCESS;
  451. break;
  452. }
  453. while (FALSE);
  454. AADEBUGP(AAD_INFO, ("AddCfInfoNotify: pCfInfo x%x, ClientCtx x%x, ret x%x\n",
  455. pCfInfo, *pClientCfInfoContext, GpcStatus));
  456. #if DBG
  457. if (GpcStatus == GPC_STATUS_SUCCESS)
  458. {
  459. AADEBUGP(AAD_INFO, (" : SendPeak %d, SendAvg %d, SendPktSize %d, ServType %d\n",
  460. pFlowInfo->FlowSpec.SendPeakBandwidth,
  461. pFlowInfo->FlowSpec.SendAvgBandwidth,
  462. pFlowInfo->FlowSpec.SendMaxSize,
  463. pFlowInfo->FlowSpec.SendServiceType));
  464. AADEBUGP(AAD_INFO, (" : RecvPeak %d, RecvAvg %d, RecvPktSize %d, ServType %d\n",
  465. pFlowInfo->FlowSpec.ReceivePeakBandwidth,
  466. pFlowInfo->FlowSpec.ReceiveAvgBandwidth,
  467. pFlowInfo->FlowSpec.ReceiveMaxSize,
  468. pFlowInfo->FlowSpec.ReceiveServiceType));
  469. }
  470. #endif
  471. return (GpcStatus);
  472. }
  473. VOID
  474. AtmArpGpcModifyCfInfoComplete(
  475. IN GPC_CLIENT_HANDLE ClientContext,
  476. IN GPC_CLIENT_HANDLE ClientCfInfoContext,
  477. IN GPC_STATUS GpcStatus
  478. )
  479. /*++
  480. Routine Description:
  481. This is the entry point called by GPC when a pended call to
  482. GpcModifyCfInfo() has completed. Since we never call GpcModifyCfInfo,
  483. we should never be called here.
  484. Addendum: Apparently this is called even if another client calls
  485. GpcModifyCfInfo, just to notify this client that the modify operation
  486. finished.
  487. Arguments:
  488. <Not used>
  489. Return Value:
  490. None
  491. --*/
  492. {
  493. return;
  494. }
  495. GPC_STATUS
  496. AtmArpGpcModifyCfInfoNotify(
  497. IN GPC_CLIENT_HANDLE ClientContext,
  498. IN GPC_CLIENT_HANDLE ClientCfInfoContext,
  499. IN ULONG CfInfoSize,
  500. IN PVOID pNewCfInfo
  501. )
  502. /*++
  503. Routine Description:
  504. This is the entry point called by GPC when an existing flow has
  505. been modified.
  506. If the flow info for this flow is linked with a VC, we unlink it,
  507. and start an aging timeout on the VC. We update the flow info structure
  508. with this new information. The next packet that falls into this
  509. classification will cause a new VC with updated QoS to be created.
  510. Arguments:
  511. ClientContext - Pointer to our global context
  512. ClientCfInfoContext - Pointer to our FLOW INFO structure
  513. CfInfoSize - Length of the following
  514. pNewCfInfo - Updated flow info
  515. Return Value:
  516. GPC_STATUS_SUCCESS always.
  517. --*/
  518. {
  519. PATMARP_FLOW_INFO pFlowInfo;
  520. PATMARP_VC pVc;
  521. GPC_STATUS GpcStatus;
  522. PCF_INFO_QOS pQosInfo;
  523. ULONG rc;
  524. pQosInfo = (PCF_INFO_QOS)pNewCfInfo;
  525. pFlowInfo = (PATMARP_FLOW_INFO)ClientCfInfoContext;
  526. GpcStatus = GPC_STATUS_SUCCESS;
  527. do
  528. {
  529. GpcStatus = AtmArpGpcValidateCfInfo(pNewCfInfo, CfInfoSize);
  530. if (GpcStatus != GPC_STATUS_SUCCESS)
  531. {
  532. break;
  533. }
  534. pVc = (PATMARP_VC) InterlockedExchangePointer(
  535. &(pFlowInfo->VcContext),
  536. NULL
  537. );
  538. if (pVc == NULL_PATMARP_VC)
  539. {
  540. //
  541. // This flow isn't associated with a VC.
  542. //
  543. break;
  544. }
  545. //
  546. // Unlink the flow from the VC.
  547. //
  548. AA_ACQUIRE_VC_LOCK(pVc);
  549. AA_ASSERT(pVc->FlowHandle == (PVOID)pFlowInfo);
  550. pVc->FlowHandle = NULL;
  551. rc = AtmArpDereferenceVc(pVc); // GPC Unlink flow info (modify)
  552. if (rc != 0)
  553. {
  554. AA_SET_FLAG(pVc->Flags,
  555. AA_VC_GPC_MASK,
  556. AA_VC_GPC_IS_UNLINKED_FROM_FLOW);
  557. //
  558. // Age out this VC if it isn't aging out yet.
  559. //
  560. if (!AA_IS_TIMER_ACTIVE(&(pVc->Timer)))
  561. {
  562. AtmArpStartTimer(
  563. pVc->pInterface,
  564. &(pVc->Timer),
  565. AtmArpVcAgingTimeout,
  566. 1, // Age out in 1 second
  567. (PVOID)pVc
  568. );
  569. AtmArpReferenceVc(pVc); // GPC Flow remove decay timer ref
  570. }
  571. AA_RELEASE_VC_LOCK(pVc);
  572. }
  573. //
  574. // else the VC is gone.
  575. //
  576. //
  577. // Update the flow info.
  578. //
  579. AA_GPC_COPY_FLOW_PARAMS(pFlowInfo, pQosInfo);
  580. break;
  581. }
  582. while (FALSE);
  583. AADEBUGP(AAD_INFO, ("ModCfInfo: pFlowInfo x%x, VC x%x, New SendBW %d, SendPktSz %d\n",
  584. pFlowInfo,
  585. pFlowInfo->VcContext,
  586. pFlowInfo->FlowSpec.SendAvgBandwidth,
  587. pFlowInfo->FlowSpec.SendMaxSize));
  588. return (GpcStatus);
  589. }
  590. VOID
  591. AtmArpGpcRemoveCfInfoComplete(
  592. IN GPC_CLIENT_HANDLE ClientContext,
  593. IN GPC_CLIENT_HANDLE ClientCfInfoContext,
  594. IN GPC_STATUS GpcStatus
  595. )
  596. /*++
  597. Routine Description:
  598. This is the entry point called by GPC when a pended call to
  599. GpcRemoveCfInfo() has completed. Since we never call GpcRemoveCfInfo,
  600. we should never be called here.
  601. Arguments:
  602. <Not used>
  603. Return Value:
  604. None
  605. --*/
  606. {
  607. AA_ASSERT(FALSE);
  608. }
  609. GPC_STATUS
  610. AtmArpGpcRemoveCfInfoNotify(
  611. IN GPC_CLIENT_HANDLE ClientContext,
  612. IN GPC_CLIENT_HANDLE ClientCfInfoContext
  613. )
  614. /*++
  615. Routine Description:
  616. This is the entry point called by GPC to notify us that a flow
  617. is being removed. We locate our context for the flow, unlink
  618. it from the ATM VC that carries the flow, and start aging
  619. Arguments:
  620. ClientContext - Pointer to our global context
  621. ClientCfInfoContext - Pointer to our FLOW INFO structure
  622. Return Value:
  623. GPC_STATUS_SUCCESS always.
  624. --*/
  625. {
  626. PATMARP_FLOW_INFO pFlowInfo;
  627. PATMARP_VC pVc;
  628. GPC_STATUS GpcStatus;
  629. ULONG rc;
  630. pFlowInfo = (PATMARP_FLOW_INFO)ClientCfInfoContext;
  631. AADEBUGP(AAD_INFO, ("RemCfInfo: pFlowInfo x%x, VC x%x, SendBW %d, SendPktSz %d\n",
  632. pFlowInfo,
  633. pFlowInfo->VcContext,
  634. pFlowInfo->FlowSpec.SendAvgBandwidth,
  635. pFlowInfo->FlowSpec.SendMaxSize));
  636. GpcStatus = GPC_STATUS_SUCCESS;
  637. do
  638. {
  639. pVc = (PATMARP_VC) InterlockedExchangePointer(
  640. &(pFlowInfo->VcContext),
  641. NULL
  642. );
  643. if (pVc == NULL_PATMARP_VC)
  644. {
  645. //
  646. // This flow isn't associated with a VC.
  647. //
  648. break;
  649. }
  650. //
  651. // Unlink the flow from the VC.
  652. //
  653. AA_ACQUIRE_VC_LOCK(pVc);
  654. AA_ASSERT(pVc->FlowHandle == (PVOID)pFlowInfo);
  655. pVc->FlowHandle = NULL;
  656. rc = AtmArpDereferenceVc(pVc); // GPC Unlink flow info (modify)
  657. if (rc != 0)
  658. {
  659. AA_SET_FLAG(pVc->Flags,
  660. AA_VC_GPC_MASK,
  661. AA_VC_GPC_IS_UNLINKED_FROM_FLOW);
  662. //
  663. // Age out this VC if it isn't aging out yet.
  664. //
  665. if (!AA_IS_TIMER_ACTIVE(&(pVc->Timer)))
  666. {
  667. AtmArpStartTimer(
  668. pVc->pInterface,
  669. &(pVc->Timer),
  670. AtmArpVcAgingTimeout,
  671. 1, // Age out in 1 second
  672. (PVOID)pVc
  673. );
  674. AtmArpReferenceVc(pVc); // GPC Flow remove decay timer ref
  675. }
  676. AA_RELEASE_VC_LOCK(pVc);
  677. }
  678. //
  679. // else the VC is gone.
  680. //
  681. break;
  682. }
  683. while (FALSE);
  684. //
  685. // Unlink this flow from the global list.
  686. //
  687. AA_ACQUIRE_GLOBAL_LOCK(pAtmArpGlobalInfo);
  688. if (pFlowInfo->pNextFlow != NULL)
  689. {
  690. pFlowInfo->pNextFlow->pPrevFlow = pFlowInfo->pPrevFlow;
  691. }
  692. if (pFlowInfo->pPrevFlow != NULL)
  693. {
  694. pFlowInfo->pPrevFlow->pNextFlow = pFlowInfo->pNextFlow;
  695. }
  696. else
  697. {
  698. pAtmArpGlobalInfo->pFlowInfoList = pFlowInfo->pNextFlow;
  699. }
  700. AA_RELEASE_GLOBAL_LOCK(pAtmArpGlobalInfo);
  701. //
  702. // Delete this flow info structure.
  703. //
  704. AA_FREE_MEM(pFlowInfo);
  705. return (GpcStatus);
  706. }
  707. GPC_STATUS
  708. AtmArpValidateFlowSpec(
  709. IN PATMARP_INTERFACE pInterface, LOCKIN LOCKOUT
  710. IN FLOWSPEC * pFS,
  711. IN BOOLEAN fSending
  712. )
  713. /*++
  714. Routine Description:
  715. Check the contents of a CF INFO structure that's been given to us.
  716. Arguments:
  717. pFS - The FLOWSPEC struct to check.
  718. pInterface - Pointer to the interface (assumed to be locked).
  719. fSending - if TRUE this is a sending flow otherwise it is a receiving
  720. flow.
  721. Return Value:
  722. GPC_STATUS_SUCCESS if the structure is OK, error code otherwise.
  723. --*/
  724. {
  725. /*
  726. Here is the validation plan for the
  727. fields of FLOWSPEC:
  728. Ignored fields:
  729. Latency
  730. DelayVariation
  731. If ServiceType == NO_TRAFFIC, we ignore all other fields.
  732. Default handling
  733. MinimumPolicedSize: ignored
  734. TokenRate: BE:line-rate; GS:invalid CLS: invalid
  735. TokenBucketSize: MTU
  736. PeakBandwidth: line-rate
  737. ServiceType:BE
  738. MaxSduSize: MTU
  739. Valid ranges
  740. MinimumPolicedSize <= MTU
  741. 0<TokenRate <= LineRate
  742. 0<TokenBucketSize
  743. 0<TokenRate <= PeakBandwidth
  744. ServiceType: valid type
  745. 0<MaxSduSize <= MTU
  746. MaxSduSize <= TokenBucketSize
  747. */
  748. GPC_STATUS Status = GPC_STATUS_SUCCESS;
  749. do
  750. {
  751. ULONG MTU = pInterface->pAdapter->MaxPacketSize;
  752. UINT LineRate = (fSending)
  753. ? pInterface->pAdapter->LineRate.Outbound
  754. : pInterface->pAdapter->LineRate.Inbound;
  755. //
  756. // Check service types.
  757. //
  758. switch(pFS->ServiceType)
  759. {
  760. case SERVICETYPE_GUARANTEED: // fall through
  761. case SERVICETYPE_CONTROLLEDLOAD:
  762. if (pFS->TokenRate == QOS_NOT_SPECIFIED)
  763. {
  764. AADEBUGP(AAD_INFO,
  765. ("GpcValidateCfInfo: FAIL: Token rate U for ST G/CL. ST=0x%lx\n",
  766. pFS->ServiceType));
  767. Status = QOS_STATUS_INVALID_TOKEN_RATE;
  768. // Status = GPC_STATUS_INVALID_PARAMETER;
  769. }
  770. break;
  771. case SERVICETYPE_NOTRAFFIC: // fall through
  772. case SERVICETYPE_BESTEFFORT: // fall through
  773. case QOS_NOT_SPECIFIED:
  774. break;
  775. default:
  776. // Status = GPC_STATUS_INVALID_PARAMETER;
  777. Status = QOS_STATUS_INVALID_SERVICE_TYPE;
  778. AADEBUGP(AAD_INFO,
  779. ("GpcValidateCfInfo: FAIL: Unknown ST 0x%lx\n", pFS->ServiceType));
  780. break;
  781. }
  782. if (Status != GPC_STATUS_SUCCESS)
  783. {
  784. break;
  785. }
  786. //
  787. // If service type is notraffic, we ignore all other parameters...
  788. //
  789. if (pFS->ServiceType == SERVICETYPE_NOTRAFFIC)
  790. {
  791. break;
  792. }
  793. //
  794. // Check that non-default values fall into valid ranges...
  795. //
  796. #define EXCEEDSMAX(_value,_max) \
  797. ((_value) != QOS_NOT_SPECIFIED && (_value) > (_max))
  798. if (EXCEEDSMAX(pFS->MinimumPolicedSize, MTU))
  799. {
  800. AADEBUGP(AAD_INFO,
  801. ("GpcValidateCfInfo: FAIL: MinPolSz(%lu)>MTU(%lu)\n",
  802. pFS->MinimumPolicedSize,
  803. MTU));
  804. Status = GPC_STATUS_RESOURCES;
  805. break;
  806. }
  807. if (EXCEEDSMAX(pFS->TokenRate, LineRate))
  808. {
  809. AADEBUGP(AAD_INFO,
  810. ("GpcValidateCfInfo: FAIL: TokRt(%lu)>LineRt(%lu)\n",
  811. pFS->TokenRate,
  812. LineRate));
  813. Status = QOS_STATUS_INVALID_TOKEN_RATE;
  814. // Status = GPC_STATUS_RESOURCES;
  815. break;
  816. }
  817. if (EXCEEDSMAX(pFS->TokenRate, pFS->PeakBandwidth))
  818. {
  819. AADEBUGP(AAD_INFO,
  820. ("GpcValidateCfInfo: FAIL: TokRt(%lu)>PkBw(%lu)\n",
  821. pFS->TokenRate,
  822. pFS->PeakBandwidth));
  823. //
  824. // 3/15/1999 JosephJ: According to EricEil, in this condition
  825. // we should return INVALID_PEAK_RATE, not
  826. // INVALID_TOKEN_RATE
  827. //
  828. Status = QOS_STATUS_INVALID_PEAK_RATE;
  829. break;
  830. }
  831. if (EXCEEDSMAX(pFS->MaxSduSize, MTU))
  832. {
  833. AADEBUGP(AAD_INFO,
  834. ("GpcValidateCfInfo: FAIL: MaxSduSz(%lu)>MTU(%lu)\n",
  835. pFS->MaxSduSize,
  836. MTU));
  837. Status = GPC_STATUS_RESOURCES;
  838. break;
  839. }
  840. if (EXCEEDSMAX(pFS->MaxSduSize, pFS->TokenBucketSize))
  841. {
  842. AADEBUGP(AAD_INFO,
  843. ("GpcValidateCfInfo: FAIL: MaxSduSz(%lu)>TokBktSz(%lu)\n",
  844. pFS->MaxSduSize,
  845. pFS->TokenBucketSize));
  846. Status = GPC_STATUS_INVALID_PARAMETER;
  847. break;
  848. }
  849. if (
  850. pFS->TokenRate==0
  851. || pFS->TokenBucketSize==0
  852. || pFS->MaxSduSize==0)
  853. {
  854. AADEBUGP(AAD_INFO,
  855. ("GpcValidateCfInfo: FAIL: !TokRt || !TokBktSz || !MaxSduSz\n"));
  856. if (pFS->TokenRate == 0)
  857. {
  858. Status = QOS_STATUS_INVALID_TOKEN_RATE;
  859. }
  860. else
  861. {
  862. Status = GPC_STATUS_INVALID_PARAMETER;
  863. }
  864. break;
  865. }
  866. } while (FALSE);
  867. return Status;
  868. }
  869. GPC_STATUS
  870. AtmArpGpcValidateCfInfo(
  871. IN PVOID pCfInfo,
  872. IN ULONG CfInfoSize
  873. )
  874. /*++
  875. Routine Description:
  876. Check the contents of a CF INFO structure that's been given to us.
  877. Arguments:
  878. pCfInfo - Pointer to the newly created INFO block
  879. CfInfoSize - Length of the above
  880. Return Value:
  881. GPC_STATUS_SUCCESS if the structure is OK, error code otherwise.
  882. --*/
  883. {
  884. GPC_STATUS GpcStatus;
  885. PCF_INFO_QOS pQosInfo;
  886. PATMARP_INTERFACE pInterface;
  887. pQosInfo = (PCF_INFO_QOS)pCfInfo;
  888. GpcStatus = GPC_STATUS_SUCCESS;
  889. do
  890. {
  891. if(CfInfoSize < (FIELD_OFFSET(CF_INFO_QOS, GenFlow) +
  892. FIELD_OFFSET(TC_GEN_FLOW, TcObjects)))
  893. {
  894. GpcStatus = GPC_STATUS_INVALID_PARAMETER;
  895. break;
  896. }
  897. #ifdef ATMARP_WMI
  898. //
  899. // Check that both recv and send servicetypes are not both notraffic
  900. //
  901. if ( pQosInfo->GenFlow.ReceivingFlowspec.ServiceType==SERVICETYPE_NOTRAFFIC
  902. && pQosInfo->GenFlow.SendingFlowspec.ServiceType==SERVICETYPE_NOTRAFFIC)
  903. {
  904. GpcStatus = GPC_STATUS_INVALID_PARAMETER;
  905. break;
  906. }
  907. //
  908. // Check if this notification is actually for us.
  909. //
  910. pInterface = AtmArpWmiGetIfByName(
  911. (PWSTR)&pQosInfo->InstanceName[0],
  912. pQosInfo->InstanceNameLength
  913. );
  914. if (pInterface != NULL_PATMARP_INTERFACE)
  915. {
  916. AA_ACQUIRE_IF_LOCK(pInterface);
  917. if (pInterface->AdminState != IF_STATUS_UP)
  918. {
  919. //
  920. // Oh oh -- interface is not up and about....
  921. //
  922. AtmArpDereferenceInterface(pInterface); // WMI: Tmp ref.
  923. AA_RELEASE_IF_LOCK(pInterface);
  924. pInterface = NULL;
  925. }
  926. }
  927. if (pInterface == NULL_PATMARP_INTERFACE)
  928. {
  929. AADEBUGP(AAD_WARNING,
  930. ("GpcValidateCfInfo: pQosInfo 0x%x, unknown instance name %ws\n",
  931. pQosInfo, pQosInfo->InstanceName));
  932. GpcStatus = GPC_STATUS_IGNORED;
  933. break;
  934. }
  935. //
  936. // We have the interface lock -- don't break without releasing it first!
  937. //
  938. GpcStatus = AtmArpValidateFlowSpec(
  939. pInterface,
  940. &(pQosInfo->GenFlow.ReceivingFlowspec),
  941. FALSE
  942. );
  943. if (GpcStatus == GPC_STATUS_SUCCESS)
  944. {
  945. GpcStatus = AtmArpValidateFlowSpec(
  946. pInterface,
  947. &(pQosInfo->GenFlow.SendingFlowspec),
  948. TRUE
  949. );
  950. }
  951. AtmArpDereferenceInterface(pInterface); // WMI: Tmp ref.
  952. AA_RELEASE_IF_LOCK(pInterface);
  953. #endif // ATMARP_WMI
  954. break;
  955. }
  956. while (FALSE);
  957. return (GpcStatus);
  958. }
  959. EXTERN
  960. GPC_STATUS
  961. AtmArpGpcGetCfInfoName(
  962. IN GPC_CLIENT_HANDLE ClientContext,
  963. IN GPC_CLIENT_HANDLE ClientCfInfoContext,
  964. OUT PNDIS_STRING InstanceName
  965. )
  966. /*++
  967. Routine Description:
  968. The GPC can issue this call to get from us the WMI manageable
  969. InstanceName which Ndis created for the flow associated with
  970. the CfInfo struct.
  971. We guarantee to keep the string buffer around until the CfInfo
  972. structure is removed.
  973. Arguments:
  974. ClientContext - Client context supplied to GpcRegisterClient
  975. ClientCfInfoContext - Client's CfInfo context
  976. InstanceName - We return a pointer to our string.
  977. Return Value:
  978. Status
  979. --*/
  980. {
  981. PATMARP_FLOW_INFO pFlowInfo = (PATMARP_FLOW_INFO)ClientCfInfoContext;
  982. InstanceName->Buffer = pFlowInfo->FlowInstanceName;
  983. InstanceName->Length = sizeof(pFlowInfo->FlowInstanceName);
  984. InstanceName->MaximumLength = sizeof(pFlowInfo->FlowInstanceName);
  985. return NDIS_STATUS_SUCCESS;
  986. }
  987. #endif // GPC