|
1 // Copyright (c) 2004-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 #include <bluetooth/logger.h> |
|
17 |
|
18 #include "l2capSigPacketConfigure.h" |
|
19 |
|
20 #include "l2capSignalHandler.h" |
|
21 #include "L2CapChannelConfig.h" |
|
22 |
|
23 #include "l2util.h" |
|
24 |
|
25 #ifdef __FLOG_ACTIVE |
|
26 _LIT8(KLogComponent, LOG_COMPONENT_L2CAP); |
|
27 #endif |
|
28 |
|
29 // CONFIGURE REQUEST COMMAND |
|
30 |
|
31 |
|
32 //Pass in a TL2ConfigOptions packets. Any options set to valid will be negotiated with there set values |
|
33 HConfigureRequest* HConfigureRequest::New(TL2CAPPort aRemotePort, CL2CapChannelConfig& aConfig, |
|
34 TUint8 aRTXTimerDuration, |
|
35 TUint16 aERTXTimerDuration) |
|
36 |
|
37 { |
|
38 LOG_STATIC_FUNC |
|
39 HConfigureRequest* cmd = NULL; |
|
40 RMBufChain buf; |
|
41 TRAPD(rerr, buf.AllocL(KConfigRequestEmptyLength)); |
|
42 if(rerr == KErrNone) |
|
43 { |
|
44 cmd = new HConfigureRequest(buf, aRTXTimerDuration, aERTXTimerDuration); |
|
45 if(cmd) |
|
46 { |
|
47 // Setup message contents. |
|
48 cmd->SetCode(EConfigureRequest); |
|
49 cmd->SetID(KUninitialisedID); |
|
50 |
|
51 cmd->SetDestinationCID(aRemotePort); |
|
52 cmd->SetFlags(KNoConfigurationFlags); |
|
53 |
|
54 // Add the options |
|
55 rerr = cmd->AddOptionsToCommand(aConfig); |
|
56 if(rerr != KErrNone) |
|
57 { |
|
58 delete cmd; |
|
59 cmd = NULL; |
|
60 } |
|
61 } |
|
62 else |
|
63 { |
|
64 // Free the allocated buffer. |
|
65 buf.Free(); |
|
66 } |
|
67 } |
|
68 return cmd; |
|
69 } |
|
70 |
|
71 /** |
|
72 Verifies that the buffer contains a structurally correct command. |
|
73 This does not ensure that the content of the command is semantically valid. |
|
74 |
|
75 @param aCommmand A new HL2CapCommand if the buffer contains a structurally valid command. |
|
76 @param aBuffer The buffer containing the command |
|
77 @return KErrNone if the command if created. |
|
78 KErrNoMemory if the command structure is valid but cannot be created. |
|
79 KErrCorrupt if the command structure is invalid. |
|
80 */ |
|
81 TInt HConfigureRequest::NewCommandIfValid(RMBufChain& aBuffer, HL2CapCommand*& aCommand) |
|
82 { |
|
83 LOG_STATIC_FUNC |
|
84 TInt length = aBuffer.Length(); |
|
85 if(length < KConfigRequestEmptyLength) |
|
86 { |
|
87 // Dodge length! |
|
88 return KErrCorrupt; |
|
89 } |
|
90 |
|
91 if(TL2CapConfigParamOptions::VerifyOptionsStructure(KOptionsOffset, aBuffer)) |
|
92 { |
|
93 // Top! The structure's fine, go ahead and create the command. |
|
94 aCommand = new HConfigureRequest(aBuffer); |
|
95 if(aCommand) |
|
96 { |
|
97 return KErrNone; |
|
98 } |
|
99 else |
|
100 { |
|
101 return KErrNoMemory; |
|
102 } |
|
103 } |
|
104 else |
|
105 { |
|
106 // We'll not have any of this nonsense! |
|
107 return KErrCorrupt; |
|
108 } |
|
109 } |
|
110 |
|
111 HConfigureRequest::HConfigureRequest(RMBufChain& aCommand, |
|
112 TUint8 aRTXTimerDuration, |
|
113 TUint16 aERTXTimerDuration) |
|
114 : HL2CapCommand(aCommand, aRTXTimerDuration, aERTXTimerDuration) |
|
115 { |
|
116 LOG_FUNC |
|
117 } |
|
118 |
|
119 TBool HConfigureRequest::ProcessCommand(CL2CapSignalHandler& aSignalHandler) |
|
120 { |
|
121 LOG_FUNC |
|
122 if(aSignalHandler.HandleConfigureRequest(this)) |
|
123 { |
|
124 // The command has been handled. Delete it. |
|
125 delete this; |
|
126 return ETrue; |
|
127 } |
|
128 else |
|
129 { |
|
130 return EFalse; |
|
131 } |
|
132 } |
|
133 |
|
134 TInt HConfigureRequest::ParseOptions(TL2CapConfigParamOptions& aConfigOptions, RMBufChain& aUnknownOptions) const |
|
135 { |
|
136 LOG_FUNC |
|
137 return aConfigOptions.ParseOptions(KOptionsOffset, iCommand, aUnknownOptions); |
|
138 } |
|
139 |
|
140 TInt HConfigureRequest::AddOptionsToCommand(CL2CapChannelConfig& aConfig) |
|
141 { |
|
142 LOG_FUNC |
|
143 TInt rerr = TL2CapConfigParamOptions::AddConfigRequestOptions(aConfig, KOptionsOffset, iCommand); |
|
144 if(rerr == KErrNone) |
|
145 { |
|
146 WriteDataLength(); |
|
147 } |
|
148 return rerr; |
|
149 } |
|
150 |
|
151 |
|
152 // CONFIGURE RESPONSE COMMAND |
|
153 //Constructs a command response ready for transmission |
|
154 HConfigureResponse* HConfigureResponse::New(TUint8 aId, TL2CAPPort aRemotePort, TConfigFlags aFlags, TConfigResponseResult aResult) |
|
155 { |
|
156 LOG_STATIC_FUNC |
|
157 HConfigureResponse* cmd = NULL; |
|
158 RMBufChain buf; |
|
159 TRAPD(rerr, buf.AllocL(KConfigResponseEmptyLength)); |
|
160 if(rerr == KErrNone) |
|
161 { |
|
162 cmd = new HConfigureResponse(buf); |
|
163 if(cmd) |
|
164 { |
|
165 // Setup message contents. |
|
166 cmd->SetCode(EConfigureResponse); |
|
167 cmd->SetID(aId); |
|
168 |
|
169 cmd->SetSourceCID(aRemotePort); |
|
170 cmd->SetFlags(aFlags); |
|
171 cmd->SetResults(aResult); |
|
172 } |
|
173 else |
|
174 { |
|
175 // Free the allocated buffer. |
|
176 buf.Free(); |
|
177 } |
|
178 } |
|
179 return cmd; |
|
180 } |
|
181 |
|
182 /** |
|
183 Verifies that the buffer contains a structurally correct command. |
|
184 This does not ensure that the content of the command is semantically valid. |
|
185 |
|
186 @param aCommmand A new HL2CapCommand if the buffer contains a structurally valid command. |
|
187 @param aBuffer The buffer containing the command |
|
188 @return KErrNone if the command if created. |
|
189 KErrNoMemory if the command structure is valid but cannot be created. |
|
190 KErrCorrupt if the command structure is invalid. |
|
191 */ |
|
192 TInt HConfigureResponse::NewCommandIfValid(RMBufChain& aBuffer, HL2CapCommand*& aCommand) |
|
193 { |
|
194 LOG_STATIC_FUNC |
|
195 if(aBuffer.Length() < KConfigResponseEmptyLength) |
|
196 { |
|
197 // Dodge length! |
|
198 return KErrCorrupt; |
|
199 } |
|
200 |
|
201 if(TL2CapConfigParamOptions::VerifyOptionsStructure(KOptionsOffset, aBuffer)) |
|
202 { |
|
203 // Top! The structure's fine, go ahead and create the command. |
|
204 aCommand = new HConfigureResponse(aBuffer); |
|
205 if(aCommand) |
|
206 { |
|
207 return KErrNone; |
|
208 } |
|
209 else |
|
210 { |
|
211 return KErrNoMemory; |
|
212 } |
|
213 } |
|
214 else |
|
215 { |
|
216 // We'll not have any of this nonsense! |
|
217 return KErrCorrupt; |
|
218 } |
|
219 } |
|
220 |
|
221 HConfigureResponse::HConfigureResponse(RMBufChain& aCommand) |
|
222 : HL2CapCommand(aCommand) |
|
223 { |
|
224 LOG_FUNC |
|
225 } |
|
226 |
|
227 TBool HConfigureResponse::ProcessCommand(CL2CapSignalHandler& aSignalHandler) |
|
228 { |
|
229 LOG_FUNC |
|
230 if(aSignalHandler.HandleConfigureResponse(this)) |
|
231 { |
|
232 // The command has been handled. Delete it. |
|
233 delete this; |
|
234 return ETrue; |
|
235 } |
|
236 else |
|
237 { |
|
238 return EFalse; |
|
239 } |
|
240 } |
|
241 |
|
242 //Put this here to allow base function to be protected, ie not all commands expose functionality |
|
243 TInt HConfigureResponse::ParseOptions(TL2CapConfigParamOptions& aConfigOptions, RMBufChain& aUnknownOptions) const |
|
244 { |
|
245 LOG_FUNC |
|
246 return aConfigOptions.ParseOptions(KOptionsOffset, iCommand, aUnknownOptions); |
|
247 } |
|
248 |
|
249 TInt HConfigureResponse::AddOptionsToCommand(CL2CapChannelConfig& aConfig, TConfigResponseResult aResult) |
|
250 { |
|
251 LOG_FUNC |
|
252 TInt rerr = TL2CapConfigParamOptions::AddConfigResponseOptions(aConfig, KOptionsOffset, iCommand, aResult); |
|
253 if(rerr == KErrNone) |
|
254 { |
|
255 WriteDataLength(); |
|
256 } |
|
257 return rerr; |
|
258 } |
|
259 |
|
260 void HConfigureResponse::AddUnknownOptionsToCommand(RMBufChain& aUnknownOptions) |
|
261 { |
|
262 LOG_FUNC |
|
263 iCommand.Append(aUnknownOptions); |
|
264 WriteDataLength(); |
|
265 } |
|
266 |
|
267 |
|
268 TL2CapConfigParamOptions::TL2CapConfigParamOptions() |
|
269 : iMtuSet(EFalse), |
|
270 iMtu(ML2CapConfigurationOption::ESpecDefaultValue), |
|
271 iFlushTimeoutSet(EFalse), |
|
272 iFlushTimeout(ML2CapConfigurationOption::ESpecDefaultValue), |
|
273 iFecSet(EFalse), |
|
274 iQosSet(EFalse), |
|
275 iQos(ML2CapConfigurationOption::ESpecDefaultValue) |
|
276 { |
|
277 LOG_FUNC |
|
278 } |
|
279 |
|
280 TBool TL2CapConfigParamOptions::operator==(const TL2CapConfigParamOptions& aThat) |
|
281 { |
|
282 LOG_FUNC |
|
283 // The exactly same options must be included in both sets... |
|
284 if (iMtuSet != aThat.iMtuSet || |
|
285 iFlushTimeoutSet != aThat.iFlushTimeoutSet || |
|
286 iFecSet != aThat.iFecSet || |
|
287 iQosSet != aThat.iQosSet) |
|
288 { |
|
289 return EFalse; |
|
290 } |
|
291 else |
|
292 { |
|
293 // ... and the included option's values must be the same. |
|
294 return (!iMtuSet || iMtu == aThat.iMtu) && |
|
295 (!iFlushTimeoutSet || iFlushTimeout == aThat.iFlushTimeout) && |
|
296 (!iFecSet || iFec == aThat.iFec) && |
|
297 (!iQosSet || iQos == aThat.iQos); |
|
298 } |
|
299 } |
|
300 |
|
301 TInt TL2CapConfigParamOptions::ParseOptions(TUint8 aOptionOffset, const RMBufChain& aCommand, RMBufChain& aUnknownOptions) |
|
302 { |
|
303 LOG_FUNC |
|
304 TUint8 optionDataLen = 0; |
|
305 TInt startOfCurrentOption = aOptionOffset; |
|
306 TInt commandLength = aCommand.Length(); |
|
307 TInt rerr = KErrNone; |
|
308 |
|
309 // Parse the command options. Ensure that there is at least an option header |
|
310 // left to read. |
|
311 while(startOfCurrentOption + KOptionHeaderLength <= commandLength && |
|
312 (rerr == KErrNone || rerr == KErrConfigUnknownOptions)) |
|
313 { |
|
314 TBuf8<KOptionHeaderLength> headerBuf(KOptionHeaderLength); |
|
315 aCommand.CopyOut(headerBuf, startOfCurrentOption); |
|
316 |
|
317 TUint8 optionType = headerBuf[KTypeOffset]; |
|
318 optionDataLen = headerBuf[KLengthOffset]; |
|
319 |
|
320 // Switch on the option type. Option type could have hint bit set, remove it |
|
321 switch(optionType & ~KOptionTypeIsHintMask) |
|
322 { |
|
323 case EConfigOptionTypeMTU: |
|
324 { |
|
325 TBuf8<KMTUOptionDataLen> mtuBuf(KMTUOptionDataLen); |
|
326 aCommand.CopyOut(mtuBuf, startOfCurrentOption + KDataOffset); |
|
327 |
|
328 TMTUOption mtu(LittleEndian::Get16(mtuBuf.Ptr())); |
|
329 SetMtu(mtu); |
|
330 } |
|
331 break; |
|
332 |
|
333 case EConfigOptionTypeFlushTimeoutDuration: |
|
334 { |
|
335 TBuf8<KFlushOptionDataLen> flushTimeoutBuf(KFlushOptionDataLen); |
|
336 aCommand.CopyOut(flushTimeoutBuf, startOfCurrentOption + KDataOffset); |
|
337 |
|
338 TFlushTimeoutDurationOption flushTimeoutDuration(LittleEndian::Get16(flushTimeoutBuf.Ptr())); |
|
339 SetFlushTimeout(flushTimeoutDuration); |
|
340 } |
|
341 break; |
|
342 |
|
343 case EConfigOptionTypeQOS: |
|
344 { |
|
345 TBuf8<KQOSOptionDataLen> qosBuf(KQOSOptionDataLen); |
|
346 aCommand.CopyOut(qosBuf, startOfCurrentOption + KDataOffset); |
|
347 |
|
348 TQualityOfServiceOption qos(static_cast<TQOSServiceType>(qosBuf[KQOSServiceTypeOffset]), |
|
349 LittleEndian::Get32(qosBuf.Ptr()+KTokenRateOffset), |
|
350 LittleEndian::Get32(qosBuf.Ptr()+KTokenBucketSizeOffset), |
|
351 LittleEndian::Get32(qosBuf.Ptr()+KPeakBandwidthOffset), |
|
352 LittleEndian::Get32(qosBuf.Ptr()+KLatencyOffset), |
|
353 LittleEndian::Get32(qosBuf.Ptr()+KDelayVariationOffset)); |
|
354 SetQos(qos); |
|
355 } |
|
356 break; |
|
357 |
|
358 case EConfigOptionTypeRTxAndFEC: |
|
359 { |
|
360 TBuf8<KFECOptionDataLen> fecBuf(KFECOptionDataLen); |
|
361 aCommand.CopyOut(fecBuf, startOfCurrentOption + KDataOffset); |
|
362 |
|
363 TRetransmissionAndFlowControlOption fec(static_cast<TL2CapChannelMode>(fecBuf[KLinkModeOffset]), |
|
364 fecBuf[KTxWindowSizeOffset], |
|
365 fecBuf[KMaxTransmitOffset], |
|
366 LittleEndian::Get16(fecBuf.Ptr() + KRetransmissionTimeoutOffset), |
|
367 LittleEndian::Get16(fecBuf.Ptr() + KMonitorTimeoutOffset), |
|
368 LittleEndian::Get16(fecBuf.Ptr() + KMaximumPDUSizeOffset)); |
|
369 SetFec(fec); |
|
370 } |
|
371 break; |
|
372 |
|
373 case EConfigOptionTypeFcs: |
|
374 // Special case. Even though we don't support the 'FCS option' option |
|
375 // (i.e. we always do FCS), this can be silently ignored because of |
|
376 // its specific semantics: FCS is only disabled on a channel on which |
|
377 // both ends include this option with the value = 'No FCS'. Since we |
|
378 // will never do that, the value we receive from the peer has no effect |
|
379 // and can be ignored instead of responding with 'Unknown Option', |
|
380 // even though 'FCS Option' is 0 in our supported feature mask - some |
|
381 // people still send the option even in this case. |
|
382 break; |
|
383 |
|
384 default: |
|
385 { |
|
386 // Store the unknown options into the buffer argument. |
|
387 // If the hint bit is set (MSB of option type field) ignore the unknown |
|
388 // parameter. |
|
389 if(!(optionType & KOptionTypeIsHintMask)) |
|
390 { |
|
391 // This is not a hint option - add it to the list of unknown options |
|
392 // to be sent in the subsequent response. |
|
393 RMBufChain unknownOption; |
|
394 TRAP(rerr, aCommand.CopyL(unknownOption, startOfCurrentOption, KOptionHeaderLength + optionDataLen)); |
|
395 if(rerr == KErrNone) |
|
396 { |
|
397 aUnknownOptions.Append(unknownOption); |
|
398 rerr = KErrConfigUnknownOptions; |
|
399 } |
|
400 } |
|
401 } |
|
402 break; |
|
403 } |
|
404 |
|
405 // Move to the next option. |
|
406 startOfCurrentOption += (optionDataLen + KOptionHeaderLength); |
|
407 } |
|
408 return rerr; |
|
409 } |
|
410 |
|
411 /*static*/ TInt TL2CapConfigParamOptions::AddConfigResponseOptions(CL2CapChannelConfig& aConfig, TUint8 aOptionOffset, RMBufChain& aOptions, TConfigResponseResult aResult) |
|
412 { |
|
413 LOG_STATIC_FUNC |
|
414 TInt rerr = KErrNone; |
|
415 TInt currentCommandIndex = 0; |
|
416 // General rule is that we include accepted options only in positive responses. |
|
417 TBool isUnacceptableParams = (aResult == EConfigUnacceptableParams); |
|
418 |
|
419 const TL2CapConfigurationOptionGroupBase::TOptionConfigStatus mtuStatus = aConfig.OutgoingMTU().ConfigOptionStatus(); |
|
420 const TL2CapConfigurationOptionGroupBase::TOptionConfigStatus flushToStatus = aConfig.IncomingFlushTimeout().ConfigOptionStatus(); |
|
421 const TL2CapConfigurationOptionGroupBase::TOptionConfigStatus qosStatus = aConfig.IncomingQOS().ConfigOptionStatus(); |
|
422 const TL2CapConfigurationOptionGroupBase::TOptionConfigStatus fecStatus = aConfig.FecNegotiator().OutgoingConfigOptionStatus(); |
|
423 |
|
424 __ASSERT_DEBUG(isUnacceptableParams || |
|
425 (mtuStatus != TL2CapConfigurationOptionGroupBase::EOptionConfigOutstanding && |
|
426 flushToStatus != TL2CapConfigurationOptionGroupBase::EOptionConfigOutstanding && |
|
427 qosStatus != TL2CapConfigurationOptionGroupBase::EOptionConfigOutstanding && |
|
428 fecStatus != TL2CapConfigurationOptionGroupBase::EOptionConfigOutstanding), |
|
429 Panic(EL2CapConstructingPositiveConfigResponseWithUnresolvedOptionStatus)); |
|
430 |
|
431 // The BT spec (sec 5.1) specifies that positive Config Responses will always |
|
432 // contain the MTU that is to be used on the channel. |
|
433 if (!(isUnacceptableParams && mtuStatus != TL2CapConfigurationOptionGroupBase::EOptionConfigFailed)) |
|
434 { |
|
435 TRAP(rerr, currentCommandIndex += AddMtuOptionL(aConfig.OutgoingMTU().Preferred().MTU(), |
|
436 aOptionOffset + currentCommandIndex, |
|
437 aOptions)); |
|
438 } |
|
439 |
|
440 if (rerr == KErrNone && |
|
441 ((isUnacceptableParams && flushToStatus == TL2CapConfigurationOptionGroupBase::EOptionConfigFailed) || |
|
442 (!isUnacceptableParams && aConfig.IncomingFlushTimeout().NeedToIncludeInPositiveConfigResponse()))) |
|
443 { |
|
444 TRAP(rerr, currentCommandIndex += AddFlushOptionL(aConfig.IncomingFlushTimeout().Preferred().FlushTimeoutDuration(), |
|
445 aOptionOffset + currentCommandIndex, |
|
446 aOptions)); |
|
447 } |
|
448 |
|
449 if (rerr == KErrNone && |
|
450 ((isUnacceptableParams && qosStatus == TL2CapConfigurationOptionGroupBase::EOptionConfigFailed) || |
|
451 (!isUnacceptableParams && aConfig.IncomingQOS().NeedToIncludeInPositiveConfigResponse()))) |
|
452 { |
|
453 TRAP(rerr, currentCommandIndex += AddQosOptionL(aConfig.IncomingQOS().Preferred(), |
|
454 aOptionOffset + currentCommandIndex, |
|
455 aOptions)); |
|
456 } |
|
457 |
|
458 if (rerr == KErrNone && |
|
459 ((isUnacceptableParams && fecStatus == TL2CapConfigurationOptionGroupBase::EOptionConfigFailed) || |
|
460 (!isUnacceptableParams && aConfig.FecNegotiator().NeedToIncludeInPositiveConfigResponse()))) |
|
461 { |
|
462 TRAP(rerr, currentCommandIndex += AddFecOptionL(aConfig.FecNegotiator().OutgoingPreferred(), |
|
463 aOptionOffset + currentCommandIndex, |
|
464 aOptions)); |
|
465 } |
|
466 |
|
467 return rerr; |
|
468 } |
|
469 |
|
470 /*static*/ TInt TL2CapConfigParamOptions::AddConfigRequestOptions(CL2CapChannelConfig& aConfig, TUint8 aOptionOffset, RMBufChain& aOptions) |
|
471 { |
|
472 LOG_STATIC_FUNC |
|
473 TInt rerr = KErrNone; |
|
474 TInt currentCommandIndex = 0; |
|
475 |
|
476 // Config Request parameters. |
|
477 |
|
478 if(aConfig.IncomingMTU().ConfigOptionStatus() != TL2CapConfigurationOptionGroupBase::EOptionConfigComplete && rerr == KErrNone) |
|
479 { |
|
480 TRAP(rerr, currentCommandIndex += AddMtuOptionL(aConfig.IncomingMTU().Preferred().MTU(), |
|
481 aOptionOffset + currentCommandIndex, |
|
482 aOptions)); |
|
483 } |
|
484 |
|
485 if(aConfig.OutgoingFlushTimeout().ConfigOptionStatus() != TL2CapConfigurationOptionGroupBase::EOptionConfigComplete && rerr == KErrNone) |
|
486 { |
|
487 TRAP(rerr, currentCommandIndex += AddFlushOptionL(aConfig.OutgoingFlushTimeout().Preferred().FlushTimeoutDuration(), |
|
488 aOptionOffset + currentCommandIndex, |
|
489 aOptions)); |
|
490 } |
|
491 |
|
492 if(aConfig.OutgoingQOS().ConfigOptionStatus() != TL2CapConfigurationOptionGroupBase::EOptionConfigComplete && rerr == KErrNone) |
|
493 { |
|
494 TRAP(rerr, currentCommandIndex += AddQosOptionL(aConfig.OutgoingQOS().Preferred(), |
|
495 aOptionOffset + currentCommandIndex, |
|
496 aOptions)); |
|
497 } |
|
498 |
|
499 if(aConfig.FecNegotiator().IncomingConfigOptionStatus() != TL2CapConfigurationOptionGroupBase::EOptionConfigComplete && rerr == KErrNone) |
|
500 { |
|
501 TRAP(rerr, currentCommandIndex += AddFecOptionL(aConfig.FecNegotiator().IncomingPreferred(), |
|
502 aOptionOffset + currentCommandIndex, |
|
503 aOptions)); |
|
504 } |
|
505 |
|
506 return rerr; |
|
507 } |
|
508 |
|
509 /* static */ TInt TL2CapConfigParamOptions::AddMtuOptionL(TInt16 aMtu, TUint8 aOptionOffset, RMBufChain& aOptions) |
|
510 { |
|
511 LOG_STATIC_FUNC |
|
512 aOptions.AppendL(KOptionHeaderLength + KMTUOptionDataLen); |
|
513 |
|
514 TBuf8<KOptionHeaderLength + KMTUOptionDataLen> mtuBuf(KOptionHeaderLength + KMTUOptionDataLen); |
|
515 |
|
516 mtuBuf[KTypeOffset] = EConfigOptionTypeMTU; |
|
517 mtuBuf[KLengthOffset] = KMTUOptionDataLen; |
|
518 LittleEndian::Put16(&mtuBuf[KDataOffset], aMtu); |
|
519 |
|
520 aOptions.CopyIn(mtuBuf, aOptionOffset); |
|
521 |
|
522 return KOptionHeaderLength + KMTUOptionDataLen; |
|
523 } |
|
524 |
|
525 /* static */ TInt TL2CapConfigParamOptions::AddFlushOptionL(TInt16 aFlushTimeout, TUint8 aOptionOffset, RMBufChain& aOptions) |
|
526 { |
|
527 LOG_STATIC_FUNC |
|
528 aOptions.AppendL(KOptionHeaderLength + KFlushOptionDataLen); |
|
529 |
|
530 TBuf8<KOptionHeaderLength + KFlushOptionDataLen> flushBuf(KOptionHeaderLength + KFlushOptionDataLen); |
|
531 |
|
532 flushBuf[KTypeOffset] = EConfigOptionTypeFlushTimeoutDuration; |
|
533 flushBuf[KLengthOffset] = KFlushOptionDataLen; |
|
534 LittleEndian::Put16(&flushBuf[KDataOffset], aFlushTimeout); |
|
535 |
|
536 aOptions.CopyIn(flushBuf, aOptionOffset); |
|
537 |
|
538 return KOptionHeaderLength + KFlushOptionDataLen; |
|
539 } |
|
540 |
|
541 /* static */ TInt TL2CapConfigParamOptions::AddQosOptionL(const TQualityOfServiceOption& aQosOption, TUint8 aOptionOffset, RMBufChain& aOptions) |
|
542 { |
|
543 LOG_STATIC_FUNC |
|
544 aOptions.AppendL(KOptionHeaderLength + KQOSOptionDataLen); |
|
545 |
|
546 TBuf8<KOptionHeaderLength + KQOSOptionDataLen> qosBuf(KOptionHeaderLength + KQOSOptionDataLen); |
|
547 |
|
548 qosBuf[KTypeOffset] = EConfigOptionTypeQOS; |
|
549 qosBuf[KLengthOffset] = KQOSOptionDataLen; |
|
550 qosBuf[KDataOffset] = 0; |
|
551 |
|
552 // Now insert each of the QOS options |
|
553 qosBuf[KDataOffset + KQOSServiceTypeOffset] = static_cast<TUint8>(aQosOption.ServiceType()); |
|
554 LittleEndian::Put32(&qosBuf[KDataOffset + KTokenRateOffset], aQosOption.TokenRate()); |
|
555 LittleEndian::Put32(&qosBuf[KDataOffset + KTokenBucketSizeOffset], aQosOption.TokenBucketSize()); |
|
556 LittleEndian::Put32(&qosBuf[KDataOffset + KPeakBandwidthOffset], aQosOption.PeakBandwidth()); |
|
557 LittleEndian::Put32(&qosBuf[KDataOffset + KLatencyOffset], aQosOption.Latency()); |
|
558 LittleEndian::Put32(&qosBuf[KDataOffset + KDelayVariationOffset], aQosOption.DelayVariation()); |
|
559 |
|
560 aOptions.CopyIn(qosBuf, aOptionOffset); |
|
561 |
|
562 return KOptionHeaderLength + KQOSOptionDataLen; |
|
563 } |
|
564 |
|
565 /* static */ TInt TL2CapConfigParamOptions::AddFecOptionL(const TRetransmissionAndFlowControlOption& aFecOption, TUint8 aOptionOffset, RMBufChain& aOptions) |
|
566 { |
|
567 LOG_STATIC_FUNC |
|
568 aOptions.AppendL(KOptionHeaderLength + KFECOptionDataLen); |
|
569 |
|
570 TBuf8<KOptionHeaderLength + KFECOptionDataLen> fecBuf(KOptionHeaderLength + KFECOptionDataLen); |
|
571 |
|
572 fecBuf[KTypeOffset] = EConfigOptionTypeRTxAndFEC; |
|
573 fecBuf[KLengthOffset] = KFECOptionDataLen; |
|
574 |
|
575 fecBuf[KDataOffset] = aFecOption.LinkModeAsUnsignedByte(); |
|
576 fecBuf[KDataOffset + KTxWindowSizeOffset] = aFecOption.TxWindowSize(); |
|
577 fecBuf[KDataOffset + KMaxTransmitOffset] = aFecOption.MaxTransmit(); |
|
578 LittleEndian::Put16(&fecBuf[KDataOffset + KRetransmissionTimeoutOffset], aFecOption.RetransmissionTimeout()); |
|
579 LittleEndian::Put16(&fecBuf[KDataOffset + KMonitorTimeoutOffset], aFecOption.MonitorTimeout()); |
|
580 LittleEndian::Put16(&fecBuf[KDataOffset + KMaximumPDUSizeOffset], aFecOption.MaximumPDUSize()); |
|
581 |
|
582 aOptions.CopyIn(fecBuf, aOptionOffset); |
|
583 |
|
584 return KOptionHeaderLength + KFECOptionDataLen; |
|
585 } |
|
586 |
|
587 /* static */ TBool TL2CapConfigParamOptions::VerifyOptionsStructure(TUint8 aOptionOffset, const RMBufChain& aCommand) |
|
588 { |
|
589 LOG_STATIC_FUNC |
|
590 TUint8 optionDataLen = 0; |
|
591 TInt startOfCurrentOption = aOptionOffset; |
|
592 TInt commandLength = aCommand.Length(); |
|
593 TBuf8<KOptionHeaderLength> headerBuf(KOptionHeaderLength); |
|
594 |
|
595 TBool valid = ETrue; |
|
596 // Parse the command options. Ensure that there is at least an option header |
|
597 // left to read. |
|
598 while(startOfCurrentOption + KOptionHeaderLength <= commandLength && valid) |
|
599 { |
|
600 aCommand.CopyOut(headerBuf, startOfCurrentOption); |
|
601 |
|
602 TUint8 optionType = headerBuf[KTypeOffset]; |
|
603 optionDataLen = headerBuf[KLengthOffset]; |
|
604 |
|
605 // Switch on the option type. Option type could have hint bit set, remove it |
|
606 switch(optionType & ~KOptionTypeIsHintMask) |
|
607 { |
|
608 case EConfigOptionTypeMTU: |
|
609 if(optionDataLen != KMTUOptionDataLen || |
|
610 startOfCurrentOption + KOptionHeaderLength + optionDataLen > commandLength) |
|
611 { |
|
612 valid = EFalse; |
|
613 } |
|
614 break; |
|
615 |
|
616 case EConfigOptionTypeFlushTimeoutDuration: |
|
617 if(optionDataLen != KFlushOptionDataLen || |
|
618 startOfCurrentOption + KOptionHeaderLength + optionDataLen > commandLength) |
|
619 { |
|
620 valid = EFalse; |
|
621 } |
|
622 break; |
|
623 |
|
624 case EConfigOptionTypeQOS: |
|
625 if(optionDataLen != KQOSOptionDataLen || |
|
626 startOfCurrentOption + KOptionHeaderLength + optionDataLen > commandLength) |
|
627 { |
|
628 valid = EFalse; |
|
629 } |
|
630 break; |
|
631 |
|
632 case EConfigOptionTypeRTxAndFEC: |
|
633 if(optionDataLen != KFECOptionDataLen || |
|
634 startOfCurrentOption + KOptionHeaderLength + optionDataLen > commandLength) |
|
635 { |
|
636 valid = EFalse; |
|
637 } |
|
638 break; |
|
639 |
|
640 case EConfigOptionTypeFcs: |
|
641 if(optionDataLen != KFcsOptionDataLen || |
|
642 startOfCurrentOption + KOptionHeaderLength + optionDataLen > commandLength) |
|
643 { |
|
644 valid = EFalse; |
|
645 } |
|
646 break; |
|
647 |
|
648 default: |
|
649 // Store the unknown options into the buffer argument. |
|
650 if(startOfCurrentOption + KOptionHeaderLength + optionDataLen > commandLength) |
|
651 { |
|
652 // The option is not correctly formatted. |
|
653 valid = EFalse; |
|
654 } |
|
655 break; |
|
656 }; |
|
657 // Move to the next option. |
|
658 startOfCurrentOption += (optionDataLen + KOptionHeaderLength); |
|
659 } |
|
660 |
|
661 if(startOfCurrentOption != commandLength) |
|
662 { |
|
663 // Spurious bytes |
|
664 valid = EFalse; |
|
665 } |
|
666 |
|
667 return valid; |
|
668 } |
|
669 |