linklayerprotocols/pppnif/SPPP/PPPOPT.CPP
changeset 0 af10295192d8
equal deleted inserted replaced
-1:000000000000 0:af10295192d8
       
     1 // Copyright (c) 1997-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 "PPPBASE.H"
       
    17 
       
    18 // Options are based on aligned MBuf Chains.
       
    19 // Steps are taken to guarantee that the first 128 bytes
       
    20 // of an option are held in the first MBuf
       
    21 
       
    22 RPppOption::RPppOption()
       
    23 	{
       
    24 	}
       
    25 
       
    26 RPppOption::RPppOption(RMBufChain& aChain)
       
    27 //
       
    28 // Note: this empties the original chain
       
    29 //
       
    30 	{
       
    31 	Assign(aChain);
       
    32 	Align(KMBufSmallSize);
       
    33 	}
       
    34 
       
    35 void RPppOption::SetL(TUint8 aType, const TAny* aPtr, TInt aLen)
       
    36 	{
       
    37 
       
    38 	aLen += 2;
       
    39 
       
    40 	if (aLen>MaxLength())
       
    41 		{
       
    42 		Free();
       
    43 		AllocL(aLen);
       
    44 		}
       
    45 	else
       
    46 		SetLength(aLen);
       
    47 
       
    48 	First()->Put(aType, 0);
       
    49 	First()->Put((TUint8)aLen, 1);
       
    50 	if (aLen>0)
       
    51 		CopyIn(TPtrC8((TUint8*)aPtr, aLen-2), 2);
       
    52 	}
       
    53 
       
    54 void RPppOption::SetValueLength(TInt aLen)
       
    55 	{
       
    56 	aLen += 2;
       
    57 	ASSERT(aLen<=KMBufSmallSize);
       
    58 	First()->Put((TUint8)aLen, 1);
       
    59 	First()->SetLength(aLen);
       
    60 	}
       
    61 
       
    62 TUint8 RPppOption::OptType() const
       
    63 	{
       
    64 	return First()->Get(0);	
       
    65 	}
       
    66 
       
    67 void RPppOption::SetType(const TUint8 aType)
       
    68 	{
       
    69 	TUint8* Ptr;
       
    70 
       
    71 	Ptr = First()->Ptr();
       
    72 	*Ptr = aType;	
       
    73 	}
       
    74 
       
    75 TInt RPppOption::ValueLength() const
       
    76 	{
       
    77 	return First()->Get(1)-2;	
       
    78 	}
       
    79 
       
    80 TUint8* RPppOption::ValuePtr()
       
    81 	{
       
    82 	return First()->Ptr()+2;
       
    83 	}
       
    84 
       
    85 const TUint8* RPppOption::ValuePtr() const
       
    86 	{
       
    87 	return First()->Ptr()+2;
       
    88 	}
       
    89 
       
    90 /**
       
    91 Re-aligns the underlying storage in an MBuf chain
       
    92 droppng any MBufs that are no longer needed
       
    93 DOES NOT preserve data.
       
    94 */
       
    95 TInt RPppOption::SetLength(TInt aLength)
       
    96 	{
       
    97 	RMBuf* p = NULL;
       
    98 	RMBuf* m = First();
       
    99 	while (m!=NULL && aLength>0)
       
   100 		{
       
   101 		TInt n = m->Size();
       
   102 		aLength -= n;
       
   103 		m->SetData(0, n);
       
   104 		if (aLength<0)
       
   105 			m->AdjustEnd(aLength);
       
   106 		p = m;
       
   107 		m = m->Next();
       
   108 		}
       
   109 	if (m!=NULL && p!=NULL)
       
   110 		{
       
   111 		p->Unlink();
       
   112 		m->Free();
       
   113 		}
       
   114 	if (aLength>0)
       
   115 		return KErrGeneral;
       
   116 	return KErrNone;
       
   117 	}
       
   118 
       
   119 /**
       
   120 Return the size of underlying storage in an MBuf chain
       
   121 */
       
   122 TInt RPppOption::MaxLength() const
       
   123 	{
       
   124 	TInt len = 0;
       
   125 	const RMBuf* m = First();
       
   126 	while (m!=NULL)
       
   127 		{
       
   128 		len += m->Size();
       
   129 		m = m->Next();
       
   130 		}
       
   131 	return len;
       
   132 	}
       
   133 
       
   134 void RPppOptionList::SetL(RMBufChain& aPacket, TInt aLength)
       
   135 	{
       
   136 	CleanupStack::PushL(*this);
       
   137 	CleanupStack::PushL(aPacket);
       
   138 
       
   139 	if (aLength==0)
       
   140 		aLength = aPacket.Length();
       
   141 
       
   142 	RMBufChain tmp;
       
   143  	while (aLength>=2)
       
   144 		{
       
   145 		aPacket.Align(2);
       
   146 		TInt len = aPacket.First()->Get(1);
       
   147 		
       
   148 		// Carlson97 (p.41) suggests that option length of 0 or 1 
       
   149 		// should be treated as 2 for the sake of verifying 
       
   150 		// the packet integrity when doing the length checks:
       
   151 		//
       
   152 		// "If, however, and option has an improper Len field for that
       
   153 		// type of option, but all of the lengths otherwise add up correctly, then
       
   154 		// the option should, according to the RFC 1661, be included in a Configure Nak message
       
   155 		// with the Len field changed to the proper length. (Dealing with a Len field set to 00 or 01 is a grey 
       
   156 		// area in the standard. I recommend treating this as as though it had been 02 for the sake of verifying 
       
   157 		// the packet integrity when doing the length checks; if these checks succeed, a Configure Nak should be 
       
   158 		// returned with the correct Len field for those options. ...)"
       
   159 		//
       
   160 		// This targets cases where the option fields have correct length, but the option Len value is incorrect.
       
   161 		// That is, the packet can be correctly parsed.
       
   162 		// Setting option len to 2 may result in either overruning the packet length during parsing, 
       
   163 		// or in parsing the packet incorrectly (incorrect option ID, values, etc). Both cases are checked for later.		 
       
   164 		if (len < 2)
       
   165 			len = 2;
       
   166 		
       
   167 		if (len > aLength) // The option extends beyond the end of the packet.
       
   168 			User::Leave(KErrCorrupt);
       
   169 
       
   170 		aPacket.SplitL(len, tmp);
       
   171 		Append(aPacket);
       
   172 		aPacket.Assign(tmp);
       
   173 		aLength -= len;
       
   174 		}
       
   175 	// If there is anything left over, then the list and packet
       
   176 	// are discarded as we probably have a truncated option.
       
   177 	if (aLength>0)
       
   178 		User::Leave(KErrCorrupt);
       
   179 
       
   180 	CleanupStack::Pop(2);
       
   181 	}
       
   182 
       
   183 TBool RPppOptionList::IsSubsetOf(RPppOptionList& aList)
       
   184 /**
       
   185 Check if the current option list is a subset of the OptionsList presented (aList).
       
   186 
       
   187 All the options in the current list must be contained and must be in the same order as the options in aList
       
   188 All the option arguments must also be identical
       
   189 
       
   190 @param aList option list to compare against.
       
   191 @return ETrue if option lists match, else EFalse
       
   192 */
       
   193 	{
       
   194 	TMBufPktQIter iter1(*this);
       
   195 	TMBufPktQIter iter2(aList);
       
   196 
       
   197 	RPppOption opt1;
       
   198 	RPppOption opt2;
       
   199 	
       
   200 	opt1 = iter1++;
       
   201 	opt2 = iter2++;
       
   202 
       
   203 	while (!opt1.IsEmpty())
       
   204 		{
       
   205 		if (opt2.IsEmpty())
       
   206 			{
       
   207 			return EFalse;
       
   208 			}
       
   209 		if (opt1.OptType() == opt2.OptType())
       
   210 			{	
       
   211 			if (opt1.ValueLength() == opt2.ValueLength() &&
       
   212 				Mem::Compare(opt1.ValuePtr(), opt1.ValueLength(), opt2.ValuePtr(), opt2.ValueLength()) == 0) //Arguments are the same
       
   213 				{
       
   214 				opt1 = iter1++; //We can move on to the next option aList is incremented later
       
   215 				}
       
   216 			else
       
   217 				{
       
   218 				return EFalse; //option arguemts are different therefore comparison fails
       
   219 				}
       
   220 			//if the option types are different then we move on to the next option in aList
       
   221 			}
       
   222 		opt2 = iter2++;
       
   223 		}
       
   224 	return ETrue;	
       
   225 	}
       
   226 
       
   227 TBool RPppOptionList::EqualTo(RPppOptionList& aList)
       
   228 /**
       
   229 Check if the current option list exactly matches that of the option list specified as argument.
       
   230 
       
   231 The options in each list must have the same type in the same order and have the same value.
       
   232 If one option list has extra options at the end, then this also counts as a mismatch.
       
   233 Note that aList should really be a const, but this would require propagation of the constness
       
   234 to several related classes.
       
   235 
       
   236 @param aList option list to compare against.
       
   237 @return ETrue if option lists match, else EFalse
       
   238 */
       
   239 	{
       
   240 	TMBufPktQIter iter1(*this);
       
   241 	TMBufPktQIter iter2(aList);
       
   242 
       
   243 	RPppOption opt1;
       
   244 	RPppOption opt2;
       
   245 	
       
   246 	opt1 = iter1++;
       
   247 	opt2 = iter2++;
       
   248 
       
   249 	while (!opt1.IsEmpty() && !opt2.IsEmpty())
       
   250 		{
       
   251 		if (opt1.OptType() != opt2.OptType() || opt1.ValueLength() != opt2.ValueLength() ||
       
   252 			Mem::Compare(opt1.ValuePtr(), opt1.ValueLength(), opt2.ValuePtr(), opt2.ValueLength()) != 0)
       
   253 			{
       
   254 			return EFalse;
       
   255 			}
       
   256 		opt1 = iter1++;
       
   257 		opt2 = iter2++;
       
   258 		}
       
   259 
       
   260 	// finally, check for the case where one option list has extra options
       
   261 	
       
   262 	return (opt1.IsEmpty() && opt2.IsEmpty());
       
   263 	}
       
   264 
       
   265 /**
       
   266 Build an MBuf chain by copying the underlying packet queue,
       
   267 leaving space on the front for a protocol header.
       
   268 */
       
   269 TInt RPppOptionList::CopyL(RMBufChain& aPacket, TInt aHdrSize) const
       
   270 	{
       
   271 	__ASSERT_ALWAYS(aHdrSize<KMBufSmallSize, PppPanic(EPppPanic_PacketHeaderTooBig));
       
   272 
       
   273 	RMBufChain i;
       
   274 
       
   275 	// Get total length of chain needed
       
   276 	TInt pktlen, len = 0;
       
   277 	i = First();
       
   278 	while (!i.IsEmpty())
       
   279 		{
       
   280 		len += i.Length();
       
   281 		i = i.Next();
       
   282 		}
       
   283 	
       
   284 	// Allocate the chain
       
   285 	pktlen = len+aHdrSize;
       
   286 	aPacket.AllocL(pktlen);
       
   287 	
       
   288 	// Do the copy
       
   289 	TInt n, n1, n2;
       
   290 	TUint8* p1, * p2;
       
   291 	RMBuf* m1, * m2;
       
   292 
       
   293 	i = First();
       
   294 	m1 = i.First();
       
   295 	p1 = m1->Ptr();
       
   296 	n1 = m1->Length();
       
   297 
       
   298 	m2 = aPacket.First();
       
   299 	p2 = m2->Ptr();
       
   300 	n2 = m2->Length();
       
   301 
       
   302 	if (aHdrSize>0)
       
   303 		{
       
   304 		if (aHdrSize==KMBufSmallSize)
       
   305 			{
       
   306 			m2 = m2->Next();
       
   307 			p2 = m2->Ptr();
       
   308 			n2 = m2->Length();
       
   309 			}
       
   310 		else
       
   311 			{
       
   312 			p2 += aHdrSize;		
       
   313 			n2 -= aHdrSize;
       
   314 			}
       
   315 		}
       
   316 
       
   317 	while (len>0)
       
   318 		{
       
   319 		n = n1<n2 ? n1 : n2;
       
   320 		Mem::Copy(p2, p1, n);
       
   321 		if (n1 -= n, n1==0)
       
   322 			{
       
   323 			if (m1 = m1->Next(), m1==NULL)
       
   324 				{
       
   325 				i = i.Next();
       
   326 				m1 = i.First();
       
   327 				}
       
   328 			if (m1!=NULL)
       
   329 				{
       
   330 				p1 = m1->Ptr();
       
   331 				n1 = m1->Length();
       
   332 				}
       
   333 			}
       
   334 		else
       
   335 			p1 += n;
       
   336 		if (n2 -= n, n2==0)
       
   337 			{
       
   338 			if (m2 = m2->Next(), m2!=NULL)
       
   339 				{
       
   340 				p2 = m2->Ptr();
       
   341 				n2 = m2->Length();
       
   342 				}
       
   343 			}
       
   344 		else
       
   345 			p2 += n;
       
   346 		len -= n;
       
   347 		}
       
   348 
       
   349 	return pktlen;	
       
   350 	}
       
   351 
       
   352 /**
       
   353 For each option in aReplaceList, delete the original in this list
       
   354 and replace it with the given one.
       
   355 */
       
   356 TInt RPppOptionList::ReplaceOptions(RPppOptionList& aReplaceList)
       
   357 	{
       
   358 	RPppOption opt;
       
   359 	while (aReplaceList.Remove(opt))
       
   360 		{
       
   361 		TInt err;
       
   362 		if (err = ReplaceOption(opt), err!=KErrNone)
       
   363 			return err;
       
   364 		}
       
   365 	return KErrNone;
       
   366 	}
       
   367 
       
   368 /**
       
   369 For each option in aRejectList, delete the original in this list
       
   370 */
       
   371 TInt RPppOptionList::RemoveOptions(RPppOptionList& aRejectList)
       
   372 	{
       
   373 	RPppOption opt;
       
   374 	while (aRejectList.Remove(opt))
       
   375 		{
       
   376 		TInt err;
       
   377 		if (err = RemoveOption(opt), err!=KErrNone)
       
   378 			return err;
       
   379 		opt.Free();
       
   380 		}
       
   381 	return KErrNone;
       
   382 	}
       
   383 
       
   384 TInt RPppOptionList::ReplaceOption(RPppOption& aOption)
       
   385 //
       
   386 //
       
   387 //
       
   388 	{
       
   389 	TMBufPktQIter iter(*this);
       
   390 	RPppOption opt;
       
   391 	while (opt = iter++, !opt.IsEmpty())
       
   392 		{
       
   393 		if (opt.OptType()==aOption.OptType())
       
   394 			{
       
   395 			opt.SetValueLength(aOption.ValueLength());
       
   396 			Mem::Copy(opt.ValuePtr(), aOption.ValuePtr(), aOption.ValueLength());
       
   397 			return KErrNone;
       
   398 			}
       
   399 		}
       
   400 	return KErrNotFound;
       
   401 	}
       
   402 
       
   403 
       
   404 TInt RPppOptionList::RemoveOption(RPppOption& aOption)
       
   405 //
       
   406 //
       
   407 //
       
   408 	{
       
   409 	TMBufPktQIter iter(*this);
       
   410 	RPppOption opt;
       
   411 	while (opt = iter.Current(), !opt.IsEmpty())
       
   412 		{
       
   413 		if (opt.OptType()==aOption.OptType())
       
   414 			{
       
   415 			opt.Init();
       
   416 			iter.Remove(opt);
       
   417 			opt.Free();
       
   418 			return KErrNone;
       
   419 			}
       
   420 		iter++;
       
   421 		}
       
   422 	return KErrNotFound;
       
   423 	}
       
   424 
       
   425 
       
   426 /**
       
   427 Calculate the FCS of an Option list
       
   428 Used for detecting non-convergence
       
   429 */
       
   430 void RPppOptionList::Crc32(TPppFcs32& aFcs, TBool aInitFcs)
       
   431 	{
       
   432 	if (aInitFcs)
       
   433 		aFcs.Init();
       
   434 	
       
   435 	RPppOption opt;
       
   436 	TMBufPktQIter iter(*this);
       
   437 	
       
   438 	while (opt = iter++, !opt.IsEmpty())
       
   439 		{
       
   440 		RMBuf* m = opt.First();
       
   441 		while (m!=NULL)
       
   442 			{
       
   443 			aFcs.Calc(m->Ptr(), m->EndPtr());
       
   444 			m = m->Next();
       
   445 			}
       
   446 		}
       
   447 	}
       
   448 
       
   449 /**
       
   450 Creates an options packet from an options list
       
   451 
       
   452 @param aPacket Return value for the constructed packet
       
   453 @param aPppId Protocol (e.g. LCP, IPCP etc).
       
   454 @param aType Type field of packet (e.g. Config-Request etc).
       
   455 @param aId Id field of packet
       
   456 @param aCreateEmptyPacket Set to ETrue if an empty packet is required.
       
   457 @see RFC1661, 5.
       
   458 @see MPppFsm::NewPacket
       
   459 */
       
   460 void RPppOptionList::CreatePacketL(RMBufPacket& aPacket, TUint aPppId, TUint8 aType, TUint8 aId, TBool aCreateEmptyPacket)
       
   461 	{
       
   462 	RMBufPktInfo* info=NULL;
       
   463 	TInt len;
       
   464 
       
   465 	CleanupStack::PushL(aPacket);
       
   466 	if (aCreateEmptyPacket)
       
   467 		{
       
   468 		// An empty packet contains just a header (Type (1) + Id (1) + Length (2))
       
   469 		len = 4;
       
   470 		aPacket.AllocL(len);
       
   471 		}
       
   472 	else
       
   473 		{
       
   474 	len = CopyL(aPacket, 4);
       
   475 		}
       
   476 	info = aPacket.NewInfoL();
       
   477 	CleanupStack::Pop();
       
   478 
       
   479 	info->iLength = len;
       
   480 	TPppAddr::Cast(info->iDstAddr).SetProtocol(aPppId);
       
   481 	TUint8* ptr = aPacket.First()->Ptr();
       
   482 	*ptr++ = aType;
       
   483 	*ptr++ = aId;
       
   484 	BigEndian::Put16(ptr, (TUint16)len);
       
   485 	aPacket.Pack();
       
   486 	}
       
   487 
       
   488 void RPppOptionList::CreateAndAddL(TUint8 aType)
       
   489 	{
       
   490 	RPppOption opt;
       
   491 	opt.SetL(aType, NULL, 0);
       
   492 	Append(opt);
       
   493 	}
       
   494 
       
   495 void RPppOptionList::CreateAndAddL(TUint8 aType, TUint8 aValue)
       
   496 	{
       
   497 	RPppOption opt;
       
   498 	opt.SetL(aType, &aValue, sizeof(aValue));
       
   499 	Append(opt);
       
   500 	}
       
   501 
       
   502 void RPppOptionList::CreateAndAddL(TUint8 aType, TUint16 aValue)
       
   503 	{
       
   504 	RPppOption opt;
       
   505 	TUint8 swapped[2];
       
   506 	// swap the byte order if necessary
       
   507 	BigEndian::Put16(swapped, aValue);
       
   508 	opt.SetL(aType, swapped, sizeof(swapped));
       
   509 	Append(opt);
       
   510 	}
       
   511 
       
   512 void RPppOptionList::CreateAndAddL(TUint8 aType, TUint32 aValue)
       
   513 	{
       
   514 	RPppOption opt;
       
   515 	TUint8 swapped[4];
       
   516 	// swap the byte order if necessary
       
   517 	BigEndian::Put32(swapped, aValue);
       
   518 	opt.SetL(aType, swapped, sizeof(swapped));
       
   519 	Append(opt);
       
   520 	}
       
   521 
       
   522 void RPppOptionList::CreateAndAddL(TUint8 aType, const TUint8 * aBuf, TInt aLen )
       
   523 	{
       
   524 	RPppOption opt;
       
   525 	opt.SetL(aType, aBuf, aLen);
       
   526 	Append(opt);
       
   527 	}
       
   528 
       
   529 void RPppOptionList::CreateAndAddL(TUint8 aType, TPtrC8& aValue )
       
   530 	{
       
   531 	RPppOption opt;
       
   532 	opt.SetL(aType, aValue.Ptr(), aValue.Length());
       
   533 	Append(opt);
       
   534 	}
       
   535 
       
   536 
       
   537 
       
   538 MPppOptionsExtender::MPppOptionsExtender()
       
   539 	{
       
   540 	iExtOptHandlerList.SetOffset(_FOFF(MPppOptionHandler, iOptHandlerLink));
       
   541 	}
       
   542 
       
   543 void MPppOptionsExtender::ExtOptRegister(MPppOptionHandler* aHandler)
       
   544 	{
       
   545 	iExtOptHandlerList.AddLast(*aHandler);
       
   546 	}
       
   547 
       
   548 void MPppOptionsExtender::ExtOptDeregister(MPppOptionHandler* aHandler)
       
   549 	{
       
   550 	aHandler->iOptHandlerLink.Deque();
       
   551 	}
       
   552 
       
   553 void MPppOptionsExtender::ExtOptNegotiationStarted()
       
   554 	{
       
   555 	TDblQueIter<MPppOptionHandler> iter(iExtOptHandlerList);
       
   556 	MPppOptionHandler* handler;
       
   557 	
       
   558 	while (handler = iter++, handler!=NULL)
       
   559 		handler->OptNegotiationStarted();
       
   560 	}
       
   561 
       
   562 void MPppOptionsExtender::ExtOptNegotiationAborted()
       
   563 	{
       
   564 	TDblQueIter<MPppOptionHandler> iter(iExtOptHandlerList);
       
   565 	MPppOptionHandler* handler;
       
   566 	
       
   567 	while (handler = iter++, handler!=NULL)
       
   568 		handler->OptNegotiationAborted();
       
   569 	}
       
   570 
       
   571 void MPppOptionsExtender::ExtOptNegotiationComplete()
       
   572 	{
       
   573 	TDblQueIter<MPppOptionHandler> iter(iExtOptHandlerList);
       
   574 	MPppOptionHandler* handler;
       
   575 	
       
   576 	while (handler = iter++, handler!=NULL)
       
   577 		handler->OptNegotiationComplete();
       
   578 	}
       
   579 
       
   580 void MPppOptionsExtender::ExtOptFillinConfigRequestL(RPppOptionList& aRequestList)
       
   581 	{
       
   582 	TDblQueIter<MPppOptionHandler> iter(iExtOptHandlerList);
       
   583 	MPppOptionHandler* handler;
       
   584 	while (handler = iter++, handler!=NULL)
       
   585 		handler->OptFillinConfigRequestL(aRequestList);
       
   586 	}
       
   587 
       
   588 void MPppOptionsExtender::ExtOptCheckConfigRequest(RPppOption& aOption, RPppOptionList &aAckList, RPppOptionList &aNakList, RPppOptionList &aRejList)
       
   589 	{ 
       
   590 	MPppOptionHandler* handler = ExtOptLookup(aOption.OptType());
       
   591 	TPppOptResponse res = (handler==NULL) ? EPppOptReject : handler->OptCheckConfigRequest(aOption);
       
   592 	switch (res)
       
   593 		{
       
   594 	case EPppOptAck:
       
   595 		aAckList.Append(aOption);
       
   596 		break;
       
   597 	case EPppOptNak:
       
   598 		aNakList.Append(aOption);
       
   599 		break;
       
   600 	case EPppOptReject:
       
   601 		aRejList.Append(aOption);
       
   602 		break;
       
   603 		}
       
   604 	}
       
   605 
       
   606 void MPppOptionsExtender::ExtOptApplyConfigRequest(RPppOption& aOption)
       
   607 	{
       
   608 	MPppOptionHandler* handler = ExtOptLookup(aOption.OptType());
       
   609 	if (handler!=NULL)
       
   610 		handler->OptApplyConfigRequest(aOption);
       
   611 	}
       
   612 
       
   613 void MPppOptionsExtender::ExtOptRecvConfigAck(RPppOption& aOption)
       
   614 	{
       
   615 	MPppOptionHandler* handler = ExtOptLookup(aOption.OptType());
       
   616 	if (handler!=NULL)
       
   617 		handler->OptRecvConfigAck(aOption);
       
   618 	}
       
   619 
       
   620 void MPppOptionsExtender::ExtOptRecvConfigNak(RPppOption& aOption, RPppOptionList& aReqList)
       
   621 	{
       
   622 	MPppOptionHandler* handler = ExtOptLookup(aOption.OptType());
       
   623 	if (handler!=NULL)
       
   624 		handler->OptRecvConfigNak(aOption, aReqList);
       
   625 	}
       
   626 
       
   627 void MPppOptionsExtender::ExtOptRecvConfigReject(RPppOption& aOption, RPppOptionList& aReqList)
       
   628 	{
       
   629 	MPppOptionHandler* handler = ExtOptLookup(aOption.OptType());
       
   630 	if (handler!=NULL)
       
   631 		handler->OptRecvConfigReject(aOption, aReqList);
       
   632 	}
       
   633 
       
   634 MPppOptionHandler* MPppOptionsExtender::ExtOptLookup(TUint8 aOptId)
       
   635 	{
       
   636 	TDblQueIter<MPppOptionHandler> iter(iExtOptHandlerList);
       
   637 	MPppOptionHandler* handler;
       
   638 	
       
   639 	while (handler = iter++, handler!=NULL)
       
   640 		{
       
   641 		TInt i;
       
   642 		for (i=0; i<handler->iNumOptions; i++)
       
   643 			{
       
   644 			if (handler->iOptionList[i]==aOptId)
       
   645 				return handler;
       
   646 			}
       
   647 		}
       
   648 	return NULL;
       
   649 	}
       
   650 
       
   651 MPppOptionHandler::MPppOptionHandler()
       
   652 	{
       
   653 	iNumOptions = 0;
       
   654 	iOptionList = NULL;
       
   655 	}
       
   656 
       
   657 void MPppOptionHandler::OptRegister(MPppOptionsExtender* aExtender, const TUint8* aOptList, TInt aNumOpts)
       
   658 	{
       
   659 	iNumOptions = aNumOpts;
       
   660 	iOptionList = aOptList;
       
   661 	aExtender->ExtOptRegister(this);
       
   662 	}
       
   663 
       
   664 // Default Implementations of option handler functions
       
   665 
       
   666 void MPppOptionHandler::OptNegotiationStarted()
       
   667 	{
       
   668 	return;
       
   669 	}
       
   670 
       
   671 void MPppOptionHandler::OptNegotiationAborted()
       
   672 	{
       
   673 	return;
       
   674 	}
       
   675 
       
   676 void MPppOptionHandler::OptNegotiationComplete()
       
   677 	{
       
   678 	return;
       
   679 	}
       
   680 
       
   681 void MPppOptionHandler::OptFillinConfigRequestL(RPppOptionList& /*aRequestList*/)
       
   682 	{
       
   683 	return;
       
   684 	}
       
   685 
       
   686 TPppOptResponse MPppOptionHandler::OptCheckConfigRequest(RPppOption& /*aOption*/)
       
   687 	{
       
   688 	return EPppOptReject;
       
   689 	}
       
   690 
       
   691 void MPppOptionHandler::OptApplyConfigRequest(RPppOption& /*aOption*/)
       
   692 	{
       
   693 	return;
       
   694 	}
       
   695 
       
   696 void MPppOptionHandler::OptRecvConfigAck(RPppOption& /*aOption*/)
       
   697 	{
       
   698 	return;
       
   699 	}
       
   700 
       
   701 void MPppOptionHandler::OptRecvConfigNak(RPppOption& aOption, RPppOptionList& aReqList)
       
   702 	{
       
   703 	aReqList.ReplaceOption(aOption);
       
   704 	}
       
   705 
       
   706 void MPppOptionHandler::OptRecvConfigReject(RPppOption& aOption, RPppOptionList& aReqList)
       
   707 	{
       
   708 	aReqList.RemoveOption(aOption);
       
   709 	}