static gboolean get_mdep_from_rec(const sdp_record_t *rec, uint8_t role, uint16_t d_type, uint8_t *mdep, char **desc) { sdp_data_t *list, *feat; if (desc == NULL && mdep == NULL) return TRUE; list = sdp_data_get(rec, SDP_ATTR_SUPPORTED_FEATURES_LIST); if (list == NULL || !SDP_IS_SEQ(list->dtd)) return FALSE; for (feat = list->val.dataseq; feat; feat = feat->next) { sdp_data_t *data_type, *mdepid, *role_t, *desc_t; if (!SDP_IS_SEQ(feat->dtd)) continue; mdepid = feat->val.dataseq; if (mdepid == NULL) continue; data_type = mdepid->next; if (data_type == NULL) continue; role_t = data_type->next; if (role_t == NULL) continue; desc_t = role_t->next; if (data_type->dtd != SDP_UINT16 || mdepid->dtd != SDP_UINT8 || role_t->dtd != SDP_UINT8) continue; if (data_type->val.uint16 != d_type || !check_role(role_t->val.uint8, role)) continue; if (mdep != NULL) *mdep = mdepid->val.uint8; if (desc != NULL && desc_t != NULL && SDP_IS_TEXT_STR(desc_t->dtd)) *desc = g_strdup(desc_t->val.str); return TRUE; } return FALSE; }
/* See HID profile specification v1.0, "7.11.6 HIDDescriptorList" for details * on the attribute format. */ static int extract_hid_desc_data(sdp_record_t *rec, struct hidp_connadd_req *req) { sdp_data_t *d; d = sdp_data_get(rec, SDP_ATTR_HID_DESCRIPTOR_LIST); if (!d) goto invalid_desc; if (!SDP_IS_SEQ(d->dtd)) goto invalid_desc; /* First HIDDescriptor */ d = d->val.dataseq; if (!SDP_IS_SEQ(d->dtd)) goto invalid_desc; /* ClassDescriptorType */ d = d->val.dataseq; if (d->dtd != SDP_UINT8) goto invalid_desc; /* ClassDescriptorData */ d = d->next; if (!d || !SDP_IS_TEXT_STR(d->dtd)) goto invalid_desc; req->rd_data = g_try_malloc0(d->unitSize); if (req->rd_data) { memcpy(req->rd_data, d->val.str, d->unitSize); req->rd_size = d->unitSize; epox_endian_quirk(req->rd_data, req->rd_size); } return 0; invalid_desc: error("Missing or invalid HIDDescriptorList SDP attribute"); return -EINVAL; }
static void hid_sdp_search_cb(sdp_list_t *recs, int err, gpointer data) { struct hid_device *dev = data; sdp_list_t *list; GError *gerr = NULL; DBG(""); if (err < 0) { error("hidhost: Unable to get SDP record: %s", strerror(-err)); goto fail; } if (!recs || !recs->data) { error("hidhost: No SDP records found"); goto fail; } for (list = recs; list != NULL; list = list->next) { sdp_record_t *rec = list->data; sdp_data_t *data; data = sdp_data_get(rec, SDP_ATTR_HID_COUNTRY_CODE); if (data) dev->country = data->val.uint8; data = sdp_data_get(rec, SDP_ATTR_HID_DEVICE_SUBCLASS); if (data) dev->subclass = data->val.uint8; data = sdp_data_get(rec, SDP_ATTR_HID_BOOT_DEVICE); if (data) dev->boot_dev = data->val.uint8; data = sdp_data_get(rec, SDP_ATTR_HID_DESCRIPTOR_LIST); if (data) { if (!SDP_IS_SEQ(data->dtd)) goto fail; /* First HIDDescriptor */ data = data->val.dataseq; if (!SDP_IS_SEQ(data->dtd)) goto fail; /* ClassDescriptorType */ data = data->val.dataseq; if (data->dtd != SDP_UINT8) goto fail; /* ClassDescriptorData */ data = data->next; if (!data || !SDP_IS_TEXT_STR(data->dtd)) goto fail; dev->rd_size = data->unitSize; dev->rd_data = g_memdup(data->val.str, data->unitSize); } } if (dev->ctrl_io) { if (uhid_create(dev) < 0) goto fail; return; } dev->ctrl_io = bt_io_connect(control_connect_cb, dev, NULL, &gerr, BT_IO_OPT_SOURCE_BDADDR, &adapter_addr, BT_IO_OPT_DEST_BDADDR, &dev->dst, BT_IO_OPT_PSM, L2CAP_PSM_HIDP_CTRL, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW, BT_IO_OPT_INVALID); if (gerr) { error("hidhost: Failed to connect control channel (%s)", gerr->message); g_error_free(gerr); goto fail; } return; fail: bt_hid_notify_state(dev, HAL_HIDHOST_STATE_DISCONNECTED); hid_device_remove(dev); }