bluetoothcommsprofiles/btpan/panagt/pancoexistenceconnectioncontroller.cpp
changeset 0 29b1cd4cb562
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bluetoothcommsprofiles/btpan/panagt/pancoexistenceconnectioncontroller.cpp	Fri Jan 15 08:13:17 2010 +0200
@@ -0,0 +1,328 @@
+// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include <bluetooth/logger.h>
+
+#include "pancoexistenceconnectioncontroller.h"
+#include "panagtutils.h"
+
+#ifdef __FLOG_ACTIVE
+_LIT8(KLogComponent, LOG_COMPONENT_PAN_AGENT);
+#endif
+
+// This is the identifer of the shared mutex used to allow safe read / write of the coexistence P&S key.
+// This can only be changed if all other existing definitions of the mutex name are also changed.
+_LIT(KIPBearerCoexistenceMutex, "IPBearerCoexistenceMutex");
+
+using namespace PanAgent;
+
+CPanCoexistenceConnectionController* CPanCoexistenceConnectionController::NewL(MPanCoexistenceConnectionObserver& aObserver)
+	{
+	CPanCoexistenceConnectionController* self = new(ELeave) CPanCoexistenceConnectionController(aObserver);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CPanCoexistenceConnectionController::CPanCoexistenceConnectionController(MPanCoexistenceConnectionObserver& aObserver)
+	: CActive(EPriorityStandard),iPanCoexistenceConnectionObserver(aObserver) 
+	{
+	CActiveScheduler::Add(this);
+	}
+
+CPanCoexistenceConnectionController::~CPanCoexistenceConnectionController()
+	{
+	Cancel();
+	iProperty.Close();
+	iMutex.Close();
+	}
+
+void CPanCoexistenceConnectionController::ConstructL()
+	{
+	LOG_FUNC
+	
+	// Creates a global mutex and open a handle to the mutex.
+	// (Note if CreateGlobal returns wirh KErrNone then the mutex is also opened).  
+	TInt err = iMutex.CreateGlobal(KIPBearerCoexistenceMutex);
+	if (err==KErrAlreadyExists)
+		{
+		err=iMutex.OpenGlobal(KIPBearerCoexistenceMutex);
+		}
+    
+    User::LeaveIfError(err);
+
+	// Define property
+    err = DefineProperty();
+
+	if(err != KErrNone && err != KErrAlreadyExists)
+		{
+		User::Leave(err);
+		}
+	
+	// Attach to the property
+	TSecureId thisSID = RProcess().SecureId();
+	User::LeaveIfError(iProperty.Attach(thisSID, KIPBearerCoexistenceProperty));
+	
+	SubscribeToProperty();
+	}
+
+//Define the P&S key
+TInt CPanCoexistenceConnectionController::DefineProperty()
+	{
+	TInt err;
+	_LIT_SECURITY_POLICY_PASS(KPassPolicy);
+	_LIT_SECURITY_POLICY_C1(KNetworkControl, ECapabilityNetworkControl); 
+
+	err=iProperty.Define(KIPBearerCoexistenceProperty,
+						 RProperty::EInt,
+						 KPassPolicy,	    //	Read policy
+						 KNetworkControl);	//	Write policy
+	return err;
+	}
+
+// If another IP bearer has not set the key then this method will set the P&S key to indicate 
+// that a PAN connection is active.
+TInt CPanCoexistenceConnectionController::TryToCreateNewPanConnection()
+	{	
+	LOG_FUNC
+	
+	TInt err = KErrNone;
+	
+	// Wait for the Mutex to become free and then acquire it.
+	iMutex.Wait();
+	
+	//Get the property	
+	TIPBearerCoexistenceStatus value = ReadStatus();
+	
+	switch (value)
+		{
+		case ENoneIsActive:
+			iActivePanConnectionExists = ETrue;
+			iLocallyInitiatedTransition = ETrue;
+
+			WriteStatus(EBTPanIsActive);
+			break;
+
+		case EBTPanIsActive:
+			//P&S key is allready set to EBTPanIsActive 
+			__ASSERT_DEBUG(EFalse, PanAgentPanic(EBTPanIsAlreadyActive));
+			break;
+
+		case ERndisIsActive:
+			//BT PAN cannot be active at the point, since Rndis holds the key
+			__ASSERT_DEBUG(!iActivePanConnectionExists, PanAgentPanic(ERndisIsActiveWhenBTPanTriesToBeActive));
+			err = KErrAccessDenied;
+			break;
+
+		default:
+			__ASSERT_DEBUG(EFalse, PanAgentPanic(EInvalidIPBearerCoexistanceProperty));
+			break;
+		}
+		
+	//Release the mutex
+	iMutex.Signal();
+	return err; 
+	}
+
+// If the co-existence P&S key has been set by the PAN service then
+// clear the P&S key
+void CPanCoexistenceConnectionController::HandleAllPanConnectionsClosed()
+	{
+	LOG_FUNC
+	
+	// Get the property	
+	TIPBearerCoexistenceStatus value = ReadStatus();
+	
+	switch(value)
+		{
+		case ENoneIsActive:
+			// The P&S key is ENoneIsActive, when BT PAN tries to clear it.
+			__ASSERT_DEBUG(EFalse, PanAgentPanic(EClearKeyWhenNoneIsActive));
+			break;
+		
+		case ERndisIsActive:
+			// This is the race condition where RNDIS sets the key when BT PAN incoming connection request
+			// goes through the stack, we didn't own the key, do nothing
+			LOG(_L("CPanCoexistenceConnectionController::HandleAllPanConnectionsClosed, enter the race condition"));
+			break;
+			
+		case EBTPanIsActive:
+			__ASSERT_DEBUG(iActivePanConnectionExists, PanAgentPanic(ENoPanConnectionExistsWhileInPanIsActiveCoexistencePandSState));
+			iActivePanConnectionExists = EFalse;
+			iLocallyInitiatedTransition = ETrue;
+
+			WriteStatus(ENoneIsActive);
+			break;
+
+		default:
+			__ASSERT_DEBUG(EFalse, PanAgentPanic(EInvalidIPBearerCoexistanceProperty));
+			break;
+		}
+	}
+
+// Read property and handle error conditions
+TIPBearerCoexistenceStatus CPanCoexistenceConnectionController::ReadStatus()
+	{
+	LOG_FUNC
+
+	//Get the property
+	TInt value = ENoneIsActive;
+	TInt err = iProperty.Get(value);
+	
+	if(err)
+		{
+		if (err == KErrNotFound)
+			{
+			__ASSERT_DEBUG(EFalse, PanAgentPanic(EIPBearerCoexistancePropertyIsNotDefined));
+					
+			//Redefine property if property has been deleted	
+			err = DefineProperty();
+			 			
+			if (err == KErrNone)
+				{
+				value = iActivePanConnectionExists ? EBTPanIsActive : ENoneIsActive;
+				err = iProperty.Set(value);
+				if (err)
+					{
+					//reset failed, log the error and assert the debug
+					LOG1(_L("CPanCoexistenceConnectionController::ReadProperty reset Property with error: %d"), err);
+					__ASSERT_DEBUG(EFalse, PanAgentPanic(EIPBearerCoexistancePropertySetFailed));
+					}
+				}
+			else
+				{
+				//Define P&S failed, log the error and assert the debug
+				LOG1(_L("CPanCoexistenceConnectionController::ReadProperty Define Property with error: %d"), err);
+				__ASSERT_DEBUG(EFalse, PanAgentPanic(EIPBearerCoexistancePropertyCanNotBeDefined));
+				}			
+			}
+		else
+			{
+			//Getter returns error rather than KErrNotFound, log the error and assert the debug
+			LOG1(_L("CPanCoexistenceConnectionController::ReadProperty Get Property with error: %d"), err);
+			__ASSERT_DEBUG(EFalse, PanAgentPanic(EIPBearerCoexistancePropertyGetFailed));
+			}
+		}
+	
+	return static_cast<TIPBearerCoexistenceStatus>(value);
+	}
+
+//Write the property and handle setter errors
+void CPanCoexistenceConnectionController::WriteStatus(TIPBearerCoexistenceStatus aStatus)
+	{
+	LOG_FUNC
+	
+	//Set the property
+	TInt err = iProperty.Set(aStatus);
+	if (err)
+		{
+		if (err == KErrNotFound)
+			{
+			__ASSERT_DEBUG(EFalse, PanAgentPanic(EIPBearerCoexistancePropertyIsNotDefined));
+					
+			//Redefine property if property has been deleted				
+			err = DefineProperty();
+			 	
+			if (err == KErrNone)
+				{
+				//Reset the property
+				err = iProperty.Set(aStatus);
+				if (err)
+					{
+					LOG1(_L("CPanCoexistenceConnectionController::WriteStatus Set Property with error: %d"), err);
+					__ASSERT_DEBUG(EFalse, PanAgentPanic(EIPBearerCoexistancePropertySetFailed));
+					}
+				}
+			else
+				{
+				//Define P&S failed, log the error and assert the debug
+				LOG1(_L("CPanCoexistenceConnectionController::ReadProperty Define Property with error: %d"), err);
+				__ASSERT_DEBUG(EFalse, PanAgentPanic(EIPBearerCoexistancePropertyCanNotBeDefined));
+				//Nothing else we can do at this stage
+				}
+
+			}
+		else
+			{
+			//Setter returns error rather than KErrNotFound
+			LOG1(_L("CPanCoexistenceConnectionController::WriteStatus Set Property with error: %d"), err);
+			__ASSERT_DEBUG(EFalse, PanAgentPanic(EIPBearerCoexistancePropertySetFailed));
+			}
+		}
+	}
+
+void CPanCoexistenceConnectionController::SubscribeToProperty()
+	{
+	LOG_FUNC
+	iProperty.Subscribe(iStatus);
+	SetActive();
+	}
+
+void CPanCoexistenceConnectionController::DoCancel()
+	{
+	LOG_FUNC
+	iProperty.Cancel();
+	}
+
+void CPanCoexistenceConnectionController::RunL()
+	{	
+	LOG_FUNC
+	
+	// Do not check the iStatus, since the ReadStatus() will redefine the P&S key if the key 
+	// has been deleted by mistakes
+
+	//Read the property
+	TIPBearerCoexistenceStatus value = ReadStatus();
+	
+	switch(value)
+		{
+		case ENoneIsActive:
+			if (!iLocallyInitiatedTransition)
+				{
+				// BT PAN cannot be active at this point, since the P&S key is ENoneIsActive
+				__ASSERT_DEBUG(!iActivePanConnectionExists, PanAgentPanic(EPropertyIsNoneIsActiveWhenBTPanIsActive));
+						
+				// Notify Agent P&S Key has been updated
+				iPanCoexistenceConnectionObserver.MpccoPanCoexistenceConnectionUpdated(ENoneIsActive);
+				}
+			break;
+
+		case ERndisIsActive:
+			// BT PAN cannot be active at this point
+			__ASSERT_DEBUG(!iActivePanConnectionExists, PanAgentPanic(ERndisIsActiveWhenBTPanTriesToBeActive));
+			__ASSERT_DEBUG(!iLocallyInitiatedTransition, PanAgentPanic(EBTPanInitiateDirectTransitionToRndis));
+			
+			//from non service to Rndis
+			//Notify Agent P&S Key has been updated
+			iPanCoexistenceConnectionObserver.MpccoPanCoexistenceConnectionUpdated(ERndisIsActive);
+			break;
+
+		case EBTPanIsActive:
+			//Setting the P&S key to EBTPanIsActive when BT PAN is not active or BT PAN is already active
+			__ASSERT_DEBUG(iActivePanConnectionExists && iLocallyInitiatedTransition, PanAgentPanic(EImproperSituationToSetPropertyToBTPanIsActive));
+			break;
+
+		default:
+			__ASSERT_DEBUG(EFalse, PanAgentPanic(EInvalidIPBearerCoexistanceProperty));
+			break;
+		}
+	
+	iLocallyInitiatedTransition = EFalse;
+
+	//Resubscribe to the property
+	SubscribeToProperty();
+	}
+