|
1 // Copyright (c) 1999-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // Manages the negotiation of L2Cap configuration parameters. |
|
15 // |
|
16 // |
|
17 |
|
18 #include <bluetooth/logger.h> |
|
19 #include <es_prot.h> |
|
20 #include "l2util.h" |
|
21 #include "L2CapChannelConfig.h" |
|
22 #include "l2capEntityConfig.h" |
|
23 #include "l2capSigPacketConfigure.h" |
|
24 |
|
25 #ifndef __UNITTest__ |
|
26 #include "l2constants.h" |
|
27 #include "l2capSAPSignalHandler.h" |
|
28 #else |
|
29 #include "cl2capconfigproxy.h" |
|
30 #ifdef _DEBUG |
|
31 #include "l2capDebugControlInterface.h" |
|
32 #endif |
|
33 #endif |
|
34 |
|
35 #ifdef __FLOG_ACTIVE |
|
36 _LIT8(KLogComponent, LOG_COMPONENT_L2CAP); |
|
37 #endif |
|
38 |
|
39 |
|
40 // A helper for the implementation of a workaround for a bug in the negotiation algorithm |
|
41 // of some remotes. |
|
42 NONSHARABLE_STRUCT(SL2CapChannelIncomingConfigOptionSnapshot) |
|
43 { |
|
44 SL2CapChannelIncomingConfigOptionSnapshot(const CL2CapChannelConfig& aChannelConfig); |
|
45 TBool operator==(const SL2CapChannelIncomingConfigOptionSnapshot& aThat); |
|
46 |
|
47 TMTUOption iMtu; |
|
48 TL2CapConfigurationOptionGroupBase::TOptionConfigStatus iMtuStatus; |
|
49 |
|
50 TFlushTimeoutDurationOption iFlushTimeout; |
|
51 TL2CapConfigurationOptionGroupBase::TOptionConfigStatus iFlushTimeoutStatus; |
|
52 |
|
53 TRetransmissionAndFlowControlOption iFec; |
|
54 TL2CapConfigurationOptionGroupBase::TOptionConfigStatus iFecStatus; |
|
55 |
|
56 TQualityOfServiceOption iQos; |
|
57 TL2CapConfigurationOptionGroupBase::TOptionConfigStatus iQosStatus; |
|
58 }; |
|
59 |
|
60 |
|
61 /*static*/ CL2CapChannelConfig* CL2CapChannelConfig::NewL(CL2CapSAPSignalHandler& aSAPSignalHandler) |
|
62 { |
|
63 LOG_STATIC_FUNC |
|
64 CL2CapChannelConfig* self = new(ELeave) CL2CapChannelConfig(aSAPSignalHandler); |
|
65 CleanupStack::PushL(self); |
|
66 self->ConstructL(); |
|
67 CleanupStack::Pop(); |
|
68 return self; |
|
69 } |
|
70 |
|
71 CL2CapChannelConfig::~CL2CapChannelConfig() |
|
72 { |
|
73 LOG_FUNC |
|
74 delete iIncomingMTU; |
|
75 delete iOutgoingMTU; |
|
76 delete iIncomingFlushTimeoutDuration; |
|
77 delete iOutgoingFlushTimeoutDuration; |
|
78 delete iIncomingQOS; |
|
79 delete iOutgoingQOS; |
|
80 } |
|
81 |
|
82 void CL2CapChannelConfig::ConstructL() |
|
83 { |
|
84 LOG_FUNC |
|
85 |
|
86 // Initialise the configuration options. |
|
87 iIncomingMTU = new (ELeave)TL2CapConfigurationOptionGroup<TMTUOption> |
|
88 (TMTUOption::EPreferredValue, |
|
89 TMTUOption::EAbsoluteMinimumValue, |
|
90 TMTUOption::EPreferredValue, |
|
91 TMTUOption::ESpecDefaultValue, |
|
92 TL2CapConfigurationOptionGroupBase::ENegotiateToMinimum); |
|
93 iOutgoingMTU = new (ELeave)TL2CapConfigurationOptionGroup<TMTUOption> |
|
94 (TMTUOption::EMaximumValue, |
|
95 TMTUOption::ESpecMinimumValue, |
|
96 TMTUOption::EPreferredValue, |
|
97 TMTUOption::ESpecDefaultValue, |
|
98 TL2CapConfigurationOptionGroupBase::ENegotiateToMinimum); |
|
99 |
|
100 // Flush timeout is settable in the SAP but not implemented so we're not looking at the SAP value. |
|
101 iIncomingFlushTimeoutDuration = new (ELeave)TL2CapConfigurationOptionGroup<TFlushTimeoutDurationOption> |
|
102 (TFlushTimeoutDurationOption::EMaximumValue, |
|
103 TFlushTimeoutDurationOption::ESpecMinimumValue, |
|
104 TFlushTimeoutDurationOption::ESpecDefaultValue, |
|
105 TFlushTimeoutDurationOption::ESpecDefaultValue, |
|
106 TL2CapConfigurationOptionGroupBase::ENegotiated); |
|
107 iOutgoingFlushTimeoutDuration = new (ELeave)TL2CapConfigurationOptionGroup<TFlushTimeoutDurationOption> |
|
108 (TFlushTimeoutDurationOption::EMaximumValue, |
|
109 TFlushTimeoutDurationOption::EMaximumValue, |
|
110 TFlushTimeoutDurationOption::ESpecDefaultValue, |
|
111 TFlushTimeoutDurationOption::ESpecDefaultValue, |
|
112 TL2CapConfigurationOptionGroupBase::ENegotiated); |
|
113 |
|
114 // QOS isn't implemented nor settable in the SAP. |
|
115 iIncomingQOS = new (ELeave)TL2CapConfigurationOptionGroup<TQualityOfServiceOption> |
|
116 (TQualityOfServiceOption::EMaximumValue, |
|
117 TQualityOfServiceOption::ESpecMinimumValue, |
|
118 TQualityOfServiceOption::ESpecDefaultValue, |
|
119 TQualityOfServiceOption::ESpecDefaultValue, |
|
120 TL2CapConfigurationOptionGroupBase::ENegotiated); |
|
121 iOutgoingQOS = new (ELeave)TL2CapConfigurationOptionGroup<TQualityOfServiceOption> |
|
122 (TQualityOfServiceOption::EMaximumValue, |
|
123 TQualityOfServiceOption::ESpecMinimumValue, |
|
124 TQualityOfServiceOption::ESpecDefaultValue, |
|
125 TQualityOfServiceOption::ESpecDefaultValue, |
|
126 TL2CapConfigurationOptionGroupBase::ENegotiated); |
|
127 |
|
128 iRequestedChannelReliability = TL2CapConfig::EReliableChannel; |
|
129 iLegacyModesDisallowed = EFalse; |
|
130 iRequestedFlushTimeout = TL2CapConfig::EDefaultDataObsolescenceTimeout; |
|
131 iRequestedRetransmissionTimeout = TL2CapConfig::EDefaultRetransmission; |
|
132 |
|
133 LOG2(_L("CL2CapChannelConfig.iFecNegotiator = %X.%X"), (TAny*)this, (TAny*)&iFecNegotiator) |
|
134 } |
|
135 |
|
136 |
|
137 #ifndef __UNITTest__ |
|
138 CL2CapChannelConfig::CL2CapChannelConfig(CL2CapSAPSignalHandler& aSAPSignalHandler) |
|
139 : iSAPSignalHandler(aSAPSignalHandler) |
|
140 #else |
|
141 CL2CapChannelConfig::CL2CapChannelConfig(CL2CapConfigProxy& aSAPSignalHandler) |
|
142 : iSAPSignalHandler(aSAPSignalHandler) |
|
143 #endif |
|
144 { |
|
145 LOG_FUNC |
|
146 } |
|
147 |
|
148 void CL2CapChannelConfig::CloneChannelConfig(const CL2CapChannelConfig& aCopy) |
|
149 { |
|
150 LOG_FUNC |
|
151 |
|
152 // Copy all aspects of this class that should be cloned from the listening SAP. |
|
153 *iIncomingMTU = *(aCopy.iIncomingMTU); |
|
154 *iOutgoingMTU = *(aCopy.iOutgoingMTU); |
|
155 *iIncomingFlushTimeoutDuration = *(aCopy.iIncomingFlushTimeoutDuration); |
|
156 *iOutgoingFlushTimeoutDuration = *(aCopy.iOutgoingFlushTimeoutDuration); |
|
157 *iOutgoingQOS = *(aCopy.iOutgoingQOS); |
|
158 *iIncomingQOS = *(aCopy.iIncomingQOS); |
|
159 |
|
160 iRequestedChannelReliability = aCopy.iRequestedChannelReliability; |
|
161 iLegacyModesDisallowed = aCopy.iLegacyModesDisallowed; |
|
162 iRequestedFlushTimeout = aCopy.iRequestedFlushTimeout; |
|
163 iRequestedRetransmissionTimeout = aCopy.iRequestedRetransmissionTimeout; |
|
164 // iFecNegotiator gets updated using the iRequested... field values on OpenChannelRequest. |
|
165 } |
|
166 |
|
167 |
|
168 TInt CL2CapChannelConfig::HandleConfigRequest(HConfigureRequest& aConfigRequest, RMBufChain& aUnknownOptions) |
|
169 { |
|
170 LOG_FUNC |
|
171 // Pile these options on top of the previously received ones in case it's |
|
172 // a continuation packet. They're all processed once we've received the |
|
173 // whole transaction, in ConfigRequestComplete(). |
|
174 return aConfigRequest.ParseOptions(iReceivedConfigRequestOptions, aUnknownOptions); |
|
175 } |
|
176 |
|
177 TInt CL2CapChannelConfig::HandleConfigResponse(HConfigureResponse& aConfigResponse, RMBufChain& aUnknownOptions) |
|
178 { |
|
179 LOG_FUNC |
|
180 // Note: If it's a positive response (Success), then any parameters not specified by |
|
181 // the peer are assumed to be as requested. |
|
182 // If it's negative then it only includes suggested values for rejected parameters |
|
183 // and the ones not rejected will have to be re-requested in following message exchanges. |
|
184 |
|
185 TL2CapConfigParamOptions options; |
|
186 TInt err = aConfigResponse.ParseOptions(options, aUnknownOptions); |
|
187 if (err) |
|
188 { |
|
189 return err; |
|
190 } |
|
191 |
|
192 const TBool isUnacceptableParameters = (aConfigResponse.Results() == EConfigUnacceptableParams); |
|
193 const TBool isSuccess = (aConfigResponse.Results() == EConfigSuccess); |
|
194 |
|
195 // Prelude to the negotiation problem described at the bottom: |
|
196 // snapshot current option status for comparison after the message is processed. |
|
197 SL2CapChannelIncomingConfigOptionSnapshot optionStatusBeforeProcessing(*this); |
|
198 |
|
199 // MTU |
|
200 if (options.IsMtuSet()) |
|
201 { |
|
202 if (isUnacceptableParameters) |
|
203 { |
|
204 iIncomingMTU->PeerRejectsOption(options.Mtu()); |
|
205 } |
|
206 else |
|
207 { |
|
208 iIncomingMTU->PeerAcceptsOption(options.Mtu()); |
|
209 } |
|
210 } |
|
211 else if (isSuccess) |
|
212 { |
|
213 // A positive response acknowledges all options - if one is not |
|
214 // included then it means that the peer agrees with our proposal |
|
215 // (or the default, or the last accepted value). |
|
216 iIncomingMTU->PeerAcceptsOption(); |
|
217 } |
|
218 // [else]: if an option is not explicitly mentioned and it's not |
|
219 // a positive response, then the option's status remains untouched. |
|
220 |
|
221 // Flush Timeout Duration |
|
222 if (options.IsFlushTimeoutSet()) |
|
223 { |
|
224 if (isUnacceptableParameters) |
|
225 { |
|
226 iOutgoingFlushTimeoutDuration->PeerRejectsOption(options.FlushTimeout()); |
|
227 } |
|
228 else |
|
229 { |
|
230 // Note: we're ignoring the explicitly set value as it can only |
|
231 // be what we sent, otherwise it's a broken/malicious peer and we don't |
|
232 // want to use the value. |
|
233 iOutgoingFlushTimeoutDuration->PeerAcceptsOption(); |
|
234 } |
|
235 } |
|
236 else if (isSuccess) |
|
237 { |
|
238 iOutgoingFlushTimeoutDuration->PeerAcceptsOption(); |
|
239 } |
|
240 |
|
241 // Quality Of Service |
|
242 if (options.IsQosSet()) |
|
243 { |
|
244 if (isUnacceptableParameters) |
|
245 { |
|
246 iOutgoingQOS->PeerRejectsOption(options.Qos()); |
|
247 } |
|
248 else |
|
249 { |
|
250 iOutgoingQOS->PeerAcceptsOption(options.Qos()); |
|
251 } |
|
252 } |
|
253 else if (isSuccess) |
|
254 { |
|
255 iOutgoingQOS->PeerAcceptsOption(); |
|
256 } |
|
257 |
|
258 // Retransmission And Flow Control |
|
259 if (options.IsFecSet()) |
|
260 { |
|
261 if (isUnacceptableParameters) |
|
262 { |
|
263 err = iFecNegotiator.PeerRejectsOption(options.Fec()); |
|
264 } |
|
265 else |
|
266 { |
|
267 err = iFecNegotiator.PeerAcceptsOption(options.Fec()); |
|
268 } |
|
269 } |
|
270 else if (isSuccess) |
|
271 { |
|
272 iFecNegotiator.PeerAcceptsOption(); |
|
273 } |
|
274 |
|
275 if (isUnacceptableParameters && !err) |
|
276 { |
|
277 // negotiation algorithm bug workaround. |
|
278 |
|
279 // The problem this tries to work around is as follows: |
|
280 // S - local Symbian entity, C - remote host |
|
281 // SDP connection is being opened, C supports (E)RTM so we try to negotiate it: |
|
282 // 1. S sends ConfigReq[FEC=ERTM, MTU=n]. |
|
283 // 2. C responds with ConfigRsp(UnacceptableParameters)[MTU=n]. |
|
284 // 3. S obeys the reject, thinking C is rejecting the MTU (note the MTU value proposed |
|
285 // by C is the same value we sent in (1)); |
|
286 // S sends a new ConfigReq, including the proposed MTU and the FEC which is still pending |
|
287 // a response, thus creating a ConfigReq identical to the one from (1). |
|
288 // 4. C responds like in (2). |
|
289 // 5. S reacts like in (3). |
|
290 // -- we got into an infinite loop -- |
|
291 // The whole situation is due to C in (2) responding with ConfigRsp(UnacceptableParameters)[MTU=n] |
|
292 // while what it really means is ConfigRsp(UnacceptableParameters)[FEC=Basic]. |
|
293 // This was found at UPF33 - June 2009 and they fixed their code then, but there still |
|
294 // might be a lot of devices out doing the wrong thing. |
|
295 // |
|
296 // The workaround is to snapshot option status before and after the peer's |
|
297 // Config Response is processed and compare it. If it's exactly the same then |
|
298 // we're in a stalemate, so we cross our fingers and then drop our FEC proposal |
|
299 // to Basic. Remote accepts the ConfigReq with Basic mode and the whole palaver is over. |
|
300 // (the status snapshot includes the Preferred value and the config status of all |
|
301 // options). |
|
302 SL2CapChannelIncomingConfigOptionSnapshot optionStatusAfterProcessing(*this); |
|
303 if (optionStatusBeforeProcessing == optionStatusAfterProcessing) |
|
304 { |
|
305 err = iFecNegotiator.PeerRejectsOption(TRetransmissionAndFlowControlOption()); |
|
306 // Note: we'll also fall here if an option has started off with status Failed and |
|
307 // the peer rejected our preferred value, suggesting a value that's again unacceptable. |
|
308 // Example: user requests incoming MTU = 500 which is less than 672, which means |
|
309 // the default peer value of 672 is unacceptable and so the option's status is Failed |
|
310 // by default. If the value of 500 is then rejected by the peer, and it suggests |
|
311 // something else, be it 672 or anything > 500, the status and the actual value will |
|
312 // remain Failed and 500 - so if the status of the other options hasn't changed, |
|
313 // we'll fall in here. It's harmless though because it means we've failed to agree |
|
314 // and will disconnect, so it doesn't matter whether the FEC value is changed. |
|
315 } |
|
316 } |
|
317 return err; |
|
318 } |
|
319 |
|
320 TInt CL2CapChannelConfig::ConfigRequestComplete(TBool aConfigRequestSent, TConfigResponseResult& aResult) |
|
321 { |
|
322 LOG_FUNC |
|
323 TInt err = KErrNone; |
|
324 |
|
325 // Note that this method applies a different interpretation of the spec than |
|
326 // HandleConfigResponse. This is due to an ambiguity in the spec which yields two |
|
327 // possible interpretations: |
|
328 // (Interpretation A) When handling a Config Response, we assume that: |
|
329 // (1) if it's positive, then it acknowledges all the options we've sent in Config Request; |
|
330 // (2) if it's negative, then it only rejects the options that it includes, and neither |
|
331 // acknowledges nor rejects the ones that are not included. |
|
332 // (Interpretation B) When responding to a Config Request, we effectively assume |
|
333 // the following: |
|
334 // (1) is the same, |
|
335 // (2) if it's negative, then it only rejects the options that it includes and acknowledges |
|
336 // the ones that are not included. |
|
337 // There are implementations using both interpetations, so we do different things depending |
|
338 // on negotiation direction for maximum interop - we assume that interpretation A taken in |
|
339 // HandleConfigResponse makes more sense, but to be interoperable with both algorithms, we |
|
340 // respond to a ConfigRequest using interpretation B. |
|
341 // Here is why, by example: |
|
342 // 1. Peer sends us Config Request with MTU and FEC; |
|
343 // 2. We reject the MTU but FEC is ok, so we send a Config Response [Unacceptable Parameters](MTU); |
|
344 // According to interpretation B we also accept the FEC, while interpretation A |
|
345 // means we ignore it and Peer will include it again in the following ConfigRequest. |
|
346 // 3a. If Peer implements interpretation B, then it assumes we've accepted the FEC |
|
347 // and considers the option value to have been agreed, so it will not include it |
|
348 // in the next Config Request along with MTU. Fortunately, we use the same |
|
349 // interpretation here so we're in sync. |
|
350 // 3b. If Peer implements interpretation A, then it will include the FEC in the next |
|
351 // Config Request anyway because it's still outstanding, so what we do to the option |
|
352 // now doesn't matter. Theoretically Peer could suddenly change its mind and forego |
|
353 // negotiating FEC, but obviously unless it's a human no implemntation will do it :) |
|
354 |
|
355 if (iReceivedConfigRequestOptions.IsMtuSet()) |
|
356 { |
|
357 iOutgoingMTU->PeerRequestsOption(iReceivedConfigRequestOptions.Mtu()); |
|
358 } |
|
359 else |
|
360 { |
|
361 iOutgoingMTU->PeerRequestsLastAcceptedValue(); |
|
362 } |
|
363 |
|
364 if (iReceivedConfigRequestOptions.IsFlushTimeoutSet()) |
|
365 { |
|
366 iIncomingFlushTimeoutDuration->PeerRequestsOption(iReceivedConfigRequestOptions.FlushTimeout()); |
|
367 } |
|
368 else |
|
369 { |
|
370 iIncomingFlushTimeoutDuration->PeerRequestsLastAcceptedValue(); |
|
371 } |
|
372 |
|
373 if (iReceivedConfigRequestOptions.IsQosSet()) |
|
374 { |
|
375 iIncomingQOS->PeerRequestsOption(iReceivedConfigRequestOptions.Qos()); |
|
376 } |
|
377 else |
|
378 { |
|
379 iIncomingQOS->PeerRequestsLastAcceptedValue(); |
|
380 } |
|
381 |
|
382 if (iReceivedConfigRequestOptions.IsFecSet()) |
|
383 { |
|
384 err = iFecNegotiator.PeerRequestsOption(iReceivedConfigRequestOptions.Fec()); |
|
385 } |
|
386 else |
|
387 { |
|
388 err = iFecNegotiator.PeerRequestsLastAcceptedValue(); |
|
389 if (err == KErrNone) |
|
390 { |
|
391 // Check if the outgoing FEC connection needs to be downgraded to basic mode. |
|
392 // NB This ONLY makes sense if our config request has not already been queued... |
|
393 // ...otherwise it would break the config algorithm. |
|
394 if(!aConfigRequestSent) |
|
395 { |
|
396 FecNegotiator().DowngradeIncomingToBasicIfOutgoingIsBasic(); |
|
397 } |
|
398 } |
|
399 } |
|
400 |
|
401 // Now reset the Config Request option store in case there's a next negotiation round. |
|
402 iReceivedConfigRequestOptions = TL2CapConfigParamOptions(); |
|
403 |
|
404 /* |
|
405 For a config request we know the peer values - so the peer and the actual values should |
|
406 either be the same, or the peer should be outside our limits (See the implementation of |
|
407 TL2CapConfigurationOptionGroupBase::TOptionConfigStatus.) |
|
408 If this __ASSERT_DEBUG is hit, it is likely that the API has been upgraded or |
|
409 the default values have been upgraded in a way which breaks the configuration logic. |
|
410 */ |
|
411 __ASSERT_DEBUG(iOutgoingMTU->ConfigOptionStatus() != TL2CapConfigurationOptionGroupBase::EOptionConfigOutstanding && |
|
412 iIncomingFlushTimeoutDuration->ConfigOptionStatus() != TL2CapConfigurationOptionGroupBase::EOptionConfigOutstanding && |
|
413 iIncomingQOS->ConfigOptionStatus() != TL2CapConfigurationOptionGroupBase::EOptionConfigOutstanding && |
|
414 iFecNegotiator.OutgoingConfigOptionStatus() != TL2CapConfigurationOptionGroupBase::EOptionConfigOutstanding, |
|
415 Panic(EL2CAPInvalidConfigOptionState)); |
|
416 |
|
417 // Check the response code required for the subsequent Config Response. |
|
418 if(iOutgoingMTU->ConfigOptionStatus() == TL2CapConfigurationOptionGroupBase::EOptionConfigFailed || |
|
419 iIncomingFlushTimeoutDuration->ConfigOptionStatus() == TL2CapConfigurationOptionGroupBase::EOptionConfigFailed || |
|
420 iIncomingQOS->ConfigOptionStatus() == TL2CapConfigurationOptionGroupBase::EOptionConfigFailed || |
|
421 iFecNegotiator.OutgoingConfigOptionStatus() == TL2CapConfigurationOptionGroupBase::EOptionConfigFailed) |
|
422 { |
|
423 aResult = EConfigUnacceptableParams; |
|
424 } |
|
425 else |
|
426 { |
|
427 aResult = EConfigSuccess; |
|
428 } |
|
429 |
|
430 return err; |
|
431 } |
|
432 |
|
433 /** |
|
434 Process the entity information received from peer. Used to make sure that we don't try |
|
435 and negotiate a configuration that the peer is not capable of negotiating. The predominant use |
|
436 case is to make sure that we do not negotiate FEC parameters with a device that is only capable |
|
437 of basic mode. |
|
438 **/ |
|
439 TInt CL2CapChannelConfig::UpdateLocalConfigWithEntityCapabilities() |
|
440 { |
|
441 LOG_FUNC |
|
442 TL2CapEntityInfo config; |
|
443 TInt err = iL2CapEntityConfig->PeerL2CapSupportedFeatures(config); |
|
444 if (err == KErrNone) |
|
445 { |
|
446 // Signalling state machine is responsible for not calling us until we've got |
|
447 // peer entity information. |
|
448 __ASSERT_DEBUG(config.LinkInfoState() == EL2CapEntityInfoDefined, |
|
449 Panic(EL2CAPUpdateLocalConfigCalledWithoutPeerEntityConfig)); |
|
450 // Based on knowledge about the peer's extended information, set up mode negotiator. |
|
451 TBool peerSupportsRequestedConfig = GenerateFecOptions(config); |
|
452 if (!peerSupportsRequestedConfig) |
|
453 { |
|
454 err = KErrL2CAPPeerDoesNotSupportRequestedChannelMode; |
|
455 } |
|
456 } |
|
457 return err; |
|
458 } |
|
459 |
|
460 /** |
|
461 Handles configurable options provided in TL2CapConfig by user APIs. |
|
462 aOnTheAirConfigRequired will be set to True if the specified parameters require the |
|
463 L2CAP reconfiguration process, False otherwise. |
|
464 **/ |
|
465 TInt CL2CapChannelConfig::UpdateConfigAPIChange(const TL2CapConfig& aApiConfig, TBool& aOnTheAirReconfigRequired) |
|
466 { |
|
467 LOG_FUNC |
|
468 TInt err = KErrNone; |
|
469 |
|
470 aOnTheAirReconfigRequired = EFalse; |
|
471 |
|
472 err = UpdateReliability(aApiConfig); |
|
473 if (err == KErrNone) |
|
474 { |
|
475 err = UpdateMtuMru(aApiConfig, aOnTheAirReconfigRequired); |
|
476 } |
|
477 |
|
478 // GenerateFecOptions() will be called on OpenChannelRequest to transform these options |
|
479 // into concrete FEC option values groups. |
|
480 |
|
481 return err; |
|
482 } |
|
483 |
|
484 |
|
485 /** |
|
486 Returns true if all the configuration elements included in a incoming configuration response |
|
487 have been successfully configured |
|
488 **/ |
|
489 CL2CapChannelConfig::TChannelConfigStatus CL2CapChannelConfig::LocalConfigurationStatus() const |
|
490 { |
|
491 LOG_FUNC |
|
492 TChannelConfigStatus status = EChannelConfigOutstanding; |
|
493 |
|
494 if((iIncomingMTU->ConfigOptionStatus() == TL2CapConfigurationOptionGroupBase::EOptionConfigComplete) && |
|
495 (iOutgoingFlushTimeoutDuration->ConfigOptionStatus() == TL2CapConfigurationOptionGroupBase::EOptionConfigComplete) && |
|
496 (iOutgoingQOS->ConfigOptionStatus() == TL2CapConfigurationOptionGroupBase::EOptionConfigComplete) && |
|
497 (iFecNegotiator.IncomingConfigOptionStatus() == TL2CapConfigurationOptionGroupBase::EOptionConfigComplete)) |
|
498 { |
|
499 status = EChannelConfigComplete; |
|
500 } |
|
501 else |
|
502 { |
|
503 if((iIncomingMTU->ConfigOptionStatus() == TL2CapConfigurationOptionGroupBase::EOptionConfigFailed) || |
|
504 (iOutgoingFlushTimeoutDuration->ConfigOptionStatus() == TL2CapConfigurationOptionGroupBase::EOptionConfigFailed) || |
|
505 (iOutgoingQOS->ConfigOptionStatus() == TL2CapConfigurationOptionGroupBase::EOptionConfigFailed) || |
|
506 (iFecNegotiator.IncomingConfigOptionStatus() == TL2CapConfigurationOptionGroupBase::EOptionConfigFailed)) |
|
507 { |
|
508 status = EChannelConfigFailed; |
|
509 } |
|
510 } |
|
511 return status; |
|
512 } |
|
513 |
|
514 /** |
|
515 Public function that registers the entity channel configuration with this channel configuration |
|
516 **/ |
|
517 void CL2CapChannelConfig::RegisterL2CapEntityConfig(TL2CAPEntityConfig& aL2CapEntityConfig) |
|
518 { |
|
519 LOG_FUNC |
|
520 __ASSERT_DEBUG(!iL2CapEntityConfig, Panic(EL2CAPAttemptToRegisterEntityConfigTwice)); |
|
521 iL2CapEntityConfig = &aL2CapEntityConfig; |
|
522 } |
|
523 |
|
524 /** |
|
525 Channel configuration is being taken down. |
|
526 **/ |
|
527 void CL2CapChannelConfig::DetachChannelConfig() |
|
528 { |
|
529 LOG_FUNC |
|
530 // If the channel config has registered with the Entity |
|
531 // config remove the association. |
|
532 iL2CapEntityConfig = NULL; |
|
533 } |
|
534 |
|
535 // Translates abstract 'Channel Reliability' etc. into concrete option groups. |
|
536 // Called just-in-time on OpenChannelRequest, when the L2CAP connection is being made. |
|
537 // Should only be called once in the lifetime of a connection. |
|
538 TBool CL2CapChannelConfig::GenerateFecOptions(const TL2CapEntityInfo& aPeerEntityConfig) |
|
539 { |
|
540 LOG_FUNC |
|
541 |
|
542 __ASSERT_DEBUG(aPeerEntityConfig.LinkInfoState() == EL2CapEntityInfoDefined, |
|
543 Panic(EL2CAPFecConfigAttemptWithoutPeerInfo)); |
|
544 |
|
545 // We may end up falling back from Streaming to ERTM, so set up a sensible MaxTransmit value |
|
546 // for both Reliable and Unreliable case. |
|
547 TUint8 maxTransmit = TRetransmissionAndFlowControlOption::KMaxValidEnhancedNumberTransmit; |
|
548 // TL2CapConfig::EDefaultRetransmission is 0xffff, which is a special value in the API that |
|
549 // means 'maximum possible MaxTransmit'. Note that we assume here that the maximum MaxTransmit |
|
550 // is 0, which is only true for enhanced modes. If a legacy mode is negotiated, FECNegotiator |
|
551 // will change the 0 to 255. |
|
552 if (iRequestedRetransmissionTimeout != TL2CapConfig::EDefaultRetransmission) |
|
553 { |
|
554 maxTransmit = static_cast<TUint8>(iRequestedRetransmissionTimeout / TRetransmissionAndFlowControlOption::KDefaultRetransmissionTimeout); |
|
555 } |
|
556 |
|
557 TBool peerSupportsRequestedConfig = iFecNegotiator.Setup(iRequestedChannelReliability, iLegacyModesDisallowed, aPeerEntityConfig, maxTransmit); |
|
558 if (peerSupportsRequestedConfig) |
|
559 { |
|
560 // Set the outgoing flush parameters NOT to allow flushing. |
|
561 // Note: the TL2CapConfig API does allow setting of the flush timeout, and we do have some |
|
562 // support for it across the board, but that code is unused. This is the place where |
|
563 // iRequestedFlushTimeout gets ignored and if ever start supporting flushing, then we should |
|
564 // take it into account and set the flushTimeoutDuration accordingly if unreliable channel |
|
565 // is requested. |
|
566 TFlushTimeoutDurationOption flushTimeoutDuration(TFlushTimeoutDurationOption::EMaximumValue); |
|
567 iOutgoingFlushTimeoutDuration->SetRequiredValue(flushTimeoutDuration, flushTimeoutDuration, flushTimeoutDuration); |
|
568 } |
|
569 |
|
570 return peerSupportsRequestedConfig; |
|
571 } |
|
572 |
|
573 TInt CL2CapChannelConfig::UpdateReliability(const TL2CapConfig& aApiConfig) |
|
574 { |
|
575 LOG_FUNC |
|
576 TInt err = KErrNone; |
|
577 TBool specified = EFalse; |
|
578 TL2CapConfig::TChannelReliability reliability = aApiConfig.ChannelReliability(specified); |
|
579 if (specified) |
|
580 { |
|
581 if (iSAPSignalHandler.IsChannelClosed()) |
|
582 { |
|
583 TBool getFlushTimeout = EFalse; |
|
584 TBool getRtxTimeout = EFalse; |
|
585 |
|
586 if (reliability == TL2CapConfig::EUnreliableDesiredChannel) |
|
587 { |
|
588 getFlushTimeout = getRtxTimeout = ETrue; |
|
589 } |
|
590 else if (reliability == TL2CapConfig::EUnreliableChannel) |
|
591 { |
|
592 getFlushTimeout = ETrue; |
|
593 } |
|
594 else // Reliable |
|
595 { |
|
596 getRtxTimeout = ETrue; |
|
597 } |
|
598 |
|
599 TUint16 timeout = 0; |
|
600 |
|
601 if (getFlushTimeout) |
|
602 { |
|
603 timeout = aApiConfig.ObsolescenceTimer(specified); |
|
604 if (!specified) |
|
605 { |
|
606 err = KErrArgument; |
|
607 } |
|
608 else |
|
609 { |
|
610 iRequestedFlushTimeout = timeout; |
|
611 } |
|
612 } |
|
613 |
|
614 if (getRtxTimeout) |
|
615 { |
|
616 timeout = aApiConfig.RetransmissionTimer(specified); |
|
617 if (!specified) |
|
618 { |
|
619 err = KErrArgument; |
|
620 } |
|
621 else |
|
622 { |
|
623 iRequestedRetransmissionTimeout = timeout; |
|
624 } |
|
625 } |
|
626 |
|
627 if (err == KErrNone) |
|
628 { |
|
629 iRequestedChannelReliability = reliability; |
|
630 iLegacyModesDisallowed = aApiConfig.LegacyModesDisallowed(); |
|
631 |
|
632 if (iRequestedFlushTimeout < KMinOutgoingFlushTimeout) |
|
633 { |
|
634 iRequestedFlushTimeout = KMinOutgoingFlushTimeout; |
|
635 } |
|
636 } |
|
637 } // channel Closed |
|
638 else |
|
639 { |
|
640 // Channel not in Closed state - can't change reliability. |
|
641 err = KErrInUse; |
|
642 } |
|
643 } // reliability specified |
|
644 return err; |
|
645 } |
|
646 |
|
647 TInt CL2CapChannelConfig::UpdateMtuMru(const TL2CapConfig& aApiConfig, TBool& aOnTheAirReconfigRequired) |
|
648 { |
|
649 LOG_FUNC |
|
650 |
|
651 // MTU-related params. |
|
652 TBool mtuSpecified = EFalse; |
|
653 TBool minMtuSpecified = EFalse; |
|
654 TUint16 newMTU = aApiConfig.MaxTransmitUnitSize(mtuSpecified); |
|
655 TUint16 newMinMTU = aApiConfig.MinMTU(minMtuSpecified); |
|
656 TMTUOption currentMTU = iOutgoingMTU->Preferred(); |
|
657 |
|
658 // MRU-related params. |
|
659 TBool mruSpecified = EFalse; |
|
660 TBool minMruSpecified = EFalse; |
|
661 TUint16 newMRU = aApiConfig.MaxReceiveUnitSize(mruSpecified); |
|
662 TUint16 newMinMRU = aApiConfig.MinMRU(minMruSpecified); |
|
663 TMTUOption currentMRU = iIncomingMTU->Preferred(); |
|
664 |
|
665 if ((mtuSpecified || minMtuSpecified || mruSpecified || minMruSpecified) && |
|
666 !iSAPSignalHandler.IsChannelClosed() && !iSAPSignalHandler.IsChannelOpen()) |
|
667 { |
|
668 // Not the brightest idea to mess with these during ongoing config. |
|
669 return KErrInUse; |
|
670 } |
|
671 else |
|
672 { |
|
673 if (mtuSpecified || minMtuSpecified) |
|
674 { |
|
675 TMTUOption mtuToSet = mtuSpecified ? newMTU : currentMTU; |
|
676 // if !minMtuSpecified then assume the lower bound to be = newMTU |
|
677 TMTUOption minMtuToSet = minMtuSpecified ? newMinMTU : newMTU; |
|
678 |
|
679 if (minMtuToSet > mtuToSet) |
|
680 { |
|
681 return KErrL2CAPAttemptToSetMinMtuGreaterThanMtu; |
|
682 } |
|
683 |
|
684 iOutgoingMTU->SetRequiredValue(TMTUOption(TMTUOption::EMaximumValue), minMtuToSet, mtuToSet); |
|
685 aOnTheAirReconfigRequired = ETrue; |
|
686 } |
|
687 |
|
688 if (mruSpecified || minMruSpecified) |
|
689 { |
|
690 TMTUOption mruToSet = mruSpecified ? newMRU : currentMRU; |
|
691 // if !minMruSpecified then assume the lower bound is the spec minimum |
|
692 TMTUOption minMruToSet = minMruSpecified ? newMinMRU : TMTUOption(TMTUOption::ESpecMinimumValue); |
|
693 |
|
694 if (minMruToSet > mruToSet) |
|
695 { |
|
696 return KErrL2CAPAttemptToSetMinMruGreaterThanMru; |
|
697 } |
|
698 |
|
699 iIncomingMTU->SetRequiredValue(mruToSet, minMruToSet, mruToSet); |
|
700 aOnTheAirReconfigRequired = ETrue; |
|
701 } |
|
702 } |
|
703 return KErrNone; |
|
704 } |
|
705 |
|
706 TInt CL2CapChannelConfig::GetChannelMode(TL2CapChannelMode& aMode) const |
|
707 { |
|
708 LOG_FUNC |
|
709 __ASSERT_DEBUG(iFecNegotiator.IncomingLinkMode() == iFecNegotiator.OutgoingLinkMode(), |
|
710 Panic(EL2CAPAsymmetricChannelModes)); |
|
711 aMode = iFecNegotiator.IncomingLinkMode(); |
|
712 return KErrNone; |
|
713 } |
|
714 |
|
715 |
|
716 SL2CapChannelIncomingConfigOptionSnapshot::SL2CapChannelIncomingConfigOptionSnapshot(const CL2CapChannelConfig& aChannelConfig) |
|
717 : iMtu(aChannelConfig.IncomingMTU().Preferred()), |
|
718 iMtuStatus(aChannelConfig.IncomingMTU().ConfigOptionStatus()), |
|
719 iFlushTimeout(aChannelConfig.OutgoingFlushTimeout().Preferred()), |
|
720 iFlushTimeoutStatus(aChannelConfig.OutgoingFlushTimeout().ConfigOptionStatus()), |
|
721 iFec(aChannelConfig.FecNegotiator().IncomingPreferred()), |
|
722 iFecStatus(aChannelConfig.FecNegotiator().IncomingConfigOptionStatus()), |
|
723 iQos(aChannelConfig.OutgoingQOS().Preferred()), |
|
724 iQosStatus(aChannelConfig.OutgoingQOS().ConfigOptionStatus()) |
|
725 { |
|
726 LOG_FUNC |
|
727 } |
|
728 |
|
729 TBool SL2CapChannelIncomingConfigOptionSnapshot::operator==(const SL2CapChannelIncomingConfigOptionSnapshot& aThat) |
|
730 { |
|
731 LOG_FUNC |
|
732 return iMtu == aThat.iMtu && iMtuStatus == aThat.iMtuStatus && |
|
733 iFlushTimeout == aThat.iFlushTimeout && iFlushTimeoutStatus == aThat.iFlushTimeoutStatus && |
|
734 iFec == aThat.iFec && iFecStatus == aThat.iFecStatus && |
|
735 iQos == aThat.iQos && iQosStatus == aThat.iQosStatus; |
|
736 } |