/**
 * @brief       Respond to a passcode request.
 * 
 * @param       connectionHandle - connection handle of the connected device or 0xFFFF
 *                                 if all devices in database.
 * @param       status - SUCCESS if passcode is available, otherwise see @ref SMP_PAIRING_FAILED_DEFINES.
 * @param       passcode - integer value containing the passcode.
 *
 * @return      SUCCESS - bond record found and changed,<BR>
 *              bleIncorrectMode - Link not found.
 */
bStatus_t GAPBondMgr_PasscodeRsp( uint16 connectionHandle, uint8 status, uint32 passcode )
{
  bStatus_t ret = SUCCESS;
  
  if ( status == SUCCESS )
  {
    // Truncate the passcode
    passcode = passcode % (GAP_PASSCODE_MAX + 1);
    
    ret = GAP_PasscodeUpdate( passcode, connectionHandle );
    if ( ret != SUCCESS )
    {
      VOID GAP_TerminateAuth( connectionHandle, SMP_PAIRING_FAILED_PASSKEY_ENTRY_FAILED );
    }
  }
  else
  {
    VOID GAP_TerminateAuth( connectionHandle, status );
  }
  
  return ret;
}
Example #2
0
/*********************************************************************
 * @fn      gapRole_processGAPMsg
 *
 * @brief   Process an incoming task message.
 *
 * @param   pMsg - message to process
 *
 * @return  none
 */
static void gapRole_processGAPMsg(gapEventHdr_t *pMsg)
{
    uint8_t notify = FALSE;   // State changed notify the app? (default no)

    switch (pMsg->opcode)
    {
    case GAP_DEVICE_INIT_DONE_EVENT:
    {
        gapDeviceInitDoneEvent_t *pPkt = (gapDeviceInitDoneEvent_t *)pMsg;
        bStatus_t stat = pPkt->hdr.status;

        if (stat == SUCCESS)
        {
            // Save off the generated keys
            VOID osal_snv_write(BLE_NVID_IRK, KEYLEN, gapRole_IRK);
            VOID osal_snv_write(BLE_NVID_CSRK, KEYLEN, gapRole_SRK);

            // Save off the information
            VOID memcpy(gapRole_bdAddr, pPkt->devAddr, B_ADDR_LEN);

            gapRole_state = GAPROLE_STARTED;

            // Update the advertising data
            stat = GAP_UpdateAdvertisingData(selfEntity,
                                             TRUE, gapRole_AdvertDataLen, gapRole_AdvertData);
        }

        if (stat != SUCCESS)
        {
            gapRole_state = GAPROLE_ERROR;
        }

        notify = TRUE;
    }
    break;

    case GAP_ADV_DATA_UPDATE_DONE_EVENT:
    {
        gapAdvDataUpdateEvent_t *pPkt = (gapAdvDataUpdateEvent_t *)pMsg;

        if (pPkt->hdr.status == SUCCESS)
        {
            if (pPkt->adType)
            {
                // Setup the Response Data
                pPkt->hdr.status = GAP_UpdateAdvertisingData(selfEntity,
                                   FALSE, gapRole_ScanRspDataLen, gapRole_ScanRspData);
            }
            else if ((gapRole_state != GAPROLE_ADVERTISING)   &&
                     (gapRole_state != GAPROLE_CONNECTED_ADV) &&
                     (gapRole_state != GAPROLE_CONNECTED ||
                      gapRole_AdvNonConnEnabled == TRUE)      &&
                     (Util_isActive(&startAdvClock) == FALSE))
            {
                // Start advertising
                gapRole_setEvent(START_ADVERTISING_EVT);
            }
        }

        if (pPkt->hdr.status != SUCCESS)
        {
            // Set into Error state
            gapRole_state = GAPROLE_ERROR;
            notify = TRUE;
        }
    }
    break;

    case GAP_MAKE_DISCOVERABLE_DONE_EVENT:
    case GAP_END_DISCOVERABLE_DONE_EVENT:
    {
        gapMakeDiscoverableRspEvent_t *pPkt = (gapMakeDiscoverableRspEvent_t *)pMsg;

        if (pPkt->hdr.status == SUCCESS)
        {
            if (pMsg->opcode == GAP_MAKE_DISCOVERABLE_DONE_EVENT)
            {
                if (gapRole_state == GAPROLE_CONNECTED)
                {
                    gapRole_state = GAPROLE_CONNECTED_ADV;
                }
                else if (gapRole_AdvEnabled)
                {
                    gapRole_state = GAPROLE_ADVERTISING;
                }
                else
                {
                    gapRole_state = GAPROLE_ADVERTISING_NONCONN;
                }
            }
            else // GAP_END_DISCOVERABLE_DONE_EVENT
            {
                if (gapRole_AdvertOffTime != 0)
                {
                    if ((gapRole_AdvEnabled) || (gapRole_AdvNonConnEnabled))
                    {
                        Util_restartClock(&startAdvClock, gapRole_AdvertOffTime);
                    }
                }
                else
                {
                    // Since gapRole_AdvertOffTime is set to 0, the device should not
                    // automatically become discoverable again after a period of time.
                    // Set enabler to FALSE; device will become discoverable again when
                    // this value gets set to TRUE
                    if (gapRole_AdvEnabled == TRUE)
                    {
                        gapRole_AdvEnabled = FALSE;
                    }
                    else
                    {
                        gapRole_AdvNonConnEnabled = FALSE;
                    }
                }

                // Update state.
                if (gapRole_state == GAPROLE_CONNECTED_ADV)
                {
                    // In the Advertising Off period
                    gapRole_state = GAPROLE_CONNECTED;
                }
                else
                {
                    // In the Advertising Off period
                    gapRole_state = GAPROLE_WAITING;
                }
            }
        }
        else
        {
            gapRole_state = GAPROLE_ERROR;
        }

        notify = TRUE;
    }
    break;

    case GAP_LINK_ESTABLISHED_EVENT:
    {
        gapEstLinkReqEvent_t *pPkt = (gapEstLinkReqEvent_t *)pMsg;

        if (pPkt->hdr.status == SUCCESS)
        {
            VOID memcpy(gapRole_ConnectedDevAddr, pPkt->devAddr, B_ADDR_LEN);
            gapRole_ConnectionHandle = pPkt->connectionHandle;
            gapRole_state = GAPROLE_CONNECTED;

            // Store connection information
            gapRole_ConnInterval = pPkt->connInterval;
            gapRole_ConnSlaveLatency = pPkt->connLatency;
            gapRole_ConnTimeout = pPkt->connTimeout;
            gapRole_ConnectedDevAddrType = pPkt->devAddrType;

            // Check whether update parameter request is enabled
            if (gapRole_ParamUpdateEnable == TRUE)
            {
                // Get the minimum time upon connection establishment before the
                // peripheral can start a connection update procedure.
                uint16_t timeout = GAP_GetParamValue(TGAP_CONN_PAUSE_PERIPHERAL);

                Util_restartClock(&startUpdateClock, timeout*1000);
            }

            // Notify the Bond Manager to the connection
            VOID GAPBondMgr_LinkEst(pPkt->devAddrType, pPkt->devAddr,
                                    pPkt->connectionHandle, GAP_PROFILE_PERIPHERAL);
        }
        else if (pPkt->hdr.status == bleGAPConnNotAcceptable)
        {
            // Set enabler to FALSE; device will become discoverable again when
            // this value gets set to TRUE
            gapRole_AdvEnabled = FALSE;

            // Go to WAITING state, and then start advertising
            gapRole_state = GAPROLE_WAITING;
        }
        else
        {
            gapRole_state = GAPROLE_ERROR;
        }
        notify = TRUE;
    }
    break;

    case GAP_LINK_TERMINATED_EVENT:
    {
        gapTerminateLinkEvent_t *pPkt = (gapTerminateLinkEvent_t *)pMsg;

        GAPBondMgr_LinkTerm(pPkt->connectionHandle);

        memset(gapRole_ConnectedDevAddr, 0, B_ADDR_LEN);

        // Erase connection information
        gapRole_ConnInterval = 0;
        gapRole_ConnSlaveLatency = 0;
        gapRole_ConnTimeout = 0;
        gapRole_ConnTermReason = pPkt->reason;

        // Cancel all connection parameter update timers (if any active)
        Util_stopClock(&startUpdateClock);
        Util_stopClock(&updateTimeoutClock);

        notify = TRUE;

        gapRole_ConnectionHandle = INVALID_CONNHANDLE;

        // If device was advertising when connection dropped
        if (gapRole_AdvNonConnEnabled)
        {
            // Continue advertising.
            gapRole_state = GAPROLE_ADVERTISING_NONCONN;
        }
        // Else go to WAITING state.
        else
        {
            if(pPkt->reason == LL_SUPERVISION_TIMEOUT_TERM)
            {
                gapRole_state = GAPROLE_WAITING_AFTER_TIMEOUT;
            }
            else
            {
                gapRole_state = GAPROLE_WAITING;
            }

            // Start advertising, if enabled.
            gapRole_setEvent(START_ADVERTISING_EVT);
        }
    }
    break;

    case GAP_LINK_PARAM_UPDATE_EVENT:
    {
        gapLinkUpdateEvent_t *pPkt = (gapLinkUpdateEvent_t *)pMsg;

        // Cancel connection param update timeout timer (if active)
        Util_stopClock(&updateTimeoutClock);

        if (pPkt->hdr.status == SUCCESS)
        {
            // Store new connection parameters
            gapRole_ConnInterval = pPkt->connInterval;
            gapRole_ConnSlaveLatency = pPkt->connLatency;
            gapRole_ConnTimeout = pPkt->connTimeout;

            // Make sure there's no pending connection update procedure
            if(Util_isActive(&startUpdateClock) == FALSE)
            {
                // Notify the application with the new connection parameters
                if (pGapRoles_ParamUpdateCB != NULL)
                {
                    (*pGapRoles_ParamUpdateCB)(gapRole_ConnInterval,
                                               gapRole_ConnSlaveLatency,
                                               gapRole_ConnTimeout);
                }
            }
        }
    }
    break;

    case GAP_PAIRING_REQ_EVENT:
    {
        gapPairingReqEvent_t *pPkt = (gapPairingReqEvent_t *)pMsg;

        // Send Pairing Failed Response
        VOID GAP_TerminateAuth(pPkt->connectionHandle,
                               SMP_PAIRING_FAILED_NOT_SUPPORTED);
    }
    break;

    default:
        break;
    }

    if (notify == TRUE)
    {
        // Notify the application with the new state change
        if (pGapRoles_AppCGs && pGapRoles_AppCGs->pfnStateChange)
        {
            pGapRoles_AppCGs->pfnStateChange(gapRole_state);
        }
    }
}
/*********************************************************************
 * @fn      gapRole_ProcessGAPMsg
 *
 * @brief   Process an incoming task message.
 *
 * @param   pMsg - message to process
 *
 * @return  none
 */
void gapBondMgr_ProcessGAPMsg( gapEventHdr_t *pMsg )
{
  switch ( pMsg->opcode )
  {
    case GAP_PASSKEY_NEEDED_EVENT:
      {
        gapPasskeyNeededEvent_t *pPkt = (gapPasskeyNeededEvent_t *)pMsg;
        
        if ( pGapBondCB && pGapBondCB->passcodeCB )
        {
          // Ask app for a passcode
          pGapBondCB->passcodeCB( pPkt->deviceAddr, pPkt->connectionHandle, pPkt->uiInputs, pPkt->uiOutputs );
        }
        else
        {
          // No app support, use the default passcode
          if ( GAP_PasscodeUpdate( gapBond_Passcode, pPkt->connectionHandle ) != SUCCESS )
          {
            VOID GAP_TerminateAuth( pPkt->connectionHandle, SMP_PAIRING_FAILED_PASSKEY_ENTRY_FAILED );
          }
        }        
      }
      break;
      
    case GAP_AUTHENTICATION_COMPLETE_EVENT:
      {
        gapAuthCompleteEvent_t *pPkt = (gapAuthCompleteEvent_t *)pMsg;
        
        // Should we save bonding information
        if ( (pPkt->hdr.status == SUCCESS) && (pPkt->authState & SM_AUTH_STATE_BONDING) )
        {
          gapBondRec_t bondRec;
          
          VOID osal_memset( &bondRec, 0, sizeof ( gapBondRec_t ) ) ;
          
          // Do we have a public address in the data?
          if ( pPkt->pIdentityInfo )
          {
            VOID osal_memcpy( bondRec.publicAddr, pPkt->pIdentityInfo->bd_addr, B_ADDR_LEN );
          }
          else
          {
            linkDBItem_t *pLinkItem = linkDB_Find( pPkt->connectionHandle );
            if ( pLinkItem )
            {
              VOID osal_memcpy( bondRec.publicAddr, pLinkItem->addr, B_ADDR_LEN );
            }
            else
            {
              // We don't have an address, so ignore the message.
              break;
            }
          }
          
          // Save off of the authentication state
          bondRec.stateFlags |= (pPkt->authState & SM_AUTH_STATE_AUTHENTICATED) ? GAP_BONDED_STATE_AUTHENTICATED : 0;
          
          VOID gapBondMgrAddBond( &bondRec, 
                             (gapBondLTK_t *)pPkt->pSecurityInfo, 
                             (gapBondLTK_t *)pPkt->pDevSecInfo,
                             ((uint8 *)((pPkt->pIdentityInfo) ? pPkt->pIdentityInfo->irk : NULL )),
                             ((uint8 *)((pPkt->pSigningInfo) ? pPkt->pSigningInfo->srk : NULL )),
                             ((uint32)((pPkt->pSigningInfo) ? pPkt->pSigningInfo->signCounter : GAP_INIT_SIGN_COUNTER )) );
                             
        }
        
        // Call app state callback
        if ( pGapBondCB && pGapBondCB->pairStateCB )
        {
          pGapBondCB->pairStateCB( GAPBOND_PAIRING_STATE_COMPLETE, pPkt->hdr.status );
        }
      }
      break;
        
    case GAP_BOND_COMPLETE_EVENT:
      // This message is received when the bonding is complete.  If hdr.status is SUCCESS
      // then call app state callback.  If hdr.status is NOT SUCCESS, the connection will be 
      // dropped at the LL because of a MIC failure, so again nothing to do.
      if ( pGapBondCB && pGapBondCB->pairStateCB && pMsg->hdr.status == SUCCESS )
      {
        pGapBondCB->pairStateCB( GAPBOND_PAIRING_STATE_BONDED, pMsg->hdr.status );
      }  
      break;
      
    case GAP_SIGNATURE_UPDATED_EVENT:
      {
        uint8 idx;
        gapSignUpdateEvent_t *pPkt = (gapSignUpdateEvent_t *)pMsg;
        
        idx = GAPBondMgr_ResolveAddr( pPkt->addrType, pPkt->devAddr, NULL );
        if ( idx < GAP_BONDINGS_MAX )
        {
          // Save the sign counter
          VOID osal_snv_write( devSignCounterNvID(idx), sizeof ( uint32 ), &(pPkt->signCounter) );
        }
      }
      break;
      
    case GAP_PAIRING_REQ_EVENT:
      {
        gapPairingReqEvent_t *pPkt = (gapPairingReqEvent_t *)pMsg;
        
        if ( gapBond_AutoFail != FALSE )
        {
          // Auto Fail TEST MODE (DON'T USE THIS) - Sends pre-setup reason
          VOID GAP_TerminateAuth( pPkt->connectionHandle, gapBond_AutoFailReason );
        }
        else if ( gapBond_PairingMode == GAPBOND_PAIRING_MODE_NO_PAIRING )
        {
          // No Pairing - Send error
          VOID GAP_TerminateAuth( pPkt->connectionHandle, SMP_PAIRING_FAILED_NOT_SUPPORTED );
        }
        else
        {
          gapAuthParams_t params;
          linkDBItem_t *pLinkItem = linkDB_Find( pPkt->connectionHandle );
          
          // Requesting bonding?
          if ( pPkt->pairReq.authReq & SM_AUTH_STATE_BONDING )
          {
            if ( pLinkItem ) 
            {
              if ( (pLinkItem->addrType != ADDRTYPE_PUBLIC) && (pPkt->pairReq.keyDist.mIdKey == FALSE) )
              {
                uint8 publicAddr[B_ADDR_LEN];
                
                // Check if we already have the public address in NV
                if ( GAPBondMgr_ResolveAddr(pLinkItem->addrType, pLinkItem->addr, publicAddr ) == FALSE )
                {
                  // Can't bond to a non-public address if we don't know the public address
                  VOID GAP_TerminateAuth( pPkt->connectionHandle, SMP_PAIRING_FAILED_AUTH_REQ );
                  break;
                }
              }
            }
            else
            {
              // Can't find the connection, ignore the message
              break;
            }
          }

          VOID osal_memset( &params, 0, sizeof ( gapAuthParams_t ) );
          
          // Setup the pairing parameters
          params.connectionHandle = pPkt->connectionHandle;
          params.secReqs.ioCaps = gapBond_IOCap;
          params.secReqs.oobAvailable = gapBond_OOBDataFlag;
          params.secReqs.maxEncKeySize = gapBond_KeySize;
          
          // TBD - Should we distribute keys if bonding is turned off???
          params.secReqs.keyDist.sEncKey = (gapBond_KeyDistList | GAPBOND_KEYDIST_SENCKEY) ? TRUE : FALSE;
          params.secReqs.keyDist.sIdKey = (gapBond_KeyDistList | GAPBOND_KEYDIST_SIDKEY) ? TRUE : FALSE;
          params.secReqs.keyDist.mEncKey = (gapBond_KeyDistList | GAPBOND_KEYDIST_MENCKEY) ? TRUE : FALSE;
          params.secReqs.keyDist.mIdKey = (gapBond_KeyDistList | GAPBOND_KEYDIST_MIDKEY) ? TRUE : FALSE;
          params.secReqs.keyDist.mSign = (gapBond_KeyDistList | GAPBOND_KEYDIST_MSIGN) ? TRUE : FALSE;
          params.secReqs.keyDist.sSign = (gapBond_KeyDistList | GAPBOND_KEYDIST_SSIGN) ? TRUE : FALSE;
          
          // Is bond manager setup for OOB data?
          if ( gapBond_OOBDataFlag )
          {
            VOID osal_memcpy( params.secReqs.oob, gapBond_OOBData, KEYLEN );
          }
          
          if ( (pPkt->pairReq.authReq & SM_AUTH_STATE_BONDING) && (gapBond_Bonding) )
          {
            params.secReqs.authReq |= SM_AUTH_STATE_BONDING;
            if ( pLinkItem->addrType != ADDRTYPE_PUBLIC )
            {
              // Force a master ID key 
              params.secReqs.keyDist.mIdKey = TRUE;
            }
          }
          
          // Is Bond Manager setup for passkey protection?
          if ( gapBond_MITM )
          {
            params.secReqs.authReq |= SM_AUTH_STATE_AUTHENTICATED;
          }
          
          VOID GAP_Authenticate( &params, &(pPkt->pairReq) );
        }
        
        // Call app state callback
        if ( pGapBondCB && pGapBondCB->pairStateCB )
        {
          pGapBondCB->pairStateCB( GAPBOND_PAIRING_STATE_STARTED, pPkt->hdr.status );
        }        
      }
      break;
      
    default:
      break;
  }
}
/*********************************************************************
 * @fn      gapRole_processGAPMsg
 *
 * @brief   Process an incoming task message.
 *
 * @param   pMsg - message to process
 *
 * @return  none
 */
static uint8_t gapRole_processGAPMsg(gapEventHdr_t *pMsg) {
	uint8_t notify = FALSE;   // State changed notify the app? (default no)

	switch (pMsg->opcode) {
	case GAP_DEVICE_INIT_DONE_EVENT: {
		gapDeviceInitDoneEvent_t *pPkt = (gapDeviceInitDoneEvent_t *) pMsg;
		bStatus_t stat = pPkt->hdr.status;

		if (stat == SUCCESS) {
			// Save off the generated keys
			VOID osal_snv_write(BLE_NVID_IRK, KEYLEN, gapRole_IRK);
			VOID osal_snv_write(BLE_NVID_CSRK, KEYLEN, gapRole_SRK);

			// Save off the information
			VOID memcpy(gapRole_bdAddr, pPkt->devAddr, B_ADDR_LEN);

			gapRole_peripheralState = GAPROLE_STARTED;
			gapRole_peripheralStateChangeHandler(gapRole_peripheralState);

			// Update the advertising data
			stat = GAP_UpdateAdvertisingData(selfEntity,
			TRUE, gapRole_AdvertDataLen, gapRole_AdvertData);
		}

		if (stat != SUCCESS) {
			gapRole_peripheralState = GAPROLE_ERROR;
			gapRole_peripheralStateChangeHandler(gapRole_peripheralState);
			//gapRole_abort();
		}

		notify = TRUE;
	}
		break;

	case GAP_ADV_DATA_UPDATE_DONE_EVENT: {
		gapAdvDataUpdateEvent_t *pPkt = (gapAdvDataUpdateEvent_t *) pMsg;

        if (pPkt->hdr.status == SUCCESS)
        {
          if (pPkt->adType)
          {
            // Setup the Response Data
            pPkt->hdr.status = GAP_UpdateAdvertisingData(selfEntity,
                              FALSE, gapRole_ScanRspDataLen, gapRole_ScanRspData);
          }
          else if ((gapRole_peripheralState != GAPROLE_ADVERTISING)   &&
                   (gapRole_peripheralState != GAPROLE_CONNECTED_ADV) &&
                   (gapRole_peripheralState != GAPROLE_CONNECTED ||
                    gapRole_AdvNonConnEnabled == TRUE)      &&
                   (Util_isActive(&startAdvClock) == FALSE))
          {
            // Start advertising
            gapRole_setEvent(START_ADVERTISING_EVT);
          }
          notify = FALSE;
        }else {
			// Set into Error state
			gapRole_peripheralState = GAPROLE_ERROR;
			gapRole_peripheralStateChangeHandler(gapRole_peripheralState);
			//gapRole_abort();
			notify = TRUE;
		}
	}
		break;

	case GAP_MAKE_DISCOVERABLE_DONE_EVENT:
	case GAP_END_DISCOVERABLE_DONE_EVENT: {
		gapMakeDiscoverableRspEvent_t *pPkt = (gapMakeDiscoverableRspEvent_t *) pMsg;

		if (pPkt->hdr.status == SUCCESS) {
			if (pMsg->opcode == GAP_MAKE_DISCOVERABLE_DONE_EVENT) {
				if (gapRole_peripheralState == GAPROLE_CONNECTED) {
					gapRole_peripheralState = GAPROLE_CONNECTED_ADV;
					gapRole_peripheralStateChangeHandler(gapRole_peripheralState);
				} else if (gapRole_AdvEnabled) {
					gapRole_peripheralState = GAPROLE_ADVERTISING;
					gapRole_peripheralStateChangeHandler(gapRole_peripheralState);
				} else {
					gapRole_peripheralState = GAPROLE_ADVERTISING_NONCONN;
					gapRole_peripheralStateChangeHandler(gapRole_peripheralState);
				}
			} else // GAP_END_DISCOVERABLE_DONE_EVENT
			{
				if (gapRole_AdvertOffTime != 0) //restart advertising if param is set
						{
					if ((gapRole_AdvEnabled) || (gapRole_AdvNonConnEnabled)) {
						Util_restartClock(&startAdvClock, gapRole_AdvertOffTime);
					}
				} else {
					// Since gapRole_AdvertOffTime is set to 0, the device should not
					// automatically become discoverable again after a period of time.
					// Set enabler to FALSE; device will become discoverable again when
					// this value gets set to TRUE
					if (gapRole_AdvEnabled == TRUE) {
						gapRole_AdvEnabled = FALSE;
					} else {
						gapRole_AdvNonConnEnabled = FALSE;
					}
				}

				// Update state.
				if (gapRole_peripheralState == GAPROLE_CONNECTED_ADV) {
					// In the Advertising Off period
					gapRole_peripheralState = GAPROLE_CONNECTED;
					gapRole_peripheralStateChangeHandler(gapRole_peripheralState);
				} else {
					// In the Advertising Off period
					gapRole_peripheralState = GAPROLE_WAITING;
					gapRole_peripheralStateChangeHandler(gapRole_peripheralState);
				}
			}
			notify = TRUE;
		} else if (pPkt->hdr.status == LL_STATUS_ERROR_COMMAND_DISALLOWED) //we're already advertising
		{
			notify = FALSE;
		} else {
			gapRole_peripheralState = GAPROLE_ERROR;
			gapRole_peripheralStateChangeHandler(gapRole_peripheralState);
			//gapRole_abort();
		}
	}
		break;

	case GAP_LINK_ESTABLISHED_EVENT: {
		gapEstLinkReqEvent_t *pPkt = (gapEstLinkReqEvent_t *) pMsg;

		if (pPkt->hdr.status == SUCCESS) {
			//add to database
			gapRoleInfo_Add(pPkt);

			// advertising will stop when a connection forms in the peripheral role
			if (pPkt->connRole == GAP_PROFILE_PERIPHERAL) {

				gapRole_peripheralState = GAPROLE_CONNECTED;
				gapRole_peripheralStateChangeHandler(gapRole_peripheralState);

				// Check whether update parameter request is enabled
				if (gapRole_ParamUpdateEnable == TRUE) {
						// Get the minimum time upon connection establishment before the
						// peripheral can start a connection update procedure.
						uint16_t timeout = GAP_GetParamValue(
						TGAP_CONN_PAUSE_PERIPHERAL);

						Util_restartClock(&startUpdateClock, timeout * 1000);

				}
			}
			// Notify the Bond Manager to the connection
			VOID GAPBondMgr_LinkEst(pPkt->devAddrType, pPkt->devAddr, pPkt->connectionHandle, pPkt->connRole);
		} else if (pPkt->hdr.status == bleGAPConnNotAcceptable) {
			// Set enabler to FALSE; device will become discoverable again when
			// this value gets set to TRUE
			gapRole_AdvEnabled = FALSE;

	        // Go to WAITING state, and then start advertising
			if (pPkt->connRole == GAP_PROFILE_PERIPHERAL) {
				gapRole_peripheralState = GAPROLE_WAITING;
				gapRole_peripheralStateChangeHandler(gapRole_peripheralState);
			}
		} else {
			if (pPkt->connRole == GAP_PROFILE_PERIPHERAL) {
				gapRole_peripheralState = GAPROLE_ERROR;
				gapRole_peripheralStateChangeHandler(gapRole_peripheralState);
			} else {
				gapRole_abort();
			}
		}
		notify = TRUE;
	}
		break;

	case GAP_LINK_TERMINATED_EVENT: {
		gapTerminateLinkEvent_t *pPkt = (gapTerminateLinkEvent_t *) pMsg;

		// notify bond manager
		GAPBondMgr_LinkTerm(pPkt->connectionHandle);

		// Erase connection information (maybe make this a function)
		uint8 connHandleIndex = gapRoleInfo_Find(pPkt->connectionHandle);
		multiConnInfo[connHandleIndex].gapRole_ConnectionHandle = INVALID_CONNHANDLE;
		multiConnInfo[connHandleIndex].gapRole_ConnInterval = 0;
		multiConnInfo[connHandleIndex].gapRole_ConnSlaveLatency = 0;
		multiConnInfo[connHandleIndex].gapRole_ConnTimeout = 0;

		// Cancel all connection parameter update timers (if any active)
		Util_stopClock(&startUpdateClock);
		Util_stopClock(&updateTimeoutClock);

		notify = TRUE;

		if (multiConnInfo[connHandleIndex].gapRole_ConnRole == GAP_PROFILE_PERIPHERAL) {
			// If device was advertising when connection dropped
			if (gapRole_AdvNonConnEnabled) {
				// Continue advertising.
				gapRole_peripheralState = GAPROLE_ADVERTISING_NONCONN;
				gapRole_peripheralStateChangeHandler(gapRole_peripheralState);
			}
			// Else go to WAITING state.
			else {
				if (pPkt->reason == LL_SUPERVISION_TIMEOUT_TERM) {
					gapRole_peripheralState = GAPROLE_WAITING_AFTER_TIMEOUT;
					gapRole_peripheralStateChangeHandler(gapRole_peripheralState);
				} else {
					gapRole_peripheralState = GAPROLE_WAITING;
					gapRole_peripheralStateChangeHandler(gapRole_peripheralState);
				}

				// Start advertising, if enabled.
				gapRole_setEvent(START_ADVERTISING_EVT);
			}
		}
	}
		break;

	case GAP_LINK_PARAM_UPDATE_EVENT: {
		gapLinkUpdateEvent_t *pPkt = (gapLinkUpdateEvent_t *) pMsg;

		// Cancel connection param update timeout timer (if active)
		Util_stopClock(&updateTimeoutClock);

		if (pPkt->hdr.status == SUCCESS) {
			// Store new connection parameters
//              gapRole_ConnInterval = pPkt->connInterval;
//              gapRole_ConnSlaveLatency = pPkt->connLatency;
//              gapRole_ConnTimeout = pPkt->connTimeout;

			// Make sure there's no pending connection update procedure
			if (Util_isActive(&startUpdateClock) == FALSE) {
//                // Notify the application with the new connection parameters
//                if (pGapRoles_ParamUpdateCB != NULL)
//                {
//                  (*pGapRoles_ParamUpdateCB)(gapRole_ConnInterval,
//                                             gapRole_ConnSlaveLatency,
//                                             gapRole_ConnTimeout);
//                }
			}
		}
		notify = TRUE;
	}
		break;

	case GAP_PAIRING_REQ_EVENT: {
		gapPairingReqEvent_t *pPkt = (gapPairingReqEvent_t *) pMsg;

		// Send Pairing Failed Response
		VOID GAP_TerminateAuth(pPkt->connectionHandle,
		SMP_PAIRING_FAILED_NOT_SUPPORTED);
	}
		break;

	case GAP_SLAVE_REQUESTED_SECURITY_EVENT: {
        uint16_t connHandle = ((gapSlaveSecurityReqEvent_t *)pMsg)->connectionHandle;
        uint8_t authReq = ((gapSlaveSecurityReqEvent_t *)pMsg)->authReq;

        GAPBondMgr_SlaveReqSecurity(connHandle, authReq);
	}
		break;

	case GAP_DEVICE_INFO_EVENT:
	case GAP_DEVICE_DISCOVERY_EVENT:
		notify = TRUE;
		break;

	default:
		notify = FALSE;
		break;
	}

	if (notify == TRUE) //app needs to take further action
	{
		if (pGapRoles_AppCGs && pGapRoles_AppCGs->pfnPassThrough) {
			return (pGapRoles_AppCGs->pfnPassThrough((gapMultiRoleEvent_t *) pMsg));
		}
	}

	return TRUE;

}