gboolean gatt_parse_record(const sdp_record_t *rec, uuid_t *prim_uuid, uint16_t *psm, uint16_t *start, uint16_t *end) { sdp_list_t *list; uuid_t uuid; gboolean ret; if (sdp_get_service_classes(rec, &list) < 0) return FALSE; memcpy(&uuid, list->data, sizeof(uuid)); sdp_list_free(list, free); if (sdp_get_access_protos(rec, &list) < 0) return FALSE; ret = parse_proto_params(list, psm, start, end); sdp_list_foreach(list, (sdp_list_func_t) sdp_list_free, NULL); sdp_list_free(list, NULL); /* FIXME: replace by bt_uuid_t after uuid_t/sdp code cleanup */ if (ret && prim_uuid) memcpy(prim_uuid, &uuid, sizeof(uuid_t)); return ret; }
static gboolean set_sdp_services_uuid(sdp_record_t *record, HdpRole role) { uuid_t svc_uuid_source, svc_uuid_sink; sdp_list_t *svc_list = NULL; sdp_uuid16_create(&svc_uuid_sink, HDP_SINK_SVCLASS_ID); sdp_uuid16_create(&svc_uuid_source, HDP_SOURCE_SVCLASS_ID); sdp_get_service_classes(record, &svc_list); if (role == HDP_SOURCE) { if (!sdp_list_find(svc_list, &svc_uuid_source, sdp_uuid_cmp)) svc_list = sdp_list_append(svc_list, &svc_uuid_source); } else if (role == HDP_SINK) { if (!sdp_list_find(svc_list, &svc_uuid_sink, sdp_uuid_cmp)) svc_list = sdp_list_append(svc_list, &svc_uuid_sink); } if (sdp_set_service_classes(record, svc_list) < 0) { sdp_list_free(svc_list, NULL); return FALSE; } sdp_list_free(svc_list, NULL); return TRUE; }
static int set_sdp_services_uuid(sdp_record_t *rec, uint8_t role) { uuid_t source, sink; sdp_list_t *list = NULL; sdp_uuid16_create(&sink, HDP_SINK_SVCLASS_ID); sdp_uuid16_create(&source, HDP_SOURCE_SVCLASS_ID); sdp_get_service_classes(rec, &list); switch (role) { case HAL_HEALTH_MDEP_ROLE_SOURCE: if (!sdp_list_find(list, &source, sdp_uuid_cmp)) list = sdp_list_append(list, &source); break; case HAL_HEALTH_MDEP_ROLE_SINK: if (!sdp_list_find(list, &sink, sdp_uuid_cmp)) list = sdp_list_append(list, &sink); break; } if (sdp_set_service_classes(rec, list) < 0) { sdp_list_free(list, NULL); return -1; } sdp_list_free(list, NULL); return 0; }
sdp_record_t *find_record_in_list(sdp_list_t *recs, const char *uuid) { sdp_list_t *seq; for (seq = recs; seq; seq = seq->next) { sdp_record_t *rec = (sdp_record_t *) seq->data; sdp_list_t *svcclass = NULL; char *uuid_str; if (sdp_get_service_classes(rec, &svcclass) < 0) continue; /* Extract the uuid */ uuid_str = bt_uuid2string(svcclass->data); if (!uuid_str) { sdp_list_free(svcclass, free); continue; } if (!strcasecmp(uuid_str, uuid)) { sdp_list_free(svcclass, free); free(uuid_str); return rec; } sdp_list_free(svcclass, free); free(uuid_str); } return NULL; }
/* * utility function to perform an SDP search on a connected session. Builds * and returns a python list of dictionaries. Each dictionary represents a * service record match */ static PyObject * do_search( sdp_session_t *sess, uuid_t *uuid ) { sdp_list_t *response_list = NULL, *attrid_list, *search_list, *r; uint32_t range = 0x0000ffff; char buf[1024] = { 0 }; int err = 0; PyObject *result = 0; PyObject *rtn_list = PyList_New(0); if( ! rtn_list ) return 0; search_list = sdp_list_append( 0, uuid ); attrid_list = sdp_list_append( 0, &range ); // perform the search Py_BEGIN_ALLOW_THREADS err = sdp_service_search_attr_req( sess, search_list, \ SDP_ATTR_REQ_RANGE, attrid_list, &response_list); Py_END_ALLOW_THREADS if( err ) { PyErr_SetFromErrno( bluetooth_error ); result = 0; goto cleanup; } // parse the results (ewww....) // go through each of the service records for (r = response_list; r; r = r->next ) { PyObject *dict = PyDict_New(); sdp_record_t *rec = (sdp_record_t*) r->data; sdp_list_t *proto_list = NULL, *svc_class_list = NULL, *profile_list = NULL; PyObject *py_class_list = NULL, *py_profile_list = NULL; uuid_t service_id = { 0 }; if( ! dict ) return 0; // initialize service class list py_class_list = PyList_New(0); if( ! py_class_list ) return 0; dict_set_str_pyobj( dict, "service-classes", py_class_list ); Py_DECREF( py_class_list ); // initialize profile list py_profile_list = PyList_New(0); if( ! py_profile_list ) return 0; dict_set_str_pyobj( dict, "profiles", py_profile_list ); Py_DECREF( py_profile_list ); // set service name if( ! sdp_get_service_name( rec, buf, sizeof(buf) ) ) { dict_set_strings( dict, "name", buf ); memset(buf, 0, sizeof( buf ) ); } else { dict_set_str_pyobj( dict, "name", Py_None ); } // set service description if( ! sdp_get_service_desc( rec, buf, sizeof(buf) ) ) { dict_set_strings( dict, "description", buf ); memset(buf, 0, sizeof( buf ) ); } else { dict_set_str_pyobj( dict, "description", Py_None ); } // set service provider name if( ! sdp_get_provider_name( rec, buf, sizeof(buf) ) ) { dict_set_strings( dict, "provider", buf ); memset(buf, 0, sizeof( buf ) ); } else { dict_set_str_pyobj( dict, "provider", Py_None ); } // set service id if( ! sdp_get_service_id( rec, &service_id ) ) { uuid2str( &service_id, buf ); dict_set_strings( dict, "service-id", buf ); memset(buf, 0, sizeof( buf ) ); } else { dict_set_str_pyobj( dict, "service-id", Py_None ); } // get a list of the protocol sequences if( sdp_get_access_protos( rec, &proto_list ) == 0 ) { sdp_list_t *p = proto_list; int port; if( ( port = sdp_get_proto_port( p, RFCOMM_UUID ) ) != 0 ) { dict_set_strings( dict, "protocol", "RFCOMM" ); dict_set_str_long( dict, "port", port ); } else if ( (port = sdp_get_proto_port( p, L2CAP_UUID ) ) != 0 ) { dict_set_strings( dict, "protocol", "L2CAP" ); dict_set_str_long( dict, "port", port ); } else { dict_set_strings( dict, "protocol", "UNKNOWN" ); dict_set_str_pyobj( dict, "port", Py_None ); } // sdp_get_access_protos allocates data on the heap for the // protocol list, so we need to free the results... for( ; p ; p = p->next ) { sdp_list_free( (sdp_list_t*)p->data, 0 ); } sdp_list_free( proto_list, 0 ); } else { dict_set_str_pyobj( dict, "protocol", Py_None ); dict_set_str_pyobj( dict, "port", Py_None ); } // get a list of the service classes if( sdp_get_service_classes( rec, &svc_class_list ) == 0 ) { sdp_list_t *iter; for( iter = svc_class_list; iter != NULL; iter = iter->next ) { PyObject *pystr; char uuid_str[40] = { 0 }; uuid2str( (uuid_t*)iter->data, uuid_str ); pystr = PyString_FromString( uuid_str ); PyList_Append( py_class_list, pystr ); Py_DECREF( pystr ); } sdp_list_free( svc_class_list, free ); } // get a list of the profiles if( sdp_get_profile_descs( rec, &profile_list ) == 0 ) { sdp_list_t *iter; for( iter = profile_list; iter != NULL; iter = iter->next ) { PyObject *tuple, *py_uuid, *py_version; sdp_profile_desc_t *desc = (sdp_profile_desc_t*)iter->data; char uuid_str[40] = { 0 }; uuid2str( &desc->uuid, uuid_str ); py_uuid = PyString_FromString( uuid_str ); py_version = PyInt_FromLong( desc->version ); tuple = PyTuple_New( 2 ); PyList_Append( py_profile_list, tuple ); Py_DECREF( tuple ); PyTuple_SetItem( tuple, 0, py_uuid ); PyTuple_SetItem( tuple, 1, py_version ); // Py_DECREF( py_uuid ); // Py_DECREF( py_version ); } sdp_list_free( profile_list, free ); } PyList_Append( rtn_list, dict ); Py_DECREF( dict ); sdp_record_free( rec ); } result = rtn_list; cleanup: sdp_list_free( response_list, 0 ); sdp_list_free( search_list, 0 ); sdp_list_free( attrid_list, 0 ); return result; }
static DBusMessage *request_authorization(DBusConnection *conn, DBusMessage *msg, void *data) { struct record_data *user_record; struct service_adapter *serv_adapter = data; sdp_record_t *record; sdp_list_t *services; const char *sender; dbus_uint32_t handle; const char *address; struct pending_auth *auth; char uuid_str[MAX_LEN_UUID_STR]; uuid_t *uuid, *uuid128; bdaddr_t src; if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address, DBUS_TYPE_UINT32, &handle, DBUS_TYPE_INVALID) == FALSE) return NULL; sender = dbus_message_get_sender(msg); if (find_pending_by_sender(serv_adapter, sender)) return btd_error_does_not_exist(msg); user_record = find_record(serv_adapter, handle, sender); if (!user_record) { user_record = find_record(serv_adapter_any, handle, sender); if (!user_record) return btd_error_not_authorized(msg); } record = sdp_record_find(user_record->handle); if (record == NULL) return btd_error_not_authorized(msg); if (sdp_get_service_classes(record, &services) < 0) { sdp_record_free(record); return btd_error_not_authorized(msg); } if (services == NULL) return btd_error_not_authorized(msg); uuid = services->data; uuid128 = sdp_uuid_to_uuid128(uuid); sdp_list_free(services, bt_free); if (sdp_uuid2strn(uuid128, uuid_str, MAX_LEN_UUID_STR) < 0) { bt_free(uuid128); return btd_error_not_authorized(msg); } bt_free(uuid128); auth = g_new0(struct pending_auth, 1); auth->msg = dbus_message_ref(msg); auth->conn = dbus_connection_ref(connection); auth->sender = user_record->sender; memcpy(auth->uuid, uuid_str, MAX_LEN_UUID_STR); str2ba(address, &auth->dst); serv_adapter->pending_list = g_slist_append(serv_adapter->pending_list, auth); auth = next_pending(serv_adapter); if (auth == NULL) return btd_error_does_not_exist(msg); if (serv_adapter->adapter) adapter_get_address(serv_adapter->adapter, &src); else bacpy(&src, BDADDR_ANY); if (btd_request_authorization(&src, &auth->dst, auth->uuid, auth_cb, serv_adapter) < 0) { serv_adapter->pending_list = g_slist_remove(serv_adapter->pending_list, auth); g_free(auth); return btd_error_not_authorized(msg); } return NULL; }
static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data) { struct audio_device *dev = user_data; struct gateway *gw = dev->gateway; int ch; sdp_list_t *protos, *classes; uuid_t uuid; GIOChannel *io; GError *gerr = NULL; if (err < 0) { error("Unable to get service record: %s (%d)", strerror(-err), -err); goto fail; } if (!recs || !recs->data) { error("No records found"); err = -EIO; goto fail; } if (sdp_get_service_classes(recs->data, &classes) < 0) { error("Unable to get service classes from record"); err = -EINVAL; goto fail; } if (sdp_get_access_protos(recs->data, &protos) < 0) { error("Unable to get access protocols from record"); err = -ENODATA; goto fail; } gw->version = get_remote_profile_version(recs->data); if (gw->version == 0) { error("Unable to get profile version from record"); err = -EINVAL; goto fail; } memcpy(&uuid, classes->data, sizeof(uuid)); sdp_list_free(classes, free); if (!sdp_uuid128_to_uuid(&uuid) || uuid.type != SDP_UUID16 || uuid.value.uuid16 != HANDSFREE_AGW_SVCLASS_ID) { sdp_list_free(protos, NULL); error("Invalid service record or not HFP"); err = -EIO; goto fail; } ch = sdp_get_proto_port(protos, RFCOMM_UUID); sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL); sdp_list_free(protos, NULL); if (ch <= 0) { error("Unable to extract RFCOMM channel from service record"); err = -EIO; goto fail; } io = bt_io_connect(rfcomm_connect_cb, dev, NULL, &gerr, BT_IO_OPT_SOURCE_BDADDR, &dev->src, BT_IO_OPT_DEST_BDADDR, &dev->dst, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, BT_IO_OPT_CHANNEL, ch, BT_IO_OPT_INVALID); if (!io) { error("Unable to connect: %s", gerr->message); goto fail; } g_io_channel_unref(io); return; fail: if (gw->msg) { DBusMessage *reply = btd_error_failed(gw->msg, gerr ? gerr->message : strerror(-err)); g_dbus_send_message(btd_get_dbus_connection(), reply); } gateway_close(dev); if (gerr) g_error_free(gerr); }