bluetoothmgmt/btmgr/eirclient/src/eirdatacodec.cpp
changeset 0 29b1cd4cb562
equal deleted inserted replaced
-1:000000000000 0:29b1cd4cb562
       
     1 // Copyright (c) 2008-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  @file
       
    18  @internalTechnology
       
    19 */
       
    20 
       
    21 #include <bluetooth/eirdatacodec.h>
       
    22 #include <utf.h>
       
    23 #include <bluetooth/logger.h>
       
    24 #include "eirmanclientlogger.h"
       
    25 
       
    26 void Panic(TEirCodecPanics aCode)
       
    27 	{
       
    28 	User::Panic(KEirCodecPanicName, aCode);
       
    29 	}
       
    30 
       
    31 // Offset from Length to EIR Tag in EIR data
       
    32 const TUint8 KEIRLengthToTagOffset = 1;
       
    33 // Offset from EIR Tag to EIR data (value) in EIR data
       
    34 const TUint8 KEIRTagToDataOffset = 1;
       
    35 // number of bits in eir tag bit mask
       
    36 const TUint8 KSizeOfEIRTagBitMask = 32;
       
    37 
       
    38 /**
       
    39 Extended Inquiry Response Parser Class
       
    40 This class can take a TNameRecord reference from inquiry result, 
       
    41 which could hold both local name and Extended Inquiry Response. 
       
    42 It provides API to parse and return the local name and data for any Extended Inquiry Response tag.
       
    43 */
       
    44 
       
    45 /** 
       
    46  Default Constructs an TExtendedInquiryResponseDataCodec object.
       
    47 @internalTechnology
       
    48  */
       
    49 EXPORT_C TExtendedInquiryResponseDataCodec::TExtendedInquiryResponseDataCodec()
       
    50 : iEir(NULL, 0, 0), iOffset(0)
       
    51 	{
       
    52 	LOG_FUNC
       
    53 	}
       
    54 
       
    55 /** 
       
    56  Constructs an TExtendedInquiryResponseDataCodec object from an TNameRecord.
       
    57 
       
    58  TNameRecord.iName will be copied into a 8-bit descriptor and stored in the object.
       
    59 
       
    60  @param aDes Data buffer for extended inquiry response 
       
    61  @internalTechnology
       
    62 */
       
    63 EXPORT_C TExtendedInquiryResponseDataCodec::TExtendedInquiryResponseDataCodec(const TNameRecord& aNameRecord)
       
    64 : iEir(NULL, 0, 0), iOffset(0)
       
    65 	{
       
    66 	LOG_FUNC
       
    67 	// We won't check if the descriptor is the standard EIR size, as it can be reformed to have a whole name.
       
    68 	Set(aNameRecord);
       
    69 	}
       
    70 
       
    71 /** 
       
    72  Constructs an TExtendedInquiryResponseDataCodec object from an TNameRecord.
       
    73 
       
    74  TNameRecord.iName will be copied into a 8-bit descriptor and stored in the object.
       
    75 
       
    76  @param aDes Data buffer for extended inquiry response 
       
    77  @internalTechnology
       
    78 */
       
    79 EXPORT_C TExtendedInquiryResponseDataCodec::TExtendedInquiryResponseDataCodec(TNameRecord& aNameRecord)
       
    80 : iEir(NULL, 0, 0), iOffset(0)
       
    81 	{
       
    82 	LOG_FUNC
       
    83 	// We won't check if the descriptor is the standard EIR size, as it can be reformed to have a whole name.
       
    84 	Set(aNameRecord);
       
    85 	}
       
    86 
       
    87 /** 
       
    88  Constructs an TExtendedInquiryResponseDataCodec object from an 8-bit data buffer.
       
    89 
       
    90  A copy of the buffer is stored in the object.
       
    91 
       
    92  @param aDes Data buffer for extended inquiry response 
       
    93  @internalTechnology
       
    94 */
       
    95 EXPORT_C TExtendedInquiryResponseDataCodec::TExtendedInquiryResponseDataCodec(const TDesC8& aDes)
       
    96 :  iEir(NULL, 0, 0), iOffset(0)
       
    97 	{
       
    98 	LOG_FUNC
       
    99 	Set(aDes);
       
   100 	}
       
   101 /** 
       
   102  Constructs an TExtendedInquiryResponseDataCodec object from an 8-bit data buffer.
       
   103 
       
   104  A copy of the buffer is stored in the object.
       
   105 
       
   106  @param aDes Data buffer for extended inquiry response 
       
   107  @internalTechnology
       
   108 */
       
   109 EXPORT_C TExtendedInquiryResponseDataCodec::TExtendedInquiryResponseDataCodec(TDes8& aDes)
       
   110 :  iEir(NULL, 0, 0), iOffset(0)
       
   111 	{
       
   112 	LOG_FUNC
       
   113 	Set(aDes);
       
   114 	}
       
   115 
       
   116 /**
       
   117  Retrieve the EIR data for a particular Data Type 
       
   118  @param aDataType Data Type to look for
       
   119  @param aDes Pointer descriptor that will point to the EIR data for the Data Type requested if successful 
       
   120  (please note this does not contain the Data Type byte) 
       
   121  @return an error code
       
   122  @internalTechnology
       
   123  */
       
   124 EXPORT_C TInt TExtendedInquiryResponseDataCodec::GetData(TExtendedInquiryResponseDataType aDataType, TPtrC8& aDes) const
       
   125 	{
       
   126 	LOG_FUNC
       
   127 	TInt offset = NextDataType(0);
       
   128 
       
   129 	while(offset >= KErrNone)
       
   130 		{
       
   131 		if(iEir[offset] == aDataType)
       
   132 			{
       
   133 			aDes.Set(iEir.Mid(offset + KEIRTagToDataOffset, iEir[offset - KEIRLengthToTagOffset] - KEIRLengthToTagOffset));
       
   134 			return KErrNone;
       
   135 			}
       
   136 		else
       
   137 			{
       
   138 			offset = NextDataType(offset);
       
   139 			}
       
   140 		}
       
   141 
       
   142 	return offset;
       
   143 	}
       
   144 /**
       
   145  Retrieve the EIR data for the next Data Type 
       
   146  @param aOffset Offset to current data type (0 to start traversing)
       
   147  @param aDes Pointer descriptor that will point to the EIR data for the Data Type requested if successful 
       
   148  (please note this does not contain the Data Type byte) 
       
   149  @return TExtendedInquiryResponseDataType (TExtendedInquiryResponseDataType::EEirInvalid means there is no more eir data to get)
       
   150  @internalTechnology
       
   151  */
       
   152 EXPORT_C TExtendedInquiryResponseDataType TExtendedInquiryResponseDataCodec::GetNextData(TPtrC8& aDes)
       
   153 	{
       
   154 	LOG_FUNC
       
   155 	TExtendedInquiryResponseDataType dataType;
       
   156 	iOffset = NextDataType(iOffset);
       
   157 
       
   158 	if(iOffset >= KErrNone && iEir.Length() >= (iOffset +iEir[iOffset - KEIRLengthToTagOffset]))
       
   159 		{
       
   160 		aDes.Set(iEir.Mid(iOffset + KEIRTagToDataOffset, iEir[iOffset-KEIRLengthToTagOffset] - KEIRLengthToTagOffset));
       
   161 		dataType = static_cast<TExtendedInquiryResponseDataType>(iEir[iOffset]);
       
   162 		}
       
   163 	else
       
   164 		{
       
   165 		// Data must be malformed or corrupted
       
   166 		dataType = EEirInvalid;
       
   167 		}
       
   168 
       
   169 	return dataType;
       
   170 	}
       
   171 	
       
   172 /**
       
   173  Find out whether a particular Data Type is present in this TExtendedInquiryResponseDataCodec
       
   174  @param aDataType Data Type to look for
       
   175  @return ETrue if Data Type present, EFalse otherwise
       
   176  @internalTechnology
       
   177  */
       
   178 EXPORT_C TBool TExtendedInquiryResponseDataCodec::IsDataTypePresent(TExtendedInquiryResponseDataType aDataType) const
       
   179 	{
       
   180 	LOG_FUNC
       
   181 	TInt offset = NextDataType(0);
       
   182 	TBool found = EFalse;
       
   183 
       
   184 	while(offset >= KErrNone)
       
   185 		{
       
   186 		if(iEir[offset] == aDataType)
       
   187 			{
       
   188 			found = ETrue;
       
   189 			break;
       
   190 			}
       
   191 
       
   192 		offset = NextDataType(offset);
       
   193 		}
       
   194 
       
   195 	return found;
       
   196 	}
       
   197 
       
   198 /**
       
   199  Obtain the Device Name from inquiry response. This may be a complete or partial name depending on what is available.
       
   200  @param aName is the Device Name converted into Unicode format
       
   201  @return TEIRDataCompleteness (Partial or Complete) or an error code
       
   202  @internalTechnology
       
   203  */
       
   204 EXPORT_C TInt TExtendedInquiryResponseDataCodec::GetDeviceName(TPtrC8& aName) const
       
   205 	{
       
   206 	LOG_FUNC
       
   207 	TInt completeness = EDataComplete;
       
   208 	TInt error = GetData(EEirLocalNameComplete, aName);
       
   209 	if(error != KErrNone)
       
   210 		{
       
   211 		error = GetData(EEirLocalNamePartial, aName);
       
   212 		completeness = EDataPartial;
       
   213 		}
       
   214 
       
   215 	return error == KErrNone ? completeness : error;
       
   216 	}
       
   217 
       
   218 /**
       
   219  Set the Device Name in the EIR buffer from a TPtrC8. This may be a complete or partial name.
       
   220  @param aName is the Device Name converted into Unicode format
       
   221  @param aIsComplete is marking if the name is complete or partial
       
   222  @return TInt an error code
       
   223  @internalTechnology
       
   224  */
       
   225 EXPORT_C TInt TExtendedInquiryResponseDataCodec::SetDeviceName(const TPtrC8& aName, TBool aIsComplete)
       
   226 	{
       
   227 	TPtrC8 name;
       
   228 	TInt error = KErrNotFound;
       
   229 	TInt offset = NextDataType(0);
       
   230 	TInt nameTag = (aIsComplete ? EEirLocalNameComplete : EEirLocalNamePartial);
       
   231 	TBool replaceCurrentName = ETrue;
       
   232 
       
   233 	while(offset >= KErrNone)
       
   234 		{
       
   235 		if(iEir[offset] == EEirLocalNameComplete || iEir[offset] == EEirLocalNamePartial)
       
   236 			{
       
   237 			name.Set(iEir.Mid(offset + KEIRTagToDataOffset, iEir[offset-KEIRLengthToTagOffset] - KEIRLengthToTagOffset));
       
   238 			if(iEir[offset] == EEirLocalNameComplete && name.Compare(aName) == 0)
       
   239 				{
       
   240 				// The only scenario we don't want to replace the existing name is when
       
   241 				// it's complete and same as the new one (aName)
       
   242 				replaceCurrentName = EFalse;
       
   243 				LOG(_L("We won't replace the current name"));
       
   244 				}
       
   245 			error = KErrNone;
       
   246 			break;
       
   247 			}
       
   248 		else
       
   249 			{
       
   250 			offset = NextDataType(offset);
       
   251 			}
       
   252 		}
       
   253 
       
   254 	if(error == KErrNotFound)
       
   255 		// no device name present, we will add the name to the end of the eir data
       
   256 		{
       
   257 		if(iEir.MaxLength() < (iEir.Length() + KEIRTagToDataOffset + KEIRLengthToTagOffset + aName.Length()))
       
   258 			{
       
   259 			// Not enough space to store this name and its length & tag
       
   260 			return KErrNoMemory;
       
   261 			}
       
   262 		// Add length
       
   263 		iEir.Append(aName.Length() + KEIRTagToDataOffset);
       
   264 		// Append Tag
       
   265 		iEir.Append(nameTag);
       
   266 		// Append value
       
   267 		iEir.Append(aName);
       
   268 		LOG1(_L("EIR data with name appended: %d bytes of data"), iEir.Size());
       
   269 		LOGHEXDESC(iEir);
       
   270 		error = KErrNone;
       
   271 		}
       
   272 	else if(replaceCurrentName)
       
   273 		// device name exists in current eir and it's either partial or different from aName, we'll update it with aName
       
   274 		{
       
   275 		// move all the data on the right of device name to the left and then append new name after it
       
   276 		TPtr8 rightPtr = iEir.RightTPtr(iEir.Length() - offset - name.Length() - KEIRLengthToTagOffset);
       
   277 		iEir.Replace(offset-KEIRLengthToTagOffset, iEir.Length() - offset + KEIRLengthToTagOffset, rightPtr);
       
   278 		iEir.SetLength(offset + rightPtr.Length() - KEIRTagToDataOffset);
       
   279 		// Check if the new name is too big for iEir
       
   280 		if(iEir.MaxLength() < (iEir.Length() + KEIRTagToDataOffset + KEIRLengthToTagOffset + aName.Length()))
       
   281 			{
       
   282 			// Not enough space to store this name and its length & tag
       
   283 			return KErrNoMemory;
       
   284 			}
       
   285 		// Add length
       
   286 		iEir.Append(aName.Length() + KEIRTagToDataOffset);
       
   287 		// Append Tag
       
   288 		iEir.Append(nameTag);
       
   289 		// Append value
       
   290 		iEir.Append(aName);
       
   291 		LOG(_L("Reshuffled EIR data:"));
       
   292 		LOGHEXDESC(iEir);
       
   293 		error = KErrNone;
       
   294 		}
       
   295 	// otherwise we do nothing, as this is the case of an identical complete name is already present.
       
   296 	if(iNameRecord)
       
   297 		{
       
   298 		if(iEir.Length() > 0)
       
   299 			{
       
   300 			iNameRecord->iName.SetLength(((iEir.Length() + iEir.Length()%2)/2));
       
   301 			}
       
   302 		else
       
   303 			{
       
   304 			iNameRecord->iName.SetLength(0);
       
   305 			}
       
   306 		}
       
   307 	return error;
       
   308 	}
       
   309 
       
   310 /**
       
   311  Private Setter, used by the constructor and the assignment operator
       
   312  @param aNameRecord TNameRecord to create extended inquiry response from
       
   313  */
       
   314 EXPORT_C void TExtendedInquiryResponseDataCodec::Set(const TNameRecord& aNameRecord)
       
   315 	{
       
   316 	LOG_FUNC
       
   317 	Set(const_cast<TNameRecord&>(aNameRecord));
       
   318 	}
       
   319 
       
   320 /**
       
   321  Private Setter, used by the constructor and the assignment operator
       
   322  @param aNameRecord TNameRecord to create extended inquiry response from
       
   323  */
       
   324 EXPORT_C void TExtendedInquiryResponseDataCodec::Set(TNameRecord& aNameRecord)
       
   325 	{
       
   326 	LOG_FUNC
       
   327 	TUint8* name = (TUint8*)(aNameRecord.iName.Ptr());
       
   328 	TPtr8 namePtr(name, aNameRecord.iName.Size(), aNameRecord.iName.MaxSize());
       
   329 	iNameRecord = &aNameRecord; 
       
   330 	Set(namePtr);
       
   331 	}
       
   332 
       
   333 /**
       
   334  Private Setter, used by the constructor and the assignment operator
       
   335  @param aDes Data buffer to create extended inquiry response from
       
   336  */
       
   337 EXPORT_C void TExtendedInquiryResponseDataCodec::Set(const TDesC8& aDes)
       
   338 	{
       
   339 	LOG_FUNC
       
   340 	TPtr8 ptr(const_cast<TUint8*>(aDes.Ptr()), aDes.Length(), aDes.Length());
       
   341 	Set(ptr);
       
   342 	}
       
   343 /**
       
   344  Private Setter, used by the constructor and the assignment operator
       
   345  @param aDes Data buffer to create extended inquiry response from
       
   346  */
       
   347 EXPORT_C void TExtendedInquiryResponseDataCodec::Set(TDes8& aDes)
       
   348 	{
       
   349 	LOG_FUNC
       
   350 	// Check length consistency
       
   351 	TUint16 length = ComputeSignificantLength(aDes);
       
   352 	if(length > KNameRecord8BitMaxLength)
       
   353 		{
       
   354 		// Reset the EIR and discard any data it may contain, since it was malformed anyway
       
   355 		iEir.Set(NULL, 0, 0);
       
   356 		}
       
   357 	else
       
   358 		{
       
   359 		iEir.Set(const_cast<TUint8*>(aDes.Ptr()), length, aDes.MaxLength());
       
   360 		}
       
   361 	}
       
   362 
       
   363 EXPORT_C void TExtendedInquiryResponseDataCodec::Copy(TDesC8& aDes)
       
   364 	{
       
   365 	__ASSERT_DEBUG(iEir.MaxLength() >= aDes.Length(), Panic(EEirCodecDataTooLarge));
       
   366 	TUint16 length = ComputeSignificantLength(aDes);
       
   367 	iEir.Copy(aDes);
       
   368 	iEir.SetLength(length);
       
   369 	iNameRecord->iName.SetLength((iEir.Length()/2)+1);
       
   370 	}
       
   371 
       
   372 EXPORT_C TInt TExtendedInquiryResponseDataCodec::DoSanityCheck(TDes8& aDes)
       
   373 	{
       
   374 	TInt error = KErrNone;
       
   375 	TInt offset = NextDataType(0);
       
   376 	TUint32 eirTagPresentFlag = 0;	// this is a bit mask for existing eir types
       
   377 	TInt tag = 0;
       
   378 
       
   379 	while(offset >= KErrNone)
       
   380 		{
       
   381 		if(!IsValideDataType(iEir[offset]))
       
   382 			{
       
   383 			// the next data type isn't a known(valid) eir tag
       
   384 			error = KErrNotSupported;
       
   385 			break;
       
   386 			}
       
   387 		if(static_cast<TInt>(iEir[offset - KEIRLengthToTagOffset]) < 0)
       
   388 			{
       
   389 			// length is less than 0
       
   390 			error = KErrUnderflow;
       
   391 			break;
       
   392 			}
       
   393 		tag = (iEir[offset] == EEirVendorSpecific ? KSizeOfEIRTagBitMask : iEir[offset]);
       
   394 		// check if the tag is already present from previous parsing
       
   395 		if(eirTagPresentFlag & (1 << tag))
       
   396 			{
       
   397 			error = KErrAlreadyExists;
       
   398 			break;
       
   399 			}
       
   400 		else
       
   401 			{
       
   402 			// set flag for this data tag
       
   403 			eirTagPresentFlag |= (1 << tag);
       
   404 			offset = NextDataType(offset);
       
   405 			}
       
   406 		}
       
   407 	error = offset == KErrCorrupt ? offset : error;
       
   408 	if(error != KErrNone)
       
   409 		{
       
   410 		// remove all the data after this LTV unit
       
   411 		iEir.SetLength(offset - KEIRLengthToTagOffset);
       
   412 		aDes.SetLength(offset - KEIRLengthToTagOffset);
       
   413 		}
       
   414 	return error;
       
   415 	}
       
   416 
       
   417 /**
       
   418  Computes the length of Significant part in an Extended Inquiry Response data.
       
   419 
       
   420  @param aDes Extended Inquiry Response data
       
   421  */
       
   422 TUint16 TExtendedInquiryResponseDataCodec::ComputeSignificantLength(const TDesC8 &aDes)
       
   423 	{
       
   424 	LOG_FUNC
       
   425 	TUint desLen = aDes.Length();
       
   426 	const TUint8 *ptr = aDes.Ptr();
       
   427 	TUint16 i = 0;
       
   428 	while(i < desLen && ptr[i] != 0x00)
       
   429 		{
       
   430 		i += ptr[i] + KEIRLengthToTagOffset;
       
   431 		}
       
   432 	return i;
       
   433 	}
       
   434 
       
   435 /**
       
   436  @param aOffset Offset to current data type (0 to start traversing)
       
   437  @return an error code or Offset to the next EIR data type
       
   438  */
       
   439 TInt TExtendedInquiryResponseDataCodec::NextDataType(TInt aOffset) const
       
   440 	{
       
   441 	LOG_FUNC
       
   442 	// Check bounds
       
   443 	TInt length = iEir.Length();
       
   444 	TInt ret = KErrNotFound;
       
   445 	
       
   446 	// Check the values of aOffset and length are correct, and aOffset is not bigger than the length
       
   447 	if(aOffset > 0 && aOffset <= length)
       
   448 		{
       
   449 		// Get the Offset for next data type, aDes[aOffset-1] holds the length for each EIR structure
       
   450 		TInt newOffset = iEir[aOffset - KEIRLengthToTagOffset] + aOffset + KEIRLengthToTagOffset;
       
   451 		if(newOffset > length)
       
   452 			{
       
   453 			if(newOffset != length + KEIRLengthToTagOffset)
       
   454 				{
       
   455 				ret = KErrCorrupt;
       
   456 				}
       
   457 			}
       
   458 		else
       
   459 			{
       
   460 			ret = newOffset;
       
   461 			}
       
   462 		}
       
   463 	
       
   464 	// Offset for the first data type
       
   465 	else if(aOffset == 0 && length > 0)
       
   466 		{
       
   467 		ret = KEIRLengthToTagOffset;
       
   468 		}
       
   469 	return ret;
       
   470 	}
       
   471 
       
   472 TBool TExtendedInquiryResponseDataCodec::IsValideDataType(TInt aDataType)
       
   473 	{
       
   474 	TBool ret = EFalse;
       
   475 	if((aDataType >= EEirFlags && aDataType <= EEirOobSimplePairingRandomizerR) || aDataType == EEirVendorSpecific)
       
   476 		{
       
   477 		ret = ETrue;
       
   478 		}
       
   479 	return ret;
       
   480 	}
       
   481