linklayerprotocols/pppnif/SPPP/PPPHDLC.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 // See RFC 1662 and "PPP Design and Debugging" by James Carlson (ISBN 0201185393)
       
    15 // PPP's HDLC support
       
    16 // 
       
    17 //
       
    18 
       
    19 /**
       
    20  @file
       
    21 */
       
    22 
       
    23 #include <cdblen.h>
       
    24 #include <es_ini.h>
       
    25 #include "PPPHDLC.H"
       
    26 #include "PPPLOG.H"
       
    27 #include "ncpip.h"
       
    28 #include "PPPConfig.h"
       
    29 
       
    30 #include <commsdattypeinfov1_1.h>
       
    31 
       
    32 // Receive buffer size for the BCA layer. HDLC has a separate Rx buffer.
       
    33 static const TInt KReceiveBufferSize=4096; 
       
    34 
       
    35 // Internal flag bits (iFlags)
       
    36 static const TUint KPppHdlcSendFcs16 = 0x00000001;
       
    37 static const TUint KPppHdlcSendFcs32 = 0x00000002;
       
    38 static const TUint KPppHdlcSendCompProt = 0x00000004;
       
    39 static const TUint KPppHdlcSendCompAddrCtrl = 0x00000008;
       
    40 static const TUint KPppHdlcRecvFcs16 = 0x00000010;
       
    41 static const TUint KPppHdlcRecvFcs32 = 0x00000020;
       
    42 static const TUint KPppHdlcRecvCompProt = 0x00000040;
       
    43 static const TUint KPppHdlcRecvCompAddrCtrl = 0x00000080;
       
    44 //static const TUint KPppHdlcRecvEscSeen = 0x00000100;
       
    45 //static const TUint KPppHdlcSendXonXoff = 0x00000400;
       
    46 //static const TUint KPppHdlcRecvXonXoff = 0x00000800;
       
    47 static const TUint KPppHdlcSendBusy = 0x00001000;
       
    48 static const TUint KPppHdlcRecvEscPending = 0x00002000;
       
    49 static const TUint KPppHdlcCommConfigOk = 0x00004000;
       
    50 static const TUint KPppHdlcApplyPending = 0x00010000;
       
    51 static const TUint KPppHdlcAtApplyMark = 0x00020000;
       
    52 static const TUint KPppHdlcOrigConfig = 0x000040000;
       
    53 
       
    54 /*
       
    55 #if defined(_DEBUG) && defined (__WINS__)
       
    56 #include <f32file.h>
       
    57 #endif
       
    58 */
       
    59 
       
    60 //
       
    61 // HDLC Support
       
    62 //
       
    63 
       
    64 static const TInt KPppLoWat = 16;
       
    65 static const TInt KPppHiWat = 32;
       
    66 
       
    67 static const TInt KOptionListLen = 6;
       
    68 static const TUint8 OptionList[KOptionListLen] =
       
    69 	{
       
    70 	KPppLcpOptEscapeCharMap,
       
    71 	KPppLcpOptProtocolCompress,
       
    72 	KPppLcpOptAddrCtrlCompress,
       
    73 	KPppLcpOptFcsType,
       
    74 	KPppLcpOptPadding,
       
    75 	KPppLcpOptCompoundFrames
       
    76 	};
       
    77 
       
    78 CPppHdlcLink::CPppHdlcLink(CPppLcp* aLcp)
       
    79 	: CPppLinkBase(aLcp),
       
    80 	  iError(KErrNone),
       
    81 	  iLinkDown(ETrue) // By default
       
    82 	{
       
    83 	OptRegister(iPppLcp, OptionList, KOptionListLen);
       
    84 	iSendLoWat = KPppLoWat;
       
    85 	iSendHiWat = KPppHiWat;
       
    86 	}
       
    87 
       
    88 CPppHdlcLink::~CPppHdlcLink()
       
    89 	{
       
    90 	iSendPkt.Free();
       
    91 	iSendQ.Free();
       
    92 	iRecvPkt.Free();
       
    93 	if (iRecvMBuf)
       
    94 		{
       
    95 		iRecvMBuf->Free();
       
    96 		}
       
    97 	iRecvQ.Free();
       
    98 
       
    99 	delete iBcaReader;
       
   100 	delete iBcaWriter;
       
   101 	delete iBcaControl; // Must be deleted last, as it makes sure the BCA is closed.
       
   102 	
       
   103 	if(iBca) // Remove the BCA itself, if it was created.
       
   104 		{
       
   105 		iBca->Release();
       
   106 		}
       
   107 	}
       
   108 	
       
   109 /**
       
   110 Allocates the link resources, associated with BCA 
       
   111  
       
   112 @leave If the link cannot be created.
       
   113 */
       
   114 void CPppHdlcLink::CreateL()
       
   115     {
       
   116     if (iPppLcp->GetBCAProvision() == NULL)
       
   117         {
       
   118         User::Leave(KErrNotReady);
       
   119         }
       
   120         
       
   121 	LoadBcaL(); 
       
   122 	__ASSERT_ALWAYS(iBca, User::Panic(_L("PPP Panic"), EPppPanic_NullBca));
       
   123 	
       
   124 	iBcaControl = new (ELeave)CBcaControl(*this, *iBca); 
       
   125 	iBcaReader  = new (ELeave)CBcaReader( *this, *iBca, KPppHdlcCommReadPriority);
       
   126 	iBcaWriter  = new (ELeave)CBcaWriter( *this, *iBca, KPppHdlcCommWritePriority);	
       
   127     }
       
   128     
       
   129 /** 
       
   130 Loads the BCA based on Comms settings 
       
   131 
       
   132 @leave if the BCA cannot be loaded
       
   133 */
       
   134 void CPppHdlcLink::LoadBcaL()
       
   135 	{
       
   136 	LOG( Logger().Printf(_L("CPppHdlcLink::LoadBcaL: Loading BCA.[%S]"), GetBCAName().Ptr()); )
       
   137 		
       
   138 	User::LeaveIfError(iBcaDll.iObj.Load(iPppLcp->GetBCAProvision()->GetBCAName()));
       
   139 	
       
   140 	TNewBcaFactoryL newBcaFactoryProcL = (TNewBcaFactoryL)iBcaDll.iObj.Lookup(1);
       
   141 	if (!newBcaFactoryProcL)
       
   142 		{
       
   143 		LOG(Logger().Printf(_L("CPppHdlcLink::LoadBcaL: BCA Factory method lookup failed. ")); )
       
   144 		User::Leave(KErrBadLibraryEntryPoint);	
       
   145 		}
       
   146 	
       
   147 	MBcaFactory* bcaFactory = (*newBcaFactoryProcL)();
       
   148 	__ASSERT_ALWAYS(bcaFactory, User::Panic(_L("PPP Panic"), EPppPanic_NullBcaFactory));
       
   149 	
       
   150 	CleanupReleasePushL(*bcaFactory);
       
   151 	
       
   152 	iBca = bcaFactory->NewBcaL(); 
       
   153 	__ASSERT_ALWAYS(iBca, User::Panic(_L("PPP Panic"), EPppPanic_NullBca));
       
   154 	
       
   155 	CleanupStack::PopAndDestroy(bcaFactory); // We only need once BCA per PPP lifetime.
       
   156 	LOG(Logger().Printf(_L("CPppHdlcLink::LoadBcaL: BCA successfully loaded. ")); )
       
   157 	}
       
   158 
       
   159 
       
   160 
       
   161 void CPppHdlcLink::InitEscMap()
       
   162 /**
       
   163 Initializes the send escape map to a conservative value.
       
   164 iRecvEscMap is not set here, since Carlson says that can cause problems on
       
   165 LCP renegotiation.
       
   166 
       
   167 @post iSendEscMap is initialized
       
   168 */
       
   169 	{
       
   170 	// Always Escape bytes 0..31 initially
       
   171 	Mem::FillZ(iSendEscMap, sizeof(iSendEscMap));
       
   172 	iSendEscMap[0] = 0xffffffff;
       
   173 	// Also escape the two special bytes
       
   174 	SetEscMapBit(KPppHdlcFlagChar);
       
   175 	SetEscMapBit(KPppHdlcEscChar);
       
   176 	}
       
   177 
       
   178 void CPppHdlcLink::SetEscMapBit(TUint8 aChar)
       
   179 /**
       
   180 Marks this character to be escaped when sending.
       
   181 
       
   182 @param aChar Character
       
   183 */
       
   184 	{
       
   185 	iSendEscMap[aChar>>5] |= 1<<(aChar&0x1f);
       
   186 	}
       
   187 
       
   188 void CPppHdlcLink::DeferredApplyOptions()
       
   189 /**
       
   190 Starts using the negotiated PPP options.
       
   191 Called once LCP has completed.
       
   192 */
       
   193 	{
       
   194 //	LOG( iPppLcp->iLogger->Printf(_L("PPP Link DeferredApplyOptions()")); )
       
   195 	iFlags &= ~(KPppHdlcApplyPending|KPppHdlcAtApplyMark);
       
   196 	iFlags = (iFlags & ~iPendingMask) | iPendingFlags;
       
   197 	iSendEscMap[0] = iPendingEscMap;
       
   198 	}
       
   199 
       
   200 void CPppHdlcLink::GetSendRecvSize(TInt& aMaxRecvSize, TInt& aMaxSendSize)
       
   201 /**
       
   202 Returns the link's idea of the maximum receive and send unit sizes.
       
   203 
       
   204 @param aMaxRecvSize Returns the MRU, or 0 for default
       
   205 @param aMaxSendSize Returns the MTU, or 0 for default
       
   206 */
       
   207 	{
       
   208 	aMaxRecvSize = iPppLcp->MaxReceiveSize();
       
   209 	aMaxSendSize = iPppLcp->MaxTransferSize();
       
   210 	}
       
   211 
       
   212 void CPppHdlcLink::OptNegotiationStarted()
       
   213 	{
       
   214 //	LOG( iPppLcp->iLogger->Printf(_L("PPP Link OptNegotiationStarted()")); )
       
   215 	InitEscMap();
       
   216 
       
   217 // Initialize (most) flags
       
   218 	iFlags = (iFlags & (KPppHdlcCommConfigOk|KPppHdlcSendBusy|KPppHdlcOrigConfig))
       
   219 				| (KPppHdlcSendFcs16 | KPppHdlcRecvFcs16);
       
   220 
       
   221 	iPendingMask = 0;
       
   222 	iPendingFlags = 0;
       
   223 	iPendingEscMap = iSendEscMap[0];
       
   224 	iApplyConfigMarker = NULL;
       
   225 	}
       
   226 
       
   227 void CPppHdlcLink::OptNegotiationAborted()
       
   228 	{
       
   229 //	LOG( iPppLcp->iLogger->Printf(_L("PPP Link OptNegotiationAborted()")); )
       
   230 	}
       
   231 
       
   232 void CPppHdlcLink::OptNegotiationComplete()
       
   233 	{
       
   234 //	LOG( iPppLcp->iLogger->Printf(_L("PPP Link OptNegotiationComplete()")); )
       
   235 	iFlags |= KPppHdlcApplyPending;
       
   236 /*
       
   237 	if (!iSendQ.IsEmpty())
       
   238 		{
       
   239 		RMBufChain pkt = iSendQ.Last();
       
   240 		iApplyConfigMarker = pkt.First();
       
   241 		}
       
   242 	else
       
   243 		{
       
   244 		iFlags |= KPppHdlcAtApplyMark;
       
   245 		if (iSendPkt.IsEmpty())
       
   246 			DeferredApplyOptions();
       
   247 		}
       
   248 */
       
   249 	}
       
   250 
       
   251 void CPppHdlcLink::OptFillinConfigRequestL(RPppOptionList& aRequestList)
       
   252 	{
       
   253 	// Add XON/XOFF bits to the ACCM read from ppp.ini
       
   254 	TUint32 map = iDesiredRecvEscMap;
       
   255 	if ((iOrigConfig().iHandshake & KConfigObeyXoff)!=0 ||
       
   256 		(iOrigConfig().iHandshake & KConfigSendXoff)!=0)
       
   257 		{
       
   258 		if (iOrigConfig().iXonChar<32)
       
   259 			map |= 1<<iOrigConfig().iXonChar;
       
   260 		if (iOrigConfig().iXoffChar<32)
       
   261 			map |= 1<<iOrigConfig().iXoffChar;
       
   262 		}
       
   263 	aRequestList.CreateAndAddL(KPppLcpOptEscapeCharMap,map);
       
   264 	aRequestList.CreateAndAddL(KPppLcpOptProtocolCompress);
       
   265 	aRequestList.CreateAndAddL(KPppLcpOptAddrCtrlCompress);
       
   266 	}
       
   267 
       
   268 TPppOptResponse CPppHdlcLink::OptCheckConfigRequest(RPppOption& aOption)
       
   269 /**
       
   270 Checks options in a received config request.
       
   271 Called once for each option.
       
   272 
       
   273 @param aOption LCP option
       
   274 
       
   275 @return EPppOptAck, EPppOptNak, or EPppOptReject
       
   276 */
       
   277 	{
       
   278 	const TInt KBooleanOptDataLen = 0;
       
   279 	const TInt KOptEscapeCharMapLen = 4;
       
   280 	
       
   281 	switch (aOption.OptType())
       
   282 		{
       
   283 	case KPppLcpOptEscapeCharMap:
       
   284 		{		
       
   285 		TUint32 remoteRecvAccm = 0;
       
   286 		TBool forceNak = EFalse; // Whether the ACCM must be NAKed regardless of value.
       
   287 		
       
   288 		if(KOptEscapeCharMapLen != aOption.ValueLength()) // Invalid length: NAK 
       
   289 			{
       
   290 			aOption.SetValueLength(KOptEscapeCharMapLen); // Fix length. (value = 0x0)
       
   291 			forceNak = ETrue; 
       
   292 			}
       
   293 		else // Valid length. Extract the ACCM and negotiate.
       
   294 			{
       
   295 			remoteRecvAccm = BigEndian::Get32(aOption.ValuePtr());
       
   296 			}
       
   297 
       
   298 		// Create the sender ACCM
       
   299 		TUint32 localSendAccm = 0; // We want to escape as little as possible.
       
   300 		// Add XON/XOFF bits to the sender ACCM 
       
   301 		if ((iOrigConfig().iHandshake & KConfigObeyXoff)!=0 ||
       
   302 				(iOrigConfig().iHandshake & KConfigSendXoff)!=0)
       
   303 				{
       
   304 				if (iOrigConfig().iXonChar<32)
       
   305 					localSendAccm |= 1<<iOrigConfig().iXonChar;
       
   306 				if (iOrigConfig().iXoffChar<32)
       
   307 					localSendAccm |= 1<<iOrigConfig().iXoffChar;
       
   308 				}
       
   309 	
       
   310 		
       
   311 		// Compare the ACCMs and check if peer's proposal must be NAKed:
       
   312 		// It is NAKed if there is a disagreement on ACCM, or if the option is invalid
       
   313 		if ((~remoteRecvAccm & localSendAccm) || forceNak) 
       
   314 		    {
       
   315 			BigEndian::Put32( aOption.ValuePtr(), localSendAccm | remoteRecvAccm);
       
   316 			return EPppOptNak;
       
   317 			}
       
   318 		
       
   319 		
       
   320 		return EPppOptAck;
       
   321 		}
       
   322 
       
   323 	case KPppLcpOptProtocolCompress:
       
   324 		if(KBooleanOptDataLen == aOption.ValueLength())
       
   325 			{
       
   326 			return EPppOptAck;
       
   327 			}
       
   328 		else
       
   329 			{
       
   330 			aOption.SetValueLength(KBooleanOptDataLen);
       
   331 			return EPppOptNak;
       
   332 			}		
       
   333 	case KPppLcpOptAddrCtrlCompress:
       
   334 		if(KBooleanOptDataLen == aOption.ValueLength())
       
   335 			{
       
   336 			return EPppOptAck;
       
   337 			}
       
   338 		else
       
   339 			{
       
   340 			aOption.SetValueLength(KBooleanOptDataLen);
       
   341 			return EPppOptNak;
       
   342 			}
       
   343 
       
   344 	case KPppLcpOptFcsType:
       
   345 		{
       
   346 		if (aOption.ValueLength()<1)
       
   347 			return EPppOptReject;
       
   348 		TUint8 fcs = *aOption.ValuePtr();
       
   349 		// This only allows one FCS method at a time.
       
   350 		if (fcs==KPppHdlcFcs0Flag || fcs==KPppHdlcFcs16Flag
       
   351 #ifdef __LCP_EXTENSION_FCS_32
       
   352 		    || fcs==KPppHdlcFcs32Flag
       
   353 #endif
       
   354 	    )
       
   355 			{
       
   356 			return EPppOptAck;
       
   357 			}
       
   358 		*aOption.ValuePtr() = KPppHdlcFcs16Flag;
       
   359 		return EPppOptNak;
       
   360 		}
       
   361 
       
   362 	case KPppLcpOptPadding:
       
   363 	case KPppLcpOptCompoundFrames:
       
   364 //		if (iPppLcp->DoLcpExts())
       
   365 //			{
       
   366 			// handle the options
       
   367 //			}
       
   368 		// else fall though and reject
       
   369 	default:
       
   370 		return EPppOptReject;
       
   371 		}
       
   372 	}
       
   373 
       
   374 
       
   375 void CPppHdlcLink::CallBackOptRequestGranted()
       
   376 	{
       
   377 
       
   378 	iPppLcp->CallbackRequestGranted();
       
   379 	}
       
   380 
       
   381 
       
   382 void CPppHdlcLink::OptApplyConfigRequest(RPppOption& aOption)
       
   383 /**
       
   384 Applies options in a received config request (that was ACK'd).
       
   385 Called once for each option.
       
   386 
       
   387 @param aOption LCP option
       
   388 */
       
   389 	{
       
   390 	
       
   391 //	__LOGTEXT2_DEBUG(_L8("CPppHdlcLink::OptApplyConfigRequest() Option = %d\n"),aOption.OptType());
       
   392 	
       
   393 	switch (aOption.OptType())
       
   394 		{
       
   395 	case KPppLcpOptEscapeCharMap:
       
   396 		iPendingEscMap = BigEndian::Get32(aOption.ValuePtr());
       
   397 		break;
       
   398 	case KPppLcpOptProtocolCompress:
       
   399 		iPendingMask |= KPppHdlcSendCompProt;
       
   400 		iPendingFlags |= KPppHdlcSendCompProt;
       
   401 		break;
       
   402 	case KPppLcpOptAddrCtrlCompress:
       
   403 		iPendingMask |= KPppHdlcSendCompAddrCtrl;
       
   404 		iPendingFlags |= KPppHdlcSendCompAddrCtrl;
       
   405 		break;
       
   406 	case KPppLcpOptFcsType:
       
   407 		{
       
   408 		TUint8 fcs = *aOption.ValuePtr();
       
   409 		iPendingMask |= (KPppHdlcSendFcs16|KPppHdlcSendFcs32);
       
   410 		iPendingFlags &= ~(KPppHdlcSendFcs16|KPppHdlcSendFcs32);
       
   411 		if (fcs==KPppHdlcFcs16Flag)
       
   412 			iPendingFlags |= KPppHdlcSendFcs16;
       
   413 
       
   414 #ifdef __LCP_EXTENSION_FCS_32
       
   415 		if (fcs==KPppHdlcFcs32Flag)
       
   416 			iFlags |= KPppHdlcSendFcs32;
       
   417 #endif
       
   418 		}
       
   419 		CallBackOptRequestGranted();
       
   420 		break;
       
   421 	case KPppLcpOptCallback:
       
   422 		CallBackOptRequestGranted();
       
   423 		break;
       
   424 	case KPppLcpOptPadding:
       
   425 	case KPppLcpOptCompoundFrames:
       
   426 	default:
       
   427 		break;
       
   428 		}
       
   429 	}
       
   430 
       
   431 
       
   432 void CPppHdlcLink::OptRecvConfigAck(RPppOption& aOption)
       
   433 /**
       
   434 Receives a Config Ack - apply the option.
       
   435 Called once for each option.
       
   436 
       
   437 @param aOption LCP option
       
   438 */
       
   439 	{
       
   440 //	__LOGTEXT2_DEBUG(_L8("CPppHdlcLink::OptRecvConfigAck() Option = %d\n"),aOption.OptType());
       
   441 	switch (aOption.OptType())
       
   442 		{
       
   443 	case KPppLcpOptEscapeCharMap:
       
   444 		// Start using the new map immediately.
       
   445 		// This goes against the RFC, but is recommended by Carlson
       
   446 		iRecvEscMap = BigEndian::Get32(aOption.ValuePtr());
       
   447 		break;
       
   448 	case KPppLcpOptProtocolCompress:
       
   449 		// Start using the flag immediately
       
   450 		iFlags |= KPppHdlcRecvCompProt;
       
   451 		break;
       
   452 	case KPppLcpOptAddrCtrlCompress:
       
   453 		// Start using the flag immediately
       
   454 		iFlags |= KPppHdlcRecvCompAddrCtrl;
       
   455 		break;
       
   456 	case KPppLcpOptFcsType:
       
   457 		{
       
   458 		TUint8 fcs = *aOption.ValuePtr();
       
   459 		iPendingMask |= (KPppHdlcRecvFcs16|KPppHdlcRecvFcs32);
       
   460 		iPendingFlags &= ~(KPppHdlcRecvFcs16|KPppHdlcRecvFcs32);
       
   461 		if (fcs==KPppHdlcFcs16Flag)
       
   462 			iPendingFlags |= KPppHdlcRecvFcs16;
       
   463 
       
   464 #ifdef __LCP_EXTENSION_FCS_32
       
   465 		if (fcs==KPppHdlcFcs32Flag)
       
   466 			iPendingFlags |= KPppHdlcRecvFcs32;
       
   467 #endif		
       
   468 		}
       
   469 		break;
       
   470 	case KPppLcpOptPadding:
       
   471 	case KPppLcpOptCompoundFrames:
       
   472 	default:
       
   473 		break;
       
   474 		}
       
   475 	}
       
   476 
       
   477 void CPppHdlcLink::OptRecvConfigNak(RPppOption& aOption, RPppOptionList& aReqList)
       
   478 /**
       
   479 Modifies request after receiving a Config Nak.
       
   480 Called once for each option.
       
   481 
       
   482 @param aOption LCP option
       
   483 @param aReqList The associated original request to be modified
       
   484 */
       
   485 	{
       
   486 	switch (aOption.OptType())
       
   487 		{
       
   488 	case KPppLcpOptEscapeCharMap:
       
   489 		// Carlson says to OR this with our original request, but this will
       
   490 		// work as-is with a correctly-functioning peer
       
   491 		aReqList.ReplaceOption(aOption);
       
   492 		break;
       
   493 	case KPppLcpOptProtocolCompress:
       
   494 		aReqList.ReplaceOption(aOption);
       
   495 		break;
       
   496 	case KPppLcpOptAddrCtrlCompress:
       
   497 		aReqList.ReplaceOption(aOption);
       
   498 		break;
       
   499 	case KPppLcpOptFcsType:
       
   500 		aReqList.ReplaceOption(aOption);
       
   501 		break;
       
   502 	case KPppLcpOptPadding:
       
   503 	case KPppLcpOptCompoundFrames:
       
   504 	default:
       
   505 		break;
       
   506 		}
       
   507 	}
       
   508 
       
   509 void CPppHdlcLink::OptRecvConfigReject(RPppOption& aOption, RPppOptionList& aReqList)
       
   510 /**
       
   511 Modifies request after receiving a Config Reject
       
   512 Called once for each option.
       
   513 
       
   514 @param aOption LCP option
       
   515 @param aReqList The associated original request to be modified
       
   516 */
       
   517 	{
       
   518 //	__LOGTEXT2_DEBUG(_L8("CPppHdlcLink::OptRecvConfigReject() Option = %d\n"),aOption.OptType());
       
   519 	switch (aOption.OptType())
       
   520 		{
       
   521 	case KPppLcpOptEscapeCharMap:
       
   522 		aReqList.RemoveOption(aOption);
       
   523 		break;
       
   524 	case KPppLcpOptProtocolCompress:
       
   525 		aReqList.RemoveOption(aOption);
       
   526 		break;
       
   527 	case KPppLcpOptAddrCtrlCompress:
       
   528 		aReqList.RemoveOption(aOption);
       
   529 		break;
       
   530 	case KPppLcpOptFcsType:
       
   531 		aReqList.RemoveOption(aOption);
       
   532 		break;
       
   533 	case KPppLcpOptPadding:
       
   534 	case KPppLcpOptCompoundFrames:
       
   535 	default:
       
   536 		break;
       
   537 		}
       
   538 	}
       
   539 
       
   540 void CPppHdlcLink::OpenL()
       
   541 /**
       
   542 Starts connect establishment
       
   543 */
       
   544 	{
       
   545 	switch (iState)
       
   546 		{
       
   547 	case EPppHdlcConnecting:
       
   548 	case EPppHdlcOpen:
       
   549 		return;
       
   550 	case EPppHdlcClosed:
       
   551 		iState = EPppHdlcConnecting;
       
   552 		break;
       
   553 	case EPppHdlcDisconnecting:
       
   554 		LOG(Logger().Printf(_L("CPppHdlcLink::OpenL: Link is disconnecting. Leaving with KErrNotReady[%d]"), KErrNotReady); )
       
   555 		User::Leave(KErrNotReady);
       
   556 		break;
       
   557 	default:
       
   558 		return;
       
   559 		}
       
   560 	LOG( Logger().Printf(_L("PPP Link OpenL")); )
       
   561 	}
       
   562 
       
   563   
       
   564 /**
       
   565 Drops connection
       
   566 */
       
   567 void CPppHdlcLink::Close()
       
   568 	{
       
   569 	LOG( Logger().Printf(_L("CPppHdlcLink::Close(): Link Close requested: ")); )
       
   570 	iError = KErrNone;
       
   571 	switch (iState)
       
   572 		{
       
   573 	case EPppHdlcConnecting:		
       
   574 	case EPppHdlcOpen:
       
   575 		iState = EPppHdlcDisconnecting;
       
   576 		PacketModeOff();
       
   577 		break;
       
   578 	
       
   579 	case EPppHdlcClosed:
       
   580 	case EPppHdlcDisconnecting:
       
   581 		break;
       
   582 		
       
   583 	case EPppHdlcReconnecting: // This is not used anywhere in PPP.
       
   584 	default:
       
   585 		__ASSERT_DEBUG(EFalse, User::Panic(_L("PPP Panic"), EPppPanic_IllegalHdlcState));
       
   586 		break;
       
   587 		}
       
   588 	}
       
   589 
       
   590 
       
   591 TUint16 CPppHdlcLink::DecodeProtocolID(TUint8*& aPtr) const
       
   592 /**
       
   593 Decodes the PPP protocol ID from a buffer.
       
   594 The ID may be compressed.
       
   595 
       
   596 @param aPtr Pointer to PPP frame buffer; returns pointing one past protocol ID
       
   597 
       
   598 @return PPP protocol ID
       
   599 */
       
   600 	{
       
   601 	// Extract the protocol information - this can be either one or two bytes, but
       
   602 	// the last byte must be odd, and the first byte (if present) must be even
       
   603 	TUint16 prot = *aPtr++;
       
   604 	if(!(prot & 1))
       
   605 		{
       
   606 		prot = (TUint16) ((prot << 8) | *aPtr++);
       
   607 		}
       
   608 	return prot;
       
   609 	}
       
   610 
       
   611 TBool CPppHdlcLink::UnescapeChar(TUint8*& ptr, TUint8*& end, TUint8*& mptr, TUint8*& mend)
       
   612 /**
       
   613 Unescape the next character in the buffer. Ignore characters in the receive ACCM.
       
   614 
       
   615 @param ptr Pointer to input buffer
       
   616 @param end Pointer to one past the end of the input buffer
       
   617 @param mptr Pointer to the output buffer
       
   618 @param mend Pointer to one past the end of the output buffer (must be > mptr on entry)
       
   619 
       
   620 @return ETrue on error (error will be logged)
       
   621 
       
   622 @post KPppHdlcRecvEscPending is appropriately set or cleared in iFlags
       
   623 */
       
   624 	{
       
   625 	// See whether there's still more data in the incoming buffer
       
   626 	while (ptr<end)
       
   627 		{
       
   628 		// Check for flag sequence and silently discard the frame if it is
       
   629 		if ((*ptr)==KPppHdlcFlagChar)
       
   630 			{
       
   631 			LOG( Logger().Printf(_L("PPP: HDLC: Bad PPP frame - flag char received directly after escaping sequence")));
       
   632 			// Delete the iRecvMBuf
       
   633 			DoBadRecv();
       
   634 			return ETrue;
       
   635 			}
       
   636 
       
   637 		// If the character is not in the receive ACCM, it's good--stop searching
       
   638 		if (!IsInRecvEscMap(*ptr))
       
   639 			{
       
   640 			break;
       
   641 			}
       
   642 
       
   643 		++ptr;
       
   644 		}
       
   645 		
       
   646 	if (ptr >= end)
       
   647 		{
       
   648 		// We haven't got the data yet, so set the flag and sort it out next time DoRecv() is called
       
   649 		iFlags |= KPppHdlcRecvEscPending;
       
   650 		}
       
   651 
       
   652 	else {
       
   653 		// Successfully processing the escaped character
       
   654 		iFlags &= ~KPppHdlcRecvEscPending;
       
   655 
       
   656 		// Decode the escaped char and copy it across
       
   657 		if (DecodeChar(mptr, mend, (TUint8)(*ptr++ ^ KPppHdlcEscBit)))
       
   658 			{
       
   659 			return ETrue;	// error
       
   660 			}
       
   661 		}
       
   662 	return EFalse;
       
   663 	}
       
   664 
       
   665 
       
   666 TBool CPppHdlcLink::AppendRecvMbuf(TUint8*& aMptr, TUint8*& aMend)
       
   667 /**
       
   668 Appends the current Mbuf to the packet and allocate a new one to replace it.
       
   669 
       
   670 @param aMptr Returns a pointer to the beginning of the new buffer
       
   671 @param aMend Returns a pointer to the end of the new buffer
       
   672 
       
   673 @return ETrue when a new buffer could not be allocated
       
   674 */
       
   675 	{
       
   676 	// Queue this MBuf
       
   677 	if (iRecvMBuf != NULL)
       
   678 		{
       
   679 		iRecvPkt.Append(iRecvMBuf);
       
   680 		}
       
   681 
       
   682 	// Allocate a new one
       
   683 	TRAPD(err, iRecvMBuf = RMBuf::AllocL());
       
   684 	if (err!=KErrNone)
       
   685 		{
       
   686 		// Nuke the whole packet if we fail to allocate a new MBuf
       
   687 		iRecvMBuf = NULL;
       
   688 		iRecvPkt.Free();
       
   689 		LOG( iPppLcp->iLogger->Printf(_L("PPP: couldn't allocate MBuf")));
       
   690 		return ETrue;
       
   691 		}
       
   692 	aMptr = iRecvMBuf->Ptr();
       
   693 	aMend = iRecvMBuf->EndPtr();
       
   694 	__ASSERT_DEBUG((aMend - aMptr) == iRecvMBuf->Size(), User::Panic(_L("PPP Panic"), 0));
       
   695 	return EFalse;
       
   696 	}
       
   697 	
       
   698 void CPppHdlcLink::DoBadRecv()
       
   699 /**
       
   700 Adds a special packet to the receive queue with the meaning that
       
   701 a bad PPP frame was received. Any data in the current MBuf is
       
   702 used as the data portion of the special packet (and ignored).
       
   703 */
       
   704 	{
       
   705 	// Need at least one MBuf in the packet to create an info header.
       
   706 	// Use the current MBuf if available, or create a new one if not.
       
   707 	if (iRecvPkt.IsEmpty())
       
   708 		{
       
   709 		TUint8* ptr, * end;
       
   710 		if (AppendRecvMbuf(ptr, end))
       
   711 			{
       
   712 			return;	// error has been logged; exit
       
   713 			}
       
   714 		iRecvMBuf->SetLength(0);
       
   715 		
       
   716 		if (iRecvPkt.IsEmpty())
       
   717 			{
       
   718 			// There wasn't an MBuf available a moment ago;
       
   719 			// there is now...
       
   720 			if (AppendRecvMbuf(ptr, end))
       
   721 				{
       
   722 				return;	// error has been logged; exit
       
   723 				}
       
   724 			iRecvMBuf->SetLength(0);
       
   725 			}
       
   726 		}
       
   727 	else if (iRecvMBuf != NULL)
       
   728 		{
       
   729 		// The MBuf waiting for use may be partially filled.  Since this is
       
   730 		// DoBadRecv() we know it contains garbage, so clear it out so it's
       
   731 		// ready for reuse the next time through DoRecv().
       
   732 		iRecvMBuf->SetLength(0);
       
   733 		}
       
   734 
       
   735 	RMBufPacket pkt;
       
   736 	RMBufPktInfo* info = NULL;
       
   737 	TRAPD(err, info=pkt.CreateL(iRecvPkt, 0);)
       
   738 	if(err!=KErrNone)
       
   739 		{
       
   740 		// We can't allocate an info header, so log a message and give up.
       
   741 		LOG( iPppLcp->iLogger->Printf(_L("PPP: couldn't allocate packet")));
       
   742 		return;
       
   743 		}
       
   744 	TPppAddr::Cast(info->iDstAddr).SetCRCError(ETrue);
       
   745 	pkt.Pack();
       
   746 	iRecvQ.Append(pkt);
       
   747 	}
       
   748 
       
   749 void CPppHdlcLink::DoRecv()
       
   750 /**
       
   751 Comm Read has completed - decodes and passes to LCP.
       
   752 
       
   753 We're copying the frame from the iRecvBuf into a series of mbufs - iRecvMBuf -
       
   754 which are chained together into a RMBufPacket, which is then
       
   755 added onto the iRecvQ 
       
   756 
       
   757 @see DoBadRecv()
       
   758 */
       
   759 	{
       
   760 	// This buffer contains one frame, as we instructed the COMM port to
       
   761 	// stop reading when it encounters a KPppHdlcFlagChar
       
   762 	TUint8* ptr = (TUint8*)iRecvBuf.Ptr();
       
   763 	TUint8* end = ptr+iRecvBuf.Length();
       
   764 	TUint8* mptr = NULL;
       
   765 	TUint8* mend = NULL;
       
   766 
       
   767 	LOG( if (iLogLevel>=5) iPppLcp->iLogger->HexDump(_S("COMM Recv    "), _S("    "), ptr, end-ptr); )
       
   768 	LOG( if (iLogFormat == EpppDumpLogFormat) iPppLcp->iLogger->DumpFrame(EpppDirectionReceive,iRecvBuf); )
       
   769 
       
   770 	if (iRecvMBuf==NULL)
       
   771 		{
       
   772 		// Allocate a new MBuf
       
   773 		if (AppendRecvMbuf(mptr, mend))
       
   774 			{
       
   775 			return;	// error has been logged; exit
       
   776 			}
       
   777 		}
       
   778 	else
       
   779 		{
       
   780 		// Append to the existing MBuf
       
   781 		// Set the buffer length to the maximum to make room for received data.
       
   782 		// The correct length is set at the end of this method.
       
   783 		mptr = iRecvMBuf->EndPtr();
       
   784 		iRecvMBuf->SetLength(iRecvMBuf->Size());
       
   785 		mend = iRecvMBuf->EndPtr();
       
   786 		__ASSERT_DEBUG(mptr < mend, User::Panic(_L("PPP Panic"), 0));
       
   787 		}
       
   788 	
       
   789 	// Deal with pending escape sequence - this happens when part of a frame received, and it ends with an
       
   790  	// escaping sequence, but the char that is being escaped will be the first char in the next block of data
       
   791  	// to be received.
       
   792 	if (iFlags & KPppHdlcRecvEscPending)
       
   793 		{
       
   794 		if (UnescapeChar(ptr,end,mptr,mend))
       
   795 			{
       
   796 			return;	// error has been logged; exit
       
   797 			}
       
   798 		}
       
   799 	
       
   800 	while (ptr<end)
       
   801 		{
       
   802 		TUint8 ch = *ptr++;
       
   803 
       
   804 		// If this is the beginning or end of a frame...
       
   805 		if (ch==KPppHdlcFlagChar)
       
   806 			{
       
   807 			if (mptr!=iRecvMBuf->Ptr())
       
   808 				{
       
   809 				// If we have a partially full MBuf, set the length appropriately
       
   810 	 			// and stick it onto the receive queue for LCP
       
   811 				iRecvMBuf->SetLength(mptr - iRecvMBuf->Ptr());
       
   812 				if (AppendRecvMbuf(mptr, mend))
       
   813 					{
       
   814 					return;	// error has been logged; exit
       
   815 					}
       
   816 				}
       
   817 
       
   818 			// This is the end of the frame - so check and remove CRC
       
   819 			if (!iRecvPkt.IsEmpty())
       
   820 				{
       
   821 				// End of frame - check and remove CRC
       
   822 				TBool crcok = ETrue;
       
   823 
       
   824 				// Check the CRC for 16-bit FCS
       
   825 				if (iFlags & KPppHdlcRecvFcs16)
       
   826 					{
       
   827 					crcok = iRecvFcs16.IsGood();
       
   828 
       
   829 					// Initialize the CRC for a new packet
       
   830 					iRecvFcs16.Init();
       
   831 
       
   832 					RMBuf* m = iRecvPkt.Last();
       
   833 
       
   834 					// Attempt to remove 16 bit CRC
       
   835 					// adjend is not being used until after passing to a Decompressor
       
   836 					// hence decompressors were getting the CRC that should have been removed.
       
   837 					// 
       
   838 
       
   839 					// Replacement code 
       
   840 					if (m->Length()>2)
       
   841 						{
       
   842 						// Remove the CRC; must be at least one data byte in the last MBuf
       
   843 
       
   844 						m->AdjustEnd(-2);
       
   845 						}
       
   846 					else
       
   847 						// Special case where the CRC is the last byte/s in the buffer
       
   848 						// There is no way to remove just the last MBuf in the queue,
       
   849 						// so we must copy each MBuf except the last into a brand new
       
   850 						// RMBufQ, then copy them all back into the original one.
       
   851 						//
       
   852 						// TODO: See if it's possible to just set the length of the
       
   853 						// last MBuf to 0 and avoid all the copying.
       
   854 						{
       
   855 						// Get the odd length 0 -> 2
       
   856 						TInt oddLen = m->Length();
       
   857 						// Set up a temporary MBuf Queue and mbuf pointer
       
   858 						RMBufQ tmpQ;
       
   859 						tmpQ.Init();
       
   860 						RMBuf* tmpBuf;
       
   861 						// Loop removing all mbufs from the member queue
       
   862 						while((tmpBuf = iRecvPkt.Remove()) != NULL)
       
   863 							{
       
   864 							// Is it the last one? m points to last
       
   865 							if(tmpBuf == m)
       
   866 								// It is, so free it as it's only got CRC bytes
       
   867 								m->Free();
       
   868 							else
       
   869 								// put it on the temporary queue
       
   870 								tmpQ.Append(tmpBuf);
       
   871 							}
       
   872 						// Loop replacing the mbufs on the member queue
       
   873 						// NB : The last one was FREE'd in the previous loop
       
   874 						while((tmpBuf = tmpQ.Remove()) != NULL)
       
   875 							{
       
   876 							iRecvPkt.Append(tmpBuf);
       
   877 							}
       
   878 						m = iRecvPkt.Last();
       
   879 						if(m==NULL)
       
   880 							{
       
   881 							LOG( iPppLcp->iLogger->Printf(_L("PPP: HDLC: empty packet after CRC removal")));
       
   882 							return; // invalid frame has been discarded
       
   883 							}
       
   884 						// Subtract the CRC len from the NEW last buffer (Could be 0 -> 2)
       
   885 						m->AdjustEnd(oddLen - 2);
       
   886 						}
       
   887 					
       
   888 					}
       
   889 
       
   890 #ifdef __LCP_EXTENSION_FCS_32
       
   891 				// or calculate the CRC code for 32-bit FCSs
       
   892                 // TODO This feature is not tested
       
   893 				if (iFlags & KPppHdlcRecvFcs32)
       
   894 					{
       
   895 					crcok = iRecvFcs32.IsGood();
       
   896 
       
   897 					// Initialize the CRC for a new packet
       
   898 					if (iFlags & KPppHdlcRecvFcs32)
       
   899 						{
       
   900 						iRecvFcs32.Init();
       
   901 						}
       
   902 
       
   903 					// This doesn't handle the case of a part of the CRC sitting
       
   904 					// in a separate mbuf, which the CRC-16 code above handles.
       
   905 					// There are likely other problems with switching from
       
   906 					// 16 to 32 bit CRCs, and with sending 48 bits of CRCs
       
   907 					// (see RFC 1570).  --danfa
       
   908 					RMBuf* m = iRecvPkt.Last();
       
   909 					if (m->Length()>4)
       
   910 						m->AdjustEnd(-4);
       
   911 					else
       
   912 						adjend = 4;
       
   913 					}
       
   914 #endif
       
   915 				// We've calculated the CRC now, so continue processing
       
   916 				if (!crcok)
       
   917 					{
       
   918 					// The CRC is bad; queue a metapacket indicating so
       
   919 					LOG( iPppLcp->iLogger->Printf(_L("PPP: HDLC: Silently discarding frame due to bad CRC")));
       
   920 		 			DoBadRecv();
       
   921 		 			return;
       
   922 					}
       
   923 
       
   924 				// The CRC's OK, so sort out the other HDLC framing...
       
   925 				else
       
   926 					{
       
   927 					// Remove link header
       
   928 					RMBuf* m = iRecvPkt.First();
       
   929 
       
   930 					// Check that we have a valid frame length (<2 after FCS removal invalid according to 
       
   931  					// RFC1662)
       
   932  					// If not, silently discard the frame
       
   933  					if (m->Length() < 2)
       
   934  						{
       
   935  						LOG( iPppLcp->iLogger->Printf(_L("PPP: HDLC: Silently discarding frame due to bad length (<2 bytes after FCS removed)")));
       
   936 						DoBadRecv();
       
   937 						return;
       
   938  						}
       
   939  
       
   940 					TUint8* p = m->Ptr();
       
   941 					TUint addr=0, ctrl=0;
       
   942  					// Check to see if we've got address and control field compression active
       
   943 					if (iFlags & KPppHdlcRecvCompAddrCtrl)
       
   944 						{
       
   945 						// If we have, but they're still present anyway, adjust the start pointers appropriately
       
   946 						if (p[0]==KPppHdlcAddrByte && p[1]==KPppHdlcCtrlUIByte)
       
   947 							p += 2;
       
   948 						addr = KPppHdlcAddrByte;
       
   949 						ctrl = KPppHdlcCtrlUIByte;
       
   950 						}
       
   951 					else
       
   952 						{
       
   953 						// Get the address from the frame (RFC1662 - 1 byte - extensions may be defined later,
       
   954  						// and then we'll have to change this code)
       
   955  						addr = *p++;
       
   956  
       
   957  						// Check that the address wasn't even (all addresses must be odd - RFC1662)
       
   958  						//
       
   959  						// For full RFC compliance, we should == with 0xff here...
       
   960  						if (!(addr&0x01)) 
       
   961  							{
       
   962  							// Discard the frame
       
   963  							LOG( iPppLcp->iLogger->Printf(_L("PPP: HDLC: Silently discarding frame due to bad address field")));
       
   964 							DoBadRecv();
       
   965  							return;
       
   966  							}
       
   967 
       
   968 						// Get control byte from the frame (RFC1662 - 1 byte - extensions may be defined later,
       
   969  						// and then we'll have to change this code)
       
   970  						ctrl = *p++;
       
   971  						
       
   972  						// Check that the control field wasn't even (all control fields must be odd - RFC1662)
       
   973  						// For full RFC compliance, we should == with KPppHdlcCtrlUIByte here...
       
   974  						if (!(ctrl&0x01)) 
       
   975  							{
       
   976  							// Discard the frame
       
   977  							LOG( iPppLcp->iLogger->Printf(_L("PPP: HDLC: Silently discarding frame due to bad control field")));
       
   978  							DoBadRecv();
       
   979  							return;
       
   980  							}
       
   981  						}
       
   982 
       
   983 					// Extract the protocol information
       
   984 					TUint prot = DecodeProtocolID(p);
       
   985 
       
   986 					// Ensure that the header we just parsed doesn't extend beyond the end of the frame.
       
   987 					TInt hdrlen = p - m->Ptr();
       
   988 					if (hdrlen <= m->Length())
       
   989 						{
       
   990 						// Adjust start point to compensate for removal of address, control and protocol fields
       
   991 						m->AdjustStart(hdrlen);
       
   992 						}
       
   993 					else
       
   994 						{
       
   995 						// Catch-all safety check... looks like we've been passed
       
   996 						// a badly-framed packet.
       
   997 						LOG( iPppLcp->iLogger->Printf(_L("PPP: HDLC: Discarding badly framed packet")));
       
   998 						DoBadRecv();
       
   999  						return;
       
  1000 						}
       
  1001 
       
  1002 					// Check to see if we're running any compression
       
  1003 					if (prot == KPppIdCompressed)
       
  1004 						{
       
  1005 						// If we are, try and decompress the frame
       
  1006 						if (iPppDecompressor)
       
  1007 							{
       
  1008 							if (iPppDecompressor->Decompress(iRecvPkt))
       
  1009 								{
       
  1010 								m = iRecvPkt.First();
       
  1011 								p = m->Ptr();
       
  1012 								// Decompress OK so...
       
  1013 								// extract the protocol information
       
  1014 								prot = DecodeProtocolID(p);
       
  1015 								
       
  1016 								LOG(iPppLcp->iLogger->Printf(_L("Frame Prot %x"),prot);)
       
  1017 								m->AdjustStart(p-m->Ptr());
       
  1018 								}
       
  1019 							else
       
  1020 								{
       
  1021 								// Otherwise we couldn't decompress it, so throw away the frame
       
  1022  								LOG( iPppLcp->iLogger->Printf(_L("PPP: HDLC: Could not decode compressed packet - discarding")));
       
  1023 								DoBadRecv();
       
  1024 								return;
       
  1025 								}
       
  1026 							}
       
  1027 						}
       
  1028 					
       
  1029 					// Prepend and fill in info header and deliver to LCP
       
  1030 					RMBufPacket pkt;
       
  1031 					RMBufPktInfo* info = NULL;
       
  1032 					TRAPD(err, info=pkt.CreateL(iRecvPkt, 0);)
       
  1033 					if(err!=KErrNone)
       
  1034 						{
       
  1035 						// This is assumed to mean that we're OOM, but there might be other situations...
       
  1036 						LOG( iPppLcp->iLogger->Printf(_L("PPP: HDLC: Could not create info packet error %d"), err));
       
  1037 						//__DEBUGGER();
       
  1038 						return;
       
  1039 						}
       
  1040 
       
  1041 					TPppAddr::Cast(info->iDstAddr).SetAddress(addr);
       
  1042 					TPppAddr::Cast(info->iDstAddr).SetControl(ctrl);
       
  1043 					TPppAddr::Cast(info->iDstAddr).SetProtocol(prot);
       
  1044 
       
  1045 					TPppAddr::Cast(info->iDstAddr).SetCRCError(EFalse);
       
  1046 
       
  1047 					pkt.Pack();
       
  1048 					iRecvQ.Append(pkt);
       
  1049 					}
       
  1050 				}
       
  1051 			}
       
  1052 			
       
  1053 		// Check for escaping sequence
       
  1054 		else if (ch==KPppHdlcEscChar)
       
  1055 			{
       
  1056 			if (UnescapeChar(ptr,end,mptr,mend))
       
  1057 				{
       
  1058 				return;	// error has been logged; exit
       
  1059 				}
       
  1060 			}
       
  1061 		// Otherwise copy the char across to the iRecvMBuf - *** most executed case ***
       
  1062 		else
       
  1063 			{
       
  1064 			// If the character is in the receive ACCM, it's bogus--drop it on the floor.
       
  1065 			// Otherwise, XON/XOFF from the local DCE would be erroneously included in the packet.
       
  1066 			if (!IsInRecvEscMap(ch) &&
       
  1067 				DecodeChar(mptr, mend, ch))
       
  1068 				{
       
  1069 				return;	// error has been logged; exit
       
  1070 				}
       
  1071 			}
       
  1072 		}
       
  1073 		
       
  1074 	iRecvMBuf->SetLength(mptr - iRecvMBuf->Ptr());
       
  1075 	__ASSERT_DEBUG(mptr < mend, User::Panic(_L("PPP Panic"), 0));
       
  1076 	}
       
  1077 
       
  1078 
       
  1079 void CPppHdlcLink::BcaReadComplete(TInt aStatus)
       
  1080 /**
       
  1081 Comm Read has completed - decodes and passes to LCP
       
  1082 
       
  1083 @param aStatus Error code from CommRead()
       
  1084 */
       
  1085 	{
       
  1086 	switch (aStatus)
       
  1087 		{
       
  1088 	case KErrCommsOverrun:
       
  1089 	case KErrCommsFrame:
       
  1090 	case KErrCommsParity:
       
  1091 	case KErrNone:
       
  1092 		{
       
  1093 		if (aStatus == KErrNone)
       
  1094 			{
       
  1095 			// Unframe and queue the received packet
       
  1096 			DoRecv();
       
  1097 			}
       
  1098 		else
       
  1099 			{
       
  1100 			// Queue an error packet
       
  1101 			LOG( Logger().Printf(_L("CPppHdlcLink::BcaReadComplete: error %d. Doing Bad Receive."), aStatus); )
       
  1102 			DoBadRecv();
       
  1103 			}
       
  1104 			
       
  1105 		if (iState == EPppHdlcOpen)
       
  1106 			{
       
  1107 			iRecvBuf.SetMax();
       
  1108 			// Initiate another asynchronous read
       
  1109 			iBcaReader->Read(iRecvBuf);
       
  1110 			}
       
  1111 
       
  1112 		// Pass any received packets up the protocol chain
       
  1113 		RMBufChain pkt;
       
  1114 		while (iRecvQ.Remove(pkt))
       
  1115 			{
       
  1116 			// Parse and dump the PPP frame to the log
       
  1117 			LOG( if(iLogLevel>=4)  iPppLcp->iLogger->Dump(pkt, KPppHdlcRecvChannel); )
       
  1118 			LogUserData(pkt,KPppHdlcRecvChannel);	// MS
       
  1119 			DeliverToLcp(pkt);
       
  1120 			}
       
  1121 		}
       
  1122 		break;
       
  1123 
       
  1124 	case KErrCommsLineFail: // Usually means that the serial link was broken. (DCD/DTR down)
       
  1125 	default:
       
  1126 		LOG( Logger().Printf(_L("CPppHdlcLink::BcaReadComplete: Read Error %d"), aStatus); )
       
  1127 			
       
  1128 		LinkDown(aStatus);
       
  1129 		break;
       
  1130 		}
       
  1131 	}
       
  1132 
       
  1133 
       
  1134 /**
       
  1135 Sends more data (if the link is still open).
       
  1136 Called when CBcaWriter::Write() has completed.
       
  1137 
       
  1138 @param aStatus (ignored)
       
  1139 */
       
  1140 void CPppHdlcLink::BcaWriteComplete(TInt /*aStatus*/)
       
  1141 	{
       
  1142 	iFlags &= ~KPppHdlcSendBusy;
       
  1143 	//if (aStatus!=KErrNone)
       
  1144 	//	{
       
  1145 	//	LinkDown(aStatus);
       
  1146 	//	return;
       
  1147 	//	}
       
  1148 	if (iState == EPppHdlcOpen)
       
  1149 		{
       
  1150 		DoSend(EFalse);
       
  1151 		}		
       
  1152 	}
       
  1153 
       
  1154 TBool CPppHdlcLink::DecodeChar(TUint8*& aPtr, TUint8*& aPtrEnd, TUint8 aChar)
       
  1155 /**
       
  1156 Copies an unescaped character into a receive buffer and updates the CRC at the
       
  1157 same time. Allocates a new buffer if the current one fills up.
       
  1158 
       
  1159 @param aPtr Pointer to buffer; on return, points one past the last location used
       
  1160 @param aPtrEnd Pointer to one past the end of buffer (must be > aPtr on entry)
       
  1161 @param aChar Unescaped character
       
  1162 
       
  1163 @return ETrue when a new buffer could not be allocated
       
  1164 */
       
  1165 	{
       
  1166 	__ASSERT_DEBUG(aPtr < aPtrEnd, User::Panic(_L("PPP Panic"), 0));
       
  1167 	*aPtr++ = aChar;
       
  1168 	if (iFlags & KPppHdlcRecvFcs16)
       
  1169 		{
       
  1170 		iRecvFcs16.CalcByte(aChar);
       
  1171 		}
       
  1172 #ifdef __LCP_EXTENSION_FCS_32
       
  1173 	if (iFlags & KPppHdlcRecvFcs32)
       
  1174 		{
       
  1175 		iRecvFcs32.CalcByte(aChar);
       
  1176 		}
       
  1177 #endif
       
  1178 	if (aPtr>=aPtrEnd)
       
  1179 		{
       
  1180 		// Queue this MBuf and allocate another
       
  1181 		return AppendRecvMbuf(aPtr, aPtrEnd);
       
  1182 		}
       
  1183 	return EFalse;
       
  1184 	}
       
  1185 
       
  1186 void CPppHdlcLink::EncodeChar(TUint8*& aPtr, TUint8 aChar)
       
  1187 /**
       
  1188 Copies a character into a transmit buffer and escapes if necessary.
       
  1189 Updates the CRC at the same time.
       
  1190 
       
  1191 @param aPtr Pointer to buffer; on return, points one past the last location used
       
  1192 @param aChar Character to encode
       
  1193 */
       
  1194 	{
       
  1195 	if (IsEscapedChar(aChar))
       
  1196 		{
       
  1197 		*aPtr++=KPppHdlcEscChar;
       
  1198 		*aPtr++=(TUint8)(aChar^KPppHdlcEscBit);
       
  1199 		}
       
  1200 	else
       
  1201 		*aPtr++=aChar;
       
  1202 
       
  1203 	if (iFlags & KPppHdlcSendFcs16)
       
  1204 		{
       
  1205 		iSendFcs16.CalcByte(aChar);
       
  1206 		}
       
  1207 #ifdef __LCP_EXTENSION_FCS_32
       
  1208 	if (iFlags & KPppHdlcSendFcs32)
       
  1209 		{
       
  1210 		iSendFcs32.CalcByte(aChar);
       
  1211 		}
       
  1212 #endif
       
  1213 	}
       
  1214 
       
  1215 void CPppHdlcLink::CreateHdlcHeader(TUint8*& aPtr, TBool aRestart, TUint16 aProt)
       
  1216 /**
       
  1217 Creates and encodes an HDLC header into the output buffer and updates the CRC.
       
  1218 There must be sufficient space available in the output buffer.
       
  1219 
       
  1220 @param aPtr Pointer into buffer (must have at least 9 bytes free);
       
  1221        on return, points one past the last location used
       
  1222 @param aRestart EFalse if this frame immediately follows a previous frame
       
  1223 @param aProt PPP protocol ID
       
  1224 */
       
  1225 	{
       
  1226 	// Only send flag byte if not immediately following previous frame
       
  1227 	if (aRestart)
       
  1228 		*aPtr++ = KPppHdlcFlagChar;
       
  1229 
       
  1230 	// never apply to LCP
       
  1231 	if (aProt==KPppIdLcp || !(iFlags & KPppHdlcSendCompAddrCtrl))
       
  1232 		{
       
  1233 		EncodeChar(aPtr, KPppHdlcAddrByte);
       
  1234 		EncodeChar(aPtr, KPppHdlcCtrlUIByte);
       
  1235 		}
       
  1236 
       
  1237 	// never apply to LCP (LCP > 255 anyway!)
       
  1238 	if (aProt>0xff || !(iFlags & KPppHdlcSendCompProt))
       
  1239 		EncodeChar(aPtr, (TUint8)(aProt>>8));
       
  1240 	EncodeChar(aPtr, (TUint8)(aProt&0xff));
       
  1241 	}		
       
  1242 
       
  1243 TInt CPppHdlcLink::Send(RMBufChain& aPacket, TUint aPppId/*=KPppIdAsIs*/)
       
  1244 /**
       
  1245 Queues outgoing packet and ensures writer is active.
       
  1246 If PPP compression is enabled, the compresses the frame first then reinserts
       
  1247 it into the queue.
       
  1248 
       
  1249 @param aPacket MBuf chain containing packet
       
  1250 @param aPppId PPP protocol number
       
  1251 
       
  1252 @return KErrNoMemory when out of memory, or 1 if packet was queued,
       
  1253         or KErrNone if queue is above high water mark or HDLC is not open
       
  1254 */
       
  1255 	{
       
  1256 	RMBufPktInfo* info = RMBufPacket::PeekInfoInChain(aPacket);
       
  1257 	TPppAddr::Cast(info->iDstAddr).SetAddress(KPppHdlcAddrByte);
       
  1258 	TPppAddr::Cast(info->iDstAddr).SetControl(KPppHdlcCtrlUIByte);
       
  1259 
       
  1260 	if ((aPppId >= 0x0021) &&
       
  1261 		(aPppId <= 0x00fa))
       
  1262 		{
       
  1263 		if (iPppCompressor)
       
  1264 			{
       
  1265 			// Remove the Info Header before compressing
       
  1266 			RMBuf* Temp = aPacket.Remove();
       
  1267 
       
  1268 			//__DEBUGGER();
       
  1269 			TPppCompressReturnValue ret = iPppCompressor->Compress(aPacket, (TUint16)aPppId);
       
  1270 			
       
  1271 			if (ret == EPppCompressedOK)
       
  1272 				{
       
  1273 				// Set packet length to the new, compressed length
       
  1274 				info->iLength = aPacket.Length();
       
  1275 				
       
  1276 				aPacket.Prepend(Temp);
       
  1277 				aPppId = KPppIdCompressed;
       
  1278 				}
       
  1279 
       
  1280 			else if(ret ==EPppCompressedFrameExpanded)
       
  1281 				{
       
  1282 				// The frame expanded during compression; send original frame
       
  1283 				aPacket.Prepend(Temp);
       
  1284 				}
       
  1285 			
       
  1286 			else //(ret == EPppCompressedNotOK)
       
  1287 				{
       
  1288 				// Throw everything away
       
  1289 				//__DEBUGGER();
       
  1290 				aPacket.Free();
       
  1291 				Temp->Free();
       
  1292 				return KErrNoMemory;
       
  1293 				}			
       
  1294 			}
       
  1295 
       
  1296 		
       
  1297 /*++		
       
  1298 		if (iPppCompressor)
       
  1299 			{
       
  1300 			RMBuf* Temp;
       
  1301 
       
  1302 			Temp = aPacket.Remove();
       
  1303 
       
  1304 			//
       
  1305 			// Remove the Info Header
       
  1306 			//
       
  1307 			//__DEBUGGER();
       
  1308 			if (iPppCompressor->Compress(aPacket, (TUint16)aPppId))
       
  1309 				{
       
  1310 				//
       
  1311 				// Set the length to the new length
       
  1312 				//
       
  1313 				info->iLength = aPacket.Length();
       
  1314 				
       
  1315 				}
       
  1316 			else
       
  1317 				{
       
  1318 				//
       
  1319 				// Throw everything away
       
  1320 				//
       
  1321 				//__DEBUGGER();
       
  1322 				aPacket.Free();
       
  1323 				Temp->Free();
       
  1324 				return KErrNoMemory;
       
  1325 				}
       
  1326 			aPacket.Prepend(Temp);
       
  1327 			aPppId = KPppIdCompressed;
       
  1328 			}
       
  1329 --*/
       
  1330 
       
  1331 		}
       
  1332 
       
  1333 	if (aPppId!=KPppIdAsIs && aPppId!=KPppIdUnknown && aPppId!=KPppIdCopyAll)
       
  1334 		{
       
  1335 		TPppAddr::Cast(info->iDstAddr).SetProtocol(aPppId);
       
  1336 		}
       
  1337 	iSendNumBufs += aPacket.NumBufs();
       
  1338 	iSendQ.Append(aPacket);
       
  1339 
       
  1340 	switch (iState)
       
  1341 		{
       
  1342 	case EPppHdlcConnecting:
       
  1343 		break;
       
  1344 	case EPppHdlcOpen:
       
  1345 		if (iSendFlowOn && iSendNumBufs>=iSendHiWat)
       
  1346 			iSendFlowOn = EFalse;
       
  1347 		if (!(iFlags & KPppHdlcSendBusy))
       
  1348 			DoSend(ETrue);
       
  1349 		return iSendFlowOn ? 1 : 0;
       
  1350 	case EPppHdlcClosed:
       
  1351 		{
       
  1352 		 TRAPD(err, OpenL());
       
  1353 		 if (KErrNone != err) 
       
  1354 			{
       
  1355 			LOG( iPppLcp->iLogger->Printf(_L("PPP Link Open Failure with error %d"), err); )
       
  1356 			}
       
  1357 		}
       
  1358 		break;
       
  1359 	default:
       
  1360 		break;
       
  1361 		}
       
  1362 	return 0;
       
  1363 	}
       
  1364 
       
  1365 void CPppHdlcLink::DoSend(TBool aRestart)
       
  1366 /**
       
  1367 Writes more data to the comm port.
       
  1368 The send buffer is filled with as much of the encoded PPP frame as will
       
  1369 fit, then is transmitted to the comm port. The next call will send the
       
  1370 remaining data (if any), or start with the next PPP frame from the queue.
       
  1371 
       
  1372 @param aRestart EFalse if this call immediately follows a previous frame
       
  1373 */
       
  1374 	{
       
  1375 	__ASSERT_DEBUG(!(iFlags & KPppHdlcSendBusy), User::Panic(_L("PPP Panic"), 0));
       
  1376 
       
  1377 	TUint8* ptr = (TUint8*)(iSendBuf.Ptr());
       
  1378 	TUint8* end = ptr+(iSendBuf.MaxLength()-1);	// -1 allows safe encoding
       
  1379 	
       
  1380 	// Starting a new packet?
       
  1381 	if (iSendPkt.IsEmpty())
       
  1382 		{
       
  1383 		// Get next packet from send queue
       
  1384 		RMBufPacket pkt;
       
  1385 		if (!iSendQ.Remove(pkt))
       
  1386 			{
       
  1387 			iSendNumBufs=0; // Must be so
       
  1388 			return;
       
  1389 			}
       
  1390 
       
  1391 		// Parse and dump the PPP frame to the log
       
  1392 		LOG(if(iLogLevel>=4)  iPppLcp->iLogger->Dump(pkt, KPppHdlcSendChannel); )
       
  1393 		LogUserData(pkt,KPppHdlcSendChannel);	//MS
       
  1394 		
       
  1395 		if (iFlags & KPppHdlcSendFcs16)
       
  1396 			{
       
  1397 			iSendFcs16.Init();
       
  1398 			}
       
  1399 #ifdef __LCP_EXTENSION_FCS_32
       
  1400 		if (iFlags & KPppHdlcSendFcs32)
       
  1401 			{
       
  1402 			iSendFcs32.Init();
       
  1403 			}
       
  1404 #endif
       
  1405 		
       
  1406 /*		
       
  1407 		// Check if have reached the point after which new
       
  1408 		// link config options have to be applied
       
  1409 		if (iFlags & KPppHdlcApplyPending)
       
  1410 			{
       
  1411 			if (pkt.First()==iApplyConfigMarker)
       
  1412 				iFlags |= KPppHdlcAtApplyMark;
       
  1413 			}
       
  1414 */		
       
  1415 		RMBufPktInfo* info = pkt.Unpack();
       
  1416 		TUint16 prot = (TUint16) TPppAddr::Cast(info->iDstAddr).GetProtocol();
       
  1417 
       
  1418 /*
       
  1419 		// Apply new configuration if a non LCP frame
       
  1420 		if (prot!=KPppIdLcp && (iFlags & KPppHdlcAtApplyMark))
       
  1421 			DeferredApplyOptions();
       
  1422 */
       
  1423 		// Apply new configuration if a non LCP frame
       
  1424 		// Note: This might pose a problem if a defective Cisco router sends
       
  1425 		// an ACP packet too early.
       
  1426 		if (prot!=KPppIdLcp)
       
  1427 			{
       
  1428 			if (iFlags & KPppHdlcApplyPending)
       
  1429 				DeferredApplyOptions();
       
  1430 			}
       
  1431 
       
  1432 		// Create and encode the frame header
       
  1433 		CreateHdlcHeader(ptr, aRestart, prot);
       
  1434 		__ASSERT_DEBUG(ptr <= end, User::Panic(_L("PPP Panic"), 0));
       
  1435 		
       
  1436 		iSendPkt.Assign(pkt);
       
  1437 		pkt.FreeInfo();
       
  1438 		--iSendNumBufs;
       
  1439 		}		
       
  1440 
       
  1441 	// Sending Packet data...
       
  1442 	TInt ensure = KMBufSmallSize<<1; // worst-case is every byte is escaped
       
  1443 	if (iFlags & KPppHdlcSendFcs16)
       
  1444 		ensure += 4;	// enough space for 2 escaped bytes
       
  1445 #ifdef __LCP_EXTENSION_FCS_32
       
  1446 	if (iFlags & KPppHdlcSendFcs32)
       
  1447 		ensure += 8;	// enough space for 4 escaped bytes
       
  1448 #endif
       
  1449     // Encode all buffers in the chain (that will fit) into the send buffer
       
  1450 	while ((ptr+ensure)<end)
       
  1451 		{
       
  1452 		RMBuf *m = iSendPkt.First();
       
  1453 		TUint8* mptr = m->Ptr();
       
  1454 		TUint8* mend = m->EndPtr();
       
  1455 		// Encode frame data into send buffer & calculate CRC
       
  1456 		while (mptr<mend)
       
  1457 			{
       
  1458 			EncodeChar(ptr, *mptr++);
       
  1459 			}
       
  1460 		__ASSERT_DEBUG(ptr <= end, User::Panic(_L("PPP Panic"), 0));
       
  1461 		iSendPkt.Remove();
       
  1462 		m->Free();
       
  1463 		--iSendNumBufs;
       
  1464 		if (!iSendFlowOn && iSendNumBufs<iSendLoWat)
       
  1465 			{
       
  1466 			// The backlog of buffers is clearing, so allow more to come
       
  1467 			iSendFlowOn = ETrue;
       
  1468 			iPppLcp->LinkFlowOn();
       
  1469 			}
       
  1470 		if (iSendPkt.IsEmpty())
       
  1471 			break;
       
  1472 		}
       
  1473 
       
  1474     // If the mbuf chain is empty, we've encoded the entire packet, so end it
       
  1475 	// by appending the CRC and flag character to the send buffer.
       
  1476 	// We left ourselves enough space in the buffer for this in the loop above.
       
  1477 	if (iSendPkt.IsEmpty())
       
  1478 		{
       
  1479 		if (iFlags & KPppHdlcSendFcs16)
       
  1480 			{
       
  1481 			TUint16 fcs = iSendFcs16.Fcs();	// save FCS before it changes
       
  1482 			EncodeChar(ptr, (TUint8)(fcs & 0xff));
       
  1483 			EncodeChar(ptr, (TUint8)(fcs >> 8));
       
  1484 			}
       
  1485 #ifdef __LCP_EXTENSION_FCS_32
       
  1486 		if (iFlags & KPppHdlcSendFcs32)
       
  1487 			{
       
  1488 			TUint32 fcs = iSendFcs32.Fcs();	// save FCS before it changes
       
  1489 			EncodeChar(ptr, (TUint8)(fcs & 0xff));
       
  1490 			EncodeChar(ptr, (TUint8)((fcs>>8) & 0xff));
       
  1491 			EncodeChar(ptr, (TUint8)((fcs>>16) & 0xff));
       
  1492 			EncodeChar(ptr, (TUint8)((fcs>>24) & 0xff));
       
  1493 			}
       
  1494 #endif
       
  1495 		// Terminating flag byte
       
  1496 		*ptr++ = KPppHdlcFlagChar;
       
  1497 		__ASSERT_DEBUG(ptr <= end, User::Panic(_L("PPP Panic"), 0));
       
  1498 		}
       
  1499 	iSendBuf.SetLength(ptr - iSendBuf.Ptr());
       
  1500 
       
  1501 	// Log after HDLC framing and escaping
       
  1502 	// DoSend() might be called several times to send one (long) frame.
       
  1503 	// This is supported by EpppDumpLogFormat but not necessarily by other formats.
       
  1504 	LOG ( if (iLogLevel>=5) iPppLcp->iLogger->HexDump(_S("COMM Send    "), _S("    "), iSendBuf.Ptr(), iSendBuf.Length()); )
       
  1505 	LOG ( if (iLogFormat == EpppDumpLogFormat) iPppLcp->iLogger->DumpFrame(EpppDirectionSend,iSendBuf); )
       
  1506 
       
  1507 	iFlags |= KPppHdlcSendBusy;	// indicate that we have an outstanding write
       
  1508 	iBcaWriter->Write(iSendBuf);
       
  1509 	}
       
  1510 
       
  1511 
       
  1512 /**
       
  1513 Configures the comm port for our needs.  Also initializes flags
       
  1514 in preparation for receiving the first packet.
       
  1515 
       
  1516 */
       
  1517 void CPppHdlcLink::PacketModeOnL()
       
  1518 	{
       
  1519 	if (iFlags & KPppHdlcCommConfigOk) // Already configured.
       
  1520 		{
       
  1521 		return;
       
  1522 		}
       
  1523 
       
  1524 	// Open the BCA channel now:
       
  1525 	iBcaControl->StartStartupSequence(); // Next we are in CBcaControl::RunL	
       
  1526 	}
       
  1527 
       
  1528 /** Saves original serial port configuration.
       
  1529 
       
  1530 @param aHdlcConfig the config to save */
       
  1531 void CPppHdlcLink::SetOriginalSerialPortConfig(TCommConfig& aHdlcConfig)
       
  1532 	{
       
  1533 	if(iFlags & KPppHdlcOrigConfig) // We already have the original port settings
       
  1534 		{
       
  1535 		return; // What we have may not be original (could have been set by us)
       
  1536 		// This can happen if the link is being restarted 
       
  1537 		// It's easier to protect the settings from here, than from the BCA control
       
  1538 		}
       
  1539 	
       
  1540 	iFlags |= KPppHdlcOrigConfig;
       
  1541 	iOrigConfig = aHdlcConfig;
       
  1542 	}
       
  1543 	
       
  1544 /** Configures the BCA channel serial parameters for use by HDLC.
       
  1545 
       
  1546 @param aHdlcConfig the desirable serial configuration.
       
  1547 */
       
  1548 void CPppHdlcLink::GetSerialPortConfigForHdlc(TCommConfig& aHdlcConfig) const
       
  1549 	{
       
  1550 	LOG( iPppLcp->iLogger->Printf(_L("CPppHdlcLink::GetSerialPortConfigForHdlc()")); )
       
  1551 
       
  1552 	aHdlcConfig = iOrigConfig;
       
  1553 
       
  1554 	aHdlcConfig().iTerminatorCount = 1;
       
  1555 	aHdlcConfig().iTerminator[0] = KPppHdlcFlagChar;
       
  1556 
       
  1557 	// if 7 + parity, correct to 8N (for ISPs such as CompuServe)
       
  1558 	if ( aHdlcConfig().iDataBits == EData7 && aHdlcConfig().iParity != EParityNone )
       
  1559 		{
       
  1560 		aHdlcConfig().iDataBits = EData8;
       
  1561 		aHdlcConfig().iParity   = EParityNone;
       
  1562 		}
       
  1563 
       
  1564 	aHdlcConfig().iHandshake = GetHandShaking();
       
  1565 	}
       
  1566 
       
  1567 /**
       
  1568 Returns original serial configuration of the BCA channel
       
  1569 
       
  1570 @return the original serial port configuration.
       
  1571  */
       
  1572 TCommConfig CPppHdlcLink::OriginalSerialPortConfig() const
       
  1573 	{
       
  1574 	return iOrigConfig;
       
  1575 	}
       
  1576 
       
  1577 	
       
  1578 void CPppHdlcLink::StartPPP()
       
  1579 /** Brings up PPP link and read a packet.*/
       
  1580 	{
       
  1581 	InitEscMap();
       
  1582 		
       
  1583 	// Always expect bytes 0..31 to be escaped initially
       
  1584 	iRecvEscMap = 0xffffffff;
       
  1585 
       
  1586 	iFlags = KPppHdlcSendFcs16 | KPppHdlcRecvFcs16;
       
  1587 
       
  1588 	iFlags |= KPppHdlcCommConfigOk;
       
  1589 	
       
  1590 	iState = EPppHdlcOpen;
       
  1591 	iSendFlowOn = ETrue;
       
  1592 	iPppLcp->LinkLayerUp();
       
  1593 	
       
  1594 	iRecvBuf = GetExcessData();
       
  1595     if(iRecvBuf.Length())
       
  1596 		{
       
  1597 		// Simulate a completed read in order to force processing of excess data received from the Agent.
       
  1598 		iBcaReader->ReadReady();
       
  1599 		}
       
  1600 	else
       
  1601 		{
       
  1602 		iRecvBuf.SetMax();
       
  1603   		iBcaReader->Read(iRecvBuf);
       
  1604 		} 
       
  1605 	}
       
  1606 
       
  1607 /**
       
  1608 Triggers BCA shutdown, if applicable. This restores the original Comm port config.
       
  1609 Note: If the BCA was not opened, it will not be shut down. In this case, there is no
       
  1610 need to restore original config, because config can be set on open BCA only.
       
  1611 
       
  1612 We can be called twice: Once because PPP shuts down the link, the second time when BCA
       
  1613 reports that it has gone down. In this case, we guard against shutting down the BCA for 
       
  1614 the second time, and report link down to LCP. 
       
  1615 */
       
  1616 void CPppHdlcLink::PacketModeOff()
       
  1617 	{
       
  1618 	LOG( iPppLcp->iLogger->Printf(_L("CPppHdlcLink::PacketModeOff(): Releasing the link.")); )
       
  1619 
       
  1620 	iBcaReader->Cancel();
       
  1621 	iBcaWriter->Cancel();
       
  1622 	iBcaControl->Cancel();
       
  1623 
       
  1624 	if (iFlags & KPppHdlcCommConfigOk)
       
  1625 		{
       
  1626 		iFlags &= ~KPppHdlcCommConfigOk;
       
  1627 		}
       
  1628 			
       
  1629 	if(iBcaControl->BcaIsOpen())
       
  1630 		{
       
  1631 		LOG( iPppLcp->iLogger->Printf(_L("CPppHdlcLink::PacketModeOff(): BCA channel is open. Shutting it down.")); )
       
  1632 
       
  1633 		iBcaControl->StartShutdownSequence(); // Next we are in CBcaControl::RunL
       
  1634 		// which will call LinkTerminationComplete eventually.	
       
  1635 		}
       
  1636 	else // Nothing to shutdown, the link is finished now.
       
  1637 		{
       
  1638 		LinkTerminationComplete(); 
       
  1639 		}		
       
  1640 	}
       
  1641 
       
  1642 /**
       
  1643 Called when the HDLC link termination is complete. 
       
  1644 Releases the send buffer & notifies upper layers 
       
  1645 
       
  1646 This call MUST be made after HDLC is finished, else LCP may wait for link to report termination forever.
       
  1647 */
       
  1648 void CPppHdlcLink::LinkTerminationComplete()
       
  1649 	{
       
  1650 	LOG( iPppLcp->iLogger->Printf(_L("CPppHdlcLink::LinkTerminationComplete: HDLC Link is finished, iLinkDown[%d]: 1 Notifying upper layer."), iLinkDown); )
       
  1651 
       
  1652 	iState = EPppHdlcClosed;
       
  1653 	FreeBuf();
       
  1654 	if(iLinkDown) // LCP can ask us not to notify it.
       
  1655 		{
       
  1656 		iPppLcp->LinkLayerDown(iError);		// This is essentially PPP 'Down' event on LCP
       
  1657 		}
       
  1658 	iLinkDown = ETrue; // reset to default
       
  1659 	}
       
  1660 
       
  1661 /**
       
  1662 Does the HDLC link require graceful shutdown (as opposed to an immediate close) of the BCA channel?
       
  1663 
       
  1664 @return ETrue if yes.
       
  1665 */ 
       
  1666 TBool CPppHdlcLink::DoShutdownBcaGracefully() const
       
  1667 	{
       
  1668 	return KErrConnectionTerminated != iError;
       
  1669 	}
       
  1670 	
       
  1671 
       
  1672 /** Frees the send buffering resources of the BCA.*/
       
  1673 void CPppHdlcLink::FreeBuf()
       
  1674 	{
       
  1675 	LOG( iPppLcp->iLogger->Printf(_L("CPppHdlcLink::FreeBuf()")); )
       
  1676 	iSendPkt.Free();
       
  1677 	iSendQ.Free();
       
  1678 	iSendNumBufs=0;
       
  1679 	}
       
  1680 
       
  1681 
       
  1682 void CPppHdlcLink::LinkDown(TInt aStatus)
       
  1683 /**
       
  1684 Link down - drops out of packet mode and notifies with reason.
       
  1685 
       
  1686 @param aStatus Error code indicating the reason the link is going down
       
  1687 */
       
  1688 	{
       
  1689 	iError = (KErrNone == iError) ? aStatus : iError; // Try to get an actual error code instead of KErrNone
       
  1690 	// We can stay with KErrNone if the link closure was requested by the upper layer. This is OK, the upper layer
       
  1691 	// will take care of the error code.
       
  1692 	PacketModeOff(); // Disconnect from the link. 
       
  1693 	}
       
  1694 
       
  1695 void CPppHdlcLink::ReadIniFileL()
       
  1696 /**
       
  1697 Reads settings from the ini file.
       
  1698 Default values are assumed if the file does not exist.
       
  1699 
       
  1700 @leave Error if the ini file is found but cannot be read
       
  1701 */
       
  1702 	{
       
  1703 	// Set up defaults in case they aren't set in the .ini file
       
  1704 	iDesiredRecvEscMap = 0x00000000;
       
  1705 	iPppLcp->SetMaxReceiveSize(0);
       
  1706 
       
  1707 	// Read the correct .ini file depending on whether we're configured for server mode
       
  1708 	CESockIniData* ini = NULL;
       
  1709 	TRAPD(res,
       
  1710 		if (iPppLcp->PppLinkMode() == CPppLcpConfig::EPppLinkIsServer)
       
  1711 			{
       
  1712 			ini = CESockIniData::NewL(PPP_SERVER_INI_FILE);
       
  1713 			}
       
  1714 		else
       
  1715 			{
       
  1716 			ini = CESockIniData::NewL(PPP_INI_FILE);
       
  1717 			}
       
  1718 		)
       
  1719 	if(res!=KErrNone)
       
  1720 		{
       
  1721 		if(res==KErrNotFound)
       
  1722 			{
       
  1723 			return;
       
  1724 			}
       
  1725 		User::Leave(res);
       
  1726 		}
       
  1727 
       
  1728 	CleanupStack::PushL(ini);
       
  1729 
       
  1730 	// Each port can have its own high and low watermark settings by putting
       
  1731 	// them in a section like [link::comm::0]
       
  1732     TPortName port(iPppLcp->GetBCAProvision()->GetPortName());
       
  1733 	_LIT(KLink, "link");
       
  1734 	TName name(KLink);
       
  1735 	port.LowerCase();
       
  1736 	name.AppendFormat(_L("::%S"), &port);
       
  1737 	
       
  1738 	TInt lo, hi;
       
  1739    _LIT(KLowMark, "LoMark");
       
  1740    _LIT(KHighMark, "HiMark");
       
  1741 
       
  1742 	if (ini->FindVar(name, KLowMark, lo) && ini->FindVar(name, KHighMark, hi))
       
  1743 		{
       
  1744 		iSendLoWat = lo;
       
  1745 		iSendHiWat = hi;
       
  1746 		}
       
  1747 	else if (ini->FindVar(KLink, KLowMark, lo) && ini->FindVar(KLink, KHighMark, hi))
       
  1748 		{
       
  1749 		iSendLoWat = lo;
       
  1750 		iSendHiWat = hi;
       
  1751 		}
       
  1752 
       
  1753 #if defined (_DEBUG) 
       
  1754 //Log level
       
  1755 //
       
  1756 //Options are:
       
  1757 //n=0 Finite State Machine transition are logged.
       
  1758 //n=1 Reserved for future use.
       
  1759 //n=2 Reserved for future use.
       
  1760 //n=3 Reserved for future use.
       
  1761 //n=4 Log parsed PPP packets *SLOW* (superseded by TcpLog.log).
       
  1762 //n=5 HexDump of PPP packets *VERY SLOW* (superseded by TcpLog.log).
       
  1763 //
       
  1764 //		A new log is generated if the \logs\tcpdump folder is created.
       
  1765 //		TcpDump.log is a log created in a binary format,
       
  1766 //		hence non readable with a text editor.
       
  1767 //		It can be used as an input file for Ethereal..
       
  1768 //	Ethereal is a general purpose packet analyser, that can parse a wide variety of protocols.
       
  1769 //	It is freeware and can be fetched from: www.ethereal.com.
       
  1770 	_LIT(KLogSection, "log");
       
  1771 	_LIT(KLogLevel, "level");
       
  1772 	TInt logLevel;
       
  1773 	if (ini->FindVar(KLogSection, KLogLevel, logLevel) && (logLevel>=0 ))
       
  1774 		{
       
  1775 		iLogLevel = logLevel;
       
  1776 		}
       
  1777 	else
       
  1778 		{
       
  1779 		iLogLevel = 1;
       
  1780 		}
       
  1781 
       
  1782 //Log File Format
       
  1783 //
       
  1784 //Options are:
       
  1785 //n=0 PPPdump format
       
  1786    _LIT(KlogFormat, "logFormat");
       
  1787 	ini->FindVar(KLogSection, KlogFormat, iLogFormat);
       
  1788 	if(iLogFormat<0 || iLogFormat>=ElastLogFormat)
       
  1789 		{
       
  1790 		iLogFormat = EpppDumpLogFormat;
       
  1791 		}
       
  1792 
       
  1793 //
       
  1794 //Link format
       
  1795 //
       
  1796 //Options are:
       
  1797 //n=0 Entire PPP frame is logged (for debugging - incompatible with tcptrace)
       
  1798 //n=1 Only IP frames are logged (for performance analysis with tcptrace)
       
  1799    _LIT(KlogLinkFormat, "linkFormat");
       
  1800 	ini->FindVar(KLogSection, KlogLinkFormat, iLogLinkFormat);
       
  1801 	if(iLogLinkFormat<0 || iLogLinkFormat>=ElastLogLinkFormat)
       
  1802 		{
       
  1803 		iLogLinkFormat = EpppLogLinkFormat;
       
  1804 		}
       
  1805 #endif
       
  1806 
       
  1807 //
       
  1808 	// Added for ACCM configuration
       
  1809 	// These two strings are the ones in ppp.ini :-
       
  1810 	// The example below would enable accm config and negate the need to escape values 4 - 7 inclusive
       
  1811 	// [link]
       
  1812 	// PPPEnableAccm= 1
       
  1813 	// PPPAccm= FFFFFF0F
       
  1814 	// XON and XOFF characters are added no matter what
       
  1815 	_LIT(KEnableACCM, "PPPEnableAccm");
       
  1816 	_LIT(KACCMValue, "PPPAccm");
       
  1817 	TInt enable;
       
  1818 	// Check ACCM configuration is enabled first
       
  1819 	if (ini->FindVar(KLink,KEnableACCM, enable) && enable != 0)
       
  1820 		{
       
  1821 		TPtrC hexStr;
       
  1822 		// We are enabled, read the 8 Digit ASCII HEX value
       
  1823 		if (ini->FindVar(KLink,KACCMValue,hexStr))
       
  1824 			{
       
  1825 			// Convert it to a 32 bit integer
       
  1826 			TLex lex(hexStr);
       
  1827 			lex.Val(iDesiredRecvEscMap,EHex);
       
  1828 			}
       
  1829 		}
       
  1830 
       
  1831 //
       
  1832 	// Added for MRU configuration
       
  1833 	// These two strings are the ones in ppp.ini :-
       
  1834 	// [link]
       
  1835 	// PPPEnableMru= 1
       
  1836 	// PPPMru= 1500
       
  1837 	_LIT(KEnableMRU, "PPPEnableMru");
       
  1838 	_LIT(KMRUValue, "PPPMru");
       
  1839 	if (ini->FindVar(KLink,KEnableMRU, enable) && enable != 0)
       
  1840 		{
       
  1841 		TInt mru;
       
  1842 		// We are enabled, read a 32 Bit value
       
  1843 		if (ini->FindVar(KLink,KMRUValue,mru))
       
  1844 			{
       
  1845 			iPppLcp->SetMaxReceiveSize(mru);
       
  1846 			}
       
  1847 		}
       
  1848 //
       
  1849 
       
  1850 	CleanupStack::PopAndDestroy();
       
  1851 	}
       
  1852 
       
  1853 
       
  1854 void CPppHdlcLink::StartL()
       
  1855 /**
       
  1856 Starts the PPP link.
       
  1857 
       
  1858 @leave Error if comm port cannot be initialized
       
  1859 */
       
  1860 	{
       
  1861 	LOG( iPppLcp->iLogger->Printf(_L("PPP Link StartL")); )
       
  1862     LOG( iPppLcp->iLogger->DumpFrameFileHeader(iLogFormat, iLogLinkFormat); );
       
  1863 
       
  1864 	ReadIniFileL();
       
  1865 
       
  1866 	// Configure the Link & BCA.
       
  1867 	PacketModeOnL();
       
  1868 	}
       
  1869 	
       
  1870 
       
  1871 void CPppHdlcLink::Stop(TInt aReason, TBool aLinkDown)
       
  1872 /**
       
  1873 Shuts down the PPP link.
       
  1874 
       
  1875 @param aReason Error code indicating the reason the link has gone down
       
  1876 @param aLinkDown ETrue if the link is actually going down,
       
  1877 or EFalse if it is just being reset
       
  1878 */
       
  1879 	{
       
  1880 	LOG( iPppLcp->iLogger->Printf(_L("CPppHdlcLink::Stop: Stopping HDLC Link.")); )
       
  1881 	iError = aReason;
       
  1882 	iLinkDown = aLinkDown;
       
  1883 	PacketModeOff(); 
       
  1884 	}
       
  1885 
       
  1886 TInt CPppHdlcLink::SpeedMetric()
       
  1887 /**
       
  1888 Determines the speed of the communications port.
       
  1889 
       
  1890 @pre PacketModeOnL() must have been called
       
  1891 
       
  1892 @return Speed in bps or 0 if unknown
       
  1893 */
       
  1894 	{
       
  1895 	switch (iOrigConfig().iRate)
       
  1896 		{
       
  1897 	case EBps50:
       
  1898 		return 50;
       
  1899 	case EBps75:
       
  1900 		return 75;
       
  1901 	case EBps110:
       
  1902 		return 110;
       
  1903 	case EBps134:
       
  1904 		return 134;
       
  1905 	case EBps150:
       
  1906 		return 150;
       
  1907 	case EBps300:
       
  1908 		return 300;
       
  1909 	case EBps600:
       
  1910 		return 600;
       
  1911 	case EBps1200:
       
  1912 		return 1200;
       
  1913 	case EBps1800:
       
  1914 		return 1800;
       
  1915 	case EBps2000:
       
  1916 		return 2000;
       
  1917 	case EBps2400:
       
  1918 		return 2400;
       
  1919 	case EBps3600:
       
  1920 		return 3600;
       
  1921 	case EBps4800:
       
  1922 		return 4800;
       
  1923 	case EBps7200:
       
  1924 		return 7200;
       
  1925 	case EBps9600:
       
  1926 		return 9600;
       
  1927 	case EBps19200:
       
  1928 		return 19200;
       
  1929 	case EBps38400:
       
  1930 		return 38400;
       
  1931 	case EBps57600:
       
  1932 		return 57600;
       
  1933 	case EBps115200:
       
  1934 		return 115200;
       
  1935 	case EBps230400:
       
  1936 		return 230400;
       
  1937 	case EBps460800:
       
  1938 		return 460800;
       
  1939 	case EBps576000:
       
  1940 		return 576000;
       
  1941 	case EBps1152000:
       
  1942 		return 1152000;
       
  1943 	case EBps4000000:
       
  1944 		return 4000000;
       
  1945 	case EBpsSpecial:
       
  1946 		return iOrigConfig().iSpecialRate;
       
  1947 	default:
       
  1948 		;	// unknown speed
       
  1949 		}
       
  1950 	return 0;
       
  1951 	}
       
  1952 
       
  1953 //=======================================
       
  1954 // JGG PPP CHANGE
       
  1955 void CPppHdlcLink::GetDataTransfer(RPacketContext::TDataVolume& aData)
       
  1956 //void CPppHdlcLink::GetDataTransfer(RGprsContext::TDataVolume& aData)
       
  1957 //=======================================
       
  1958 /**
       
  1959 Returns the current total amount of IP data transferred.
       
  1960 
       
  1961 @param aData Receives the data count
       
  1962 */
       
  1963 	{
       
  1964 	aData.iBytesSent = iSentData;
       
  1965 	aData.iOverflowCounterSent = 0;
       
  1966 	aData.iBytesReceived = iRecvdData;
       
  1967 	aData.iOverflowCounterReceived = 0;
       
  1968 	}
       
  1969 
       
  1970 void CPppHdlcLink::LogUserData(RMBufChain& aPacket, TInt aChannel)
       
  1971 /**
       
  1972 Updates the current total of PPP payload bytes transferred.
       
  1973 Separate counts are maintained for bytes received and transmitted.
       
  1974 
       
  1975 @param aPacket MBuf chain containing packet
       
  1976 @param aChannel KPppHdlcRecvChannel for the receiving channel
       
  1977 or KPppHdlcSendChannel for the sending channel
       
  1978 
       
  1979 @see GetDataTransfer()
       
  1980 */
       
  1981 	{
       
  1982 	RMBufPktInfo* info = RMBufPacket::PeekInfoInChain(aPacket);
       
  1983 	const TInt len = info->iLength;
       
  1984     const TBool CrcError = TPppAddr::Cast(info->iDstAddr).CRCError();
       
  1985     if (CrcError)
       
  1986     	{
       
  1987     	// This is a metapacket containing no useful payload
       
  1988     	}
       
  1989 	else if (aChannel==KPppHdlcSendChannel)
       
  1990 		{
       
  1991 		iSentData += len;
       
  1992 		}
       
  1993 	else if (aChannel==KPppHdlcRecvChannel)
       
  1994 		{
       
  1995 		iRecvdData += len;
       
  1996 		}
       
  1997 	}
       
  1998 
       
  1999 /**
       
  2000  * Constructor. Performs standard active object initialisation.
       
  2001  *
       
  2002  * @param aObserver Reference to the observer of this PPP HdlcLink.
       
  2003  * 
       
  2004  */
       
  2005 CBcaControl::CBcaControl(CPppHdlcLink& aUser, MBca& aBca)
       
  2006 	: CActive(EPriorityStandard), 
       
  2007 	  iUser(aUser), 
       
  2008 	  iBca(aBca),
       
  2009 	  iControlStep(ENone)
       
  2010 	{
       
  2011 	CActiveScheduler::Add(this);
       
  2012 	}
       
  2013 	
       
  2014 /**
       
  2015  * Destructor.
       
  2016  */
       
  2017 CBcaControl::~CBcaControl()
       
  2018 	{
       
  2019 	Cancel();
       
  2020 	//Make sure the BCA is closed. This is not strictly necessary, as BCA destructor should do it.
       
  2021 	if(iBcaIsOpen)
       
  2022 		{
       
  2023 		iBca.Close();
       
  2024 		}
       
  2025 	}
       
  2026 
       
  2027 /** 
       
  2028 This is the central control routine of the BCA. It is called in 2 cases:
       
  2029 1. An outstanding control request on the BCA has completed.
       
  2030 2. A control sequence (startup or shutdown) has started. In this case, it is triggered by our User.
       
  2031 
       
  2032 This way, all the control actions on the BCA are dispatched from here only. 
       
  2033 */	
       
  2034 void CBcaControl::RunL()
       
  2035 	{
       
  2036 	LOG(iUser.Logger().Printf(_L("CBcaControl::RunL(): Step[%d] completed with error[%d]."), iControlStep, iStatus.Int()); )
       
  2037 	 		
       
  2038 	if(KErrNone != iStatus.Int())
       
  2039 		{
       
  2040 		// Note: For clarity, the logic below is not optimized. It called only during BCA startup /shutdown,
       
  2041 		// so the performance penalty is minimal.
       
  2042 		const TBool KOpening       = EOpeningChannel   == iControlStep;
       
  2043 		const TBool KIoctlError  = (!IsShuttingDown() && !KOpening ) && // not opening, & not shutting down.
       
  2044 						(iStatus.Int() != KErrNotSupported && // BCA may not support this Ioctl, this is OK. 
       
  2045 					     iStatus.Int() != KErrAlreadyExists); // This ioctl may not be necessary.
       
  2046 	
       
  2047 		if(KOpening || // Any error on open is fatal, 
       
  2048 		   			  // All errors on shutdown are ignored. 
       
  2049 		   KIoctlError ) // Ioctl errored out, i.e. BCA tried to do it and failed, rather than refuse to do it.
       
  2050 		    {
       
  2051 		    LOG( iUser.Logger().Printf(_L("CBcaControl: operation failed. Link down with [%d]."), iStatus.Int());)
       
  2052 			iControlStep = ENone; // We are not doing anything.
       
  2053 			iUser.LinkDown(iStatus.Int());
       
  2054 			return;
       
  2055 			}
       
  2056 		}
       
  2057 				
       
  2058 	// Our state: the previous operation has completed successfully, or we don't care about failure.
       
  2059 	
       
  2060 	// Execute the specified control action. The switch statement is structured such that a control sequence
       
  2061 	// can be read from top to bottom. (I.e. case = step, on completion go to the case below).
       
  2062 	switch(iControlStep) // Which step did just complete?
       
  2063 		{
       
  2064 		//
       
  2065 		// The startup sequence.
       
  2066 		//
       
  2067 		case EStartingStartup:
       
  2068 			{
       
  2069 			LOG(iUser.Logger().Printf(_L("CBcaControl: Bca Ioctl: Setting Iap Id[%d]."), iUser.GetIAPid()); )
       
  2070 			
       
  2071 			iControlStep = ESettingIap;
       
  2072 			TPckg<TUint32> aOpt(iUser.GetIAPid());
       
  2073 			iBca.Ioctl(iStatus,KBcaOptLevelGeneric, KBCASetIapId, aOpt);
       
  2074 			break;
       
  2075 			}
       
  2076 			
       
  2077 		case ESettingIap:
       
  2078 			{
       
  2079 			iControlStep  = ESettingBcaStack;
       
  2080 			TPtrC bcaStack(iUser.GetBCAStack());
       
  2081 			if(bcaStack.Length())
       
  2082 				{
       
  2083 				LOG(iUser.Logger().Printf(_L("CBcaControl: Bca Ioctl: Setting Bca Stack [%S]."), &bcaStack); )
       
  2084 				
       
  2085 				TBuf8<KMaxName> remainingBcaStack8;
       
  2086 				remainingBcaStack8.Copy(bcaStack);
       
  2087 				iBca.Ioctl(iStatus, KBcaOptLevelGeneric,KBCASetBcaStack,remainingBcaStack8);
       
  2088 				}
       
  2089 			else
       
  2090 				{
       
  2091 				TRequestStatus* statusPtr=&iStatus;
       
  2092 				User::RequestComplete(statusPtr,KErrNone);
       
  2093 				}
       
  2094 			break;
       
  2095 			}
       
  2096 		
       
  2097 		case ESettingBcaStack:
       
  2098 			{
       
  2099 			LOG(TPtrC portName = iUser.GetPortName(); iUser.Logger().Printf(_L("CBcaControl: Opening BCA channel [%S]."), &portName); )
       
  2100 
       
  2101             iControlStep = EOpeningChannel;
       
  2102 			__ASSERT_DEBUG(!iBcaIsOpen, User::Panic(_L("PPP Panic"), EPppPanic_UnexpectedBcaOpen));
       
  2103 			iBca.Open(iStatus,iUser.GetPortName());
       
  2104 			break;	
       
  2105 			}
       
  2106 					
       
  2107 		case EOpeningChannel:
       
  2108 			{
       
  2109 			iBcaIsOpen = ETrue;
       
  2110 			
       
  2111 			LOG(iUser.Logger().Printf(_L("CBcaControl: Bca Ioctl: Enabling link monitoring for control line failure.")); )
       
  2112 			
       
  2113 			iControlStep = EnablingLinkMonitoring;
       
  2114 			TPckgBuf<TUint32> argPckg(KFailBcaSpecificOnly);
       
  2115 			iBca.Ioctl(iStatus, KBcaOptLevelExtSerial, KSerialMonitorControlLines, argPckg);
       
  2116 			break;
       
  2117 			// We won't have to disable it when we are shutting down, BCA will do it for us.
       
  2118 			}
       
  2119 		
       
  2120 		case EnablingLinkMonitoring:
       
  2121 			{
       
  2122 			LOG(iUser.Logger().Printf(_L("CBcaControl: Bca Ioctl: Getting Serial Port Config")); )
       
  2123 			
       
  2124 			iControlStep = EGettingSerialConfig;
       
  2125 
       
  2126 			TPckgBuf<TCommConfig> argPckg(iSerialConfig);
       
  2127 			iBca.Ioctl(iStatus, KBcaOptLevelExtSerial, KSerialConfig, argPckg);
       
  2128 			iSerialConfig = argPckg();
       
  2129 			break;
       
  2130 			}			
       
  2131 			
       
  2132 		case EGettingSerialConfig:
       
  2133 			{
       
  2134 			iUser.SetOriginalSerialPortConfig(iSerialConfig); // Save our existing serial port settings, retrieved in the previous step.
       
  2135 			// N.B. If we are being restarted, we could have modified the port settings already, so what get now
       
  2136 			// would NOT be the original settings. It's users job to keep track of that, otherwise the logic here
       
  2137 			// gets too complicated. If this is not the original settings, user will not set them, i.e. the call above
       
  2138 			// should have not effects.
       
  2139 	
       
  2140 			LOG(iUser.Logger().Printf(_L("CBcaControl: Bca Ioctl: Configuring serial port for HDLC.")); )
       
  2141 						
       
  2142 			iControlStep = ESettingSerialConfigForHdlc;
       
  2143 			iUser.GetSerialPortConfigForHdlc(iSerialConfig);
       
  2144 
       
  2145 			LOG(iUser.Logger().Printf(_L("CBcaControl: Bca Ioctl: Setting Serial Config for HDLC, handshaking [%x]."), iSerialConfig().iHandshake); )
       
  2146 
       
  2147 			TPckgBuf<TCommConfig> argPckg(iSerialConfig);
       
  2148 			iBca.Ioctl(iStatus, KBcaOptLevelExtSerial, KSerialSetConfig, argPckg);
       
  2149 			break;
       
  2150 			}
       
  2151 					
       
  2152 		case ESettingSerialConfigForHdlc:
       
  2153 			{
       
  2154 			LOG(iUser.Logger().Printf(_L("CBcaControl: Bca Ioctl: Setting Rx Tx Buffer size to %d."), KReceiveBufferSize); )
       
  2155 			
       
  2156 			iControlStep = ESettingBufferSize;
       
  2157 			TPckg<TInt> bufSizeOpt(KReceiveBufferSize);
       
  2158 			iBca.Ioctl(iStatus,KBcaOptLevelExtSerial, KSerialSetTxRxBufferSize, bufSizeOpt);
       
  2159 			break;
       
  2160 			}
       
  2161 			
       
  2162 		case ESettingBufferSize:
       
  2163 			{
       
  2164 			LOG(iUser.Logger().Printf(_L("CBcaControl: Bca Ioctl: Resetting Buffers.")); )
       
  2165 			
       
  2166 			iControlStep = EResettingBuffers;
       
  2167 			TPckg<TInt> resetMask(KResetRxBuf);
       
  2168 			iBca.Ioctl(iStatus, KBcaOptLevelGeneric, KBCAResetBuffers, resetMask);
       
  2169 			break;	
       
  2170 			}
       
  2171 			
       
  2172 		case EResettingBuffers:
       
  2173 			{
       
  2174 			iControlStep = ENone; // We are finished with the startup sequence.
       
  2175 			iUser.StartPPP();
       
  2176 			break;
       
  2177 			}
       
  2178 			
       
  2179 		//
       
  2180 		// The shutdown sequence		
       
  2181 		// Some operations may fail. If we are shutting down as a result of link failure, we have no way of knowing what
       
  2182 		// exactly has failed. Errors will be ignored, so the shutdown sequence runs fully always. 
       
  2183 		
       
  2184 		case EStartingShutdown:
       
  2185 			{
       
  2186 			LOG(iUser.Logger().Printf(_L("CBcaControl: Bca Ioctl: Restoring original Serial port config.")); )
       
  2187 			
       
  2188 			iControlStep = ERestoringOrigSerialConfig;
       
  2189 			iSerialConfig = iUser.OriginalSerialPortConfig(); // In case user modifies the config before request completion.
       
  2190 
       
  2191 			TPckgBuf<TCommConfig> argPckg(iSerialConfig);
       
  2192 			iBca.Ioctl(iStatus, KBcaOptLevelExtSerial, KSerialSetConfig,  argPckg);			
       
  2193 			// This may fail, because the underlying channel provider may have caused the shutdown to start 
       
  2194 			// in the first case. Error will be ignored, we'll always execute the next step.
       
  2195 			break;
       
  2196 			}
       
  2197 			
       
  2198 		case ERestoringOrigSerialConfig:
       
  2199 			{
       
  2200 			iControlStep = EShuttingDownChannel;
       
  2201 			if(iUser.DoShutdownBcaGracefully()) 
       
  2202 				{
       
  2203 				LOG(iUser.Logger().Printf(_L("CBcaControl: Shutting down BCA.")); )
       
  2204 			
       
  2205 				iBca.Shutdown(iStatus);
       
  2206 				// This may fail. If the link is shutting down because of channel provider failure, it may not be possible
       
  2207 				// to shut it down cleanly. Error will be ignored, we'll always execute the next step.
       
  2208 				}
       
  2209 			else // No need to shutdown, BCA is closed
       
  2210 				{
       
  2211 				LOG(iUser.Logger().Printf(_L("CBcaControl: Closing BCA.")); )
       
  2212 
       
  2213 				iBca.Close(); // This is a synchronous call, so we need to complete the request ourselves to move on.
       
  2214 				TRequestStatus* statusPtr = &iStatus;
       
  2215 				User::RequestComplete(statusPtr, KErrNone);
       
  2216 				}
       
  2217 			break;
       
  2218 			}
       
  2219 			
       
  2220 		case EShuttingDownChannel:
       
  2221 			{
       
  2222 			iBcaIsOpen = EFalse;
       
  2223 			
       
  2224 			iControlStep = ENone; // We are finished with the shutdown sequence.
       
  2225 			iUser.LinkTerminationComplete(); // We don't pass error code, because erros on termination are ignored.
       
  2226 			break;
       
  2227 			}
       
  2228 			
       
  2229 		default: // Unrecognized step. RFC1661 says we SHOULD not freeze or reset if internal FSM transition is invalid.
       
  2230 			{
       
  2231 			LOG(iUser.Logger().Printf(_L("CBcaControl: ERROR: Illegal control step [%d]"), iControlStep); )
       
  2232 			__ASSERT_DEBUG(EFalse, User::Panic(_L("PPP Panic"), EPppPanic_IllegalBcaControlStep));
       
  2233 			break;
       
  2234 			}
       
  2235 			
       
  2236 		}
       
  2237 		// Complete the step.
       
  2238 		if(ENone != iControlStep) // ENone means we have no step to complete.
       
  2239 			{
       
  2240 			SetActive();
       
  2241 			}
       
  2242 	}
       
  2243 
       
  2244 	
       
  2245 /**
       
  2246  *	Cancels outstanding Control action. 
       
  2247  */
       
  2248 void CBcaControl::DoCancel()
       
  2249 	{
       
  2250 	LOG(iUser.Logger().Printf(_L("CBcaControl::DoCancel: Cancelling Ioctl. iControlStep[%d]."), iControlStep); )
       
  2251 	
       
  2252 	if(EOpeningChannel == iControlStep ||  EShuttingDownChannel== iControlStep)
       
  2253 		{
       
  2254 		iBca.Close(); // "Cancels" Open & graceful shutdown.
       
  2255 		}
       
  2256 	else if(ENone != iControlStep) // We have an Ioctl request outstanding.
       
  2257 		{
       
  2258 		iBca.CancelIoctl(); 
       
  2259 		// Some Ioctl states may not have an Ioctl outstanding. Canceling is OK, BCA ignores it.		
       
  2260 		}
       
  2261 	iControlStep = ENone;
       
  2262 		
       
  2263 	// N.B. IMPORTANT ASSUMPTION:
       
  2264 	// We are only going to be called if things went wrong, and 
       
  2265 	// the link is being terminated. I.e., after this call, the BCA is closed. 
       
  2266 		
       
  2267 	// We can't always execute an Ioctl more than once an opened BCA. I.e, we can't
       
  2268 	// always set different parameters, because the BCA may have been opened with them.
       
  2269 	
       
  2270 	// If the BCA is closed, its internal state is reset, so it is safe to restart the startup sequence.
       
  2271 	}
       
  2272 	
       
  2273 
       
  2274 /**
       
  2275 Launches the BCA channel startup sequence */	
       
  2276 void CBcaControl::StartStartupSequence()
       
  2277 	{
       
  2278 	__ASSERT_DEBUG(!IsActive(), User::Panic(_L("PPP Panic"), EPppPanic_BcaStartupAlreadyActive));
       
  2279 		
       
  2280 	// Jump to startup.
       
  2281 	iControlStep = EStartingStartup;
       
  2282 	TRequestStatus* stat = &iStatus;
       
  2283 	User::RequestComplete(stat, KErrNone);	
       
  2284 	SetActive();
       
  2285 	LOG(iUser.Logger().Printf(_L("CBcaControl: Startup sequence started.")); )
       
  2286 	}
       
  2287 	
       
  2288 /** 
       
  2289 Launches the BCA channel shutdown sequence */	
       
  2290 void CBcaControl::StartShutdownSequence()
       
  2291 	{
       
  2292 	if(IsShuttingDown())
       
  2293 		{
       
  2294 		LOG(iUser.Logger().Printf(_L("CBcaControl: Warning: Shutdown sequence already in progress.")); )
       
  2295 		return; // We are already shutting down.
       
  2296 		}
       
  2297 		
       
  2298 	Cancel(); // stop whatever we are doing and shut ourselves down.
       
  2299 	// Jump to shutdown.
       
  2300 	iControlStep = EStartingShutdown;
       
  2301 	TRequestStatus* stat = &iStatus;
       
  2302 	User::RequestComplete(stat, KErrNone);	
       
  2303 	SetActive();
       
  2304 	LOG(iUser.Logger().Printf(_L("CBcaControl: Shutdown sequence started.")); )
       
  2305 	}
       
  2306 
       
  2307 /**
       
  2308 Is the controller executing the shutdown sequence on the BCA? 
       
  2309 
       
  2310 @return ETrue if Yes.
       
  2311 */
       
  2312 TBool CBcaControl::IsShuttingDown()const
       
  2313 	{
       
  2314 	return (
       
  2315 		iControlStep == EStartingShutdown ||
       
  2316 		iControlStep == ERestoringOrigSerialConfig ||
       
  2317 		iControlStep == EShuttingDownChannel);
       
  2318 	}
       
  2319 
       
  2320 /**
       
  2321   C++ Constructor. Performs standard active object initialisation.
       
  2322  
       
  2323   @param aUser Our user: PPP HdlcLink.
       
  2324   @param aBca the BCA we read from on behalf of the user
       
  2325   @param aPriority the AO priority 
       
  2326 */
       
  2327 CBcaReader::CBcaReader(CPppHdlcLink& aUser, MBca& aBca, TInt aPriority):
       
  2328 	CActive(aPriority), 
       
  2329 	iUser(aUser),
       
  2330 	iBca(aBca)	  
       
  2331 	{
       
  2332 	CActiveScheduler::Add(this);
       
  2333 	}
       
  2334 
       
  2335 /** Destructor */
       
  2336 CBcaReader::~CBcaReader()
       
  2337 	{
       
  2338 	Cancel();
       
  2339 	}
       
  2340 	
       
  2341 /** Called when Read request completes, i.e. BCA can process another read.*/
       
  2342 void CBcaReader::RunL()
       
  2343 	{
       
  2344 	iUser.BcaReadComplete(iStatus.Int());		
       
  2345 	}
       
  2346 	
       
  2347 /** Cancels an outstanding read request.*/
       
  2348 void CBcaReader::DoCancel()
       
  2349 	{
       
  2350 	iBca.CancelRead();
       
  2351 	}
       
  2352 
       
  2353 /**
       
  2354 Triggers completion of the read */	
       
  2355 void CBcaReader::ReadReady()
       
  2356 	{
       
  2357 	TRequestStatus* statusPtr = &iStatus;
       
  2358 	User::RequestComplete(statusPtr,KErrNone);
       
  2359 	SetActive();
       
  2360 	}
       
  2361 	
       
  2362 /** Queues a read on the BCA.*/
       
  2363 void CBcaReader::Read(TDes8& aDes)
       
  2364 	{
       
  2365 	iBca.Read(iStatus,aDes);
       
  2366 	SetActive();
       
  2367 	}
       
  2368 	
       
  2369 
       
  2370 /**
       
  2371 C++ constructor 
       
  2372 
       
  2373 @param aUser: the BCA user - the HDLC link
       
  2374 @param aBca: the BCA to use for writes
       
  2375 @param aPriority write AO priority 
       
  2376 */	
       
  2377 CBcaWriter::CBcaWriter(CPppHdlcLink& aUser, MBca& aBca, TInt aPriority)
       
  2378 	: CActive(aPriority), 
       
  2379 	  iUser(aUser),
       
  2380 	  iBca(aBca)	  
       
  2381 	{
       
  2382 	CActiveScheduler::Add(this);
       
  2383 	}
       
  2384 
       
  2385 /** C++ Destructor */
       
  2386 CBcaWriter::~CBcaWriter()
       
  2387 	{
       
  2388 	Cancel();
       
  2389 	}
       
  2390 	
       
  2391 /** Called on Write completion, indicating a readiness to handle another write.*/
       
  2392 void CBcaWriter::RunL()
       
  2393 	{
       
  2394 	iUser.BcaWriteComplete(iStatus.Int());		
       
  2395 	}
       
  2396 	
       
  2397 /** Cancels an outstanding write request.*/
       
  2398 void CBcaWriter::DoCancel()
       
  2399 	{
       
  2400 	iBca.CancelWrite();
       
  2401 	}
       
  2402 	
       
  2403 /** Writes on the BCA channel.
       
  2404 
       
  2405 @param aDes the buffer to write.
       
  2406 */	
       
  2407 void CBcaWriter::Write(const TDesC8& aDes)
       
  2408 	{
       
  2409 	iBca.Write(iStatus,aDes);
       
  2410 	SetActive();
       
  2411 	}