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.

1389 lines
40 KiB

  1. /*++
  2. Copyright (c) 1996-1999 Microsoft Corporation
  3. Module Name:
  4. GpcHndlr.c
  5. Abstract:
  6. Handlers called by GPC.
  7. Author:
  8. Rajesh Sundaram (rajeshsu)
  9. Environment:
  10. Kernel Mode
  11. Revision History:
  12. One of the initial designs (yoramb/charliew/rajeshsu) consisted of an
  13. integrated call manager with a seperate packet classifying client. The
  14. design used NDIS 5.0 VCs so that they could be managed by WMI.
  15. The main limitation of the above approach was the fact that NDIS provided
  16. mechanisms to manage miniport and VCs - We really needed a way to
  17. manage other things (like WanLinks, etc).
  18. --*/
  19. #include "psched.h"
  20. #pragma hdrstop
  21. /* External */
  22. /* Static */
  23. GPC_STATUS
  24. QosAddCfInfoNotify(
  25. IN GPC_CLIENT_HANDLE ClientContext,
  26. IN GPC_HANDLE GpcCfInfoHandle,
  27. IN ULONG CfInfoSize,
  28. IN PVOID CfInfoPtr,
  29. IN PGPC_CLIENT_HANDLE ClientCfInfoContext
  30. )
  31. /*++
  32. Routine Description:
  33. A new CF_INFO has been added to the GPC database.
  34. Arguments:
  35. ClientContext - Client context supplied to GpcRegisterClient
  36. GpcCfInfoHandle - GPC's handle to CF_INFO
  37. CfInfoPtr - Pointer to the CF_INFO structure
  38. ClientCfInfoContext - Location in which to return PS's context for CF_INFO
  39. Return Value:
  40. Status
  41. --*/
  42. {
  43. PADAPTER Adapter;
  44. PGPC_CLIENT_VC Vc;
  45. PCF_INFO_QOS CfInfo;
  46. NDIS_STATUS Status;
  47. ULONG CallParamsLength;
  48. PCO_CALL_PARAMETERS CallParams = 0;
  49. PCO_CALL_MANAGER_PARAMETERS CallMgrParams;
  50. PCO_MEDIA_PARAMETERS PsMediaParameters;
  51. LPQOS_PRIORITY PriorityObject;
  52. PPS_WAN_LINK WanLink = 0;
  53. ULONG TcObjAlignedLength;
  54. CfInfo = (PCF_INFO_QOS)CfInfoPtr;
  55. //
  56. // Verify that the TcObjectsLength is consistent with the CfInfoSize. The
  57. // CfInfoSize must have been verified during the user/kernel transition.
  58. // The TcObjectsLength has not. We could bugcheck if we try to search
  59. // beyond the buffer passed in.
  60. //
  61. if(CfInfoSize < (FIELD_OFFSET(CF_INFO_QOS, GenFlow) +
  62. FIELD_OFFSET(TC_GEN_FLOW, TcObjects) +
  63. CfInfo->GenFlow.TcObjectsLength))
  64. {
  65. PsDbgOut(DBG_FAILURE, DBG_GPC_QOS,
  66. ("[QosAddCfInfoNotify]: TcObjectsLength inconsistent with "
  67. "CfInfoSize \n"));
  68. return(QOS_STATUS_TC_OBJECT_LENGTH_INVALID);
  69. }
  70. //
  71. // Using the instance name, we find the adapter or the wanlink. If the adapter or wanlink is not
  72. // ready to accept VCs, this function will return NULL. Also, if it is ready, it will take a ref
  73. // on the Adapter and the WanLink.
  74. //
  75. Adapter = FindAdapterByWmiInstanceName((USHORT) CfInfo->InstanceNameLength,
  76. (PWSTR) &CfInfo->InstanceName[0],
  77. &WanLink);
  78. if(NULL == Adapter)
  79. {
  80. PsAssert(WanLink == NULL);
  81. PsDbgOut(DBG_FAILURE, DBG_GPC_QOS,
  82. ("[QosAddCfInfoNotify]: no adapter with instance name %ws\n",
  83. CfInfo->InstanceName));
  84. return GPC_STATUS_IGNORED;
  85. }
  86. //
  87. // We have taken a ref on the adapter or wanlink. so we need to deref if we bail out with error. If
  88. // we create the VC, then the adapter and wanlink are deref'd when the VC is deleted.
  89. //
  90. do
  91. {
  92. //
  93. // Allocate the resources for the call manager parameters.
  94. //
  95. TcObjAlignedLength = ((CfInfo->GenFlow.TcObjectsLength + (sizeof(PVOID)-1)) & ~(sizeof(PVOID)-1));
  96. CallParamsLength =
  97. sizeof(CO_CALL_PARAMETERS) +
  98. FIELD_OFFSET(CO_CALL_MANAGER_PARAMETERS, CallMgrSpecific) +
  99. FIELD_OFFSET(CO_SPECIFIC_PARAMETERS, Parameters) +
  100. TcObjAlignedLength +
  101. FIELD_OFFSET(CO_MEDIA_PARAMETERS, MediaSpecific) +
  102. FIELD_OFFSET(CO_SPECIFIC_PARAMETERS, Parameters);
  103. if(Adapter->MediaType == NdisMediumWan)
  104. {
  105. CallParamsLength += sizeof(QOS_WAN_MEDIA);
  106. }
  107. else
  108. {
  109. if(!Adapter->PipeHasResources)
  110. {
  111. //
  112. // We don't want to pend GPC client VCs. The reasons are:
  113. //
  114. // a. If the cable is never plugged in, we could pend VCs indefinitely.
  115. // Waste of system resources.
  116. //
  117. // b. There is no clean way for the app to cancel these pended VCs. Since
  118. // we have pended the AddCfInfo to the GPC, the GPC cannot call back
  119. // and ask us to delete the VC.
  120. //
  121. // But, we still need to handle the case where link speed change
  122. // might be transient (10/100 case). Also, if we return error, the app
  123. // might retry causing busy cycles if the media is never connected.
  124. // For all this, the app can register for WMI notifications for GUIDs
  125. // GUID_NDIS_STATUS_MEDIA_(DIS)CONNECT
  126. //
  127. //
  128. // Also, we probably don't want to do this for the b/e VC. Otherwise,
  129. // how does it work when the user installs psched and the media is
  130. // unconnected ? Do we want him to reinstall psched after connecting
  131. // the media ?
  132. //
  133. PsDbgOut(DBG_FAILURE, DBG_GPC_QOS,
  134. ("[QosAddCfInfoNotify]: Adapter %08X is not plugged in \n", Adapter));
  135. Status = NDIS_STATUS_NETWORK_UNREACHABLE;
  136. break;
  137. }
  138. }
  139. PsAllocatePool(CallParams, CallParamsLength, CmParamsTag);
  140. if(CallParams == NULL) {
  141. PsDbgOut(DBG_FAILURE, DBG_GPC_QOS,
  142. ("[QosAddCfInfoNotify]: Adapter %08X, can't allocate call"
  143. "params \n", Adapter));
  144. Status = GPC_STATUS_RESOURCES;
  145. break;
  146. }
  147. Status = CmCreateVc(&Vc, Adapter, WanLink, CallParams, GpcCfInfoHandle, CfInfo,
  148. ClientContext);
  149. if(!NT_SUCCESS(Status)) {
  150. PsDbgOut(DBG_FAILURE, DBG_GPC_QOS,
  151. ("[QosAddCfInfoNotify]: Adapter %08X, Could not create Vc \n",
  152. Adapter));
  153. break;
  154. }
  155. *ClientCfInfoContext = Vc;
  156. } while(FALSE);
  157. if(!NT_SUCCESS(Status))
  158. {
  159. if(CallParams)
  160. {
  161. PsFreePool(CallParams);
  162. }
  163. if(WanLink)
  164. {
  165. REFDEL(&WanLink->RefCount, FALSE, 'WANV');
  166. }
  167. REFDEL(&Adapter->RefCount, FALSE, 'ADVC');
  168. return Status;
  169. }
  170. //
  171. // Create a call parameters struct for the MakeCall
  172. //
  173. CallMgrParams = (PCO_CALL_MANAGER_PARAMETERS)(CallParams + 1);
  174. CallMgrParams->Transmit = CfInfo->GenFlow.SendingFlowspec;
  175. CallMgrParams->Receive = CfInfo->GenFlow.ReceivingFlowspec;
  176. CallMgrParams->CallMgrSpecific.ParamType = PARAM_TYPE_GQOS_INFO;
  177. CallMgrParams->CallMgrSpecific.Length = CfInfo->GenFlow.TcObjectsLength;
  178. if(CfInfo->GenFlow.TcObjectsLength > 0){
  179. NdisMoveMemory(
  180. &CallMgrParams->CallMgrSpecific.Parameters,
  181. &CfInfo->GenFlow.TcObjects,
  182. CfInfo->GenFlow.TcObjectsLength);
  183. }
  184. PsMediaParameters =
  185. (PCO_MEDIA_PARAMETERS)((PUCHAR)CallMgrParams +
  186. FIELD_OFFSET(CO_CALL_MANAGER_PARAMETERS, CallMgrSpecific) +
  187. FIELD_OFFSET(CO_SPECIFIC_PARAMETERS, Parameters) +
  188. TcObjAlignedLength);
  189. PsMediaParameters->Flags = 0;
  190. PsMediaParameters->ReceivePriority = 0;
  191. PsMediaParameters->ReceiveSizeHint = CfInfo->GenFlow.SendingFlowspec.MaxSduSize;
  192. PsMediaParameters->MediaSpecific.ParamType = PARAM_TYPE_GQOS_INFO;
  193. PsMediaParameters->MediaSpecific.Length = 0;
  194. //
  195. // If this flow is being installed on a Wan interface, need to
  196. // insert the linkId into the media specific fields. This is so that
  197. // NdisWan will be able to recognize the link over which to install
  198. // the flow.
  199. //
  200. if(WanLink){
  201. LPQOS_WAN_MEDIA WanMedia;
  202. PsMediaParameters->MediaSpecific.Length += sizeof(QOS_WAN_MEDIA);
  203. WanMedia = (LPQOS_WAN_MEDIA) PsMediaParameters->MediaSpecific.Parameters;
  204. WanMedia->ObjectHdr.ObjectType = QOS_OBJECT_WAN_MEDIA;
  205. WanMedia->ObjectHdr.ObjectLength = sizeof(QOS_WAN_MEDIA);
  206. NdisMoveMemory(&WanMedia->LinkId,
  207. WanLink->OriginalRemoteMacAddress,
  208. 6);
  209. }
  210. CallParams->Flags = 0;
  211. CallParams->CallMgrParameters = CallMgrParams;
  212. CallParams->MediaParameters = (PCO_MEDIA_PARAMETERS)PsMediaParameters;
  213. Status = CmMakeCall(Vc);
  214. if(NDIS_STATUS_PENDING != Status)
  215. {
  216. CmMakeCallComplete(Status, Vc, Vc->CallParameters);
  217. }
  218. PsDbgOut(DBG_TRACE,
  219. DBG_GPC_QOS,
  220. ("[QosAddCfInfoNotify]: Adapter %08X, Created Vc %08X - returned "
  221. " PENDING \n", Adapter, Vc));
  222. #if DBG
  223. NdisInterlockedIncrement(&Adapter->GpcNotifyPending);
  224. #endif
  225. return GPC_STATUS_PENDING;
  226. }
  227. VOID
  228. SetTOSIEEEValues(PGPC_CLIENT_VC Vc)
  229. {
  230. ULONG ServiceType = Vc->CallParameters->CallMgrParameters->Transmit.ServiceType;
  231. LPQOS_OBJECT_HDR QoSObject;
  232. LONG ParamsLength;
  233. LPQOS_TRAFFIC_CLASS Tc;
  234. LPQOS_DS_CLASS Ds;
  235. PCF_INFO_QOS CfInfo = (PCF_INFO_QOS) Vc->CfInfoQoS;
  236. //
  237. // Set these based on the ServiceType
  238. //
  239. switch(ServiceType)
  240. {
  241. case SERVICETYPE_CONTROLLEDLOAD:
  242. Vc->UserPriorityConforming = Vc->Adapter->UserServiceTypeControlledLoad;
  243. CfInfo->ToSValue = Vc->Adapter->IPServiceTypeControlledLoad;
  244. Vc->IPPrecedenceNonConforming = Vc->Adapter->IPServiceTypeControlledLoadNC;
  245. break;
  246. case SERVICETYPE_GUARANTEED:
  247. Vc->UserPriorityConforming = Vc->Adapter->UserServiceTypeGuaranteed;
  248. Vc->IPPrecedenceNonConforming = Vc->Adapter->IPServiceTypeGuaranteedNC;
  249. CfInfo->ToSValue = Vc->Adapter->IPServiceTypeGuaranteed;
  250. break;
  251. case SERVICETYPE_BESTEFFORT:
  252. Vc->UserPriorityConforming = Vc->Adapter->UserServiceTypeBestEffort;
  253. CfInfo->ToSValue = Vc->Adapter->IPServiceTypeBestEffort;
  254. Vc->IPPrecedenceNonConforming = Vc->Adapter->IPServiceTypeBestEffortNC;
  255. break;
  256. case SERVICETYPE_QUALITATIVE:
  257. Vc->UserPriorityConforming = Vc->Adapter->UserServiceTypeQualitative;
  258. CfInfo->ToSValue = Vc->Adapter->IPServiceTypeQualitative;
  259. Vc->IPPrecedenceNonConforming = Vc->Adapter->IPServiceTypeQualitativeNC;
  260. break;
  261. case SERVICETYPE_NETWORK_CONTROL:
  262. Vc->UserPriorityConforming = Vc->Adapter->UserServiceTypeNetworkControl;
  263. CfInfo->ToSValue = Vc->Adapter->IPServiceTypeNetworkControl;
  264. Vc->IPPrecedenceNonConforming = Vc->Adapter->IPServiceTypeNetworkControlNC;
  265. break;
  266. }
  267. Vc->UserPriorityNonConforming = Vc->Adapter->UserServiceTypeNonConforming;
  268. //
  269. // Walk the QoS objects to see if there is a TCLASS or a DCLASS
  270. //
  271. ParamsLength = (LONG)Vc->CallParameters->CallMgrParameters->CallMgrSpecific.Length;
  272. QoSObject = (LPQOS_OBJECT_HDR)Vc->CallParameters->CallMgrParameters->CallMgrSpecific.Parameters;
  273. while(ParamsLength > 0) {
  274. switch(QoSObject->ObjectType)
  275. {
  276. case QOS_OBJECT_TCP_TRAFFIC:
  277. //
  278. // This QoS object asks us to override the ServiceType, the TCLASS and the DCLASS markings.
  279. // so, if we fidn this QoS object, we set the values, and return.
  280. //
  281. Vc->UserPriorityConforming = (UCHAR) Vc->Adapter->UserServiceTypeTcpTraffic;
  282. CfInfo->ToSValue = (UCHAR) Vc->Adapter->IPServiceTypeTcpTraffic;
  283. Vc->IPPrecedenceNonConforming = (UCHAR) Vc->Adapter->IPServiceTypeTcpTrafficNC;
  284. return;
  285. case QOS_OBJECT_TRAFFIC_CLASS:
  286. Tc = (LPQOS_TRAFFIC_CLASS)QoSObject;
  287. Vc->UserPriorityConforming = (UCHAR) Tc->TrafficClass;
  288. break;
  289. case QOS_OBJECT_DS_CLASS:
  290. Ds = (LPQOS_DS_CLASS)QoSObject;
  291. CfInfo->ToSValue = Ds->DSField << 2;
  292. break;
  293. }
  294. ParamsLength -= QoSObject->ObjectLength;
  295. QoSObject = (LPQOS_OBJECT_HDR)((UINT_PTR)QoSObject +
  296. QoSObject->ObjectLength);
  297. }
  298. return;
  299. }
  300. VOID
  301. CmMakeCallComplete(NDIS_STATUS Status, PGPC_CLIENT_VC Vc,
  302. PCO_CALL_PARAMETERS CallParameters)
  303. {
  304. PADAPTER Adapter = Vc->Adapter;
  305. GPC_HANDLE CfInfo = Vc->CfInfoHandle;
  306. PPS_WAN_LINK WanLink = Vc->WanLink;
  307. ULONG CurrentFlows;
  308. LARGE_INTEGER Increment;
  309. LARGE_INTEGER VcIndex;
  310. PsAssert(!IsBestEffortVc(Vc));
  311. Increment.QuadPart = 1;
  312. if(NT_SUCCESS(Status))
  313. {
  314. //
  315. // Create an Instance name for this VC and register with WMI.
  316. //
  317. VcIndex = ExInterlockedAddLargeInteger(&Adapter->VcIndex, Increment, &Adapter->Lock.Lock.SpinLock);
  318. Status = GenerateInstanceName(&VcPrefix, Vc->Adapter, &VcIndex, &Vc->InstanceName);
  319. //
  320. // Transistion from CL_CALL_PENDING to CL_INTERNAL_CALL_COMPLETE
  321. //
  322. CallSucceededStateTransition(Vc);
  323. PS_LOCK(&Vc->Lock);
  324. SetTOSIEEEValues(Vc);
  325. PS_UNLOCK(&Vc->Lock);
  326. if(Adapter->MediaType == NdisMediumWan) {
  327. //
  328. // This variable is used to optimize the send path
  329. //
  330. InterlockedIncrement(&WanLink->CfInfosInstalled);
  331. if((Vc->Flags & GPC_ISSLOW_FLOW)) {
  332. //
  333. // Tell NDISWAN about the fragment size
  334. //
  335. MakeLocalNdisRequest(Adapter,
  336. Vc->NdisWanVcHandle,
  337. NdisRequestLocalSetInfo,
  338. OID_QOS_ISSLOW_FRAGMENT_SIZE,
  339. &Vc->ISSLOWFragmentSize,
  340. sizeof(ULONG),
  341. NULL);
  342. }
  343. //
  344. // This is used for OID_QOS_FLOW_COUNT - Better be thread safe
  345. //
  346. PS_LOCK(&WanLink->Lock);
  347. WanLink->FlowsInstalled ++;
  348. CurrentFlows = WanLink->FlowsInstalled;
  349. PS_UNLOCK(&WanLink->Lock);
  350. PsTcNotify(Adapter, WanLink, OID_QOS_FLOW_COUNT, &CurrentFlows, sizeof(ULONG));
  351. }
  352. else {
  353. //
  354. // This variable is used to optimize the send path
  355. //
  356. InterlockedIncrement(&Adapter->CfInfosInstalled);
  357. PS_LOCK(&Adapter->Lock);
  358. Adapter->FlowsInstalled ++;
  359. CurrentFlows = Adapter->FlowsInstalled;
  360. PS_UNLOCK(&Adapter->Lock);
  361. PsTcNotify(Adapter, 0, OID_QOS_FLOW_COUNT, &CurrentFlows, sizeof(ULONG));
  362. }
  363. //
  364. // Update Stats
  365. //
  366. InterlockedIncrement(&Vc->AdapterStats->FlowsOpened);
  367. Vc->AdapterStats->MaxSimultaneousFlows =
  368. max(Vc->AdapterStats->MaxSimultaneousFlows, CurrentFlows);
  369. //
  370. // Notify the GPC
  371. //
  372. PsDbgOut(DBG_TRACE,
  373. DBG_GPC_QOS,
  374. ("[CmMakeCallComplete]: Adapter %08X, Vc %08X succeeded - "
  375. " Notify GPC \n", Adapter, Vc));
  376. GpcEntries.GpcAddCfInfoNotifyCompleteHandler(GpcQosClientHandle,
  377. CfInfo,
  378. Status,
  379. Vc);
  380. //
  381. // Transistion from CL_INTERNAL_CALL_COMPLETE to CL_CALL_COMPLETE
  382. //
  383. CallSucceededStateTransition(Vc);
  384. }
  385. else {
  386. PsDbgOut(DBG_FAILURE,
  387. DBG_GPC_QOS,
  388. ("[CmMakeCallComplete]: Adapter %08X, Vc %08X, Make Call failed. Status = %x\n",
  389. Adapter, Vc, Status));
  390. InterlockedIncrement(&Vc->AdapterStats->FlowsRejected);
  391. GpcEntries.GpcAddCfInfoNotifyCompleteHandler(GpcQosClientHandle,
  392. CfInfo,
  393. Status,
  394. Vc);
  395. DerefClVc(Vc);
  396. }
  397. #if DBG
  398. NdisInterlockedDecrement(&Adapter->GpcNotifyPending);
  399. #endif
  400. } // CmMakeCallComplete
  401. GPC_STATUS
  402. QosClGetCfInfoName(
  403. IN GPC_CLIENT_HANDLE ClientContext,
  404. IN GPC_CLIENT_HANDLE ClientCfInfoContext,
  405. OUT PNDIS_STRING InstanceName
  406. )
  407. /*++
  408. Routine Description:
  409. The GPC can issue this call to get from us the WMI manageable
  410. InstanceName which Ndis created for the flow associated with
  411. the CfInfo struct.
  412. We guarantee to keep the string buffer around until the CfInfo
  413. structure is removed.
  414. Arguments:
  415. ClientContext - Client context supplied to GpcRegisterClient
  416. GpcCfInfoHandle - GPC's handle to CF_INFO
  417. InstanceName - We return a pointer to our string.
  418. Return Value:
  419. Status
  420. --*/
  421. {
  422. PGPC_CLIENT_VC GpcClientVc = (PGPC_CLIENT_VC)ClientCfInfoContext;
  423. if(GpcClientVc->InstanceName.Buffer){
  424. InstanceName->Buffer = GpcClientVc->InstanceName.Buffer;
  425. InstanceName->Length = GpcClientVc->InstanceName.Length;
  426. InstanceName->MaximumLength =
  427. GpcClientVc->InstanceName.MaximumLength;
  428. return(NDIS_STATUS_SUCCESS);
  429. }
  430. else{
  431. return(NDIS_STATUS_FAILURE);
  432. }
  433. }
  434. VOID
  435. QosAddCfInfoComplete(
  436. IN GPC_CLIENT_HANDLE ClientContext,
  437. IN GPC_CLIENT_HANDLE ClientCfInfoContext,
  438. IN GPC_STATUS Status
  439. )
  440. /*++
  441. Routine Description:
  442. The GPC has completed processing an AddCfInfo request.
  443. Arguments:
  444. ClientContext - Client context supplied to GpcRegisterClient
  445. ClientCfInfoContext - CfInfo context
  446. Status - Final status
  447. Return Value:
  448. --*/
  449. {
  450. //
  451. // The PS never adds CF_INFO's so this routine should never be called
  452. //
  453. DEBUGCHK;
  454. } // QosAddCfInfoComplete
  455. GPC_STATUS
  456. QosModifyCfInfoNotify(
  457. IN GPC_CLIENT_HANDLE ClientContext,
  458. IN GPC_CLIENT_HANDLE ClientCfInfoContext,
  459. IN ULONG CfInfoSize,
  460. IN PVOID NewCfInfoPtr
  461. )
  462. /*++
  463. Routine Description:
  464. A CF_INFO is being modified.
  465. Arguments:
  466. ClientContext - Client context supplied to GpcRegisterClient
  467. ClientCfInfoContext - CfInfo context
  468. NewCfInfoPtr - Pointer to proposed CF_INFO content
  469. Return Value:
  470. Status
  471. --*/
  472. {
  473. PGPC_CLIENT_VC GpcClientVc = (PGPC_CLIENT_VC)ClientCfInfoContext;
  474. PCF_INFO_QOS NewCfInfo = (PCF_INFO_QOS)NewCfInfoPtr;
  475. NDIS_STATUS Status;
  476. ULONG CallParamsLength;
  477. PCO_CALL_PARAMETERS CallParams;
  478. PCO_CALL_MANAGER_PARAMETERS CallMgrParams;
  479. PCO_MEDIA_PARAMETERS PsMediaParameters;
  480. LPQOS_PRIORITY PriorityObject;
  481. PADAPTER Adapter;
  482. ULONG TcObjAlignedLength;
  483. //
  484. // Do sanity checks
  485. //
  486. //
  487. // Verify that the TcObjectsLength is consistent with the
  488. // CfInfoSize. The CfInfoSize must have been verified during
  489. // the user/kernel transition. The TcObjectsLength has not.
  490. // We could bugcheck if we try to search beyond the buffer
  491. // passed in.
  492. //
  493. if(CfInfoSize < (FIELD_OFFSET(CF_INFO_QOS, GenFlow) +
  494. FIELD_OFFSET(TC_GEN_FLOW, TcObjects) +
  495. NewCfInfo->GenFlow.TcObjectsLength)){
  496. PsDbgOut(DBG_FAILURE, DBG_GPC_QOS,
  497. ("[QosModifyCfInfoNotify]: TcObjectsLength inconsistent with "
  498. "CfInfoSize \n"));
  499. return(ERROR_TC_OBJECT_LENGTH_INVALID);
  500. }
  501. Adapter = GpcClientVc->Adapter;
  502. PS_LOCK(&Adapter->Lock);
  503. if(Adapter->PsMpState != AdapterStateRunning) {
  504. PS_UNLOCK(&Adapter->Lock);
  505. PsDbgOut(DBG_FAILURE, DBG_GPC_QOS,
  506. ("[QosModifyCfInfoNotify]: Adapter %08X closing, cannot accept "
  507. "modify request \n", Adapter));
  508. return GPC_STATUS_NOTREADY;
  509. }
  510. PS_UNLOCK(&Adapter->Lock);
  511. //
  512. // Allocate the resources for the call manager parameters
  513. //
  514. TcObjAlignedLength = ((NewCfInfo->GenFlow.TcObjectsLength + (sizeof(PVOID)-1)) & ~(sizeof(PVOID)-1));
  515. CallParamsLength =
  516. sizeof(CO_CALL_PARAMETERS) +
  517. FIELD_OFFSET(CO_CALL_MANAGER_PARAMETERS, CallMgrSpecific) +
  518. FIELD_OFFSET(CO_SPECIFIC_PARAMETERS, Parameters) +
  519. TcObjAlignedLength +
  520. FIELD_OFFSET(CO_MEDIA_PARAMETERS, MediaSpecific) +
  521. FIELD_OFFSET(CO_SPECIFIC_PARAMETERS, Parameters);
  522. if(Adapter->MediaType == NdisMediumWan) {
  523. CallParamsLength += sizeof(QOS_WAN_MEDIA);
  524. }
  525. PsAllocatePool( CallParams, CallParamsLength, CmParamsTag );
  526. if ( CallParams == NULL ) {
  527. PsDbgOut(DBG_FAILURE, DBG_GPC_QOS,
  528. ("[QosModifyCfInfoNotify]: Adapter %08X, can't allocate call params\n"));
  529. return NDIS_STATUS_RESOURCES;
  530. }
  531. //
  532. // Create a call parameters struct for the ModifyCallQoS
  533. //
  534. CallMgrParams = (PCO_CALL_MANAGER_PARAMETERS)(CallParams + 1);
  535. CallMgrParams->Transmit = NewCfInfo->GenFlow.SendingFlowspec;
  536. CallMgrParams->Receive = NewCfInfo->GenFlow.ReceivingFlowspec;
  537. CallMgrParams->CallMgrSpecific.ParamType = PARAM_TYPE_GQOS_INFO;
  538. CallMgrParams->CallMgrSpecific.Length = NewCfInfo->GenFlow.TcObjectsLength;
  539. if (NewCfInfo->GenFlow.TcObjectsLength > 0) {
  540. NdisMoveMemory(
  541. CallMgrParams->CallMgrSpecific.Parameters,
  542. NewCfInfo->GenFlow.TcObjects,
  543. NewCfInfo->GenFlow.TcObjectsLength);
  544. }
  545. // Ndis requires at least 8 bytes of media specific! Use dummy.
  546. PsMediaParameters =
  547. (PCO_MEDIA_PARAMETERS)((PUCHAR)CallMgrParams +
  548. FIELD_OFFSET(CO_CALL_MANAGER_PARAMETERS, CallMgrSpecific) +
  549. FIELD_OFFSET(CO_SPECIFIC_PARAMETERS, Parameters) +
  550. TcObjAlignedLength);
  551. PsMediaParameters->Flags = 0;
  552. PsMediaParameters->ReceivePriority = 0;
  553. PsMediaParameters->ReceiveSizeHint = NewCfInfo->GenFlow.SendingFlowspec.MaxSduSize;
  554. PsMediaParameters->MediaSpecific.ParamType = PARAM_TYPE_GQOS_INFO;
  555. PsMediaParameters->MediaSpecific.Length = 0;
  556. if(Adapter->MediaType == NdisMediumWan) {
  557. LPQOS_WAN_MEDIA WanMedia;
  558. PsMediaParameters->MediaSpecific.Length += sizeof(QOS_WAN_MEDIA);
  559. WanMedia = (LPQOS_WAN_MEDIA) PsMediaParameters->MediaSpecific.Parameters;
  560. WanMedia->ObjectHdr.ObjectType = QOS_OBJECT_WAN_MEDIA;
  561. WanMedia->ObjectHdr.ObjectLength = sizeof(QOS_WAN_MEDIA);
  562. NdisMoveMemory(&WanMedia->LinkId,
  563. GpcClientVc->WanLink->OriginalRemoteMacAddress,
  564. 6);
  565. }
  566. CallParams->Flags = 0;
  567. CallParams->CallMgrParameters = CallMgrParams;
  568. CallParams->MediaParameters = (PCO_MEDIA_PARAMETERS)PsMediaParameters;
  569. GpcClientVc->ModifyCallParameters = CallParams;
  570. GpcClientVc->ModifyCfInfoQoS = NewCfInfo;
  571. PS_LOCK(&GpcClientVc->Lock);
  572. switch(GpcClientVc->ClVcState) {
  573. case CL_INTERNAL_CALL_COMPLETE:
  574. // CL_INTERNAL_CALL_COMPLETE:
  575. // If we are in this state, then probably we have
  576. // told the GPC about the Add, & the GPC has turned right
  577. // back and asked us to modify before we have got a chance
  578. // to transistion to CL_CALL_COMPLETE.
  579. //
  580. // Remember that we have got a modify, we will complete the modify
  581. // when we transistion to the CL_CALL_COMPLETE state.
  582. //
  583. GpcClientVc->Flags |= GPC_MODIFY_REQUESTED;
  584. PS_UNLOCK(&GpcClientVc->Lock);
  585. #if DBG
  586. NdisInterlockedIncrement(&Adapter->GpcNotifyPending);
  587. #endif
  588. return NDIS_STATUS_PENDING;
  589. case CL_CALL_COMPLETE:
  590. GpcClientVc->ClVcState = CL_MODIFY_PENDING;
  591. PS_UNLOCK(&GpcClientVc->Lock);
  592. break;
  593. default:
  594. //
  595. // In general, we expect the call to be in the
  596. // CL_CALL_COMPLETE state when a modify request comes
  597. // in. It could be in the following states as well:
  598. //
  599. // CALL_PENDING:
  600. // If we are in this state, then we have not
  601. // completed the AddCfInfo request from the GPC. This
  602. // should not happen.
  603. //
  604. //
  605. // GPC_CLOSE_PENDING:
  606. // If an InternalCloseCall is requested, we
  607. // change to this state before asking the GPC to
  608. // close. The GPC could slip in this window and
  609. // ask us to modify the call.
  610. //
  611. // MODIFY_PENDING:
  612. // We have not told the GPC about the previous modify
  613. // request. Therefore, the GPC cannot ask us to modify a
  614. // call if we are in this state.
  615. //
  616. PsAssert(GpcClientVc->ClVcState != CL_CALL_PENDING);
  617. PsAssert(GpcClientVc->ClVcState != CL_MODIFY_PENDING);
  618. PsAssert(GpcClientVc->ClVcState != CL_GPC_CLOSE_PENDING);
  619. PS_UNLOCK(&GpcClientVc->Lock);
  620. PsFreePool(CallParams);
  621. GpcClientVc->ModifyCallParameters = 0;
  622. GpcClientVc->ModifyCfInfoQoS = 0;
  623. PsDbgOut(DBG_FAILURE, DBG_GPC_QOS,
  624. ("[QosModifyCfInfoNotify]: Adapter %08X, Vc %08X, State %08X, Flags %08X -"
  625. " Not ready to modify flow !\n",
  626. Adapter, GpcClientVc, GpcClientVc->ClVcState, GpcClientVc->Flags));
  627. return(GPC_STATUS_NOTREADY);
  628. }
  629. //
  630. // Now issue the ModifyCallQoS to the PS call manager
  631. //
  632. Status = CmModifyCall(GpcClientVc);
  633. if(Status != NDIS_STATUS_PENDING) {
  634. CmModifyCallComplete(Status, GpcClientVc, CallParams);
  635. }
  636. PsDbgOut(DBG_TRACE, DBG_GPC_QOS,
  637. ("[QosModifyCfInfoNotify]: Adapter %08X, Vc %08X, State %08X, Flags %08X -"
  638. " modify flow returns pending \n",
  639. Adapter, GpcClientVc, GpcClientVc->ClVcState, GpcClientVc->Flags));
  640. #if DBG
  641. NdisInterlockedIncrement(&Adapter->GpcNotifyPending);
  642. #endif
  643. return NDIS_STATUS_PENDING;
  644. } // QosModifyCfInfoNotify
  645. VOID
  646. CmModifyCallComplete(
  647. IN NDIS_STATUS Status,
  648. IN PGPC_CLIENT_VC GpcClientVc,
  649. IN PCO_CALL_PARAMETERS CallParameters
  650. )
  651. /*++
  652. Routine Description:
  653. The call manager has finished processing a ModifyCallQoS request.
  654. Arguments:
  655. See the DDK
  656. Return Value:
  657. --*/
  658. {
  659. PADAPTER Adapter = GpcClientVc->Adapter;
  660. //
  661. // We call this to change back to the CALL_COMPLETE state.
  662. // We make the same call whether the modify actually completed
  663. // or not, since the call remains up.
  664. //
  665. // The internal best effort VC is not known by
  666. // the GPC and therefore, is never modified by it.
  667. //
  668. PsAssert(!IsBestEffortVc(GpcClientVc));
  669. if(Status != NDIS_STATUS_SUCCESS){
  670. PsDbgOut(DBG_FAILURE,
  671. DBG_GPC_QOS,
  672. ("[CmModifyCallQoSComplete]: Adapter %08X, Vc %08x, modify QoS failed. Status = %x\n",
  673. Adapter, GpcClientVc, Status));
  674. PsFreePool(GpcClientVc->ModifyCallParameters);
  675. InterlockedIncrement(&GpcClientVc->AdapterStats->FlowModsRejected);
  676. //
  677. // Transistion from CL_MODIFY_PENDING to CL_INTERNAL_CALL_COMPLETE
  678. //
  679. CallSucceededStateTransition(GpcClientVc);
  680. }
  681. else
  682. {
  683. PsDbgOut(DBG_TRACE,
  684. DBG_GPC_QOS,
  685. ("[CmModifyCallQoSComplete]: Adapter %08X, Vc %08X, modify QoS succeeded. \n",
  686. Adapter, GpcClientVc));
  687. //
  688. // Tell NDISWAN about the fragment size
  689. //
  690. if((Adapter->MediaType == NdisMediumWan) && (GpcClientVc->Flags & GPC_ISSLOW_FLOW))
  691. {
  692. MakeLocalNdisRequest(Adapter,
  693. GpcClientVc->NdisWanVcHandle,
  694. NdisRequestLocalSetInfo,
  695. OID_QOS_ISSLOW_FRAGMENT_SIZE,
  696. &GpcClientVc->ISSLOWFragmentSize,
  697. sizeof(ULONG),
  698. NULL);
  699. }
  700. //
  701. // Update Stats
  702. //
  703. InterlockedIncrement(&GpcClientVc->AdapterStats->FlowsModified);
  704. PsFreePool(GpcClientVc->CallParameters);
  705. GpcClientVc->CallParameters = CallParameters;
  706. GpcClientVc->ModifyCallParameters = NULL;
  707. GpcClientVc->CfInfoQoS = GpcClientVc->ModifyCfInfoQoS;
  708. GpcClientVc->ModifyCfInfoQoS = 0;
  709. //
  710. // Transistion from CL_MODIFY_PENDING to CL_INTERNAL_CALL_COMPLETE
  711. //
  712. CallSucceededStateTransition(GpcClientVc);
  713. //
  714. // Mark the TOS Byte for this service type
  715. //
  716. PS_LOCK(&GpcClientVc->Lock);
  717. SetTOSIEEEValues(GpcClientVc);
  718. PS_UNLOCK(&GpcClientVc->Lock);
  719. }
  720. PsAssert(GpcEntries.GpcModifyCfInfoNotifyCompleteHandler);
  721. GpcEntries.GpcModifyCfInfoNotifyCompleteHandler(GpcQosClientHandle,
  722. GpcClientVc->CfInfoHandle,
  723. Status);
  724. //
  725. // Transistion from CL_INTERNAL_CALL_COMPLETE to CL_CALL_COMPLETE
  726. //
  727. CallSucceededStateTransition(GpcClientVc);
  728. #if DBG
  729. NdisInterlockedDecrement(&Adapter->GpcNotifyPending);
  730. #endif
  731. } // ClModifyCallQoSComplete
  732. VOID
  733. QosModifyCfInfoComplete(
  734. IN GPC_CLIENT_HANDLE ClientContext,
  735. IN GPC_CLIENT_HANDLE ClientCfInfoContext,
  736. IN GPC_STATUS Status
  737. )
  738. /*++
  739. Routine Description:
  740. The GPC has completed processing an AddCfInfo request.
  741. Arguments:
  742. ClientContext - Client context supplied to GpcRegisterClient
  743. ClientCfInfoContext - CfInfo context
  744. Status - Final status
  745. Return Value:
  746. --*/
  747. {
  748. } // QosModifyCfInfoComplete
  749. GPC_STATUS
  750. QosRemoveCfInfoNotify(
  751. IN GPC_CLIENT_HANDLE ClientContext,
  752. IN GPC_CLIENT_HANDLE ClientCfInfoContext
  753. )
  754. /*++
  755. Routine Description:
  756. A CF_INFO is being removed.
  757. Arguments:
  758. ClientContext - Client context supplied to GpcRegisterClient
  759. ClientCfInfoContext - CfInfo context
  760. Return Value:
  761. Status
  762. --*/
  763. {
  764. PGPC_CLIENT_VC Vc = (PGPC_CLIENT_VC)ClientCfInfoContext;
  765. NDIS_STATUS Status;
  766. ULONG CurrentFlows;
  767. PADAPTER Adapter = Vc->Adapter;
  768. PsAssert(!IsBestEffortVc(Vc));
  769. PsDbgOut(DBG_TRACE, DBG_GPC_QOS,
  770. ("[QosRemoveCfInfoNotify]: Adapter %08X, Vc %08X, State %08X,"
  771. "Flags %08X \n", Adapter, Vc, Vc->ClVcState, Vc->Flags));
  772. //
  773. // Check the state of the VC.
  774. //
  775. PS_LOCK(&Vc->Lock);
  776. switch(Vc->ClVcState){
  777. case CL_CALL_PENDING:
  778. case CL_MODIFY_PENDING:
  779. // CL_NDIS_CLOSE_PENDING:
  780. //
  781. // The GPC has to close before Ndis closes. So - if we're here, the GPC has already
  782. // closed, in which case - it should not be trying to close again.
  783. //
  784. // CL_CALL_PENDING, CL_MODIFY_PENDING:
  785. //
  786. // The GPC is asking us to close a VC which we never told it about. Note that even
  787. // though we can change from CL_INTERNAL_CALL_COMPLETE to CL_MODIFY_PENDING,
  788. // the GPC can *never* ask us to close in CL_MODIFY_PENDING because
  789. // even if the above case happens, we have not completed the modify with the GPC.
  790. //
  791. PS_UNLOCK(&Vc->Lock);
  792. PsDbgOut(DBG_FAILURE,
  793. DBG_STATE,
  794. ("[QosRemoveCfInfoNotify]: bad state %s on VC %x\n",
  795. GpcVcState[Vc->ClVcState], Vc));
  796. PsAssert(0);
  797. return(GPC_STATUS_FAILURE);
  798. case CL_INTERNAL_CALL_COMPLETE:
  799. //
  800. // We tell the GPC in the CL_INTERNAL_CALL_COMPLETE state and then transistion
  801. // to the CL_CALL_COMPLETE state. However, there is a small window when the GPC
  802. // can ask us to delete this VC in the CL_INTERNAL_CALL_COMPLETE state
  803. // We wait till we move to CL_CALL_COMPLETE before deleting the Vc.
  804. //
  805. Vc->Flags |= GPC_CLOSE_REQUESTED;
  806. PS_UNLOCK(&Vc->Lock);
  807. #if DBG
  808. NdisInterlockedIncrement(&Adapter->GpcNotifyPending);
  809. #endif
  810. return (GPC_STATUS_PENDING);
  811. case CL_CALL_COMPLETE:
  812. //
  813. // Normal GPC close request.
  814. //
  815. Vc->ClVcState = CL_GPC_CLOSE_PENDING;
  816. Vc->Flags |= GPC_CLOSE_REQUESTED;
  817. PS_UNLOCK(&Vc->Lock);
  818. Status = CmCloseCall(Vc);
  819. PsAssert(Status == NDIS_STATUS_PENDING);
  820. #if DBG
  821. NdisInterlockedIncrement(&Adapter->GpcNotifyPending);
  822. #endif
  823. return(GPC_STATUS_PENDING);
  824. case CL_INTERNAL_CLOSE_PENDING:
  825. //
  826. // We're here cause we were about to initiate a close and we're waiting
  827. // for it to complete. It looks like the GPC asked us to close, before
  828. // we actually asked it to close. First - check that the GPC has not
  829. // asked us to close prior to this request.
  830. //
  831. PsAssert(!(Vc->Flags & GPC_CLOSE_REQUESTED));
  832. //
  833. // If the GPC is asking us to close, the GPC MUST fail the call when we
  834. // ask it to close. So, we'll simply wait here till that happens. Note that
  835. // we cannot pend this call and complete it later from the Internal Close handler.
  836. //
  837. // If we Deref the VC from the Internal Close Complete handler, there could be a race
  838. // condition and we could be looking at a stale VC pointer. So, the VC MUST be Deref'd
  839. // from here. We do not have to call CmCloseCall because we called it from the InternalClose
  840. // handler.
  841. //
  842. Vc->Flags |= GPC_CLOSE_REQUESTED;
  843. PS_UNLOCK(&Vc->Lock);
  844. NdisWaitEvent(&Vc->GpcEvent, 0);
  845. DerefClVc(Vc);
  846. return GPC_STATUS_SUCCESS;
  847. default:
  848. PS_UNLOCK(&Vc->Lock);
  849. PsDbgOut(DBG_FAILURE,
  850. DBG_STATE,
  851. ("[QosRemoveCfInfoNotify]: invalid state %s on VC %x\n",
  852. GpcVcState[Vc->ClVcState], Vc));
  853. PsAssert(0);
  854. return GPC_STATUS_FAILURE;
  855. }
  856. } // QosRemoveCfInfoNotify
  857. VOID
  858. CmCloseCallComplete(
  859. IN NDIS_STATUS Status,
  860. IN PGPC_CLIENT_VC Vc
  861. )
  862. /*++
  863. Routine Description:
  864. The call manager has finished processing a CloseCall request.
  865. Arguments:
  866. See the DDK
  867. Return Value:
  868. --*/
  869. {
  870. PADAPTER Adapter = Vc->Adapter;
  871. NDIS_STATUS LocalStatus;
  872. ULONG CurrentFlows;
  873. PsAssert(!IsBestEffortVc(Vc));
  874. if(Adapter->MediaType == NdisMediumWan) {
  875. //
  876. // To optimize send path
  877. //
  878. InterlockedDecrement(&Vc->WanLink->CfInfosInstalled);
  879. PS_LOCK(&Vc->WanLink->Lock);
  880. Vc->WanLink->FlowsInstalled --;
  881. CurrentFlows = Vc->WanLink->FlowsInstalled;
  882. PS_UNLOCK(&Vc->WanLink->Lock);
  883. PsTcNotify(Adapter, Vc->WanLink, OID_QOS_FLOW_COUNT, &CurrentFlows, sizeof(ULONG));
  884. }
  885. else
  886. {
  887. //
  888. // To optimize send path
  889. //
  890. InterlockedDecrement(&Adapter->CfInfosInstalled);
  891. PS_LOCK(&Adapter->Lock);
  892. Adapter->FlowsInstalled --;
  893. CurrentFlows = Adapter->FlowsInstalled;
  894. PS_UNLOCK(&Adapter->Lock);
  895. PsTcNotify(Adapter, 0, OID_QOS_FLOW_COUNT, &CurrentFlows, sizeof(ULONG));
  896. }
  897. //
  898. // Update stats
  899. //
  900. InterlockedIncrement(&Vc->AdapterStats->FlowsClosed);
  901. Vc->AdapterStats->MaxSimultaneousFlows =
  902. max(Vc->AdapterStats->MaxSimultaneousFlows, CurrentFlows);
  903. PS_LOCK(&Vc->Lock);
  904. if(Vc->Flags & INTERNAL_CLOSE_REQUESTED)
  905. {
  906. // We have asked to close this call. Let's process the close now.
  907. // Note that we don't really care if the GPC has asked us to close.
  908. //
  909. // Because -
  910. // 1. If we had initiated an internal close after the GPC asks us to close, we ignore the internal close,
  911. // and the above flag will not be set.
  912. // 2. If the GPC had asked us to close, we have pended it - We will now complete it when the GPC fails our
  913. // call to close the Vc.
  914. //
  915. PS_UNLOCK(&Vc->Lock);
  916. PsDbgOut(DBG_TRACE, DBG_GPC_QOS,
  917. ("[CmCloseCallComplete]: Adapter %08X, Vc %08X (State %08X, Flags %08X), "
  918. "Internal Close requested \n",
  919. Adapter, Vc, Vc->ClVcState, Vc->Flags));
  920. Status = GpcEntries.GpcRemoveCfInfoHandler(GpcQosClientHandle, Vc->CfInfoHandle);
  921. if(Status != NDIS_STATUS_PENDING) {
  922. QosRemoveCfInfoComplete(NULL, Vc, Status);
  923. }
  924. return;
  925. }
  926. PS_UNLOCK(&Vc->Lock);
  927. //
  928. // Complete the request with the GPC.
  929. //
  930. GpcEntries.GpcRemoveCfInfoNotifyCompleteHandler(GpcQosClientHandle,
  931. Vc->CfInfoHandle,
  932. GPC_STATUS_SUCCESS);
  933. #if DBG
  934. NdisInterlockedDecrement(&Adapter->GpcNotifyPending);
  935. #endif
  936. DerefClVc(Vc);
  937. return;
  938. }
  939. VOID
  940. DerefClVc(
  941. PGPC_CLIENT_VC Vc
  942. )
  943. {
  944. ULONG RefCount;
  945. RefCount = InterlockedDecrement(&Vc->RefCount);
  946. if(!RefCount)
  947. {
  948. PsDbgOut(DBG_INFO,
  949. DBG_STATE,
  950. ("DerefClVc: deref'd to 0. State is %s on VC %x\n",
  951. GpcVcState[Vc->ClVcState], Vc));
  952. if(Vc->NdisWanVcHandle)
  953. {
  954. WanCloseCall(Vc);
  955. }
  956. else
  957. {
  958. CmDeleteVc(Vc);
  959. }
  960. }
  961. } // DerefClVc
  962. VOID
  963. QosRemoveCfInfoComplete(
  964. IN GPC_CLIENT_HANDLE ClientContext,
  965. IN GPC_CLIENT_HANDLE ClientCfInfoContext,
  966. IN GPC_STATUS Status
  967. )
  968. /*++
  969. Routine Description:
  970. The GPC has completed processing an AddCfInfo request.
  971. Arguments:
  972. ClientContext - Client context supplied to GpcRegisterClient
  973. ClientCfInfoContext - CfInfo context
  974. Status - Final status
  975. Return Value:
  976. --*/
  977. {
  978. PGPC_CLIENT_VC Vc = (PGPC_CLIENT_VC)ClientCfInfoContext;
  979. PsDbgOut(DBG_TRACE, DBG_GPC_QOS,
  980. ("[QosRemoveCfInfoComplete]: Adapter %08X, Vc %08X "
  981. "(State = %08X, Flags = %08X), Status %08X \n", Vc->Adapter, Vc,
  982. Vc->ClVcState, Vc->Flags, Status));
  983. if(Status != NDIS_STATUS_SUCCESS)
  984. {
  985. //
  986. // The GPC has requested a close, which has been pended. Complete that request.
  987. //
  988. PsDbgOut(DBG_TRACE,
  989. DBG_GPC_QOS,
  990. ("[QosRemoveCfInfoComplete]: Vc %08X, completing with GPC \n", Vc));
  991. NdisSetEvent(&Vc->GpcEvent);
  992. }
  993. else {
  994. DerefClVc(Vc);
  995. }
  996. } // QosRemoveCfInfoComplete