bool connectionAddTaskMap(conn_type type, map_id id, Task task, const profile_task_recipe *recipe) { uint16 match_index; /* Check to see if we already have this entry if we do return false */ if (findMatchInMap(type, id, &match_index)) { return FALSE; } else { /* Create a new map array */ conn_task_map new_map; new_map.type = type; new_map.id = id; new_map.appTask = task; new_map.task_recipe = recipe; /* Allocate one more element in the array - initially map_ptr should be null */ map = (conn_task_map *) PanicNull(realloc(map, (sizeof(conn_task_map) * (mapSize+1)))); /* Add new element */ map[mapSize] = new_map; /* Don't forget to increment the size count */ mapSize++; /* New element added successfully! */ return TRUE; } }
static void deleteElement(uint16 match_index) { conn_task_map *new_map; /* Reduce the size by one */ mapSize--; /* Realocate the array with one fewer element */ new_map = (conn_task_map *) PanicNull(malloc(sizeof(conn_task_map) * mapSize)); /* Copy all the elements apart from the one being deleted */ if (match_index == 0) { memmove(new_map, map+1, sizeof(conn_task_map)*mapSize); } else { /* Copy the elements before the one being remove */ memmove(new_map, map, sizeof(conn_task_map)*match_index); /* Copy the elements after the one being removed if its not the last one */ if ((mapSize-match_index) > 0) memmove(new_map+match_index, map+match_index+1, sizeof(conn_task_map)*(mapSize-match_index)); } /* Free the old map array */ free(map); /* Need to point to the new one */ map = new_map; }
/************************************************************************* NAME gattHandleInternalExecuteWriteReq DESCRIPTION This function is handler for GATT_INTERNAL_EXECUTE_WRITE_REQ internal message. RETURNS */ void gattHandleInternalExecuteWriteReq(GATT_INTERNAL_EXECUTE_WRITE_REQ_T *m) { cid_map_t *conn = PanicNull(gattFindConn(m->common.cid)); /* never NULL */ gattSetConnState(conn, m->common.task, gatt_ms_execute_write); gatt_execute_write_req(m->common.cid, m->flags); }
static void send_pio_timed_message(PioState *pioState, const TimedMessage *p, int hold_repeat) { const TimedMessage **m = (const TimedMessage **) PanicNull(malloc(sizeof(const TimedMessage *))); *m = p; if (hold_repeat) MessageSendLater(&pioState->task, internal_pio_timer_message, m, p->msecRepeat); else MessageSendLater(&pioState->task, internal_pio_timer_message, m, p->msec); }
/************************************************************************* NAME gattHandleInternalWriteReq DESCRIPTION This function is handler for GATT_INTERNAL_WRITE_REQ internal message. RETURNS */ void gattHandleInternalWriteReq(GATT_INTERNAL_WRITE_REQ_T *m) { cid_map_t *conn = PanicNull(gattFindConn(m->common.cid)); /* never NULL */ STASH(conn, stash, WRITE_CHARACTERISTIC_VALUE); uint16 flags; switch (m->id) { #if (GATT_FEATURES & GATT_WRITE_COMMAND) case gatt_ms_write_without_response: flags = ATT_WRITE_COMMAND; break; #endif #if (GATT_FEATURES & GATT_WRITE_SIGNED) case gatt_ms_signed_write_without_response: flags = ATT_WRITE_COMMAND | ATT_WRITE_SIGNED; break; #endif #if (GATT_FEATURES & GATT_WRITE) case gatt_ms_write_characteristic_value: flags = ATT_WRITE_REQUEST; break; #endif #if (GATT_FEATURES & GATT_WRITE_LONG) case gatt_ms_write_long_characteristic_value: handleInternalWriteReqLong(conn, m); return; #endif #if (GATT_FEATURES & GATT_WRITE_RELIABLE) case gatt_ms_prepare_write: handleInternalWriteReqPrepare(conn, m); return; #endif default: /* horror error which can't happen, ever. */ flags = 0; Panic(); } gattSetConnState(conn, m->common.task, m->id); gatt_write_req(m->common.cid, m->handle, flags, m->size_value, m->value); /* Create the response message */ MAKE_STASH(conn, stash, WRITE_CHARACTERISTIC_VALUE); stash->cid = m->common.cid; stash->handle = m->handle; }
/**************************************************************************** NAME inquiryAddEirData PARAMS [IN/OUT] size_eir_data Current size of the eir_data [OUT] eir_data Buffer into which the EIR data needs to be copied [IN] size_data Length of data to be copied [IN] eir_data_part Array from which the data needs to be copied from DESCRIPTION Copy a block of data from an eir data part to the eir result. RETURNS */ static uint8* inquiryAddEirData(uint8* size_eir_data, uint8* eir_data, uint8 size_data, const uint8* eir_data_part) { /* Allocate space for the new data in result */ uint8* result = PanicNull( realloc(eir_data, (*size_eir_data) + size_data) ); /* Copy data from data part to result */ memmove( (result + (*size_eir_data)), eir_data_part, size_data ); /* Update size */ *size_eir_data += size_data; return result; }
/**************************************************************************** NAME gattLockCid DESCRIPTION Lock on CID for an active message scenario. New scenarios can't start until the current one is complete and the CID unlocked. RETURNS */ bool gattLockCid(uint16 cid, gatt_msg_scen_t scenario) { cid_map_t *ptr = (cid_map_t *)PanicNull(gattFindConn(cid)); if (ptr->data.scenario) { return FALSE; /* CID is already mapped to a scenario */ } else { ptr->data.scenario = scenario; } return TRUE; }
/************************************************************************* NAME gattHandleInternalDiscoverAllDescriptorsReq DESCRIPTION This function is handler for GATT_DISCOVER_ALL_DESCRIPTORS_REQ internal message. RETURNS */ void gattHandleInternalDiscoverAllDescriptorsReq( GATT_INTERNAL_DISCOVER_ALL_DESCRIPTORS_REQ_T *m) { cid_map_t *conn = PanicNull(gattFindConn(m->common.cid)); /* never NULL */ gattSetConnState(conn, m->common.task, gatt_ms_discover_all_descriptors); conn->data.req.discover_all_descriptors.start = m->start; conn->data.req.discover_all_descriptors.end = m->end; gatt_find_info_req(m->common.cid, conn->data.req.discover_all_descriptors.start, conn->data.req.discover_all_descriptors.end); }
/**************************************************************************** NAME scanKickInquiryScan DESCRIPTION Starts inquiry process. */ void scanKickInquiryScan (void) { DEBUG_SCAN(("Kick inquiry scan\n")); the_app->remote_profiles = ProfileNone; if ( s_inquiry_scan_data == NULL ) { s_inquiry_scan_data = (mvdInquiryScanData *)malloc( sizeof(mvdInquiryScanData) ); PanicNull( s_inquiry_scan_data ); } s_inquiry_scan_data->read_idx = 0; s_inquiry_scan_data->write_idx = 0; ConnectionInquire(&the_app->task, 0x9e8b33, INQUIRY_SCAN_BUFFER_SIZE, 4, (uint32)AV_MAJOR_DEVICE_CLASS); }
void SwatInit(Task clientTask, uint16 max_remote_devs, swat_role role, bool auto_handle, const uint8 *service_record, uint16 size_service_record, const sync_config_params * esco_config) { /* Attempt to initialise the task data */ if ( !swat ) { swat = PanicUnlessNew(swatTaskData); memset( swat, 0, sizeof(swatTaskData) ); SWAT_DEBUG(("[SWAT] Sizeof(swatTaskData) = %u\n", sizeof(swatTaskData))); /* Initialise the swat profile data */ swat->l2cap_task.handler = swatL2capHandler; swat->profile_task.handler = swatProfileHandler; swat->command_task.handler = swatCommandHandler; swat->clientTask = clientTask; swat->auto_handle = auto_handle; swat->role = role; swat->max_remote_devs = max_remote_devs; /* Allocate memory to store remote device data depending on number of allowed devices */ swat->remote_devs = (remoteDevice *)PanicNull(malloc(max_remote_devs * sizeof(remoteDevice))); memset(swat->remote_devs, 0, (max_remote_devs * sizeof(remoteDevice))); /* Use service record supplied by client */ if (service_record) { ConnectionRegisterServiceRecord(&swat->l2cap_task, (sizeof(uint8) * size_service_record), service_record); } /* Use library default service record */ else { ConnectionRegisterServiceRecord(&swat->l2cap_task, sizeof(swat_service_record), swat_service_record); } /* Use eSCO config supplied by client */ if (esco_config) { swat->esco_config = esco_config; } else { swat->esco_config = NULL; } } else { swatSendInitCfmToClient(swat_init_failed); } }
/**************************************************************************** NAME gattUnlockCid DESCRIPTION Clear data associated with a message scenario locking on a CID. RETURNS */ void gattUnlockCid(uint16 cid) { cid_map_t *ptr = (cid_map_t *)PanicNull(gattFindConn(cid)); #if GATT_DEBUG_LIB if (!ptr->data.scenario) { printf("gattUnlockCid: No scenario associated with CID\n"); Panic(); } #endif /* clear associated connection data. */ free(ptr->data.stash); memset( &ptr->data, 0, sizeof(conn_data_t) ); }
/************************************************************************* NAME gattHandleAttFindInfoCfm DESCRIPTION This function handles Bluestack response for ATT_FIND_INFO_REQ. RETURNS */ void gattHandleAttFindInfoCfm(ATT_FIND_INFO_CFM_T *m) { cid_map_t *conn = PanicNull(gattFindConn(m->cid)); /* never NULL */ STASH(conn, stash, DISCOVER_ALL_CHARACTERISTIC_DESCRIPTORS); bool more; bool send; if (!gatt_message_prepare( conn, &more, &send, m->result, m->handle >= conn->data.req.discover_all_descriptors.end, stash ? &stash->more_to_come : NULL, GATT_DISCOVER_ALL_CHARACTERISTIC_DESCRIPTORS_CFM)) { return; } /* Create the message */ MAKE_STASH(conn, stash, DISCOVER_ALL_CHARACTERISTIC_DESCRIPTORS); stash->cid = m->cid; stash->handle = m->handle; stash->uuid_type = m->uuid_type; memmove(stash->uuid, m->uuid, GATT_UUID_SIZE); stash->more_to_come = more; stash->status = gatt_message_status(m->result); /* schedule new round for getting more information */ if (!send) { gatt_find_info_req(m->cid, m->handle + 1, conn->data.req.discover_all_descriptors.end); } /* only sent the message if we are not waiting for more information */ else { gatt_message_send(conn, GATT_DISCOVER_ALL_CHARACTERISTIC_DESCRIPTORS_CFM); if (!more) { gattSetConnState(conn, NULL, gatt_ms_none); } } }
/**************************************************************************** NAME aghfpHandleSyncConnectInd DESCRIPTION Incoming audio notification, accept if we recognise the sink reject otherwise. RETURNS void */ void aghfpHandleSyncConnectInd(AGHFP *aghfp, const CL_DM_SYNC_CONNECT_IND_T *ind) { uint16 i=0; uint16 my_audio = 0; uint16 num_sinks = 5; tp_bdaddr tp_addr = { {TYPED_BDADDR_PUBLIC, { 0, 0, 0 }}, TRANSPORT_BREDR_ACL}; /* Sink array to store the sinks on the acl. */ Sink *all_sinks = (Sink *)PanicNull(calloc(num_sinks, sizeof(Sink))); tp_addr.taddr.addr = ind->bd_addr; if(StreamSinksFromBdAddr(&num_sinks, all_sinks, &tp_addr)) { for (i=0; i<num_sinks; i++) { /* Make sure this profile instance owns the unlerlying sink */ if (all_sinks[i] && all_sinks[i] == aghfp->rfcomm_sink) { my_audio = 1; break; } } } free(all_sinks); /* If this is our audio connection then ask the app, otherwise reject outright */ if (my_audio) { MAKE_AGHFP_MESSAGE(AGHFP_AUDIO_CONNECT_IND); message->aghfp = aghfp; message->bd_addr = ind->bd_addr; MessageSend(aghfp->client_task, AGHFP_AUDIO_CONNECT_IND, message); aghfp->audio_connection_state = aghfp_audio_accepting; } else { ConnectionSyncConnectResponse(&aghfp->task, &ind->bd_addr, FALSE, 0); } }
/**************************************************************************** NAME powerManagerConfig DESCRIPTION Initialise the power handling. */ bool powerManagerConfig(const power_config_type* config) { bool success = TRUE; the_app->power = (power_type *)malloc(sizeof(power_type)); PanicNull(the_app->power); if (config) { /* Store power configuration */ the_app->power->config = *config; } else { success = FALSE; } return success; }
/************************************************************************* NAME gattHandleAttWriteCfm DESCRIPTION This function handles Bluestack response for ATT_WRITE_REQ. RETURNS */ void gattHandleAttWriteCfm(ATT_WRITE_CFM_T *m) { cid_map_t *conn = PanicNull(gattFindConn(m->cid)); /* never NULL */ STASH(conn, stash, WRITE_CHARACTERISTIC_VALUE); uint16 id; stash->status = gatt_message_status(m->result); switch (conn->data.scenario) { #if (GATT_FEATURES & GATT_WRITE_COMMAND) case gatt_ms_write_without_response: id = GATT_WRITE_WITHOUT_RESPONSE_CFM; break; #endif #if (GATT_FEATURES & GATT_WRITE_SIGNED) case gatt_ms_signed_write_without_response: id = GATT_SIGNED_WRITE_WITHOUT_RESPONSE_CFM; break; #endif #if (GATT_FEATURES & GATT_WRITE) case gatt_ms_write_characteristic_value: id = GATT_WRITE_CHARACTERISTIC_VALUE_CFM; break; #endif default: /* horror error which can't happen, ever. */ id = 0; Panic(); } gatt_message_send(conn, id); gattSetConnState(conn, NULL, gatt_ms_none); }
/************************************************************************* NAME gattHandleAttExecuteWriteCfm DESCRIPTION This function handles Bluestack response for ATT_EXECUTE_WRITE_REQ. RETURNS */ void gattHandleAttExecuteWriteCfm(ATT_EXECUTE_WRITE_CFM_T *m) { cid_map_t *conn = PanicNull(gattFindConn(m->cid)); /* never NULL */ switch (conn->data.scenario) { #if (GATT_FEATURES & GATT_WRITE_LONG) case gatt_ms_write_long_characteristic_value: handleAttExecuteWriteCfmLong(conn, m); return; #endif #if (GATT_FEATURES & GATT_WRITE_RELIABLE) case gatt_ms_execute_write: handleAttExecuteWriteCfmExecute(conn, m); return; #endif default: /* horror error which can't happen, ever. */ Panic(); } }
/**************************************************************************** NAME inquiryParseEir DESCRIPTION Take the EIR data structure received from bluestack and concat the data into a single block to send to the application RETURNS A pointer to a single block containing the EIR data and the size of the eir data */ static uint8* inquiryParseEir(uint8* size_eir_data, uint8 *inquiry_data[HCI_EIR_DATA_PACKET_PTRS], bool limit_data_size) { /* Data Part */ uint8 i = 0; /* Index into inquiry_data */ uint8 size_data_part; /* Size un-parsed data left in current part */ uint8* eir_data_part; /* Pointer to start of un-parsed data */ uint8* eir_data_part_base; /* Pointer to base of the current data part */ /* Field Data */ uint8 size_field; /* Size of the field we're parsing */ bool limit_exceeded; /* If the field should be written */ /* Result */ uint8* eir_data = NULL; /* Parsed EIR Data */ *size_eir_data = 0; /* Size of Parsed Data */ /* Return early if we have nothing to parse */ if(inquiry_data[0] == NULL) { return eir_data; } /* Setup First Data Part */ size_data_part = HCI_EIR_DATA_BYTES_PER_PTR; eir_data_part_base = VmGetPointerFromHandle(inquiry_data[i]); eir_data_part = eir_data_part_base; /* Get the size of the first field */ size_field = (*eir_data_part) + 1; limit_exceeded = (((*size_eir_data) + size_field) > MAX_EIR_DATA_SIZE); /* Keep going until we reach NULL terminator */ while(*eir_data_part != 0) { /* If the field is all in this part */ if(size_field < size_data_part) { /* Copy to the end of field */ if(!limit_data_size || !limit_exceeded) eir_data = inquiryAddEirData(size_eir_data, eir_data, size_field, eir_data_part); /* Move to the next field */ size_data_part -= size_field; eir_data_part += size_field; size_field = (*eir_data_part) + 1; limit_exceeded = (((*size_eir_data) + size_field) > MAX_EIR_DATA_SIZE); } /* Field is split over multiple parts */ else { /* Copy to the end of the data part */ if(!limit_data_size || !limit_exceeded) eir_data = inquiryAddEirData(size_eir_data, eir_data, size_data_part, eir_data_part); /* Check if there's any more data parts to go */ if(inquiry_data[++i] != NULL) { /* We're finished with this part so free it */ free(eir_data_part_base); /* Move to the next data part */ size_field -= size_data_part; size_data_part = HCI_EIR_DATA_BYTES_PER_PTR; eir_data_part_base = VmGetPointerFromHandle(inquiry_data[i]); eir_data_part = eir_data_part_base; /* Update field size if new field */ if(size_field == 0) { size_field = (*eir_data_part) + 1; limit_exceeded = (((*size_eir_data) + size_field) > MAX_EIR_DATA_SIZE); } } /* Out of data */ else { /* Data part will be freed below, just break */ break; } } } /* Free the final data part */ free(eir_data_part_base); /* NULL Terminate Data */ (*size_eir_data)++; eir_data = PanicNull( realloc(eir_data, *size_eir_data) ); *(eir_data + (*size_eir_data) - 1) = 0; return eir_data; }
/**************************************************************************** NAME gattGetCidMappedTask DESCRIPTION Returns the the task associated with the cid, the task that created the connection. RETURNS Task ptr */ Task gattGetCidMappedTask(uint16 cid) { cid_map_t *ptr = (cid_map_t *)PanicNull(gattFindConn(cid)); return ptr->task; }
void A2dpInit(Task clientTask, uint16 role, service_record_type *service_records, uint16 size_seps, sep_data_type *seps, uint16 linkloss_timeout) { /* Initialise the task data */ if ( !a2dp ) { uint8 device_id; a2dp = PanicUnlessNew(A2DP); memset( a2dp, 0, sizeof(A2DP) ); for (device_id=0; device_id<A2DP_MAX_REMOTE_DEVICES_DEFAULT; device_id++) { a2dpInitialiseRemoteDevice(&a2dp->remote_conn[device_id],device_id); } PRINT(("sizeof(A2DP)=0x%u\n", sizeof(A2DP))); /* Set the handler function */ a2dp->task.handler = a2dpProfileHandler; /* Set up the lib client */ a2dp->clientTask = clientTask; a2dp->linkloss_timeout = linkloss_timeout; a2dp->max_remote_devs = A2DP_MAX_REMOTE_DEVICES_DEFAULT; a2dp->profile_role = role; blockInit(); if ( seps && size_seps && validateSeps(seps, size_seps) ) { for (device_id=0; device_id<A2DP_MAX_REMOTE_DEVICES; device_id++) { sep_data_type *sep_list = (sep_data_type *)PanicNull( blockAdd( device_id, data_block_sep_list, size_seps, sizeof(sep_data_type) ) ); memmove( sep_list, (sep_data_type *)seps, size_seps*sizeof(sep_data_type) ); } } else { a2dpSendInitCfmToClient(a2dp_invalid_parameters); return; } /* Used to count the number of SDP records registered. Decremented again by a2dpHandleSdpRegisterCfm() and will kick off a call to a2dpRegisterL2cap() when it hits zero - i.e. all CFM messages for SDP regsitering process have been received. */ a2dp->sdp_register_outstanding = 0; if (service_records) { if (service_records->size_service_record_a && service_records->service_record_a) { /* Client has supplied their own record so register it without checking */ ConnectionRegisterServiceRecord(&a2dp->task, service_records->size_service_record_a, service_records->service_record_a); a2dp->sdp_register_outstanding++; } if (service_records->size_service_record_b && service_records->service_record_b) { /* Client has supplied their own record so register it without checking */ ConnectionRegisterServiceRecord(&a2dp->task, service_records->size_service_record_b, service_records->service_record_b); a2dp->sdp_register_outstanding++; } } else { /* Client using default library record */ if (role & A2DP_INIT_ROLE_SINK) { ConnectionRegisterServiceRecord(&a2dp->task, sizeof(a2dp_sink_service_record), a2dp_sink_service_record); PRINT(("Register Sink Service Rec\n")); a2dp->sdp_register_outstanding++; } if (role & A2DP_INIT_ROLE_SOURCE) { ConnectionRegisterServiceRecord(&a2dp->task, sizeof(a2dp_source_service_record), a2dp_source_service_record); PRINT(("Register Source Service Rec\n")); a2dp->sdp_register_outstanding++; } } if ( a2dp->sdp_register_outstanding==0 ) { /* Skip the service record registering if the user doesn't require any at this point. */ a2dpRegisterL2cap(); } } }
/************************************************************************* NAME gattHandleAttReadByTypeCfmCharacteristic DESCRIPTION This function handles Bluestack response for ATT_READ_BY_TYPE_REQ during Relationship Discovery. RETURNS */ void gattHandleAttReadByTypeCfmCharacteristic(ATT_READ_BY_TYPE_CFM_T *m) { cid_map_t *conn = PanicNull(gattFindConn(m->cid)); /* never NULL */ STASH(conn, stash, DISCOVER_ALL_CHARACTERISTICS); uint8 *data; uint8 *p; bool more; bool send; p = data = VmGetPointerFromHandle(m->value); if (!gatt_message_prepare(conn, &more, &send, m->result, m->handle >= conn->data.req.discover_all_characteristics.end, stash ? &stash->more_to_come : NULL, GATT_DISCOVER_ALL_CHARACTERISTICS_CFM)) { free(data); return; } /* Create the message */ MAKE_STASH(conn, stash, DISCOVER_ALL_CHARACTERISTICS); stash->cid = m->cid; stash->more_to_come = more; stash->status = gatt_message_status(m->result); stash->declaration = m->handle; /* read values from the response */ if (stash->status == ATT_RESULT_SUCCESS) { stash->properties = gatt_read8(&p); stash->handle = gatt_read16(&p); gatt_get_att_uuid(stash->uuid, &stash->uuid_type, m->size_value - 3, p); } /* schedule new round for getting more information */ if (!send) { gatt_read_by_type_req(m->cid, m->handle + 1, conn->data.req.discover_all_characteristics.end, ATT_UUID16, &uuid_characteristic); } /* only sent the message if we are not waiting for more information */ else { gatt_message_send(conn, GATT_DISCOVER_ALL_CHARACTERISTICS_CFM); if (!more) { gattSetConnState(conn, NULL, gatt_ms_none); } } free(data); }
/**************************************************************************** NAME gattHandleAttConnectCfm DESCRIPTION Handles the ATT_CONNECT_CFM from BlueStack. Pass on the INITIATING state so that the app can 'disconnect' the CID before the connection is established. Also, unless prepared, an ATT_CONNECT_CFM can be received for an ATT over BR/EDR slave connection and the GATT library won't know what to do with it. In that case Panic in debug and ignore in default lib version. RETURNS */ void gattHandleAttConnectCfm(gattState *theGatt, ATT_CONNECT_CFM_T *cfm) { /* PENDING is received for a master BR/EDR connection, after INITIALISING * has already been received, so just ignore it. */ if (L2CA_CONNECT_PENDING != cfm->result) { cid_map_t *conn; gatt_status_t status; Task theAppTask = theGatt->conn_req_task; typed_bdaddr taddr; BdaddrConvertTypedBluestackToVm(&taddr, &cfm->addrt); switch (cfm->result) { /* INITIATING is received for any BLE connection. This is when the * CID for the connection is known and can be passed to the app. */ case L2CA_CONNECT_INITIATING: if ( !gattCidIsValid(cfm->cid) ) gattAddCid(cfm->cid, theGatt->conn_req_task); gattLockCid(cfm->cid, gatt_ms_connect_req); status = gatt_status_initialising; break; case L2CA_CONNECT_SUCCESS: /* By the time the SUCCESS is received, the cid & task should * already be registered with GATT. */ conn = PanicNull(gattFindConn(cfm->cid)); theAppTask = conn->task; /* Clear the connection scenario lock for this cid. */ gattUnlockCid(cfm->cid); status = gatt_status_success; conn->mtu = cfm->mtu; theGatt->conn_req_task = 0; if (L2CA_CONFLAG_IS_LE(cfm->flags)) conn->bredr = FALSE; else conn->bredr = TRUE; break; default: if ( (conn = gattFindConn(cfm->cid)) ) theAppTask = conn->task; /* If we are responding to a BR/EDR connect and it failed * Don't clear the con_req_task, as an LE connection could * still be coming in. */ if (!conn || conn->data.scenario != gatt_ms_connect_rsp) theGatt->conn_req_task = 0; status = gattConvertL2capConnectStatus(cfm->result); gattDeleteCid(cfm->cid); GATT_DEBUG_INFO(( "gattHandleAttConnectCfm: result 0x%x\n", cfm->result )); break; } /* theAppTask can be 0, if max BLE connections have been made. Send * cfm to task that initialised GATT instead. */ if (!theAppTask) theAppTask = gattGetAppTask(); gattSendConnectionCfm( theAppTask, status, &taddr, cfm->flags, cfm->mtu, cfm->cid ); } }