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.

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