|
1 // Copyright (c) 2006-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 // |
|
15 |
|
16 |
|
17 |
|
18 /** |
|
19 @file |
|
20 @internalComponent |
|
21 */ |
|
22 |
|
23 #include <bluetooth/logger.h> |
|
24 #include "L2CapFecNegotiator.h" |
|
25 #include "L2CapPDU.h" |
|
26 |
|
27 static TBool operator<=(TL2CapChannelMode aLeft, TL2CapChannelMode aRight); |
|
28 template<typename T> static inline TBool IsWithinBounds(const T aValue, const T aLeftBound, const T aRightBound); |
|
29 |
|
30 #ifdef __FLOG_ACTIVE |
|
31 _LIT8(KLogComponent, LOG_COMPONENT_L2CAP); |
|
32 #endif |
|
33 |
|
34 // |
|
35 // Mode-specific handlers |
|
36 // |
|
37 |
|
38 TBool TModeSpecificFecOptionHandlerBase::BuildPositiveResponse(TRetransmissionAndFlowControlOption& aPreferred, |
|
39 const TRetransmissionAndFlowControlOption& aPeer) const |
|
40 { |
|
41 LOG_FUNC |
|
42 // As simple as that according to the general negotiation process, i.e. not when negotiating |
|
43 // the 2.1 Core Spec Addendum 1 - introduced modes. |
|
44 aPreferred = aPeer; |
|
45 // Don't include the exactly same FEC in response. |
|
46 return EFalse; |
|
47 } |
|
48 |
|
49 void TModeSpecificFecOptionHandlerBase::BuildNegativeResponse(TRetransmissionAndFlowControlOption& /*aPreferred*/, |
|
50 const TRetransmissionAndFlowControlOption& /*aPeer*/) const |
|
51 { |
|
52 LOG_FUNC |
|
53 // Just send what we've got in Preferred. |
|
54 } |
|
55 |
|
56 void TModeSpecificFecOptionHandlerBase::SetMaxTransmit(TRetransmissionAndFlowControlOption& aFecOption, TUint8 /*aMaxTransmit*/) const |
|
57 { |
|
58 LOG_FUNC |
|
59 aFecOption.SetMaxTransmit(0); |
|
60 } |
|
61 |
|
62 void TModeSpecificFecOptionHandlerBase::PrepareImplicitPeerResponse(TRetransmissionAndFlowControlOption& aImplicitResponse, |
|
63 const TRetransmissionAndFlowControlOption& aPreferred) const |
|
64 { |
|
65 LOG_FUNC |
|
66 aImplicitResponse = aPreferred; |
|
67 } |
|
68 |
|
69 void TModeSpecificFecOptionHandlerBase::ZeroUnspecifiedRequestFields(TRetransmissionAndFlowControlOption& /*aFecOption*/) const |
|
70 {LOG_FUNC} |
|
71 |
|
72 void TModeSpecificFecOptionHandlerBase::ZeroUnspecifiedResponseFields(TRetransmissionAndFlowControlOption& /*aFecOption*/) const |
|
73 {LOG_FUNC} |
|
74 |
|
75 |
|
76 // Streaming Mode |
|
77 |
|
78 TBool TStreamingFecHandler::IsOptionValid(const TRetransmissionAndFlowControlOption& aFecOption) const |
|
79 { |
|
80 LOG_FUNC |
|
81 return aFecOption.MaximumPDUSize() >= TRetransmissionAndFlowControlOption::KMinValidMaximumPDUSize; |
|
82 } |
|
83 |
|
84 TBool TStreamingFecHandler::IsPeerResponseAcceptable(const TRetransmissionAndFlowControlOption& aPreferred, |
|
85 const TRetransmissionAndFlowControlOption& aPeer) const |
|
86 { |
|
87 LOG_FUNC |
|
88 return aPeer.MaximumPDUSize() <= aPreferred.MaximumPDUSize(); |
|
89 } |
|
90 |
|
91 TBool TStreamingFecHandler::BuildPositiveResponse(TRetransmissionAndFlowControlOption& aPreferred, |
|
92 const TRetransmissionAndFlowControlOption& aPeer) const |
|
93 { |
|
94 LOG_FUNC |
|
95 TRetransmissionAndFlowControlOption response = aPeer; |
|
96 // Trim MPS to our desired value. |
|
97 response.SetMaximumPDUSize(Min(TRetransmissionAndFlowControlOption::KDefaultMaximumPDUSize, |
|
98 response.MaximumPDUSize())); |
|
99 // Zero the ignored fields no matter what peer sent us in them. |
|
100 ZeroUnspecifiedResponseFields(response); |
|
101 |
|
102 aPreferred = response; |
|
103 // Include the FEC in ConfigRsp. |
|
104 return ETrue; |
|
105 } |
|
106 |
|
107 void TStreamingFecHandler::BuildNegativeResponse(TRetransmissionAndFlowControlOption& aPreferred, |
|
108 const TRetransmissionAndFlowControlOption& /*aPeer*/) const |
|
109 { |
|
110 LOG_FUNC |
|
111 // Channel Mode has been already set and that's the parameter that what we're actually |
|
112 // rejecting. The rest is informational and should be set by the remote to its own |
|
113 // liking based on the mode proposed, so we _could_ set them to 0, but just in case |
|
114 // we're talking to a dumb peer - or a bit older version of my own code that wouldn't |
|
115 // accept 0s, for that matter - set them to sensible defaults. |
|
116 aPreferred = TRetransmissionAndFlowControlOption(aPreferred.LinkMode(), ETrue); |
|
117 ZeroUnspecifiedRequestFields(aPreferred); |
|
118 } |
|
119 |
|
120 void TStreamingFecHandler::ZeroUnspecifiedRequestFields(TRetransmissionAndFlowControlOption& aFecOption) const |
|
121 { |
|
122 LOG_FUNC |
|
123 aFecOption.SetTxWindowSize(0); |
|
124 aFecOption.SetMaxTransmit(0); |
|
125 aFecOption.SetRetransmissionTimeout(0); |
|
126 aFecOption.SetMonitorTimeout(0); |
|
127 } |
|
128 |
|
129 void TStreamingFecHandler::ZeroUnspecifiedResponseFields(TRetransmissionAndFlowControlOption& aFecOption) const |
|
130 { |
|
131 LOG_FUNC |
|
132 aFecOption.SetTxWindowSize(0); |
|
133 aFecOption.SetMaxTransmit(0); |
|
134 aFecOption.SetRetransmissionTimeout(0); |
|
135 aFecOption.SetMonitorTimeout(0); |
|
136 } |
|
137 |
|
138 |
|
139 // Enhanced Retransmission Mode |
|
140 |
|
141 TBool TErtmFecHandler::IsOptionValid(const TRetransmissionAndFlowControlOption& aFecOption) const |
|
142 { |
|
143 LOG_FUNC |
|
144 return aFecOption.MaximumPDUSize() >= TRetransmissionAndFlowControlOption::KMinValidMaximumPDUSize && |
|
145 aFecOption.TxWindowSize() >= TRetransmissionAndFlowControlOption::KMinValidTxWindowSize && |
|
146 aFecOption.TxWindowSize() <= TRetransmissionAndFlowControlOption::KMaxValidEnhancedTxWindowSize; |
|
147 } |
|
148 |
|
149 TBool TErtmFecHandler::IsPeerResponseAcceptable(const TRetransmissionAndFlowControlOption& aPreferred, |
|
150 const TRetransmissionAndFlowControlOption& aPeer) const |
|
151 { |
|
152 LOG_FUNC |
|
153 return // MaxTransmit in response doesn't matter. |
|
154 IsWithinBounds(aPeer.RetransmissionTimeout(), |
|
155 TRetransmissionAndFlowControlOption::KMinAcceptableRetransmissionTimeout, |
|
156 TRetransmissionAndFlowControlOption::KMaxAcceptableRetransmissionTimeout) && |
|
157 IsWithinBounds(aPeer.MonitorTimeout(), |
|
158 TRetransmissionAndFlowControlOption::KMinAcceptableMonitorTimeout, |
|
159 TRetransmissionAndFlowControlOption::KMaxAcceptableMonitorTimeout) && |
|
160 aPeer.TxWindowSize() <= aPreferred.TxWindowSize() && |
|
161 aPeer.MaximumPDUSize() <= aPreferred.MaximumPDUSize(); |
|
162 } |
|
163 |
|
164 TBool TErtmFecHandler::BuildPositiveResponse(TRetransmissionAndFlowControlOption& aPreferred, |
|
165 const TRetransmissionAndFlowControlOption& aPeer) const |
|
166 { |
|
167 LOG_FUNC |
|
168 TRetransmissionAndFlowControlOption response = aPeer; |
|
169 // Peer sends us 0s in Retransmission and Monitor time-outs in Request and expects us |
|
170 // to send values for the timers we're going to use in the response. |
|
171 response.SetRetransmissionTimeout(TRetransmissionAndFlowControlOption::KDefaultRetransmissionTimeout); |
|
172 response.SetMonitorTimeout(TRetransmissionAndFlowControlOption::KDefaultMonitorTimeout); |
|
173 ZeroUnspecifiedResponseFields(response); |
|
174 |
|
175 // Trim TxWindow and MPS to our preferred values. |
|
176 response.SetTxWindowSize(Min(TRetransmissionAndFlowControlOption::KDefaultEnhancedTxWindowSize, |
|
177 response.TxWindowSize())); |
|
178 response.SetMaximumPDUSize(Min(TRetransmissionAndFlowControlOption::KDefaultMaximumPDUSize, |
|
179 response.MaximumPDUSize())); |
|
180 |
|
181 aPreferred = response; |
|
182 // Include the FEC in ConfigRsp. |
|
183 return ETrue; |
|
184 } |
|
185 |
|
186 void TErtmFecHandler::BuildNegativeResponse(TRetransmissionAndFlowControlOption& aPreferred, |
|
187 const TRetransmissionAndFlowControlOption& /*aPeer*/) const |
|
188 { |
|
189 LOG_FUNC |
|
190 // Channel Mode has been already set and that's the parameter that what we're actually |
|
191 // rejecting. The rest is informational and should be set by the remote to its own |
|
192 // liking based on the mode proposed, so we _could_ set them to 0, but just in case |
|
193 // we're talking to a dumb peer - or a bit older version of my own code that wouldn't |
|
194 // accept 0s, for that matter - set them to sensible defaults. |
|
195 aPreferred = TRetransmissionAndFlowControlOption(aPreferred.LinkMode(), ETrue); |
|
196 ZeroUnspecifiedRequestFields(aPreferred); |
|
197 } |
|
198 |
|
199 void TErtmFecHandler::SetMaxTransmit(TRetransmissionAndFlowControlOption& aFecOption, TUint8 aMaxTransmit) const |
|
200 { |
|
201 aFecOption.SetMaxTransmit(aMaxTransmit); |
|
202 } |
|
203 |
|
204 void TErtmFecHandler::PrepareImplicitPeerResponse(TRetransmissionAndFlowControlOption& aImplicitResponse, |
|
205 const TRetransmissionAndFlowControlOption& aPreferred) const |
|
206 { |
|
207 LOG_FUNC |
|
208 TModeSpecificFecOptionHandlerBase::PrepareImplicitPeerResponse(aImplicitResponse, aPreferred); |
|
209 // Peer is supposed to send us time-out values that it will use. It should always send |
|
210 // a response FEC if we're negotiating enhanced modes, so eventually we will get the real |
|
211 // values (unless the peer is broken). |
|
212 aImplicitResponse.SetRetransmissionTimeout(TRetransmissionAndFlowControlOption::KDefaultRetransmissionTimeout); |
|
213 aImplicitResponse.SetMonitorTimeout(TRetransmissionAndFlowControlOption::KDefaultMonitorTimeout); |
|
214 } |
|
215 |
|
216 void TErtmFecHandler::ZeroUnspecifiedRequestFields(TRetransmissionAndFlowControlOption& aFecOption) const |
|
217 { |
|
218 aFecOption.SetRetransmissionTimeout(0); |
|
219 aFecOption.SetMonitorTimeout(0); |
|
220 } |
|
221 |
|
222 void TErtmFecHandler::ZeroUnspecifiedResponseFields(TRetransmissionAndFlowControlOption& aFecOption) const |
|
223 { |
|
224 aFecOption.SetMaxTransmit(0); |
|
225 } |
|
226 |
|
227 // Flow Control Mode and Retransmission Mode |
|
228 |
|
229 TBool TLegacyFecHandler::IsOptionValid(const TRetransmissionAndFlowControlOption& aFecOption) const |
|
230 { |
|
231 LOG_FUNC |
|
232 return aFecOption.MaximumPDUSize() >= TRetransmissionAndFlowControlOption::KMinValidMaximumPDUSize && |
|
233 aFecOption.TxWindowSize() >= TRetransmissionAndFlowControlOption::KMinValidTxWindowSize && |
|
234 aFecOption.TxWindowSize() <= TRetransmissionAndFlowControlOption::KMaxValidLegacyTxWindowSize && |
|
235 aFecOption.MaxTransmit() >= TRetransmissionAndFlowControlOption::KMinValidNumberTransmit && |
|
236 aFecOption.MaxTransmit() <= TRetransmissionAndFlowControlOption::KMaxValidLegacyNumberTransmit; |
|
237 } |
|
238 |
|
239 TBool TLegacyFecHandler::IsPeerResponseAcceptable(const TRetransmissionAndFlowControlOption& aPreferred, |
|
240 const TRetransmissionAndFlowControlOption& aPeer) const |
|
241 { |
|
242 LOG_FUNC |
|
243 return aPeer == aPreferred; |
|
244 } |
|
245 |
|
246 void TLegacyFecHandler::SetMaxTransmit(TRetransmissionAndFlowControlOption& aFecOption, TUint8 aMaxTransmit) const |
|
247 { |
|
248 aFecOption.SetMaxTransmit(aMaxTransmit == TRetransmissionAndFlowControlOption::KMaxValidEnhancedNumberTransmit ? |
|
249 TRetransmissionAndFlowControlOption::KMaxValidLegacyNumberTransmit : |
|
250 aMaxTransmit); |
|
251 } |
|
252 |
|
253 // Basic mode |
|
254 |
|
255 TBool TBasicFecHandler::IsOptionValid(const TRetransmissionAndFlowControlOption& /*aFecOption*/) const |
|
256 { |
|
257 LOG_FUNC |
|
258 // Only the mode field is specified for Basic, and we know the mode is Basic already... |
|
259 return ETrue; |
|
260 } |
|
261 |
|
262 TBool TBasicFecHandler::IsPeerResponseAcceptable(const TRetransmissionAndFlowControlOption& /*aPreferred*/, |
|
263 const TRetransmissionAndFlowControlOption& /*aPeer*/) const |
|
264 { |
|
265 LOG_FUNC |
|
266 // Only the mode field is specified for Basic, and we know the mode is Basic already... |
|
267 return ETrue; |
|
268 } |
|
269 |
|
270 // TFecOptionHandlerDelegator |
|
271 |
|
272 TModeSpecificFecOptionHandlerBase& TFecOptionHandlerDelegator::Handler(const TRetransmissionAndFlowControlOption& aFecOption) |
|
273 { |
|
274 TModeSpecificFecOptionHandlerBase* handler = ModeToHandler(aFecOption.LinkMode()); |
|
275 __ASSERT_ALWAYS(handler != NULL, Panic(EL2CAPUnknownChannelMode)); |
|
276 return *handler; |
|
277 } |
|
278 |
|
279 const TModeSpecificFecOptionHandlerBase& TFecOptionHandlerDelegator::Handler(const TRetransmissionAndFlowControlOption &aFecOption) const |
|
280 { |
|
281 const TModeSpecificFecOptionHandlerBase* handler = ModeToHandler(aFecOption.LinkMode()); |
|
282 __ASSERT_ALWAYS(handler != NULL, Panic(EL2CAPUnknownChannelMode)); |
|
283 return *handler; |
|
284 } |
|
285 |
|
286 TModeSpecificFecOptionHandlerBase* TFecOptionHandlerDelegator::ModeToHandler(TL2CapChannelMode aMode) |
|
287 { |
|
288 TModeSpecificFecOptionHandlerBase* processor = 0; |
|
289 switch (aMode) |
|
290 { |
|
291 case EL2CAPStreamingMode: |
|
292 processor = &iStreamingFecHandler; |
|
293 break; |
|
294 case EL2CAPEnhancedRetransmissionMode: |
|
295 processor = &iErtmFecHandler; |
|
296 break; |
|
297 case EL2CAPRetransmissionMode: |
|
298 case EL2CAPFlowControlMode: |
|
299 processor = &iLegacyFecHandler; |
|
300 break; |
|
301 case EL2CAPBasicMode: |
|
302 processor = &iBasicFecHandler; |
|
303 break; |
|
304 default: |
|
305 break; |
|
306 // yes, return NULL. |
|
307 } |
|
308 return processor; |
|
309 } |
|
310 |
|
311 const TModeSpecificFecOptionHandlerBase* TFecOptionHandlerDelegator::ModeToHandler(TL2CapChannelMode aMode) const |
|
312 { |
|
313 return const_cast<TFecOptionHandlerDelegator&>(*this).ModeToHandler(aMode); |
|
314 } |
|
315 |
|
316 #ifdef __FLOG_ACTIVE |
|
317 void TFecOptionHandlerDelegator::LogCurrentValues(const TRetransmissionAndFlowControlOption& aPreferred, |
|
318 const TRetransmissionAndFlowControlOption& aPeer) const |
|
319 { |
|
320 TBuf<TRetransmissionAndFlowControlOption::KReadableDesSpaceRequired> buf; |
|
321 aPeer.GetReadable(buf); |
|
322 LOG1(_L("\tCurrent Peer: %S"), &buf) |
|
323 buf.Zero(); |
|
324 aPreferred.GetReadable(buf); |
|
325 LOG1(_L("\tCurrent Preferred: %S"), &buf) |
|
326 } |
|
327 #endif |
|
328 |
|
329 // |
|
330 // TL2CapSingleDirectionFecNegotiatorBase |
|
331 // |
|
332 void TL2CapSingleDirectionFecNegotiatorBase::SetupForRenegotiation() |
|
333 { |
|
334 LOG_FUNC |
|
335 if (iFecNegotiator.DesiredMode() == EL2CAPBasicMode && |
|
336 // Only skip negotiating Basic if it still is the last accepted value. |
|
337 iPeer.LinkMode() == EL2CAPBasicMode) |
|
338 { |
|
339 // See comment in Setup(). |
|
340 iConfigStatus = EOptionConfigComplete; |
|
341 } |
|
342 #ifdef __FLOG_ACTIVE |
|
343 LogState(); |
|
344 #endif |
|
345 } |
|
346 |
|
347 TBool TL2CapSingleDirectionFecNegotiatorBase::IsPeerModeAcceptable(TL2CapChannelMode aPeerMode, |
|
348 TBool& aDisconnect) const |
|
349 { |
|
350 LOG_FUNC |
|
351 TBool acceptable = ETrue; |
|
352 aDisconnect = EFalse; |
|
353 |
|
354 LOG3(_L("\tNegotiation Behavior = %d, Desired Mode = %d, Peer Mode = %d"), |
|
355 iFecNegotiator.NegotiationBehavior(), iFecNegotiator.DesiredMode(), aPeerMode) |
|
356 |
|
357 if (iFecNegotiator.NegotiationBehavior() == TL2CapFecNegotiator::EState2) |
|
358 { |
|
359 if (iFecNegotiator.DesiredMode() != aPeerMode) |
|
360 { |
|
361 // Game over. |
|
362 acceptable = EFalse; |
|
363 aDisconnect = ETrue; |
|
364 } |
|
365 } |
|
366 else // some sort of State 1 |
|
367 { |
|
368 // A safety net - check that it's legal for our peer to propose this mode. |
|
369 if (!iFecNegotiator.IsModeLegal(aPeerMode)) |
|
370 { |
|
371 // Remote is behaving out of spec. |
|
372 acceptable = EFalse; |
|
373 LOG1(_L("Peer proposed an illegal mode = %d"), aPeerMode); |
|
374 } |
|
375 else |
|
376 { |
|
377 // Check that the mode is within our limits according to the spec-defined precedence |
|
378 // hierarchy. Note that the spec only defines the precedence and State 1/2 algorithm |
|
379 // for the new modes + Basic, but we try and apply it to the legacy modes as well for |
|
380 // predictable & consistent behavior. |
|
381 acceptable = aPeerMode <= iFecNegotiator.DesiredMode(); |
|
382 // Now, the State 1 algorithm gives us two choices in case peer proposes a mode |
|
383 // that's higher precedence than our desired mode (aPeerMode < iDesiredMode) - |
|
384 // - we can either accept it or close the connection - we cannot propose a different |
|
385 // one. EState1NoUnreliableToReliable means we do not want to allow fallback from an |
|
386 // unreliable mode to a reliable one, i.e. when we propose an unreliable mode, |
|
387 // but the remote proposes a reliable one (ERTM is higher prec. than Streaming, |
|
388 // ditto RTM vs FC). |
|
389 if (acceptable && iFecNegotiator.NegotiationBehavior() == TL2CapFecNegotiator::EState1NoUnreliableToReliable && |
|
390 (iFecNegotiator.DesiredMode() == EL2CAPStreamingMode || iFecNegotiator.DesiredMode() == EL2CAPFlowControlMode) && |
|
391 (aPeerMode == EL2CAPEnhancedRetransmissionMode || aPeerMode == EL2CAPRetransmissionMode)) |
|
392 { |
|
393 acceptable = EFalse; |
|
394 if (!(iFecNegotiator.DesiredMode() == EL2CAPFlowControlMode && aPeerMode == EL2CAPRetransmissionMode)) |
|
395 { |
|
396 // Only disconnect immediately if the peer seems to be implementing enhanced |
|
397 // modes - mostly to be interoperable with pre-2.1 Core Spec Addendum 1 Symbian |
|
398 // code, which doesn't handle disconnects well when there're still unresponded |
|
399 // request commands. |
|
400 // If we don't disconnect, a FEC for our desired mode will be sent, and we'll |
|
401 // see what happens - free style negotiation is allowed with legacy remotes. |
|
402 aDisconnect = ETrue; |
|
403 } |
|
404 LOG(_L("\tRefusing to fall back from Unreliable to Reliable")); |
|
405 } |
|
406 } |
|
407 } // State 1 |
|
408 |
|
409 LOG2(_L("\tPeer channel mode acceptable = %d, disconnect required = %d"), acceptable, aDisconnect); |
|
410 return acceptable; |
|
411 } |
|
412 |
|
413 #ifdef __FLOG_ACTIVE |
|
414 void TL2CapSingleDirectionFecNegotiatorBase::LogState() const |
|
415 { |
|
416 LOG3(_L("\tdesired channel mode = %d, mode negotiation behavior = %d, config status = %d"), |
|
417 iFecNegotiator.DesiredMode(), iFecNegotiator.NegotiationBehavior(), iConfigStatus) |
|
418 TBuf<TRetransmissionAndFlowControlOption::KReadableDesSpaceRequired> readable; |
|
419 iPreferred.GetReadable(readable); |
|
420 LOG1(_L("\tpreferred FEC = %S"), &readable); |
|
421 readable.Zero(); |
|
422 iPeer.GetReadable(readable); |
|
423 LOG1(_L("\tpeer FEC = %S"), &readable); |
|
424 } |
|
425 #endif |
|
426 |
|
427 // |
|
428 // TL2CapIncomingFecNegotiator |
|
429 // |
|
430 void TL2CapIncomingFecNegotiator::Setup() |
|
431 { |
|
432 LOG_FUNC |
|
433 // Set up spec default as initial peer value. |
|
434 iPeer = TRetransmissionAndFlowControlOption(); |
|
435 |
|
436 // Set up our initial request. |
|
437 BuildRequest(iFecNegotiator.DesiredMode(), iPreferred); |
|
438 |
|
439 if (iFecNegotiator.DesiredMode() == EL2CAPBasicMode) |
|
440 { |
|
441 // Basic mode is the implicit default, so it's complete unless peer says otherwise. |
|
442 // Besides, the fact that Basic is our desired mode normally means that the peer doesn't |
|
443 // support anything else, so it would not be able to parse a TRetransmissionAndFlowControl |
|
444 // option if we sent it. |
|
445 iConfigStatus = EOptionConfigComplete; |
|
446 } |
|
447 |
|
448 #ifdef __FLOG_ACTIVE |
|
449 LogState(); |
|
450 #endif |
|
451 } |
|
452 |
|
453 void TL2CapIncomingFecNegotiator::ProcessPeerValue(const TRetransmissionAndFlowControlOption& aFecOption, |
|
454 TBool aIsUnacceptableParameters) |
|
455 { |
|
456 LOG_FUNC |
|
457 |
|
458 iPeer = aFecOption; |
|
459 |
|
460 // 'return' parameter from IsPeerModeAcceptable() - we'll ignore it because in |
|
461 // incoming direction we disconnect if response config status is failed anyway. |
|
462 TBool disconnect; |
|
463 |
|
464 TBool peerAcceptable = IsPeerModeAcceptable(iPeer.LinkMode(), disconnect); |
|
465 if (peerAcceptable && !aIsUnacceptableParameters) |
|
466 { |
|
467 peerAcceptable = iFecNegotiator.ModeSpecificHandlers().IsPeerResponseAcceptable(iPreferred, iPeer); |
|
468 } |
|
469 |
|
470 if (!peerAcceptable) |
|
471 { |
|
472 iConfigStatus = EOptionConfigFailed; |
|
473 } |
|
474 else |
|
475 { |
|
476 if (aIsUnacceptableParameters) |
|
477 { |
|
478 iConfigStatus = EOptionConfigOutstanding; |
|
479 // Only take the channel mode from peer's proposal and set informational |
|
480 // (i.e. all other) parameters to our values. |
|
481 BuildRequest(aFecOption.LinkMode(), iPreferred); |
|
482 } |
|
483 else |
|
484 { |
|
485 iConfigStatus = EOptionConfigComplete; |
|
486 } |
|
487 } |
|
488 LOG1(_L("\tIncoming FEC Config Status is now %d"), iConfigStatus); |
|
489 } |
|
490 |
|
491 void TL2CapIncomingFecNegotiator::ProcessImplicitPeerValue() |
|
492 { |
|
493 LOG_FUNC |
|
494 // We need to assume that the peer accepted our request and sent an appropriate response back. |
|
495 TRetransmissionAndFlowControlOption response; |
|
496 iFecNegotiator.ModeSpecificHandlers().PrepareImplicitPeerResponse(response, iPreferred); |
|
497 ProcessPeerValue(response, EFalse); |
|
498 } |
|
499 |
|
500 void TL2CapIncomingFecNegotiator::BuildRequest(TL2CapChannelMode aMode, TRetransmissionAndFlowControlOption& aFecOption) |
|
501 { |
|
502 LOG_FUNC |
|
503 aFecOption = TRetransmissionAndFlowControlOption(aMode, ETrue); |
|
504 iFecNegotiator.ModeSpecificHandlers().SetMaxTransmit(aFecOption, iFecNegotiator.MaxTransmit()); |
|
505 iFecNegotiator.ModeSpecificHandlers().ZeroUnspecifiedRequestFields(aFecOption); |
|
506 } |
|
507 |
|
508 // |
|
509 // TL2CapOutgoingFecNegotiator |
|
510 // |
|
511 void TL2CapOutgoingFecNegotiator::Setup() |
|
512 { |
|
513 LOG_FUNC |
|
514 // Set up spec default as initial peer value. |
|
515 iPeer = TRetransmissionAndFlowControlOption(); |
|
516 |
|
517 // iPreferred will be constructed when we process peer value once a Config Request has been received. |
|
518 #ifdef __FLOG_ACTIVE |
|
519 LogState(); |
|
520 #endif |
|
521 } |
|
522 |
|
523 TInt TL2CapOutgoingFecNegotiator::ProcessPeerValue(const TRetransmissionAndFlowControlOption& aFecOption) |
|
524 { |
|
525 LOG_FUNC |
|
526 |
|
527 TInt err = KErrNone; |
|
528 TBool disconnect = EFalse; |
|
529 TBool peerModeAcceptable = IsPeerModeAcceptable(aFecOption.LinkMode(), disconnect); |
|
530 |
|
531 if (peerModeAcceptable) |
|
532 { |
|
533 iPeer = aFecOption; |
|
534 iIncludeValueInPositiveConfigResponse = iFecNegotiator.ModeSpecificHandlers().BuildPositiveResponse(iPreferred, iPeer); |
|
535 iConfigStatus = EOptionConfigComplete; |
|
536 } |
|
537 else |
|
538 { |
|
539 if (disconnect) |
|
540 { |
|
541 // Disconnect immediately without sending an Unacceptable Parameters response. |
|
542 iConfigStatus = EOptionConfigFailed; |
|
543 err = KErrConfigRejected; |
|
544 } |
|
545 else |
|
546 { |
|
547 iPreferred.SetLinkMode(iFecNegotiator.DesiredMode()); |
|
548 iFecNegotiator.ModeSpecificHandlers().BuildNegativeResponse(iPreferred, aFecOption); |
|
549 // Cause an Unacceptable Parameters response. |
|
550 iConfigStatus = EOptionConfigFailed; |
|
551 // Preferred contains our desired FEC, it will be included in the Unaccepted Parameters response. |
|
552 } |
|
553 } |
|
554 LOG1(_L("\tOutgoing FEC Config Status is now %d"), iConfigStatus); |
|
555 return err; |
|
556 } |
|
557 |
|
558 |
|
559 // |
|
560 // TL2CapFecNegotiator |
|
561 // |
|
562 TBool TL2CapFecNegotiator::Setup(TL2CapConfig::TChannelReliability aChannelReliability, |
|
563 TBool aLegacyModesDisallowed, |
|
564 const TL2CapEntityInfo& aPeerEntityConfig, |
|
565 TUint8 aMaxTransmit) |
|
566 { |
|
567 LOG_FUNC |
|
568 |
|
569 __ASSERT_DEBUG(aPeerEntityConfig.LinkInfoState() == EL2CapEntityInfoDefined, |
|
570 Panic(EL2CAPFecConfigAttemptWithoutPeerInfo)); |
|
571 iPeerSupportedModes = aPeerEntityConfig; |
|
572 iMaxTransmit = aMaxTransmit; |
|
573 |
|
574 TBool modeNegotiable = EFalse; |
|
575 |
|
576 iDesiredMode = EL2CAPBasicMode; |
|
577 |
|
578 // From 2.4 Modes of Operation: |
|
579 // "Flow Control Mode and Retransmission mode shall only be enabled when communicating with |
|
580 // L2CAP entities that do not support either Enhanced Retransmission mode or Streaming mode." |
|
581 // From 5.4 Retransmission And Flow Control Option: |
|
582 // "Basic mode, Flow Control mode and Retransmission mode shall only be used for backwards |
|
583 // compatibility with L2CAP entities that do not support Enhanced Retransmission mode or |
|
584 // Streaming mode." |
|
585 // |
|
586 // Make of that what you will, but the official Symbian interpretation is that RTM or FC may |
|
587 // only be used if the remote doesn't support any of the new modes. |
|
588 const TBool enhancedModeSupported = iPeerSupportedModes.SupportsEnhancedRetransmissionMode() || |
|
589 iPeerSupportedModes.SupportsStreamingMode(); |
|
590 |
|
591 switch (aChannelReliability) |
|
592 { |
|
593 case TL2CapConfig::EReliableChannel: |
|
594 iNegotiationBehavior = aLegacyModesDisallowed ? EState2 : EState1; |
|
595 if (iPeerSupportedModes.SupportsEnhancedRetransmissionMode()) |
|
596 { |
|
597 iDesiredMode = EL2CAPEnhancedRetransmissionMode; |
|
598 modeNegotiable = ETrue; |
|
599 } |
|
600 else if (!aLegacyModesDisallowed) |
|
601 { |
|
602 if (iPeerSupportedModes.SupportsRetranmission() && !enhancedModeSupported) |
|
603 { |
|
604 iDesiredMode = EL2CAPRetransmissionMode; |
|
605 modeNegotiable = ETrue; |
|
606 } |
|
607 else |
|
608 { |
|
609 iDesiredMode = EL2CAPBasicMode; |
|
610 modeNegotiable = ETrue; |
|
611 } |
|
612 } |
|
613 break; |
|
614 |
|
615 case TL2CapConfig::EUnreliableChannel: |
|
616 iNegotiationBehavior = aLegacyModesDisallowed ? EState2 : EState1NoUnreliableToReliable; |
|
617 if (iPeerSupportedModes.SupportsStreamingMode()) |
|
618 { |
|
619 iDesiredMode = EL2CAPStreamingMode; |
|
620 modeNegotiable = ETrue; |
|
621 } |
|
622 else if (!aLegacyModesDisallowed) |
|
623 { |
|
624 if (iPeerSupportedModes.SupportsFlowControl() && !enhancedModeSupported) |
|
625 { |
|
626 iDesiredMode = EL2CAPFlowControlMode; |
|
627 modeNegotiable = ETrue; |
|
628 } |
|
629 else |
|
630 { |
|
631 iDesiredMode = EL2CAPBasicMode; |
|
632 modeNegotiable = ETrue; |
|
633 } |
|
634 } |
|
635 break; |
|
636 |
|
637 case TL2CapConfig::EUnreliableDesiredChannel: |
|
638 // Be open to all proposals within spec-defined constraints. |
|
639 iNegotiationBehavior = EState1; |
|
640 if (iPeerSupportedModes.SupportsStreamingMode()) |
|
641 { |
|
642 iDesiredMode = EL2CAPStreamingMode; |
|
643 modeNegotiable = ETrue; |
|
644 } |
|
645 else if (iPeerSupportedModes.SupportsFlowControl() & !enhancedModeSupported) |
|
646 { |
|
647 iDesiredMode = EL2CAPFlowControlMode; |
|
648 modeNegotiable = ETrue; |
|
649 } |
|
650 else if (iPeerSupportedModes.SupportsEnhancedRetransmissionMode()) |
|
651 { |
|
652 iDesiredMode = EL2CAPEnhancedRetransmissionMode; |
|
653 modeNegotiable = ETrue; |
|
654 } |
|
655 else if (iPeerSupportedModes.SupportsRetranmission() && !enhancedModeSupported) |
|
656 { |
|
657 iDesiredMode = EL2CAPRetransmissionMode; |
|
658 modeNegotiable = ETrue; |
|
659 } |
|
660 else |
|
661 { |
|
662 iDesiredMode = EL2CAPBasicMode; |
|
663 modeNegotiable = ETrue; |
|
664 } |
|
665 break; |
|
666 } |
|
667 |
|
668 if (modeNegotiable) |
|
669 { |
|
670 iIncomingNegotiator.Setup(); |
|
671 iOutgoingNegotiator.Setup(); |
|
672 } |
|
673 return modeNegotiable; |
|
674 } |
|
675 |
|
676 void TL2CapFecNegotiator::SetupForRenegotiation() |
|
677 { |
|
678 LOG_FUNC |
|
679 iIncomingNegotiator.SetupForRenegotiation(); |
|
680 iOutgoingNegotiator.SetupForRenegotiation(); |
|
681 } |
|
682 |
|
683 // A helper that optimizes the negotiation process by downgrading incoming preferred mode |
|
684 // to Basic if the remote requests Basic, we accept it, and haven't sent out our request yet. |
|
685 // Caveat: This should be only called if our Config Request hasn't been sent yet |
|
686 // and we know we've received peer's Config Request. |
|
687 void TL2CapFecNegotiator::DowngradeIncomingToBasicIfOutgoingIsBasic() |
|
688 { |
|
689 LOG_FUNC |
|
690 // If we've already accepted Peer's Basic mode request, we may downgrade the incoming |
|
691 // direction to Basic as well, since FEC in a single direction is forbidden. |
|
692 // Otherwise we may end up with FEC in just one direction and would have to |
|
693 // downgrade and renegotiate anyway. |
|
694 // Note: this only makes sense if we haven't sent our Config Request yet. |
|
695 // The caller is responsible for checking this. |
|
696 if ((iNegotiationBehavior == EState1 || |
|
697 iNegotiationBehavior == EState1NoUnreliableToReliable) && |
|
698 iOutgoingNegotiator.ConfigOptionStatus() != TL2CapConfigurationOptionGroupBase::EOptionConfigFailed && |
|
699 iOutgoingNegotiator.Preferred().LinkMode() == EL2CAPBasicMode && |
|
700 iIncomingNegotiator.Preferred().LinkMode() != EL2CAPBasicMode) |
|
701 { |
|
702 LOG(_L("\tReceived Basic mode Config Request, downgrading incoming channel mode to Basic")); |
|
703 // Downgrade incoming FEC to be basic mode. |
|
704 TRetransmissionAndFlowControlOption basicFec; |
|
705 iIncomingNegotiator.SetPreferred(basicFec); |
|
706 } |
|
707 } |
|
708 |
|
709 TInt TL2CapFecNegotiator::CheckNegotiatedChannelMode(TBool& aDowngrade) |
|
710 { |
|
711 LOG_FUNC |
|
712 TInt err = KErrNone; |
|
713 |
|
714 if ((iNegotiationBehavior == EState1 || |
|
715 iNegotiationBehavior == EState1NoUnreliableToReliable) |
|
716 && |
|
717 ((iOutgoingNegotiator.Preferred().LinkMode() == EL2CAPBasicMode && |
|
718 iIncomingNegotiator.Peer().LinkMode() != EL2CAPBasicMode) |
|
719 || |
|
720 (iIncomingNegotiator.Peer().LinkMode() == EL2CAPBasicMode && |
|
721 iOutgoingNegotiator.Preferred().LinkMode() != EL2CAPBasicMode))) |
|
722 { |
|
723 LOG(_L("\tDowngrading unidirectional FEC to Basic in both directions")); |
|
724 |
|
725 TRetransmissionAndFlowControlOption basicFec; |
|
726 iIncomingNegotiator.SetPreferred(basicFec); |
|
727 iOutgoingNegotiator.SetPreferred(basicFec); |
|
728 |
|
729 SetupForRenegotiation(); |
|
730 aDowngrade = ETrue; |
|
731 } |
|
732 else if (IncomingLinkMode() != OutgoingLinkMode()) |
|
733 { |
|
734 LOG2(_L("\tSomehow managed to negotiate %d incoming mode and %d outgoing mode"), |
|
735 IncomingLinkMode(), OutgoingLinkMode()); |
|
736 err = KErrL2CAPNegotiatedDifferentModesForEachDirection; |
|
737 } |
|
738 else |
|
739 { |
|
740 aDowngrade = EFalse; |
|
741 } |
|
742 |
|
743 return err; |
|
744 } |
|
745 |
|
746 TBool TL2CapFecNegotiator::IsModeLegal(TL2CapChannelMode aPeerMode) const |
|
747 { |
|
748 LOG_FUNC |
|
749 TBool legal = ETrue; |
|
750 if ((aPeerMode == EL2CAPEnhancedRetransmissionMode && !iPeerSupportedModes.SupportsEnhancedRetransmissionMode()) || |
|
751 (aPeerMode == EL2CAPStreamingMode && !iPeerSupportedModes.SupportsStreamingMode()) || |
|
752 (aPeerMode == EL2CAPRetransmissionMode && !iPeerSupportedModes.SupportsRetranmission()) || |
|
753 (aPeerMode == EL2CAPFlowControlMode && !iPeerSupportedModes.SupportsFlowControl()) || |
|
754 // if any of the new modes is supported then none of the old ones shall be used |
|
755 ((aPeerMode == EL2CAPRetransmissionMode || aPeerMode == EL2CAPFlowControlMode) && |
|
756 (iPeerSupportedModes.SupportsEnhancedRetransmissionMode() || iPeerSupportedModes.SupportsStreamingMode()))) |
|
757 { |
|
758 legal = EFalse; |
|
759 } |
|
760 return legal; |
|
761 } |
|
762 |
|
763 // The enhanced modes are ordered according to the 2.1 Core Spec Addendum 1 |
|
764 // "state 1" precedence (pt 5.4), but in reverse order. |
|
765 // 1. Streaming |
|
766 // 2. ERTM |
|
767 // 3. Basic |
|
768 // The legacy modes are ordered similarly: |
|
769 // 1. Flow Control |
|
770 // 2. RTM |
|
771 // 3. Basic |
|
772 // Additionally pairs consisting of a legacy and a new mode are never in relation. |
|
773 static TBool operator<=(TL2CapChannelMode aLeft, TL2CapChannelMode aRight) |
|
774 { |
|
775 TBool inRelation = EFalse; |
|
776 switch(aLeft) |
|
777 { |
|
778 case EL2CAPBasicMode: |
|
779 inRelation = ETrue; |
|
780 break; |
|
781 |
|
782 case EL2CAPRetransmissionMode: |
|
783 switch (aRight) |
|
784 { |
|
785 case EL2CAPBasicMode: |
|
786 inRelation = EFalse; |
|
787 break; |
|
788 case EL2CAPRetransmissionMode: |
|
789 inRelation = ETrue; |
|
790 break; |
|
791 case EL2CAPFlowControlMode: |
|
792 inRelation = ETrue; |
|
793 break; |
|
794 case EL2CAPEnhancedRetransmissionMode: |
|
795 inRelation = EFalse; |
|
796 break; |
|
797 case EL2CAPStreamingMode: |
|
798 inRelation = EFalse; |
|
799 break; |
|
800 } |
|
801 break; |
|
802 |
|
803 case EL2CAPFlowControlMode: |
|
804 switch (aRight) |
|
805 { |
|
806 case EL2CAPBasicMode: |
|
807 inRelation = EFalse; |
|
808 break; |
|
809 case EL2CAPRetransmissionMode: |
|
810 inRelation = EFalse; |
|
811 break; |
|
812 case EL2CAPFlowControlMode: |
|
813 inRelation = ETrue; |
|
814 break; |
|
815 case EL2CAPEnhancedRetransmissionMode: |
|
816 inRelation = EFalse; |
|
817 break; |
|
818 case EL2CAPStreamingMode: |
|
819 inRelation = EFalse; |
|
820 break; |
|
821 } |
|
822 break; |
|
823 |
|
824 case EL2CAPEnhancedRetransmissionMode: |
|
825 switch (aRight) |
|
826 { |
|
827 case EL2CAPBasicMode: |
|
828 inRelation = EFalse; |
|
829 break; |
|
830 case EL2CAPRetransmissionMode: |
|
831 inRelation = EFalse; |
|
832 break; |
|
833 case EL2CAPFlowControlMode: |
|
834 inRelation = EFalse; |
|
835 break; |
|
836 case EL2CAPEnhancedRetransmissionMode: |
|
837 inRelation = ETrue; |
|
838 break; |
|
839 case EL2CAPStreamingMode: |
|
840 inRelation = ETrue; |
|
841 break; |
|
842 } |
|
843 break; |
|
844 |
|
845 case EL2CAPStreamingMode: |
|
846 switch (aRight) |
|
847 { |
|
848 case EL2CAPBasicMode: |
|
849 inRelation = EFalse; |
|
850 break; |
|
851 case EL2CAPRetransmissionMode: |
|
852 inRelation = EFalse; |
|
853 break; |
|
854 case EL2CAPFlowControlMode: |
|
855 inRelation = EFalse; |
|
856 break; |
|
857 case EL2CAPEnhancedRetransmissionMode: |
|
858 inRelation = EFalse; |
|
859 break; |
|
860 case EL2CAPStreamingMode: |
|
861 inRelation = ETrue; |
|
862 break; |
|
863 } |
|
864 break; |
|
865 } |
|
866 |
|
867 return inRelation; |
|
868 } |
|
869 |
|
870 template<typename T> |
|
871 static inline TBool IsWithinBounds(const T aValue, const T aLeftBound, const T aRightBound) |
|
872 { |
|
873 return aLeftBound <= aValue && aValue <= aRightBound; |
|
874 } |