Revision: 201001 RCL_3
authorDremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Fri, 12 Mar 2010 15:49:00 +0200
branchRCL_3
changeset 10 8a27654f7b62
parent 8 2b6718f05bdb
child 11 20fda83a6398
Revision: 201001 Kit: 201008
bluetooth/btstack/l2cap/L2CapFecNegotiator.cpp
bluetooth/btstack/l2cap/L2CapFecNegotiator.h
bluetooth/btstack/l2cap/L2CapFecNegotiator.inl
bluetooth/btstack/linkmgr/physicallinks.cpp
bluetooth/btstack/linkmgr/physicallinks.h
bluetooth/btstack/secman/pairingserver.cpp
bluetooth/btstack/secman/pairingserver.h
package_definition.xml
--- a/bluetooth/btstack/l2cap/L2CapFecNegotiator.cpp	Fri Feb 19 23:56:55 2010 +0200
+++ b/bluetooth/btstack/l2cap/L2CapFecNegotiator.cpp	Fri Mar 12 15:49:00 2010 +0200
@@ -53,6 +53,26 @@
 	// Just send what we've got in Preferred.
 	}
 
+void TModeSpecificFecOptionHandlerBase::BuildRequestBasedOnUnacceptableParamsResponse(
+											TRetransmissionAndFlowControlOption& aPreferred,
+											const TRetransmissionAndFlowControlOption& aPeer,
+											const TL2CapFecNegotiator& aFecNegotiator) const
+	{
+	LOG_FUNC
+	// In general the only negotiable parameter is channel mode - that's what we should
+	// take from the suggested response passed here in aPeer. The rest of the parameters are
+	// informative and we should use our own values, based on the mode - the remote can not
+	// reject informative parameters.
+	// Note on interop:
+	// Unfortunately <= 9.4 Symbian code _WILL_ reject if e.g. we send a MaxTransmit value
+	// which is greater than its own preference. To interoperate with those this method is
+	// overridden in the Legacy handler.
+
+	aPreferred = TRetransmissionAndFlowControlOption(aPeer.LinkMode(), ETrue);
+	SetMaxTransmit(aPreferred, aFecNegotiator.MaxTransmit());
+	ZeroUnspecifiedRequestFields(aPreferred);
+	}
+
 void TModeSpecificFecOptionHandlerBase::SetMaxTransmit(TRetransmissionAndFlowControlOption& aFecOption, TUint8 /*aMaxTransmit*/) const
 	{
 	LOG_FUNC
@@ -250,6 +270,47 @@
 							  aMaxTransmit);
 	}
 
+void TLegacyFecHandler::BuildRequestBasedOnUnacceptableParamsResponse(
+		TRetransmissionAndFlowControlOption& aPreferred,
+		const TRetransmissionAndFlowControlOption& aPeer,
+		const TL2CapFecNegotiator& aFecNegotiator) const
+    {
+    LOG_FUNC
+	// In general the only negotiable parameter is channel mode - that's what we should
+	// take from the suggested response passed here in aPeer. The rest of the parameters are
+	// informative and we should use our own values, based on the mode - the remote can not
+	// reject informative parameters.
+	//
+	// HOWEVER:
+	//
+	// Unfortunately <= 9.4 Symbian code _WILL_ reject if e.g. we send a MaxTransmit value
+	// which is greater than its own preference. To interoperate with those we take
+	// the whole FEC option suggested by the remote, including the informational parameters.
+	// <= 9.4 Symbian devices implement RTM and FC modes (and not ERTM and Streaming).
+	// Additionally, pretty much noone else in the market does - most people jumped from
+	// Basic straight to ERTM & Streaming. So it can be assumed that:
+	// Legacy (RTM & FC) ~= pre-ERTM Symbian. 
+
+	typedef TRetransmissionAndFlowControlOption TFec;	// just 'coz I'm lazy
+
+	// Use the remote's whole suggestion if all informational parameters look edible ...
+	if (aPeer.TxWindowSize()          >= TFec::KMinValidTxWindowSize &&
+		aPeer.MaxTransmit()           >= TFec::KMinValidNumberTransmit &&
+		aPeer.RetransmissionTimeout() >= TFec::KMinAcceptableRetransmissionTimeout &&
+		aPeer.MonitorTimeout()        >= TFec::KMinAcceptableMonitorTimeout &&
+		aPeer.MaximumPDUSize()        >= TFec::KMinValidMaximumPDUSize)
+		{
+		aPreferred = aPeer;
+		}
+	else // ... otherwise only use channel mode to prevent DoS attacks.
+		{
+		aPreferred = TRetransmissionAndFlowControlOption(aPeer.LinkMode(), ETrue);
+		SetMaxTransmit(aPreferred, aFecNegotiator.MaxTransmit());
+		ZeroUnspecifiedRequestFields(aPreferred);
+		}
+	}
+
+
 // Basic mode
 
 TBool TBasicFecHandler::IsOptionValid(const TRetransmissionAndFlowControlOption& /*aFecOption*/) const
@@ -476,9 +537,9 @@
 	 	if (aIsUnacceptableParameters)
 			{
 	 		iConfigStatus = EOptionConfigOutstanding;
-            // Only take the channel mode from peer's proposal and set informational
-            // (i.e. all other) parameters to our values.
-            BuildRequest(aFecOption.LinkMode(), iPreferred);
+	 		// Build a new request based on suggestion sent by the peer.
+	 		iFecNegotiator.ModeSpecificHandlers().BuildRequestBasedOnUnacceptableParamsResponse(
+	 				iPreferred, iPeer, iFecNegotiator);
 			}
 		else
 			{
--- a/bluetooth/btstack/l2cap/L2CapFecNegotiator.h	Fri Feb 19 23:56:55 2010 +0200
+++ b/bluetooth/btstack/l2cap/L2CapFecNegotiator.h	Fri Mar 12 15:49:00 2010 +0200
@@ -46,6 +46,12 @@
 			   							const TRetransmissionAndFlowControlOption& aPeer) const;
 	virtual void BuildNegativeResponse(TRetransmissionAndFlowControlOption& aPreferred,
 									   const TRetransmissionAndFlowControlOption& aPeer) const;
+
+	virtual void BuildRequestBasedOnUnacceptableParamsResponse(
+					TRetransmissionAndFlowControlOption& aPreferred,
+					const TRetransmissionAndFlowControlOption& aPeer,
+					const TL2CapFecNegotiator& aFecNegotiator) const;
+
 	// In general configuration procedure (spec chapter 7 General Procedures) if the remote accepts
 	// an option from our ConfigReq, it doesn't have to include it in the response. So before
 	// processing the options from a ConfigRsp we've received, we go through the preferred values
@@ -104,6 +110,11 @@
 	virtual TBool IsOptionValid(const TRetransmissionAndFlowControlOption& aFecOption) const;
 	virtual TBool IsPeerResponseAcceptable(const TRetransmissionAndFlowControlOption& aPreferred,
 										   const TRetransmissionAndFlowControlOption& aPeer) const;
+	virtual void BuildRequestBasedOnUnacceptableParamsResponse(
+                        TRetransmissionAndFlowControlOption& aPreferred,
+                        const TRetransmissionAndFlowControlOption& aPeer,
+                        const TL2CapFecNegotiator& aFecNegotiator) const;
+
 	virtual void SetMaxTransmit(TRetransmissionAndFlowControlOption& aFecOption, TUint8 aMaxTransmit) const;
 	};
 
@@ -132,6 +143,9 @@
 									   const TRetransmissionAndFlowControlOption& aPeer) const;
 	inline void BuildNegativeResponse(TRetransmissionAndFlowControlOption& aPreferred,
 									  const TRetransmissionAndFlowControlOption& aPeer) const;
+	inline void BuildRequestBasedOnUnacceptableParamsResponse(TRetransmissionAndFlowControlOption& aPreferred,
+															  const TRetransmissionAndFlowControlOption& aPeer,
+															  const TL2CapFecNegotiator& aFecNegotiator) const;
 	inline void PrepareImplicitPeerResponse(TRetransmissionAndFlowControlOption& aImplicitResponse,
 											const TRetransmissionAndFlowControlOption& aPreferred) const;
 	inline void SetMaxTransmit(TRetransmissionAndFlowControlOption& aFecOption, TUint8 aMaxTransmit) const;
--- a/bluetooth/btstack/l2cap/L2CapFecNegotiator.inl	Fri Feb 19 23:56:55 2010 +0200
+++ b/bluetooth/btstack/l2cap/L2CapFecNegotiator.inl	Fri Mar 12 15:49:00 2010 +0200
@@ -72,6 +72,19 @@
 	Handler(aPreferred).BuildNegativeResponse(aPreferred, aPeer);
 	}
 
+inline void
+TFecOptionHandlerDelegator::BuildRequestBasedOnUnacceptableParamsResponse(
+		TRetransmissionAndFlowControlOption& aPreferred,
+		const TRetransmissionAndFlowControlOption& aPeer,
+		const TL2CapFecNegotiator& aFecNegotiator) const
+	{
+#ifdef __FLOG_ACTIVE
+	LogCurrentValues(aPreferred, aPeer);
+#endif
+	// Response has suggested mode, dispatch on that.
+	Handler(aPeer).BuildRequestBasedOnUnacceptableParamsResponse(aPreferred, aPeer, aFecNegotiator);
+	}
+
 inline void TFecOptionHandlerDelegator::PrepareImplicitPeerResponse(TRetransmissionAndFlowControlOption& aImplicitResponse,
 																	const TRetransmissionAndFlowControlOption& aPreferred) const
 	{
--- a/bluetooth/btstack/linkmgr/physicallinks.cpp	Fri Feb 19 23:56:55 2010 +0200
+++ b/bluetooth/btstack/linkmgr/physicallinks.cpp	Fri Mar 12 15:49:00 2010 +0200
@@ -384,49 +384,12 @@
 	// Store the result of the retrieval for usage later.
 	iDeviceResult = aResult;
 
-	// the HW asked earlier for a link key - we can respond now
-	__ASSERT_DEBUG(iDevice.IsValidAddress(), Panic(EBTPhysicalLinksInvalidAddress));
-	if(iWaitingForLinkKeyFromRegistry)
+	if (iLinkKeyRequestOutstanding)
 		{
-		if (aResult == KErrNone && iDevice.IsValidLinkKey())
-			{
-			if ( iDevice.LinkKeyType() != ELinkKeyCombination)
-				{
-				if (iLinksMan.SecMan().DebugMode() && iDevice.LinkKeyType() != ELinkKeyDebug)
-					{
-					LOG(_L("CPhysicalLink: Debug mode - Link to debug link key"))
-					iAuthenticationCtrl.LinkKeyRequestNegativeReply(iDevice.Address());
-					}
-				else
-				if (iRequireAuthenticatedLinkKey && iDevice.LinkKeyType() == ELinkKeyUnauthenticatedUpgradable && IsPairable())
-					{
-					LOG(_L("CPhysicalLink: Requiring Authenticated link key but currently only have unauthenticated"))
-					iAuthenticationCtrl.LinkKeyRequestNegativeReply(iDevice.Address());
-					}
-				else
-					{
-					LOG(_L("CPhysicalLink: Issuing link key to HC now"))
-					iAuthenticationCtrl.LinkKeyRequestReply(iDevice.Address(), iDevice.LinkKey());
-					}
-				}
-			else if(IsPasskeyMinLengthOK() && SimplePairingMode() != EPhySimplePairingEnabled)
-				{
-				LOG(_L("CPhysicalLink: Issuing link key to HC now"))
-				iAuthenticationCtrl.LinkKeyRequestReply(iDevice.Address(), iDevice.LinkKey());
-				}
-			else
-				{
-				LOG(_L("CPhysicalLink: Current PIN code too short!"))
-				iAuthenticationCtrl.LinkKeyRequestNegativeReply(iDevice.Address());
-				}
-			}
-		else
-			{
-			iAuthenticationCtrl.LinkKeyRequestNegativeReply(iDevice.Address());
-			}	
+		// the HW asked earlier for a link key - we can respond now
+		__ASSERT_DEBUG(iDevice.IsValidAddress(), Panic(EBTPhysicalLinksInvalidAddress));
+		LinkKeyRequestResponseAttempt(ETrue);
 		}
-	iRequireAuthenticatedLinkKey = EFalse;
-	iWaitingForLinkKeyFromRegistry = EFalse;
 
 	RegistryTaskComplete(aHelper, aResult);	 // cleans up our helper
 	}
@@ -708,15 +671,9 @@
 			}
 		else
 			{
-			// If the remote doesn't support extended features, then neither they support SSP
-			// (no way to indicate the host supported bit).  So set it as disabled.
-			TPhysicalLinkSimplePairingMode previousSetting = SimplePairingMode();
-			__ASSERT_DEBUG(((SimplePairingMode() == EPhySimplePairingDisabled) || (SimplePairingMode() == EPhySimplePairingUndefined)),Panic(EBTSSPModeChangedDuringConnection));
-			iSimplePairingMode = EPhySimplePairingDisabled;
-			if(SimplePairingMode() != previousSetting)
-				{
-				iLinksMan.SecMan().SimplePairingSupportDetermined(BDAddr());
-				}
+			// If the remote doesn't support extended features, then they cannot support SSP
+			// (no way to indicate the host supported bit).  So set feature as disabled.
+			RemoteSimplePairingModeDetermined(EPhySimplePairingDisabled);
 			}
 		}
 	else
@@ -740,18 +697,12 @@
 
 			if (aErr == EOK && aBitMask & (1 << ESecureSimplePairingHostSupportBit) && iLinksMan.SecMan().LocalSimplePairingMode())
 				{
-				__ASSERT_DEBUG(((SimplePairingMode() == EPhySimplePairingEnabled) || (SimplePairingMode() == EPhySimplePairingUndefined)),Panic(EBTSSPModeChangedDuringConnection));
-				iSimplePairingMode = EPhySimplePairingEnabled;
+				RemoteSimplePairingModeDetermined(EPhySimplePairingEnabled);
 				}
 			else
 				{
-				__ASSERT_DEBUG(((SimplePairingMode() == EPhySimplePairingDisabled) || (SimplePairingMode() == EPhySimplePairingUndefined)),Panic(EBTSSPModeChangedDuringConnection));
-				iSimplePairingMode = EPhySimplePairingDisabled;
+				RemoteSimplePairingModeDetermined(EPhySimplePairingDisabled);
 				}
-			if(SimplePairingMode()!=currentSetting)
-				{
-				iLinksMan.SecMan().SimplePairingSupportDetermined(BDAddr());
-				}			
 			break;
 			}
 		default:
@@ -2835,18 +2786,19 @@
 
 	SetAuthenticationPending(EPinRequestPending); // if not already set (because the remote initiated authentication).
 
-	__ASSERT_DEBUG(iSimplePairingMode != EPhySimplePairingEnabled, Panic(EBTSSPModeChangedDuringConnection));
-	if (iSimplePairingMode == EPhySimplePairingUndefined)
-		{
-		iSimplePairingMode = EPhySimplePairingDisabled;
-		}
-	
 	if (!IsConnected())
 		{
-		iPeerInSecurityMode3 = ETrue;
+		// If the ACL to the peer device is not yet connected, and the peer has initiated
+		// authentication then it must be in security mode 3.  This information is stored and
+		// if the connection completes the link will be set as authenticated.
+		SetPeerInSecurityMode3();
 		}
 
-	
+	// We can receive "fast" PIN requests if the remote device initiates pairing and indicates
+	// it doesn't have a link key.  If we see this then we know that we are not engaging in 
+	// simple pairing on this particular link.
+	RemoteSimplePairingModeDetermined(EPhySimplePairingDisabled);
+
 	if (iPinRequester)
 		{
 		return;
@@ -3056,9 +3008,14 @@
 	return isPasskeyMinLengthOK;
 	}
 
-void CPhysicalLink::LinkKeyRequest(const TBTDevAddr& aAddr, MLinkKeyResponseHandler& /*aRequester*/)
+void CPhysicalLink::LinkKeyRequest(const TBTDevAddr& __DEBUG_ONLY(aAddr), MLinkKeyResponseHandler& /*aRequester*/)
 	{
 	LOG_FUNC
+	__ASSERT_DEBUG(aAddr == BDAddr(), Panic(EBTConnectionBadDeviceAddress));
+	ASSERT_DEBUG(!iLinkKeyRequestOutstanding);
+
+	iLinkKeyRequestOutstanding = ETrue;
+
 	// we don't keep a copy of the device record - we just leave the one copy with
 	// the baseband - it can tell us if there's a link key
 	// we can tell if the baseband has the device record or not
@@ -3070,68 +3027,13 @@
 	// if the connection completes the link will be set as authenticated.
 	if (!IsConnected())
 		{
-		iPeerInSecurityMode3 = ETrue;
-		}
-
-	if(!iPeerInSecurityMode3 && iLinksMan.SecMan().IsDedicatedBondingAttempted(iDevice.Address()))
-		{
-		// If we are doing DedicatedBonding then we should ignore the existing linkkey
-		// in an attempt to generate a stronger one if possible.
-		// Security mode 3 is a odd case - because we get what looks like double pairing (the remote
-		// initiated pairing on connection, then the dedicated bonding pairing).  So we have removed
-		// this feature for security mode 3 devices...they will have to suffer for their transgressions
-		LOG(_L("CPhysicalLink: Dedicated bonding attempt - Sending link key request negative reply"));
-		iAuthenticationCtrl.LinkKeyRequestNegativeReply(aAddr);
-		iRequireAuthenticatedLinkKey = EFalse;
+		SetPeerInSecurityMode3();
 		}
-	else if (iDeviceResult==KErrNone && iDevice.IsValidLinkKey())
-		{
-		if (iLinksMan.SecMan().DebugMode() && iDevice.LinkKeyType() != ELinkKeyDebug)
-			{
-			LOG(_L("CPhysicalLink: Debug mode - Link to debug link key"))
-			iAuthenticationCtrl.LinkKeyRequestNegativeReply(aAddr);
-			}
-		else
-			{
-			if (iDevice.LinkKeyType() != ELinkKeyCombination)
-				{
-				if (iRequireAuthenticatedLinkKey && iDevice.LinkKeyType() == ELinkKeyUnauthenticatedUpgradable && IsPairable())
-					{
-					LOG(_L("CPhysicalLink: Requiring Authenticated link key but currently only have unauthenticated"))
-					iAuthenticationCtrl.LinkKeyRequestNegativeReply(aAddr);
-					}
-				else
-					{
-					LOG(_L("CPhysicalLink: Issuing link key to HC now"))
-					iAuthenticationCtrl.LinkKeyRequestReply(aAddr, iDevice.LinkKey());
-					}
-				}
-			else if(IsPasskeyMinLengthOK() && SimplePairingMode() != EPhySimplePairingEnabled)
-				{
-				LOG(_L("CPhysicalLink: Issuing link key to HC now"))
-				iAuthenticationCtrl.LinkKeyRequestReply(aAddr, iDevice.LinkKey());
-				}
-			else
-				{
-				LOG(_L("CPhysicalLink: Current PIN code too short!"))
-				iAuthenticationCtrl.LinkKeyRequestNegativeReply(aAddr);
-				}
-			}
-		iRequireAuthenticatedLinkKey = EFalse;
+
+	if (iLinkKeyRequestOutstanding)
+		{ // might have already been called via SetPeerInSecurityMode3()
+		LinkKeyRequestResponseAttempt();
 		}
-	else if (iDeviceResult==KErrNone && !iDevice.IsValidLinkKey() || iDeviceResult==KErrNotFound)
-		{
-		LOG(_L("CPhysicalLink: No Link key available for the device"));
-		iAuthenticationCtrl.LinkKeyRequestNegativeReply(aAddr);
-		iRequireAuthenticatedLinkKey = EFalse;
-		}
-	else
-		{
-		LOG(_L("CPhysicalLink: Waiting for link key from Registry!"))
-		// we're still waiting for the device....we'll respond when it turns up
-		iWaitingForLinkKeyFromRegistry = ETrue;
-		}
-
 	}
 
 TInt CPhysicalLink::PINCodeRequestReply(const TBTDevAddr& aDevAddr, const TDesC8& aPin) const
@@ -3613,16 +3515,11 @@
 	iOOBDataPresence = aOOBDataPresence;
 	iAuthenticationRequirement = aAuthenticationRequirement;
 	
-	//If we haven't determined the SSP pairing mode till now then enable it and notify the state m/c.
-	//This condition is to cater the fast remote device which responds very quickly,  
-	//even before we determine whether it supports simple pairing!*/ 
-	__ASSERT_DEBUG(((SimplePairingMode() == EPhySimplePairingEnabled) || (SimplePairingMode() == EPhySimplePairingUndefined)),Panic(EBTSSPModeChangedDuringConnection));
-	if(SimplePairingMode() == EPhySimplePairingUndefined)
-		{
-		//Since we have received a I/O cap response the simple pairing must be enabled
-		iSimplePairingMode = EPhySimplePairingEnabled;
-		iLinksMan.SecMan().SimplePairingSupportDetermined(BDAddr());
-		}
+	// If we haven't determined the SSP pairing mode the link is operating in yet then enable it,
+	// since we have received a I/O cap response the simple pairing must be enabled.
+	// This condition is to cater the fast remote device which responds very quickly,
+	// even before we determine whether it supports simple pairing!
+	RemoteSimplePairingModeDetermined(EPhySimplePairingEnabled);
 	}
 
 
@@ -3757,6 +3654,131 @@
 	return iSniffInterval;
 	}
 
+void CPhysicalLink::LinkKeyRequestResponseAttempt(TBool aForceResponse)
+	{
+	ASSERT_DEBUG(iLinkKeyRequestOutstanding);
+
+	if(!iPeerInSecurityMode3 && iLinksMan.SecMan().IsDedicatedBondingAttempted(iDevice.Address()))
+		{
+		// If we are doing DedicatedBonding then we should ignore the existing linkkey
+		// in an attempt to generate a stronger one if possible.
+		// Security mode 3 is a odd case - because we get what looks like double pairing (the remote
+		// initiated pairing on connection, then the dedicated bonding pairing).  So we have removed
+		// this feature for security mode 3 devices...they will have to suffer for their transgressions
+		LOG(_L("CPhysicalLink: Dedicated bonding attempt - Sending link key request negative reply"));
+		DoLinkKeyResponse(EFalse);
+		iRequireAuthenticatedLinkKey = EFalse;
+		}
+	else if (iDeviceResult==KErrNone && iDevice.IsValidLinkKey())
+		{
+		if (iLinksMan.SecMan().DebugMode() && iDevice.LinkKeyType() != ELinkKeyDebug)
+			{
+			LOG(_L("CPhysicalLink: Debug mode - Link to debug link key"))
+			DoLinkKeyResponse(EFalse);
+			}
+		else if (iDevice.LinkKeyType() != ELinkKeyCombination)
+			{
+			if (iRequireAuthenticatedLinkKey && iDevice.LinkKeyType() == ELinkKeyUnauthenticatedUpgradable && IsPairable())
+				{
+				LOG(_L("CPhysicalLink: Requiring Authenticated link key but currently only have unauthenticated"))
+				DoLinkKeyResponse(EFalse);
+				}
+			else
+				{
+				LOG(_L("CPhysicalLink: non - combination key, auth OK"))
+				DoLinkKeyResponse(ETrue);
+				}
+			}
+		else // Standard (legacy) Combination Key
+			{
+			if (SimplePairingMode() == EPhySimplePairingUndefined)
+				{
+				LOG(_L("CPhysicalLink: Waiting for Secure Simple Pairing mode to be determined"));
+				// wait for ssp mode to be determined...then try again
+				}
+			else if (IsPasskeyMinLengthOK() && SimplePairingMode() == EPhySimplePairingDisabled)
+				{
+				LOG(_L("CPhysicalLink: Combination key, Passkey len OK, no SSP"));
+				DoLinkKeyResponse(ETrue);
+				}
+			else
+				{
+				LOG(_L("CPhysicalLink: Current link key is not sufficient!"))
+				DoLinkKeyResponse(EFalse);
+				}
+			}
+		iRequireAuthenticatedLinkKey = EFalse;
+		}
+	else if (iDeviceResult==KErrNone && !iDevice.IsValidLinkKey() || iDeviceResult==KErrNotFound)
+		{
+		LOG(_L("CPhysicalLink: No Link key available for the device"));
+		DoLinkKeyResponse(EFalse);
+		iRequireAuthenticatedLinkKey = EFalse;
+		}
+	else if (aForceResponse)
+		{
+		LOG(_L("CPhysicalLink: Forcing a link key response (-ve as we don't have a link key yet)"));
+		DoLinkKeyResponse(EFalse);
+		}
+	else
+		{
+		LOG(_L("CPhysicalLink: Waiting for link key from Registry!"))
+		// we're still waiting for the device....we'll respond when it turns up
+		}
+	}
+
+/**
+Send a link key response for an outstanding request, assumes that all details
+have be validated.
+*/
+void CPhysicalLink::DoLinkKeyResponse(TBool aPositive)
+	{
+	LOG_FUNC
+	ASSERT_DEBUG(iLinkKeyRequestOutstanding);
+
+	if(aPositive)
+		{
+		LOG(_L("CPhysicalLink: Providing link key to HC..."))
+		ASSERT_DEBUG(iDevice.IsValidLinkKey());
+		iAuthenticationCtrl.LinkKeyRequestReply(iDevice.Address(), iDevice.LinkKey());
+		}
+	else
+		{
+		LOG(_L("CPhysicalLink: Indicating no link key to HC..."));
+		iAuthenticationCtrl.LinkKeyRequestNegativeReply(iDevice.Address());
+		}
+	iLinkKeyRequestOutstanding = EFalse;
+	}
+
+void CPhysicalLink::RemoteSimplePairingModeDetermined(TPhysicalLinkSimplePairingMode aSimplePairingMode)
+	{
+	LOG2(_L8("Current SimplePairingMode = %d, aSimplePairingMode = %d"), SimplePairingMode(), aSimplePairingMode);
+	ASSERT_DEBUG(aSimplePairingMode != EPhySimplePairingUndefined); // must be a definite value
+	__ASSERT_DEBUG(SimplePairingMode() == aSimplePairingMode || SimplePairingMode() == EPhySimplePairingUndefined, Panic(EBTSSPModeChangedDuringConnection));
+
+	const TPhysicalLinkSimplePairingMode previousSetting = iSimplePairingMode;
+	iSimplePairingMode = aSimplePairingMode;
+	if (previousSetting != iSimplePairingMode)
+		{
+		iLinksMan.SecMan().SimplePairingSupportDetermined(BDAddr());
+
+		// Also we may be waiting to respond to a link key request.
+		if (iLinkKeyRequestOutstanding)
+			{
+			LinkKeyRequestResponseAttempt();
+			}
+		}
+	}
+
+void CPhysicalLink::SetPeerInSecurityMode3()
+	{
+	iPeerInSecurityMode3 = ETrue;
+
+	// We also now know that the remote cannot possibly do SSP, *and* the LMP will
+	// likely lock our finding if the remote does SSP anyway while we do SM3.
+	RemoteSimplePairingModeDetermined(EPhySimplePairingDisabled);
+	}
+
 //
 // TLowPowModeCmdController
 //
--- a/bluetooth/btstack/linkmgr/physicallinks.h	Fri Feb 19 23:56:55 2010 +0200
+++ b/bluetooth/btstack/linkmgr/physicallinks.h	Fri Mar 12 15:49:00 2010 +0200
@@ -487,6 +487,12 @@
 	
 	inline TBool IsAuthenticationPending() const;
 
+	void LinkKeyRequestResponseAttempt(TBool aForceResponse = EFalse);
+	void DoLinkKeyResponse(TBool aPositive);
+
+	void RemoteSimplePairingModeDetermined(TPhysicalLinkSimplePairingMode aSimplePairingMode);
+	void SetPeerInSecurityMode3();
+
 private: // from MPINCodeResponseHandler
 	TInt PINCodeRequestReply(const TBTDevAddr& aDevAddr,const TDesC8& aPin) const;
 	TInt PINCodeRequestNegativeReply(const TBTDevAddr& aDevAddr) const;
@@ -519,9 +525,11 @@
 	// the PHY's supported logical links...
 	RPointerArray<CACLLink>					iACLLogicalLinks;
 	CBTSynchronousLink*						iSyncLogicalLink; // stack only supports a signal one per PHY
-	
+
+	TBool						iLinkKeyRequestOutstanding;	// for if we have to wait for Registry or SSP support status
 
-	MPINCodeResponseHandler*	iPinHandler;
+	MPINCodeResponseHandler*	iPinHandler;		// for forwarding responses to
+
 	TBTConnect 					iLastPendingConnection;		// for if we have to wait for Registry to decide whether to rject or accept a connection
 	TBool						iPendingConnection;  // is a connection request waiting for a reply
 	TSglQue<CBTProxySAP>		iProxySAPs;			// the proxies bound to us
@@ -571,8 +579,6 @@
 	TBool						iNewPinCodeValid;
 	TBTPinCode					iNewPinCode;
 
-	TBool						iWaitingForLinkKeyFromRegistry;
-
 private:
 	/**
 	Enumeration to represent the current state of the physical links storage in the registry,
--- a/bluetooth/btstack/secman/pairingserver.cpp	Fri Feb 19 23:56:55 2010 +0200
+++ b/bluetooth/btstack/secman/pairingserver.cpp	Fri Mar 12 15:49:00 2010 +0200
@@ -775,12 +775,18 @@
 	iProxySap = CBTProxySAP::NewL(iPhysicalLinksManager, NULL);
 
 	CleanupStack::Pop(this); // the start message cleaner
-
+	
+	// Now we've entered the realm of not leaving with an error, since the connection
+	// process has started.  Errors from now on must be via the Error() function call.
 	iState = EInitialConnectionPending;
 	iProxySap->SetNotify(this);
 	iProxySap->SetRemName(addr);
 	iProxySap->ActiveOpen();
-	DoAccessRequestL();
+	TRAPD(err, DoAccessRequestL());
+	if(err != KErrNone)
+		{
+		Error(err);
+		}
 	}
 
 void CDedicatedBondingSession::CleanupStartMessage(TAny* aPtr)
@@ -816,7 +822,11 @@
 			addr.SetBTAddr(iProxySap->RemoteAddress());
 			iProxySap->SetRemName(addr); // triggers finding a link again.
 			iProxySap->ActiveOpen();
-			DoAccessRequestL();
+			TRAPD(err, DoAccessRequestL());
+			if(err != KErrNone)
+				{
+				Error(err);
+				}
 			break;
 			}
 		// else not deferred so complete now....
@@ -864,7 +874,7 @@
 	__ASSERT_DEBUG(EFalse, PANIC(KPairingServerFaultCat, EPairingServerUnexpectedSocketCallback));
 	}
 
-void CDedicatedBondingSession::ConnectCompleteL()
+void CDedicatedBondingSession::ConnectComplete()
 	{
 	LOG_FUNC
 	switch(iState)
@@ -879,6 +889,11 @@
 	case EFinalConnection:
 		// Apparently multiple connect completes are allowed by CSocket
 		break;
+	case EShutdown:
+		// If an error occurred just after the connection request then we
+		// might receive a connection complete before the async shutdown request
+		// has been executed.
+		break;
 	default:
 		LOG1(_L("Unexpected Connect Complete in state %d"), iState);
 		__ASSERT_DEBUG(EFalse, PANIC(KPairingServerFaultCat, EPairingServerUnexpectedSocketCallback));
@@ -886,16 +901,6 @@
 		}
 	}
 
-void CDedicatedBondingSession::ConnectComplete()
-	{
-	LOG_FUNC
-	TRAPD(err, ConnectCompleteL());
-	if(err != KErrNone)
-		{
-		Error(err);
-		}
-	}
-
 void CDedicatedBondingSession::ConnectComplete(const TDesC8& /*aConnectData*/)
 	{
 	LOG_FUNC
--- a/bluetooth/btstack/secman/pairingserver.h	Fri Feb 19 23:56:55 2010 +0200
+++ b/bluetooth/btstack/secman/pairingserver.h	Fri Mar 12 15:49:00 2010 +0200
@@ -214,7 +214,6 @@
 
 	void StartBondingL(const RMessage2& aMessage);
 	void DoAccessRequestL();
-	void ConnectCompleteL();
 	void Shutdown();
 
 	void Complete(TInt aError);
--- a/package_definition.xml	Fri Feb 19 23:56:55 2010 +0200
+++ b/package_definition.xml	Fri Mar 12 15:49:00 2010 +0200
@@ -70,6 +70,11 @@
         <unit mrp="bluetoothapitest/bluetoothsvs/group/bluetoothsvs.mrp" bldFile="bluetoothapitest/bluetoothsvs/group"/>
       </component>
     </collection>
+    <collection id="atext" name="AT Extensions" level="server">
+      <component id="atext_build" name="AT Extension Build" introduced="^3" purpose="optional" filter="s60">
+        <unit bldFile="atext/group"/>
+      </component>
+    </collection>
     <collection id="bt_info" name="Bluetooth Info" level="app-if">
       <component id="bt_plat" filter="s60" class="api">
         <unit bldFile="bt_plat/group"/>