/**************************************************************************** NAME connectionHandleSdpAttributeSearchCfm DESCRIPTION A confirm to the attribute search has been received, handle it here. RETURNS void */ void connectionHandleSdpAttributeSearchCfm(connectionSdpState *state, const SDC_EX_SERVICE_ATTRIBUTE_CFM_T *cfm) { if (state->sdpSearchLock) { /* Send a cfm to the client task */ MAKE_CL_MESSAGE_WITH_LEN(CL_SDP_ATTRIBUTE_SEARCH_CFM, cfm->size_attr_list); message->status = connectionConvertSdpSearchStatus(cfm->response); message->error_code = cfm->err_code; connectionConvertBdaddr(&message->bd_addr, &cfm->bd_addr); message->size_attributes = cfm->size_attr_list; if (cfm->size_attr_list) { uint8 *attribute_list = VmGetPointerFromHandle(cfm->attr_list); memcpy(message->attributes, attribute_list, cfm->size_attr_list); free(attribute_list); } else message->attributes[0] = 0; MessageSend(state->sdpSearchLock, CL_SDP_ATTRIBUTE_SEARCH_CFM, message); /* Reset the resource lock */ state->sdpSearchLock = 0; } else { if (cfm->size_attr_list) { uint8 *attribute_list = VmGetPointerFromHandle(cfm->attr_list); free(attribute_list); } } }
/************************************************************************* NAME handleAttPrepareWriteCfmPrepare DESCRIPTION This function handles Bluestack response for ATT_PREPARE_WRITE_REQ during Prepare Write. RETURNS */ static void handleAttPrepareWriteCfmPrepare(cid_map_t *conn, ATT_PREPARE_WRITE_CFM_T *m) { gatt_write_reliable_t *data = &conn->data.req.write_reliable; STASH(conn, stash, RELIABLE_WRITE_PREPARE); /* convert the data pointer */ m->value = VmGetPointerFromHandle(m->value); if (m->result == ATT_RESULT_SUCCESS && /* check that the value matches */ (m->offset != data->offs || m->size_value != data->size_value || memcmp8(m->value, data->value, m->size_value))) { stash->status = gatt_status_value_mismatch; } else { stash->status = gatt_message_status(m->result); } /* send the response */ gatt_message_send(conn, GATT_RELIABLE_WRITE_PREPARE_CFM); gattSetConnState(conn, NULL, gatt_ms_none); /* free the stored data */ free(data->value); /* free the data pointer */ free(m->value); }
/**************************************************************************** NAME connectionHandleInquiryResultWithRssi DESCRIPTION This function handles inquiry results with RSSI as they arrive from BlueStack. RETURNS void */ void connectionHandleInquiryResultWithRssi(const connectionInquiryState *state, const DM_HCI_INQUIRY_RESULT_WITH_RSSI_IND_T*inq_result) { uint16 array; uint16 index; uint16 results_left = inq_result->num_responses; /* Iterate through the array of inquiry result ptrs */ for (array = 0; array < (inq_result->num_responses+HCI_MAX_INQ_RESULT_PER_PTR-1)/HCI_MAX_INQ_RESULT_PER_PTR; array++) { uint16 res_this_block = HCI_MAX_INQ_RESULT_PER_PTR; HCI_INQ_RESULT_WITH_RSSI_T *resarray = (HCI_INQ_RESULT_WITH_RSSI_T *) VmGetPointerFromHandle(inq_result->result[array]); if (results_left < res_this_block) res_this_block = results_left; for (index = 0; index< res_this_block; index++) { /* Send an inquiry result message to the client */ bdaddr addr; BdaddrConvertBluestackToVm(&addr, &((resarray+index)->bd_addr)); inquirySendResult(state->inquiryLock, inquiry_status_result, &addr, (resarray+index)->dev_class, (resarray+index)->clock_offset, (resarray+index)->page_scan_rep_mode, 0, (int16)(resarray+index)->rssi, 0, NULL); } /* Free the data */ free(resarray); } }
/**************************************************************************** NAME connectionHandleRemoteNameComplete DESCRIPTION Remote name result RETURNS void */ void connectionHandleRemoteNameComplete(connectionInquiryState *state, const DM_HCI_REMOTE_NAME_CFM_T* prim) { bdaddr addr; BdaddrConvertBluestackToVm(&addr, &prim->bd_addr); /* Providing the read was a success and we have a vaid name */ if (!prim->status && prim->name_part[0]) { uint16 length; uint8 i; /* Only handle the first segment */ char* name = VmGetPointerFromHandle(prim->name_part[0]); /* Find the length of the string in the first segment, limiting to MAX_NAME_LENGTH bytes */ for(length = 0; length < MAX_NAME_LENGTH; length++) { if (name[length] == '\0') break; } name[length] = '\0'; /* Free any other segments */ for(i = 1;i < HCI_LOCAL_NAME_BYTE_PACKET_PTRS;i++) { if (prim->name_part[i] != NULL) free(VmGetPointerFromHandle(prim->name_part[i])); } /* Remote name read, send Client message to notify them of the result */ remoteNameComplete(state->nameLock, &addr, rnr_success, name, length); } else { /* Read failed, send Client message to notify them of the result */ remoteNameComplete(state->nameLock, &addr, prim->status? rnr_error: rnr_completed, NULL, 0); } /* Reset resource lock */ state->nameLock = 0; }
/************************************************************************* NAME handleAttPrepareWriteCfmLong DESCRIPTION This function handles Bluestack response for ATT_PREPARE_WRITE_REQ during Long Characteristic Write. RETURNS */ static void handleAttPrepareWriteCfmLong(cid_map_t *conn, ATT_PREPARE_WRITE_CFM_T *m) { gatt_write_reliable_t *data = &conn->data.req.write_reliable; if (m->result == ATT_RESULT_SUCCESS) { data->offs += MAX_PREPARE_SIZE(conn->mtu); /* send next packet */ if (data->offs < data->size_value) { gatt_prepare_write_req(m->cid, data->handle, data->offs, data->size_value - data->offs, data->value + data->offs); } /* execute write */ else { gatt_execute_write_req(m->cid, ATT_EXECUTE_WRITE); } } /* cancel ongoing write queue */ else if (data->offs) { STASH(conn, stash, WRITE_LONG_CHARACTERISTIC_VALUE); stash->status = gatt_message_status(m->result); gatt_execute_write_req(m->cid, ATT_EXECUTE_CANCEL); } /* send failure */ else { STASH(conn, stash, WRITE_LONG_CHARACTERISTIC_VALUE); stash->status = gatt_message_status(m->result); gatt_message_send(conn, GATT_WRITE_LONG_CHARACTERISTIC_VALUE_CFM); gattSetConnState(conn, NULL, gatt_ms_none); free(data->value); } /* free the data */ free(VmGetPointerFromHandle(m->value)); }
/**************************************************************************** NAME connectionHandleSdpServiceSearchCfm DESCRIPTION SDP service search results received so handle them here. RETURNS void */ void connectionHandleSdpServiceSearchCfm(connectionSdpState *state, const SDC_EX_SERVICE_SEARCH_CFM_T *cfm) { if (state->sdpSearchLock == connectionGetCmTask()) { /* Internal CFM means we're SDP Pinging */ uint8* sdp_ptr = (uint8 *) SdpPingServiceRequest; /* Create next request */ MAKE_CL_MESSAGE(CL_INTERNAL_SDP_SERVICE_SEARCH_REQ); message->theAppTask = connectionGetCmTask(); message->bd_addr = state->sdpServerAddr; message->max_responses = 1; message->length = sizeof(SdpPingServiceRequest); message->search_pattern = (uint8*) PanicUnlessMalloc(sizeof(SdpPingServiceRequest)); memcpy(message->search_pattern, sdp_ptr, sizeof(SdpPingServiceRequest)); /* Send after 2 seconds to avoid thrashing the radio */ MessageSendLater(connectionGetCmTask(), CL_INTERNAL_SDP_SERVICE_SEARCH_REQ, message, D_SEC(2)); /* Tidy up memory in cfm */ if (cfm->size_rec_list) { uint8 *record_list = VmGetPointerFromHandle(cfm->rec_list); free(record_list); } /* Free the lock so the next request can be handled */ state->sdpSearchLock = 0; } else if (state->sdpSearchLock) { /* Send a cfm to the client task */ MAKE_CL_MESSAGE_WITH_LEN(CL_SDP_SERVICE_SEARCH_CFM, cfm->size_rec_list); message->status = connectionConvertSdpSearchStatus(cfm->response); message->num_records = cfm->num_recs_ret; message->error_code = cfm->err_code; connectionConvertBdaddr(&message->bd_addr, &cfm->bd_addr); message->size_records = cfm->size_rec_list; if (cfm->size_rec_list) { uint8 *record_list = VmGetPointerFromHandle(cfm->rec_list); memcpy(message->records, record_list, cfm->size_rec_list); free(record_list); } else message->records[0] = 0; MessageSend(state->sdpSearchLock, CL_SDP_SERVICE_SEARCH_CFM, message); /* Reset the resource lock */ state->sdpSearchLock = 0; } else { if (cfm->size_rec_list) { uint8 *record_list = VmGetPointerFromHandle(cfm->rec_list); free(record_list); } } }
/************************************************************************* 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 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; }