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; }
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 gboolean register_features(struct hdp_application *app, sdp_list_t **sup_features) { sdp_list_t *hdp_feature; hdp_feature = app_to_sdplist(app); if (hdp_feature == NULL) goto fail; if (*sup_features == NULL) { *sup_features = sdp_list_append(NULL, hdp_feature); if (*sup_features == NULL) goto fail; } else if (sdp_list_append(*sup_features, hdp_feature) == NULL) { goto fail; } return TRUE; fail: if (hdp_feature != NULL) sdp_list_free(hdp_feature, (sdp_free_func_t)sdp_data_free); if (*sup_features != NULL) sdp_list_free(*sup_features, free_hdp_list); return FALSE; }
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; }
/* * Reset the service repository by deleting its contents */ void sdp_svcdb_reset(void) { sdp_list_free(service_db, (sdp_free_func_t) sdp_record_free); service_db = NULL; sdp_list_free(access_db, access_free); access_db = NULL; }
void register_device_id(const uint16_t vendor, const uint16_t product, const uint16_t version) { const uint16_t spec = 0x0102, source = 0x0002; const uint8_t primary = 1; sdp_list_t *class_list, *group_list, *profile_list; uuid_t class_uuid, group_uuid; sdp_data_t *sdp_data, *primary_data, *source_data; sdp_data_t *spec_data, *vendor_data, *product_data, *version_data; sdp_profile_desc_t profile; sdp_record_t *record = sdp_record_alloc(); info("Adding device id record for %04x:%04x", vendor, product); btd_manager_set_did(vendor, product, version); record->handle = sdp_next_handle(); sdp_record_add(BDADDR_ANY, record); sdp_data = sdp_data_alloc(SDP_UINT32, &record->handle); sdp_attr_add(record, SDP_ATTR_RECORD_HANDLE, sdp_data); sdp_uuid16_create(&class_uuid, PNP_INFO_SVCLASS_ID); class_list = sdp_list_append(0, &class_uuid); sdp_set_service_classes(record, class_list); sdp_list_free(class_list, NULL); sdp_uuid16_create(&group_uuid, PUBLIC_BROWSE_GROUP); group_list = sdp_list_append(NULL, &group_uuid); sdp_set_browse_groups(record, group_list); sdp_list_free(group_list, NULL); sdp_uuid16_create(&profile.uuid, PNP_INFO_PROFILE_ID); profile.version = spec; profile_list = sdp_list_append(NULL, &profile); sdp_set_profile_descs(record, profile_list); sdp_list_free(profile_list, NULL); spec_data = sdp_data_alloc(SDP_UINT16, &spec); sdp_attr_add(record, 0x0200, spec_data); vendor_data = sdp_data_alloc(SDP_UINT16, &vendor); sdp_attr_add(record, 0x0201, vendor_data); product_data = sdp_data_alloc(SDP_UINT16, &product); sdp_attr_add(record, 0x0202, product_data); version_data = sdp_data_alloc(SDP_UINT16, &version); sdp_attr_add(record, 0x0203, version_data); primary_data = sdp_data_alloc(SDP_BOOL, &primary); sdp_attr_add(record, 0x0204, primary_data); source_data = sdp_data_alloc(SDP_UINT16, &source); sdp_attr_add(record, 0x0205, source_data); update_db_timestamp(); }
int main(int argc, char const *argv[]) { uint32_t svc_uuid_int[] = {0, 0, 0, 0xABCD}; int status; bdaddr_t target, source; uuid_t svc_uuid; sdp_list_t *response_list, *search_list, *attrid_list; sdp_session_t *session = 0; uint32_t range = 0x0000ffff; uint8_t port = 0; //connect to the SDP server running on the remote machine str2ba(dest, &target); str2ba(src, &source); session = sdp_connect(&source, &target, 0); if (session == NULL) { perror("sdp_connect"); exit(1); } sdp_uuid128_create(&svc_uuid, &svc_uuid_int); search_list = sdp_list_append(0, &svc_uuid); attrid_list = sdp_list_append(0, &range); //get a list of service records that have UUID 0xabcd response_list = NULL; status = sdp_service_search_attr_req(session, search_list, SDP_ATTR_REQ_RANGE, attrid_list, &response_list); if (status == 0) { sdp_list_t *proto_list = NULL; sdp_list_t *r = response_list; //go through each of the service records for (; r; r = r->next) { sdp_record_t *rec = (sdp_record_t *)r->data; //get a list of the protocol sequences if (sdp_get_access_protos(rec, &proto_list) == 0) { // get the RFCOMM port number port = sdp_get_proto_port(proto_list, RFCOMM_UUID); sdp_list_free(proto_list, 0); } sdp_record_free(rec); } } sdp_list_free(response_list, 0); sdp_list_free(search_list, 0); sdp_list_free(attrid_list, 0); sdp_close(session); if (port != 0) { printf("found service running on RFCOMM Port %d\n", port); } return 0; }
static gboolean connect_watch(GIOChannel *chan, GIOCondition cond, gpointer user_data) { struct search_context *ctxt = user_data; sdp_list_t *search, *attrids; uint32_t range = 0x0000ffff; socklen_t len; int sk, err = 0; sk = g_io_channel_unix_get_fd(chan); ctxt->io_id = 0; len = sizeof(err); if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &err, &len) < 0) { err = errno; goto failed; } if (err != 0) goto failed; if (sdp_set_notify(ctxt->session, search_completed_cb, ctxt) < 0) { err = EIO; goto failed; } search = sdp_list_append(NULL, &ctxt->uuid); attrids = sdp_list_append(NULL, &range); if (sdp_service_search_attr_async(ctxt->session, search, SDP_ATTR_REQ_RANGE, attrids) < 0) { sdp_list_free(attrids, NULL); sdp_list_free(search, NULL); err = EIO; goto failed; } sdp_list_free(attrids, NULL); sdp_list_free(search, NULL); /* Set callback responsible for update the internal SDP transaction */ ctxt->io_id = g_io_add_watch(chan, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, search_process_cb, ctxt); return FALSE; failed: sdp_close(ctxt->session); ctxt->session = NULL; if (ctxt->cb) ctxt->cb(NULL, -err, ctxt->user_data); search_context_cleanup(ctxt); return FALSE; }
static gboolean service_callback(GIOChannel *io, GIOCondition cond, gpointer user_data) { struct bluetooth_session *session = user_data; sdp_list_t *search, *attrid; uint32_t range = 0x0000ffff; GError *gerr = NULL; uuid_t uuid; if (cond & G_IO_NVAL) return FALSE; if (cond & G_IO_ERR) goto failed; if (sdp_set_notify(session->sdp, search_callback, session) < 0) goto failed; if (bt_string2uuid(&uuid, session->service) < 0) goto failed; sdp_uuid128_to_uuid(&uuid); search = sdp_list_append(NULL, &uuid); attrid = sdp_list_append(NULL, &range); if (sdp_service_search_attr_async(session->sdp, search, SDP_ATTR_REQ_RANGE, attrid) < 0) { sdp_list_free(attrid, NULL); sdp_list_free(search, NULL); goto failed; } sdp_list_free(attrid, NULL); sdp_list_free(search, NULL); g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, process_callback, session); return FALSE; failed: g_io_channel_shutdown(session->io, TRUE, NULL); g_io_channel_unref(session->io); session->io = NULL; g_set_error(&gerr, OBC_BT_ERROR, -EIO, "Unable to find service record"); if (session->func) session->func(session->io, gerr, session->user_data); g_clear_error(&gerr); session_destroy(session); return FALSE; }
static int detect_channel(bdaddr_t * bdaddr) { uuid_t group; bdaddr_t interface; sdp_list_t *attrid, *search, *seq, *next; uint32_t range = 0x0000ffff; sdp_session_t *sess; int channel = 2; int searchresult; bacpy(&interface, BDADDR_ANY); sdp_uuid16_create(&group, 0x1108); sess = sdp_connect(&interface, bdaddr, SDP_RETRY_IF_BUSY); if (!sess) { fprintf(stderr, "Failed to connect to SDP server: %s\nAssuming channel %d\n", strerror(errno), channel); return channel; } attrid = sdp_list_append(0, &range); search = sdp_list_append(0, &group); searchresult = sdp_service_search_attr_req(sess, search, SDP_ATTR_REQ_RANGE, attrid, &seq); sdp_list_free(attrid, 0); sdp_list_free(search, 0); if (searchresult) { fprintf(stderr, "Service Search failed: %s\nAssuming channel %d\n", strerror(errno), channel); sdp_close(sess); return channel; } for (; seq; seq = next) { sdp_record_t *rec = (sdp_record_t *) seq->data; sdp_list_t *list = 0; if (sdp_get_access_protos(rec, &list) == 0) { channel = sdp_get_proto_port(list, RFCOMM_UUID); } next = seq->next; free(seq); sdp_record_free(rec); } sdp_close(sess); return channel; }
static sdp_record_t *create_mas_record(uint8_t chan, const char *svc_name) { sdp_list_t *seq; sdp_profile_desc_t profile[1]; uint8_t minst = DEFAULT_MAS_INSTANCE; uint8_t mtype = DEFAULT_MAS_MSG_TYPE; sdp_record_t *record; uuid_t uuid; sdp_uuid16_create(&uuid, MAP_MSE_SVCLASS_ID); record = create_rfcomm_record(chan, &uuid, svc_name, true); if (!record) return NULL; sdp_uuid16_create(&profile[0].uuid, MAP_PROFILE_ID); profile[0].version = 0x0101; seq = sdp_list_append(NULL, profile); sdp_set_profile_descs(record, seq); sdp_attr_add_new(record, SDP_ATTR_MAS_INSTANCE_ID, SDP_UINT8, &minst); sdp_attr_add_new(record, SDP_ATTR_SUPPORTED_MESSAGE_TYPES, SDP_UINT8, &mtype); sdp_list_free(seq, NULL); return record; }
static sdp_record_t *create_pbap_record(uint8_t chan, const char *svc_name) { sdp_list_t *seq; sdp_profile_desc_t profile[1]; uint8_t formats = 0x01; sdp_record_t *record; uuid_t uuid; sdp_uuid16_create(&uuid, PBAP_PSE_SVCLASS_ID); record = create_rfcomm_record(chan, &uuid, svc_name, true); if (!record) return NULL; sdp_uuid16_create(&profile[0].uuid, PBAP_PROFILE_ID); profile[0].version = 0x0101; seq = sdp_list_append(NULL, profile); sdp_set_profile_descs(record, seq); sdp_attr_add_new(record, SDP_ATTR_SUPPORTED_REPOSITORIES, SDP_UINT8, &formats); sdp_list_free(seq, NULL); return record; }
static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data) { struct serial_port *port = user_data; struct serial_device *device = port->device; sdp_record_t *record = NULL; sdp_list_t *protos; DBusMessage *reply; GError *gerr = NULL; if (!port->listener_id) { reply = NULL; goto failed; } if (err < 0) { error("Unable to get service record: %s (%d)", strerror(-err), -err); reply = failed(port->msg, strerror(-err)); goto failed; } if (!recs || !recs->data) { error("No record found"); reply = failed(port->msg, "No record found"); goto failed; } record = recs->data; if (sdp_get_access_protos(record, &protos) < 0) { error("Unable to get access protos from port record"); reply = failed(port->msg, "Invalid channel"); goto failed; } port->channel = sdp_get_proto_port(protos, RFCOMM_UUID); sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL); sdp_list_free(protos, NULL); port->io = bt_io_connect(BT_IO_RFCOMM, rfcomm_connect_cb, port, NULL, &gerr, BT_IO_OPT_SOURCE_BDADDR, &device->src, BT_IO_OPT_DEST_BDADDR, &device->dst, BT_IO_OPT_CHANNEL, port->channel, BT_IO_OPT_INVALID); if (!port->io) { error("%s", gerr->message); reply = failed(port->msg, gerr->message); g_error_free(gerr); goto failed; } return; failed: g_dbus_remove_watch(device->conn, port->listener_id); port->listener_id = 0; g_dbus_send_message(device->conn, reply); }
static sdp_record_t *create_opp_record(uint8_t chan, const char *svc_name) { uint8_t formats[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xff }; uint8_t dtd = SDP_UINT8; uuid_t uuid; sdp_list_t *seq; sdp_profile_desc_t profile[1]; void *dtds[sizeof(formats)], *values[sizeof(formats)]; sdp_data_t *formats_list; sdp_record_t *record; size_t i; sdp_uuid16_create(&uuid, OBEX_OBJPUSH_SVCLASS_ID); record = create_rfcomm_record(chan, &uuid, svc_name, true); if (!record) return NULL; sdp_uuid16_create(&profile[0].uuid, OBEX_OBJPUSH_PROFILE_ID); profile[0].version = 0x0100; seq = sdp_list_append(NULL, profile); sdp_set_profile_descs(record, seq); for (i = 0; i < sizeof(formats); i++) { dtds[i] = &dtd; values[i] = &formats[i]; } formats_list = sdp_seq_alloc(dtds, values, sizeof(formats)); sdp_attr_add(record, SDP_ATTR_SUPPORTED_FORMATS_LIST, formats_list); sdp_list_free(seq, NULL); return record; }
static int serial_probe(struct btd_device *device, const char *uuid) { struct btd_adapter *adapter = device_get_adapter(device); const gchar *path = device_get_path(device); sdp_list_t *protos; int ch; bdaddr_t src, dst; const sdp_record_t *rec; DBG("path %s: %s", path, uuid); rec = btd_device_get_record(device, uuid); if (!rec) return -EINVAL; if (sdp_get_access_protos(rec, &protos) < 0) return -EINVAL; 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 < 1 || ch > 30) { error("Channel out of range: %d", ch); return -EINVAL; } adapter_get_address(adapter, &src); device_get_address(device, &dst); return port_register(connection, path, &src, &dst, uuid, ch); }
static void records_cb(sdp_list_t *recs, int err, gpointer data) { struct pending_reply *pr = data; int len; sdp_data_t *d; sdp_record_t *rec = NULL; char name[MAX_NAME_SIZE], *desc = NULL; if (err < 0) { error_connection_attempt_failed(pr->conn, pr->msg, -err); goto fail; } if (!recs || !recs->data) { error_not_supported(pr->conn, pr->msg); error("Invalid PAN service record"); goto fail; } rec = recs->data; /* Concat remote name and service name */ memset(name, 0, MAX_NAME_SIZE); if (read_remote_name(&pr->src, &pr->dst, name, MAX_NAME_SIZE) < 0) len = 0; else len = strlen(name); d = sdp_data_get(rec, SDP_ATTR_SVCNAME_PRIMARY); if (d) { snprintf(name + len, MAX_NAME_SIZE - len, len ? " (%.*s)" : "%.*s", d->unitSize, d->val.str); } /* Extract service description from record */ d = sdp_data_get(rec, SDP_ATTR_SVCDESC_PRIMARY); if (d) { desc = g_new0(char, d->unitSize); snprintf(desc, d->unitSize, "%.*s", d->unitSize, d->val.str); } sdp_list_free(recs, (sdp_free_func_t) sdp_record_free); if (connection_register(pr->path, &pr->src, &pr->dst, pr->id, name, desc) < 0) { error_failed(pr->conn, pr->msg, "D-Bus path registration failed"); goto fail; } connection_store(pr->path, FALSE); connection_paths = g_slist_append(connection_paths, g_strdup(pr->path)); create_path(pr->conn, pr->msg, pr->path, "ConnectionCreated"); fail: g_free(desc); pending_reply_free(pr); }
static void search_cb(sdp_list_t *recs, int err, gpointer data) { struct avrcp_device *dev = data; sdp_list_t *list; DBG(""); if (err < 0) { error("Unable to get AV_REMOTE_SVCLASS_ID SDP record: %s", strerror(-err)); goto fail; } if (!recs || !recs->data) { error("No AVRCP records found"); goto fail; } for (list = recs; list; list = list->next) { sdp_record_t *rec = list->data; sdp_list_t *l; sdp_profile_desc_t *desc; int features; if (sdp_get_profile_descs(rec, &l) < 0) continue; desc = l->data; dev->version = desc->version; if (sdp_get_int_attr(rec, SDP_ATTR_SUPPORTED_FEATURES, &features) == 0) dev->features = features; sdp_list_free(l, free); break; } if (dev->io) { GError *gerr = NULL; if (!bt_io_accept(dev->io, connect_cb, dev, NULL, &gerr)) { error("bt_io_accept: %s", gerr->message); g_error_free(gerr); goto fail; } return; } if (!avrcp_device_connect(dev, connect_cb)) { error("Unable to connect to AVRCP"); goto fail; } return; fail: avrcp_device_remove(dev); }
static sdp_record_t *a2dp_record(void) { sdp_list_t *svclass_id, *pfseq, *apseq, *root; uuid_t root_uuid, l2cap_uuid, avdtp_uuid, a2dp_uuid; sdp_profile_desc_t profile[1]; sdp_list_t *aproto, *proto[2]; sdp_record_t *record; sdp_data_t *psm, *version, *features; uint16_t lp = AVDTP_UUID; uint16_t a2dp_ver = 0x0103, avdtp_ver = 0x0103, feat = 0x000f; record = sdp_record_alloc(); if (!record) return NULL; sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); root = sdp_list_append(NULL, &root_uuid); sdp_set_browse_groups(record, root); sdp_uuid16_create(&a2dp_uuid, AUDIO_SOURCE_SVCLASS_ID); svclass_id = sdp_list_append(NULL, &a2dp_uuid); sdp_set_service_classes(record, svclass_id); sdp_uuid16_create(&profile[0].uuid, ADVANCED_AUDIO_PROFILE_ID); profile[0].version = a2dp_ver; pfseq = sdp_list_append(NULL, &profile[0]); sdp_set_profile_descs(record, pfseq); sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); proto[0] = sdp_list_append(NULL, &l2cap_uuid); psm = sdp_data_alloc(SDP_UINT16, &lp); proto[0] = sdp_list_append(proto[0], psm); apseq = sdp_list_append(NULL, proto[0]); sdp_uuid16_create(&avdtp_uuid, AVDTP_UUID); proto[1] = sdp_list_append(NULL, &avdtp_uuid); version = sdp_data_alloc(SDP_UINT16, &avdtp_ver); proto[1] = sdp_list_append(proto[1], version); apseq = sdp_list_append(apseq, proto[1]); aproto = sdp_list_append(NULL, apseq); sdp_set_access_protos(record, aproto); features = sdp_data_alloc(SDP_UINT16, &feat); sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features); sdp_set_info_attr(record, "Audio Source", NULL, NULL); sdp_data_free(psm); sdp_data_free(version); sdp_list_free(proto[0], NULL); sdp_list_free(proto[1], NULL); sdp_list_free(apseq, NULL); sdp_list_free(pfseq, NULL); sdp_list_free(aproto, NULL); sdp_list_free(root, NULL); sdp_list_free(svclass_id, NULL); return record; }
/** * Lookup for HID service records. This function returns: * - SDP HID record handle, if there is already a HID SDP record * 0 if there is no HID SDP record * <0 if any error occur. In this case, the value returned is the errno. * */ int is_hid_sdp_record_registered() { int handle; uuid_t svc_uuid; int err; sdp_list_t *response_list = NULL, *search_list, *attrid_list; sdp_uuid16_create(&svc_uuid, HID_SVCLASS_ID); search_list = sdp_list_append(NULL, &svc_uuid); uint32_t range = 0x0000ffff; attrid_list = sdp_list_append(NULL, &range); err = sdp_service_search_attr_req(sdp_session, search_list, SDP_ATTR_REQ_RANGE, attrid_list, &response_list); sdp_list_free(search_list, NULL); sdp_list_free(attrid_list, NULL); if (err < 0) { return err; } if (response_list != NULL) { sdp_record_t *rec = (sdp_record_t *)response_list->data; int handle = rec->handle; sdp_list_free(response_list, NULL); return handle; } else { return 0; } /* * code below illustrates how to iterate through records. * sdp_list_t *r = response_list; for (; r; r = r->next) { sdp_record_t *rec = (sdp_record_t *)r->data; if (rec != NULL) { printf("rec: 0x%X\n", rec->handle); } sdp_record_free(rec); } */ }
static sdp_list_t *mdeps_to_sdp_features(struct mdep_cfg *mdep) { sdp_data_t *mdepid, *dtype = NULL, *role = NULL, *descr = NULL; sdp_list_t *f_list = NULL; DBG(""); mdepid = sdp_data_alloc(SDP_UINT8, &mdep->id); if (!mdepid) return NULL; dtype = sdp_data_alloc(SDP_UINT16, &mdep->data_type); if (!dtype) goto fail; role = sdp_data_alloc(SDP_UINT8, &mdep->role); if (!role) goto fail; if (mdep->descr) { descr = sdp_data_alloc(SDP_TEXT_STR8, mdep->descr); if (!descr) goto fail; } f_list = sdp_list_append(NULL, mdepid); if (!f_list) goto fail; if (!sdp_list_append(f_list, dtype)) goto fail; if (!sdp_list_append(f_list, role)) goto fail; if (descr && !sdp_list_append(f_list, descr)) goto fail; return f_list; fail: sdp_list_free(f_list, NULL); if (mdepid) sdp_data_free(mdepid); if (dtype) sdp_data_free(dtype); if (role) sdp_data_free(role); if (descr) sdp_data_free(descr); return NULL; }
static gboolean service_callback(GIOChannel *io, GIOCondition cond, gpointer user_data) { struct callback_data *callback = user_data; sdp_list_t *search, *attrid; uint32_t range = 0x0000ffff; GError *gerr = NULL; if (cond & (G_IO_NVAL | G_IO_ERR)) goto failed; if (sdp_set_notify(callback->sdp, search_callback, callback) < 0) goto failed; search = sdp_list_append(NULL, &callback->session->uuid); attrid = sdp_list_append(NULL, &range); if (sdp_service_search_attr_async(callback->sdp, search, SDP_ATTR_REQ_RANGE, attrid) < 0) { sdp_list_free(attrid, NULL); sdp_list_free(search, NULL); goto failed; } sdp_list_free(attrid, NULL); sdp_list_free(search, NULL); g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, process_callback, callback); return FALSE; failed: sdp_close(callback->sdp); g_set_error(&gerr, OBEX_IO_ERROR, -EIO, "Unable to find service record"); callback->func(callback->session, gerr, callback->data); g_clear_error(&gerr); session_unref(callback->session); g_free(callback); return FALSE; }
/* * Determine whether the given device supports Serial or Dial-Up Networking, * and if so what the RFCOMM channel number for the service is. */ static int find_service_channel(bdaddr_t *adapter, bdaddr_t *device, int only_gnapplet, uint16_t svclass_id) { sdp_session_t *sdp = NULL; sdp_list_t *search = NULL, *attrs = NULL, *recs = NULL, *tmp; uuid_t browse_uuid, service_id; uint32_t range = 0x0000ffff; int channel = -1; sdp = sdp_connect(adapter, device, SDP_RETRY_IF_BUSY); if (!sdp) goto end; sdp_uuid16_create(&browse_uuid, PUBLIC_BROWSE_GROUP); sdp_uuid16_create(&service_id, svclass_id); search = sdp_list_append(NULL, &browse_uuid); search = sdp_list_append(search, &service_id); attrs = sdp_list_append(NULL, &range); if (sdp_service_search_attr_req(sdp, search, SDP_ATTR_REQ_RANGE, attrs, &recs)) goto end; for (tmp = recs; tmp != NULL; tmp = tmp->next) { sdp_record_t *rec = tmp->data; /* * If this service is better than what we've * previously seen, try and get the channel number. */ channel = get_rfcomm_channel(rec, only_gnapplet); if (channel > 0) goto end; } end: sdp_list_free(recs, (sdp_free_func_t)sdp_record_free); sdp_list_free(search, NULL); sdp_list_free(attrs, NULL); sdp_close(sdp); return channel; }
static sdp_list_t *app_to_sdplist(struct hdp_application *app) { sdp_data_t *mdepid, *dtype = NULL, *role = NULL, *desc = NULL; sdp_list_t *f_list = NULL; mdepid = sdp_data_alloc(SDP_UINT8, &app->id); if (mdepid == NULL) return NULL; dtype = sdp_data_alloc(SDP_UINT16, &app->data_type); if (dtype == NULL) goto fail; role = sdp_data_alloc(SDP_UINT8, &app->role); if (role == NULL) goto fail; if (app->description != NULL) { desc = sdp_data_alloc(SDP_TEXT_STR8, app->description); if (desc == NULL) goto fail; } f_list = sdp_list_append(NULL, mdepid); if (f_list == NULL) goto fail; if (sdp_list_append(f_list, dtype) == NULL) goto fail; if (sdp_list_append(f_list, role) == NULL) goto fail; if (desc != NULL) if (sdp_list_append(f_list, desc) == NULL) goto fail; return f_list; fail: if (f_list != NULL) sdp_list_free(f_list, NULL); if (mdepid != NULL) sdp_data_free(mdepid); if (dtype != NULL) sdp_data_free(dtype); if (role != NULL) sdp_data_free(role); if (desc != NULL) sdp_data_free(desc); return NULL; }
static sdp_list_t *app_to_sdplist(struct mcap_application *app) { DBG(""); sdp_data_t *mdepid, *dtype = NULL, *role = NULL, *desc = NULL; sdp_list_t *f_list = NULL; mdepid = sdp_data_alloc(SDP_UINT8, &app->id); if (!mdepid) return NULL; dtype = sdp_data_alloc(SDP_UINT16, &app->data_type); if (!dtype) goto fail; role = sdp_data_alloc(SDP_UINT8, &app->role); if (!role) goto fail; if (app->description) { desc = sdp_data_alloc(SDP_TEXT_STR8, app->description); if (!desc) goto fail; } f_list = sdp_list_append(NULL, mdepid); if (!f_list) goto fail; if (!sdp_list_append(f_list, dtype)) goto fail; if (!sdp_list_append(f_list, role)) goto fail; if (desc) if (!sdp_list_append(f_list, desc)) goto fail; return f_list; fail: if (f_list) sdp_list_free(f_list, NULL); if (mdepid) sdp_data_free(mdepid); if (dtype) sdp_data_free(dtype); if (role) sdp_data_free(role); if (desc) sdp_data_free(desc); return NULL; }
static sdp_record_t *create_rfcomm_record(uint8_t chan, uuid_t *uuid, const char *svc_name, bool has_obex) { sdp_list_t *svclass_id; sdp_list_t *seq, *proto_seq, *pbg_seq; sdp_list_t *proto[3]; uuid_t l2cap_uuid, rfcomm_uuid, obex_uuid, pbg_uuid; sdp_data_t *channel; sdp_record_t *record; record = sdp_record_alloc(); if (!record) return NULL; record->handle = sdp_next_handle(); svclass_id = sdp_list_append(NULL, uuid); sdp_set_service_classes(record, svclass_id); sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); proto[0] = sdp_list_append(NULL, &l2cap_uuid); seq = sdp_list_append(NULL, proto[0]); sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID); proto[1] = sdp_list_append(NULL, &rfcomm_uuid); channel = sdp_data_alloc(SDP_UINT8, &chan); proto[1] = sdp_list_append(proto[1], channel); seq = sdp_list_append(seq, proto[1]); if (has_obex) { sdp_uuid16_create(&obex_uuid, OBEX_UUID); proto[2] = sdp_list_append(NULL, &obex_uuid); seq = sdp_list_append(seq, proto[2]); } proto_seq = sdp_list_append(NULL, seq); sdp_set_access_protos(record, proto_seq); sdp_uuid16_create(&pbg_uuid, PUBLIC_BROWSE_GROUP); pbg_seq = sdp_list_append(NULL, &pbg_uuid); sdp_set_browse_groups(record, pbg_seq); if (svc_name) sdp_set_info_attr(record, svc_name, NULL, NULL); sdp_data_free(channel); sdp_list_free(proto[0], NULL); sdp_list_free(proto[1], NULL); if (has_obex) sdp_list_free(proto[2], NULL); sdp_list_free(seq, NULL); sdp_list_free(proto_seq, NULL); sdp_list_free(pbg_seq, NULL); sdp_list_free(svclass_id, NULL); return record; }
static int register_service_sup_features(sdp_record_t *rec, struct health_app *app) { sdp_list_t *sup_features = NULL; DBG(""); queue_foreach(app->mdeps, register_features, &sup_features); if (!sup_features) return -1; if (sdp_set_supp_feat(rec, sup_features) < 0) { sdp_list_free(sup_features, free_hdp_list); return -1; } sdp_list_free(sup_features, free_hdp_list); return 0; }
static gboolean register_service_sup_features(GSList *app_list, sdp_record_t *sdp_record) { GSList *l; sdp_list_t *sup_features = NULL; for (l = app_list; l; l = l->next) { if (!register_features(l->data, &sup_features)) return FALSE; } if (sdp_set_supp_feat(sdp_record, sup_features) < 0) { sdp_list_free(sup_features, free_hdp_list); return FALSE; } sdp_list_free(sup_features, free_hdp_list); return TRUE; }
/** * Retrieves SDP record identified by "handle". Session must be already opened. */ sdp_record_t *get_sdp_record(sdp_session_t *session, int handle) { sdp_list_t *attrid; uint32_t range = 0x0000ffff; sdp_record_t *rec; attrid = sdp_list_append(0, &range); rec = sdp_service_attr_req(session, handle, SDP_ATTR_REQ_RANGE, attrid); sdp_list_free(attrid,0); return rec; }
static void add_lang_attr(sdp_record_t *r) { sdp_lang_attr_t base_lang; sdp_list_t *langs = 0; /* UTF-8 MIBenum (http://www.iana.org/assignments/character-sets) */ base_lang.code_ISO639 = (0x65 << 8) | 0x6e; base_lang.encoding = 106; base_lang.base_offset = SDP_PRIMARY_LANG_BASE; langs = sdp_list_append(0, &base_lang); sdp_set_lang_attr(r, langs); sdp_list_free(langs, 0); }