Esempio n. 1
0
static int extract_hid_record(sdp_record_t *rec, struct hidp_connadd_req *req)
{
    sdp_data_t *pdlist;
    uint8_t attr_val;
    int err;

    err = create_hid_dev_name(rec, req);
    if (err < 0)
        DBG("No valid Service Name or Service Description found");

    pdlist = sdp_data_get(rec, SDP_ATTR_HID_PARSER_VERSION);
    req->parser = pdlist ? pdlist->val.uint16 : 0x0100;

    pdlist = sdp_data_get(rec, SDP_ATTR_HID_DEVICE_SUBCLASS);
    req->subclass = pdlist ? pdlist->val.uint8 : 0;

    pdlist = sdp_data_get(rec, SDP_ATTR_HID_COUNTRY_CODE);
    req->country = pdlist ? pdlist->val.uint8 : 0;

    pdlist = sdp_data_get(rec, SDP_ATTR_HID_VIRTUAL_CABLE);
    attr_val = pdlist ? pdlist->val.uint8 : 0;
    if (attr_val)
        req->flags |= (1 << HIDP_VIRTUAL_CABLE_UNPLUG);

    pdlist = sdp_data_get(rec, SDP_ATTR_HID_BOOT_DEVICE);
    attr_val = pdlist ? pdlist->val.uint8 : 0;
    if (attr_val)
        req->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);

    err = extract_hid_desc_data(rec, req);
    if (err < 0)
        return err;

    return 0;
}
Esempio n. 2
0
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);
}
Esempio n. 3
0
/*
 * Extract attribute identifiers from the request PDU.
 * Clients could request a subset of attributes (by id)
 * from a service record, instead of the whole set. The
 * requested identifiers are present in the PDU form of
 * the request
 */
static int extract_attrs(sdp_record_t *rec, sdp_list_t *seq, sdp_buf_t *buf)
{
	sdp_buf_t pdu;

	if (!rec)
		return SDP_INVALID_RECORD_HANDLE;

	if (seq) {
		SDPDBG("Entries in attr seq : %d", sdp_list_len(seq));
	} else {
		SDPDBG("NULL attribute descriptor");
	}

	if (seq == NULL) {
		SDPDBG("Attribute sequence is NULL");
		return 0;
	}

	sdp_gen_record_pdu(rec, &pdu);

	for (; seq; seq = seq->next) {
		struct attrid *aid = seq->data;

		SDPDBG("AttrDataType : %d", aid->dtd);

		if (aid->dtd == SDP_UINT16) {
			uint16_t attr = bt_get_unaligned((uint16_t *)&aid->uint16);
			sdp_data_t *a = (sdp_data_t *)sdp_data_get(rec, attr);
			if (a)
				sdp_append_to_pdu(buf, a);
		} else if (aid->dtd == SDP_UINT32) {
			uint32_t range = bt_get_unaligned((uint32_t *)&aid->uint32);
			uint16_t attr;
			uint16_t low = (0xffff0000 & range) >> 16;
			uint16_t high = 0x0000ffff & range;
			sdp_data_t *data;

			SDPDBG("attr range : 0x%x", range);
			SDPDBG("Low id : 0x%x", low);
			SDPDBG("High id : 0x%x", high);

			if (low == 0x0000 && high == 0xffff && pdu.data_size <= buf->buf_size) {
				/* copy it */
				memcpy(buf->data, pdu.data, pdu.data_size);
				buf->data_size = pdu.data_size;
				break;
			}
			/* (else) sub-range of attributes */
			for (attr = low; attr < high; attr++) {
				data = sdp_data_get(rec, attr);
				if (data)
					sdp_append_to_pdu(buf, data);
			}
			data = sdp_data_get(rec, high);
			if (data)
				sdp_append_to_pdu(buf, data);
		} else {
Esempio n. 4
0
/*
 * Extract attribute identifiers from the request PDU.
 * Clients could request a subset of attributes (by id)
 * from a service record, instead of the whole set. The
 * requested identifiers are present in the PDU form of
 * the request
 */
static int extract_attrs(sdp_record_t *rec, sdp_list_t *seq, uint8_t dtd, sdp_buf_t *buf)
{
	if (!rec)
		return SDP_INVALID_RECORD_HANDLE;

#ifdef SDP_DEBUG
	if (seq)
		SDPDBG("Entries in attr seq : %d\n", sdp_list_len(seq));
	else
		SDPDBG("NULL attribute descriptor\n");
	SDPDBG("AttrDataType : %d\n", dtd);
#endif
	if (seq == NULL) {
		SDPDBG("Attribute sequence is NULL\n");
		return 0;
	}
	if (dtd == SDP_UINT16)
		for (; seq; seq = seq->next) {
			uint16_t attr = sdp_get_unaligned((uint16_t *)seq->data);
			sdp_data_t *a = (sdp_data_t *)sdp_data_get(rec, attr);
			if (a)
				sdp_append_to_pdu(buf, a);
		}
	else if (dtd == SDP_UINT32) {
		sdp_buf_t pdu;
		sdp_gen_record_pdu(rec, &pdu);
		for (; seq; seq = seq->next) {
			uint32_t range = sdp_get_unaligned((uint32_t *)seq->data);
			uint16_t attr;
			uint16_t low = (0xffff0000 & range) >> 16;
			uint16_t high = 0x0000ffff & range;

			SDPDBG("attr range : 0x%x\n", range);
			SDPDBG("Low id : 0x%x\n", low);
			SDPDBG("High id : 0x%x\n", high);

			if (low == 0x0000 && high == 0xffff && pdu.data_size <= buf->buf_size) {
				/* copy it */
				memcpy(buf->data, pdu.data, pdu.data_size);
				buf->data_size = pdu.data_size;
				break;
			}
			/* (else) sub-range of attributes */
			for (attr = low; attr <= high; attr++) {
				sdp_data_t *a = (sdp_data_t *)sdp_data_get(rec, attr);
				if (a)
					sdp_append_to_pdu(buf, a);
			}
		}
		free(pdu.data);
	} else {
Esempio n. 5
0
static void extract_hid_record(sdp_record_t *rec, struct hidp_connadd_req *req)
{
	sdp_data_t *pdlist, *pdlist2;
	uint8_t attr_val;

	pdlist = sdp_data_get(rec, 0x0101);
	pdlist2 = sdp_data_get(rec, 0x0102);
	if (pdlist) {
		if (pdlist2) {
			if (strncmp(pdlist->val.str, pdlist2->val.str, 5)) {
				strncpy(req->name, pdlist2->val.str, 127);
				strcat(req->name, " ");
			}
			strncat(req->name, pdlist->val.str, 127 - strlen(req->name));
		} else
			strncpy(req->name, pdlist->val.str, 127);
	} else {
		pdlist2 = sdp_data_get(rec, 0x0100);
		if (pdlist2)
			strncpy(req->name, pdlist2->val.str, 127);
	}

	pdlist = sdp_data_get(rec, SDP_ATTR_HID_PARSER_VERSION);
	req->parser = pdlist ? pdlist->val.uint16 : 0x0100;

	pdlist = sdp_data_get(rec, SDP_ATTR_HID_DEVICE_SUBCLASS);
	req->subclass = pdlist ? pdlist->val.uint8 : 0;

	pdlist = sdp_data_get(rec, SDP_ATTR_HID_COUNTRY_CODE);
	req->country = pdlist ? pdlist->val.uint8 : 0;

	pdlist = sdp_data_get(rec, SDP_ATTR_HID_VIRTUAL_CABLE);
	attr_val = pdlist ? pdlist->val.uint8 : 0;
	if (attr_val)
		req->flags |= (1 << HIDP_VIRTUAL_CABLE_UNPLUG);

	pdlist = sdp_data_get(rec, SDP_ATTR_HID_BOOT_DEVICE);
	attr_val = pdlist ? pdlist->val.uint8 : 0;
	if (attr_val)
		req->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);

	pdlist = sdp_data_get(rec, SDP_ATTR_HID_DESCRIPTOR_LIST);
	if (pdlist) {
		pdlist = pdlist->val.dataseq;
		pdlist = pdlist->val.dataseq;
		pdlist = pdlist->next;

		req->rd_data = g_try_malloc0(pdlist->unitSize);
		if (req->rd_data) {
			memcpy(req->rd_data, (unsigned char *) pdlist->val.str,
								pdlist->unitSize);
			req->rd_size = pdlist->unitSize;
			epox_endian_quirk(req->rd_data, req->rd_size);
		}
	}
}
Esempio n. 6
0
static void hid_sdp_did_search_cb(sdp_list_t *recs, int err, gpointer data)
{
	struct hid_device *dev = data;
	sdp_list_t *list;
	uuid_t uuid;

	DBG("");

	if (err < 0) {
		error("hidhost: Unable to get Device ID SDP record: %s",
								strerror(-err));
		goto fail;
	}

	if (!recs || !recs->data) {
		error("hidhost: No Device ID SDP records found");
		goto fail;
	}

	for (list = recs; list; list = list->next) {
		sdp_record_t *rec = list->data;
		sdp_data_t *data;

		data = sdp_data_get(rec, SDP_ATTR_VENDOR_ID);
		if (data)
			dev->vendor = data->val.uint16;

		data = sdp_data_get(rec, SDP_ATTR_PRODUCT_ID);
		if (data)
			dev->product = data->val.uint16;

		data = sdp_data_get(rec, SDP_ATTR_VERSION);
		if (data)
			dev->version = data->val.uint16;
	}

	sdp_uuid16_create(&uuid, HID_SVCLASS_ID);
	if (bt_search_service(&adapter_addr, &dev->dst, &uuid,
				hid_sdp_search_cb, dev, NULL, 0) < 0) {
		error("hidhost: Failed to search SDP details");
		goto fail;
	}

	return;

fail:
	bt_hid_notify_state(dev, HAL_HIDHOST_STATE_DISCONNECTED);
	hid_device_remove(dev);
}
Esempio n. 7
0
static int get_add_prot_desc_list(const sdp_record_t *rec, uint16_t *psm)
{
	sdp_data_t *pdl, *p0, *p1;

	if (!psm)
		return -1;

	pdl = sdp_data_get(rec, SDP_ATTR_ADD_PROTO_DESC_LIST);
	if (!pdl || pdl->dtd != SDP_SEQ8)
		return -1;

	pdl = pdl->val.dataseq;
	if (pdl->dtd != SDP_SEQ8)
		return -1;

	p0 = pdl->val.dataseq;

	if (get_prot_desc_entry(p0, L2CAP_UUID, psm) < 0)
		return -1;

	p1 = p0->next;
	if (get_prot_desc_entry(p1, MCAP_DATA_UUID, NULL) < 0)
		return -1;

	return 0;
}
Esempio n. 8
0
static gboolean hdp_get_add_prot_desc_list(const sdp_record_t *rec,
								guint16 *psm)
{
	sdp_data_t *pdl, *p0, *p1;

	if (psm == NULL)
		return TRUE;

	pdl = sdp_data_get(rec, SDP_ATTR_ADD_PROTO_DESC_LIST);
	if (pdl == NULL || pdl->dtd != SDP_SEQ8)
		return FALSE;
	pdl = pdl->val.dataseq;
	if (pdl->dtd != SDP_SEQ8)
		return FALSE;

	p0 = pdl->val.dataseq;

	if (!get_prot_desc_entry(p0, L2CAP_UUID, psm))
		return FALSE;
	p1 = p0->next;
	if (!get_prot_desc_entry(p1, MCAP_DATA_UUID, NULL))
		return FALSE;

	return TRUE;
}
Esempio n. 9
0
static int hid_device_probe(struct btd_device *device, GSList *uuids)
{
	struct btd_adapter *adapter = device_get_adapter(device);
	const gchar *path = device_get_path(device);
	const sdp_record_t *rec = btd_device_get_record(device, uuids->data);
	bdaddr_t src, dst;
	sdp_data_t *pdlist;

	DBG("path %s", path);

	if (!rec)
		return -1;

	adapter_get_address(adapter, &src);
	device_get_address(device, &dst);
	if (rec)
		pdlist = sdp_data_get(rec, SDP_ATTR_HID_SDP_DISABLE);

	if (pdlist && pdlist->val.uint8) {
		DBG("cancel discovery is issued");
		bt_cancel_discovery(&src, &dst);
	}

	return input_device_register(connection, device, path, &src, &dst,
				HID_UUID, rec->handle, idle_timeout * 60);
}
void populateServiceRecord(JNIEnv *env, jobject serviceRecord, sdp_record_t* sdpRecord, sdp_list_t* attributeList) {
    jclass serviceRecordImplClass = (*env)->GetObjectClass(env, serviceRecord);
    debug("populateServiceRecord");
    jmethodID populateAttributeValueID = getGetMethodID(env, serviceRecordImplClass, "populateAttributeValue", "(ILjavax/bluetooth/DataElement;)V");
    if (populateAttributeValueID == NULL) {
        return;
    }
    int attrCount = 0;
    for(; attributeList; attributeList = attributeList->next) {
        jint attributeID=*(uint16_t*)attributeList->data;
        sdp_data_t *data = sdp_data_get(sdpRecord, (uint16_t)attributeID);
        if (data) {
            jobject dataElement = createDataElement(env, data);
            if ((*env)->ExceptionCheck(env)) {
                break;
            }
            if (dataElement == NULL) {
                break;
            }
            (*env)->CallVoidMethod(env, serviceRecord, populateAttributeValueID, attributeID, dataElement);
            if ((*env)->ExceptionCheck(env)) {
                 break;
            }
            attrCount ++;
        }
    }
    Edebug("attrCount %i", attrCount);
}
Esempio n. 11
0
static bool is_device_sdp_disable(const sdp_record_t *rec)
{
    sdp_data_t *data;

    data = sdp_data_get(rec, SDP_ATTR_HID_SDP_DISABLE);

    return data && data->val.uint8;
}
Esempio n. 12
0
static gboolean get_mdep_from_rec(const sdp_record_t *rec, uint8_t role,
				uint16_t d_type, uint8_t *mdep, char **desc)
{ DBG("");
	sdp_data_t *list, *feat;
	DBG("");
	if (!desc && !mdep)
		return TRUE;

	list = sdp_data_get(rec, SDP_ATTR_SUPPORTED_FEATURES_LIST);

	if (list->dtd != SDP_SEQ8 && list->dtd != SDP_SEQ16 &&
							list->dtd != SDP_SEQ32)
		return FALSE;

	for (feat = list->val.dataseq; feat; feat = feat->next) {
		sdp_data_t *data_type, *mdepid, *role_t, *desc_t;

		if (feat->dtd != SDP_SEQ8 && feat->dtd != SDP_SEQ16 &&
						feat->dtd != SDP_SEQ32)
			continue;

		mdepid = feat->val.dataseq;
		if (!mdepid)
			continue;

		data_type = mdepid->next;
		if (!data_type)
			continue;

		role_t = data_type->next;
		if (!role_t)
			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)
			*mdep = mdepid->val.uint8;

		if (desc  && desc_t && (desc_t->dtd == SDP_TEXT_STR8 ||
					desc_t->dtd == SDP_TEXT_STR16  ||
					desc_t->dtd == SDP_TEXT_STR32))
			*desc = g_strdup(desc_t->val.str);

		return TRUE;
	}

	return FALSE;
}
Esempio n. 13
0
static void extract_hid_props(struct input_device *idev,
                              const sdp_record_t *rec)
{
    /* Extract HID connectability */
    bool reconnect_initiate, normally_connectable;
    sdp_data_t *pdlist;

    /* HIDNormallyConnectable is optional and assumed FALSE
    * if not present. */
    pdlist = sdp_data_get(rec, SDP_ATTR_HID_RECONNECT_INITIATE);
    reconnect_initiate = pdlist ? pdlist->val.uint8 : TRUE;

    pdlist = sdp_data_get(rec, SDP_ATTR_HID_NORMALLY_CONNECTABLE);
    normally_connectable = pdlist ? pdlist->val.uint8 : FALSE;

    /* Update local values */
    idev->reconnect_mode =
        hid_reconnection_mode(reconnect_initiate, normally_connectable);
}
Esempio n. 14
0
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;
}
Esempio n. 15
0
/*
 * Taken from gnome-phone-manager
 */
static int get_rfcomm_channel(sdp_record_t *rec, int only_gnapplet)
{
	int channel = -1;
	sdp_list_t *protos = NULL;
	sdp_data_t *data;
	char name[64];

	if (sdp_get_access_protos(rec, &protos) != 0)
		goto end;

	data = sdp_data_get(rec, SDP_ATTR_SVCNAME_PRIMARY);
	if (data)
		snprintf(name, sizeof(name), "%.*s", data->unitSize, data->val.str);

	if (name == NULL)
		goto end;

	/*
	 * If we're only supposed to check for gnapplet, do it here
	 * We ignore it if we're not supposed to check for it.
	 */
	if (only_gnapplet != 0) {
		if (strcmp(name, "gnapplet") == 0)
			channel = sdp_get_proto_port(protos, RFCOMM_UUID);
		goto end;
	}

	/*
	 * We can't seem to connect to the PC Suite channel.
	 */
	if (strstr(name, "Nokia PC Suite") != NULL)
		goto end;
	/*
	 * And that type of channel on Nokia Symbian phones doesn't
	 * work either.
	 */
	if (strstr(name, "Bluetooth Serial Port") != NULL)
		goto end;
	/*
	 * Avoid the m-Router channel, same as the PC Suite on Sony Ericsson
	 * phones.
	 */
	if (strstr(name, "m-Router Connectivity") != NULL)
		goto end;

	channel = sdp_get_proto_port(protos, RFCOMM_UUID);
end:
	sdp_list_foreach(protos, (sdp_list_func_t)sdp_list_free, 0);
	sdp_list_free(protos, 0);
	return channel;
}
Esempio n. 16
0
int add_record_to_server(const bdaddr_t *src, sdp_record_t *rec)
{
	sdp_data_t *data;
	sdp_list_t *pattern;

	if (rec->handle == 0xffffffff) {
		rec->handle = sdp_next_handle();
		if (rec->handle < 0x10000)
			return -ENOSPC;
	} else {
		if (sdp_record_find(rec->handle))
			return -EEXIST;
	}

	DBG("Adding record with handle 0x%05x", rec->handle);

	sdp_record_add(src, rec);

	data = sdp_data_alloc(SDP_UINT32, &rec->handle);
	sdp_attr_replace(rec, SDP_ATTR_RECORD_HANDLE, data);

	if (sdp_data_get(rec, SDP_ATTR_BROWSE_GRP_LIST) == NULL) {
		uuid_t uuid;
		sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP);
		sdp_pattern_add_uuid(rec, &uuid);
	}

	for (pattern = rec->pattern; pattern; pattern = pattern->next) {
		char uuid[32];

		if (pattern->data == NULL)
			continue;

		sdp_uuid2strn((uuid_t *) pattern->data, uuid, sizeof(uuid));
		DBG("Record pattern UUID %s", uuid);
	}

	update_db_timestamp();

	return 0;
}
Esempio n. 17
0
static const void *bluetooth_getattribute(guint id, int attribute_id)
{
	GSList *l;
	sdp_data_t *data;

	for (l = sessions; l; l = l->next) {
		struct bluetooth_session *session = l->data;

		if (session->id != id)
			continue;

		if (session->sdp_record == NULL)
			break;

		/* Read version since UUID is already known */
		if (attribute_id == SDP_ATTR_PFILE_DESC_LIST) {
			sdp_list_t *descs;
			void *ret = NULL;

			if (sdp_get_profile_descs(session->sdp_record,
								&descs) < 0)
				return NULL;

			if (descs && descs->data) {
				sdp_profile_desc_t *desc = descs->data;
				ret = GINT_TO_POINTER(desc->version);
			}

			sdp_list_free(descs, free);

			return ret;
		}

		data = sdp_data_get(session->sdp_record, attribute_id);
		if (!data)
			break;

		return &data->val;
	}
	return NULL;
}
Esempio n. 18
0
/* 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;
}
Esempio n. 19
0
static int get_prot_desc_list(const sdp_record_t *rec, uint16_t *psm,
							uint16_t *version)
{
	sdp_data_t *pdl, *p0, *p1;

	if (!psm && !version)
		return -1;

	pdl = sdp_data_get(rec, SDP_ATTR_PROTO_DESC_LIST);
	if (!pdl || !SDP_IS_SEQ(pdl->dtd))
		return -1;

	p0 = pdl->val.dataseq;
	if (get_prot_desc_entry(p0, L2CAP_UUID, psm) < 0)
		return -1;

	p1 = p0->next;
	if (get_prot_desc_entry(p1, MCAP_CTRL_UUID, version) < 0)
		return -1;

	return 0;
}
Esempio n. 20
0
static const void *bluetooth_getattribute(guint id, int attribute_id)
{
	GSList *l;
	sdp_data_t *data;

	for (l = sessions; l; l = l->next) {
		struct bluetooth_session *session = l->data;

		if (session->id != id)
			continue;

		if (session->sdp_record == NULL)
			break;

		data = sdp_data_get(session->sdp_record, attribute_id);
		if (!data)
			break;

		return &data->val;
	}
	return NULL;
}
Esempio n. 21
0
static gboolean hdp_get_prot_desc_list(const sdp_record_t *rec, guint16 *psm,
							guint16 *version)
{
	sdp_data_t *pdl, *p0, *p1;

	if (psm == NULL && version == NULL)
		return TRUE;

	pdl = sdp_data_get(rec, SDP_ATTR_PROTO_DESC_LIST);
	if (pdl == NULL || !SDP_IS_SEQ(pdl->dtd))
		return FALSE;

	p0 = pdl->val.dataseq;
	if (!get_prot_desc_entry(p0, L2CAP_UUID, psm))
		return FALSE;

	p1 = p0->next;
	if (!get_prot_desc_entry(p1, MCAP_CTRL_UUID, version))
		return FALSE;

	return TRUE;
}
Esempio n. 22
0
static gboolean mcap_get_prot_desc_list(const sdp_record_t *rec, guint16 *psm,
							guint16 *version)
{
		DBG("");
	sdp_data_t *pdl, *p0, *p1;

	if (!psm && !version)
		return TRUE;

	pdl = sdp_data_get(rec, SDP_ATTR_PROTO_DESC_LIST);
	if (pdl->dtd != SDP_SEQ8 && pdl->dtd != SDP_SEQ16 &&
							pdl->dtd != SDP_SEQ32)
		return FALSE;

	p0 = pdl->val.dataseq;
	if (!get_prot_desc_entry(p0, L2CAP_UUID, psm))
		return FALSE;

	p1 = p0->next;
	if (!get_prot_desc_entry(p1, MCAP_CTRL_UUID, version))
		return FALSE;

	return TRUE;
}
Esempio n. 23
0
int get_sdp_device_info(const bdaddr_t *src, const bdaddr_t *dst, struct hidp_connadd_req *req)
{
	struct sockaddr_l2 addr;
	socklen_t addrlen;
	bdaddr_t bdaddr;
	uint32_t range = 0x0000ffff;
	sdp_session_t *s;
	sdp_list_t *search, *attrid, *pnp_rsp;
	sdp_record_t *rec;
	sdp_data_t *pdlist;
	uuid_t svclass;
	int err;

	s = sdp_connect(src, dst, SDP_RETRY_IF_BUSY | SDP_WAIT_ON_CLOSE);
	if (!s)
		return -1;

	sdp_uuid16_create(&svclass, PNP_INFO_SVCLASS_ID);
	search = sdp_list_append(NULL, &svclass);
	attrid = sdp_list_append(NULL, &range);

	err = sdp_service_search_attr_req(s, search,
					SDP_ATTR_REQ_RANGE, attrid, &pnp_rsp);

	sdp_list_free(search, NULL);
	sdp_list_free(attrid, NULL);

	memset(&addr, 0, sizeof(addr));
	addrlen = sizeof(addr);

	if (getsockname(s->sock, (struct sockaddr *) &addr, &addrlen) < 0)
		bacpy(&bdaddr, src);
	else
		bacpy(&bdaddr, &addr.l2_bdaddr);

	sdp_close(s);

	if (err)
		return -1;

	if (pnp_rsp) {
		rec = (sdp_record_t *) pnp_rsp->data;

		pdlist = sdp_data_get(rec, 0x0201);
		req->vendor = pdlist ? pdlist->val.uint16 : 0x0000;

		pdlist = sdp_data_get(rec, 0x0202);
		req->product = pdlist ? pdlist->val.uint16 : 0x0000;

		pdlist = sdp_data_get(rec, 0x0203);
		req->version = pdlist ? pdlist->val.uint16 : 0x0000;

		sdp_record_free(rec);
	}

	req->parser = 0x0100;
	req->subclass = 0xc0;
	req->country = 0;

	if (bacmp(&bdaddr, BDADDR_ANY))
		store_device_info(&bdaddr, dst, req);

	return 0;
}
Esempio n. 24
0
// Detect whether A2DP Sink is present at the destination or not
static int detect_a2dp(bdaddr_t *src, bdaddr_t *dst, unsigned short *psm, unsigned long *flags)
{
	sdp_session_t *sess;
	sdp_list_t *attrid, *search, *seq, *next;
	sdp_data_t *pdlist;
	uuid_t group;
	uint32_t range = 0x0000ffff;
	int err;
	int tries;

	tries = 0;
	while(!(sess = sdp_connect(src, dst, SDP_RETRY_IF_BUSY))) {
		DBG("retrying sdp connect: %s", strerror(errno));
		sleep(1);
		if(++tries > 10) {
			break;
		}
	}
	if (!sess) {
		DBG( "Warning: failed to connect to SDP server: %s", strerror(errno));
		if(psm) *psm = 25;
		if(flags) *flags = 0;
		return 0;
	}

	/* 0x1108->all? 0x1101->rf sink 0x111e->handsfree 0x1108->headset */
	sdp_uuid16_create(&group, 0x110d);
	search = sdp_list_append(0, &group);
	attrid = sdp_list_append(0, &range);
	err = sdp_service_search_attr_req(sess, search,
					SDP_ATTR_REQ_RANGE, attrid, &seq);
	sdp_list_free(search, 0);
	sdp_list_free(attrid, 0);

	if (err) {
		DBG( "Service Search failed: %s", strerror(errno));
		sdp_close(sess);
		return -1;
	}

	for (; seq; seq = next) {
		sdp_record_t *rec = (sdp_record_t *) seq->data;

		DBG( "Found A2DP Sink");
		if (psm)
			*psm = 25;

		next = seq->next;
		free(seq);
		sdp_record_free(rec);
	}

	sdp_uuid16_create(&group, PNP_INFO_SVCLASS_ID);
	search = sdp_list_append(0, &group);
	attrid = sdp_list_append(0, &range);
	err = sdp_service_search_attr_req(sess, search,
					SDP_ATTR_REQ_RANGE, attrid, &seq);
	sdp_list_free(search, 0);
	sdp_list_free(attrid, 0);

	if (err)
		goto done;

	if (flags)
		*flags = 0;

	for (; seq; seq = next) {
		sdp_record_t *rec = (sdp_record_t *) seq->data;
		uint16_t vendor, product, version;

		pdlist = sdp_data_get(rec, 0x0201);
		vendor = pdlist ? pdlist->val.uint16 : 0x0000;

		pdlist = sdp_data_get(rec, 0x0202);
		product = pdlist ? pdlist->val.uint16 : 0x0000;

		pdlist = sdp_data_get(rec, 0x0203);
		version = pdlist ? pdlist->val.uint16 : 0x0000;

		DBG( "Product ID %04x:%04x:%04x", vendor, product, version);

		if (vendor == 0x1310 && product == 0x0100 && version == 0x0104) {
			DBG( "Enabling GCT media payload workaround");
			if (flags)
				*flags |= NONSPECAUDIO;
		}

		next = seq->next;
		free(seq);
		sdp_record_free(rec);
	}

done:
	sdp_close(sess);
	return 0;
}
Esempio n. 25
0
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);
}
Esempio n. 26
0
static void search_callback(uint8_t type, uint16_t status,
			uint8_t *rsp, size_t size, void *user_data)
{
	struct bluetooth_session *session = user_data;
	unsigned int scanned, bytesleft = size;
	int seqlen = 0;
	uint8_t dataType;
	uint16_t port = 0;
	GError *gerr = NULL;

	if (status || type != SDP_SVC_SEARCH_ATTR_RSP)
		goto failed;

	scanned = sdp_extract_seqtype(rsp, bytesleft, &dataType, &seqlen);
	if (!scanned || !seqlen)
		goto failed;

	rsp += scanned;
	bytesleft -= scanned;
	do {
		sdp_record_t *rec;
		sdp_list_t *protos;
		sdp_data_t *data;
		int recsize, ch = -1;

		recsize = 0;
		rec = sdp_extract_pdu(rsp, bytesleft, &recsize);
		if (!rec)
			break;

		if (!recsize) {
			sdp_record_free(rec);
			break;
		}

		if (!sdp_get_access_protos(rec, &protos)) {
			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);
			protos = NULL;
		}

		data = sdp_data_get(rec, 0x0200);
		/* PSM must be odd and lsb of upper byte must be 0 */
		if (data != NULL && (data->val.uint16 & 0x0101) == 0x0001)
			ch = data->val.uint16;

		sdp_record_free(rec);

		if (ch > 0) {
			port = ch;
			break;
		}

		scanned += recsize;
		rsp += recsize;
		bytesleft -= recsize;
	} while (scanned < size && bytesleft > 0);

	if (port == 0)
		goto failed;

	session->port = port;

	g_io_channel_set_close_on_unref(session->io, FALSE);
	g_io_channel_unref(session->io);

	session->io = transport_connect(&session->src, &session->dst, port,
						transport_callback, session);
	if (session->io != NULL) {
		sdp_close(session->sdp);
		session->sdp = NULL;
		return;
	}

failed:
	if (session->io != NULL) {
		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);
}
Esempio n. 27
0
/*
 * Add the newly created service record to the service repository
 */
int service_register_req(sdp_req_t *req, sdp_buf_t *rsp)
{
	int scanned = 0;
	sdp_data_t *handle;
	uint8_t *p = req->buf + sizeof(sdp_pdu_hdr_t);
	int bufsize = req->len - sizeof(sdp_pdu_hdr_t);
	sdp_record_t *rec;

	req->flags = *p++;
	if (req->flags & SDP_DEVICE_RECORD) {
		bacpy(&req->device, (bdaddr_t *) p);
		p += sizeof(bdaddr_t);
		bufsize -= sizeof(bdaddr_t);
	}

	/* save image of PDU: we need it when clients request this attribute */
	rec = extract_pdu_server(&req->device, p, bufsize, 0xffffffff, &scanned);
	if (!rec)
		goto invalid;

	if (rec->handle == 0xffffffff) {
		rec->handle = sdp_next_handle();
		if (rec->handle < 0x10000) {
			sdp_record_free(rec);
			goto invalid;
		}
	} else {
		if (sdp_record_find(rec->handle)) {
			/* extract_pdu_server will add the record handle
			 * if it is missing. So instead of failing, skip
			 * the record adding to avoid duplication. */
			goto success;
		}
	}

	sdp_record_add(&req->device, rec);
	if (!(req->flags & SDP_RECORD_PERSIST))
		sdp_svcdb_set_collectable(rec, req->sock);

	handle = sdp_data_alloc(SDP_UINT32, &rec->handle);
	sdp_attr_replace(rec, SDP_ATTR_RECORD_HANDLE, handle);

success:
	/* if the browse group descriptor is NULL,
	 * ensure that the record belongs to the ROOT group */
	if (sdp_data_get(rec, SDP_ATTR_BROWSE_GRP_LIST) == NULL) {
		uuid_t uuid;
		sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP);
		sdp_pattern_add_uuid(rec, &uuid);
	}

	update_db_timestamp();

	/* Build a rsp buffer */
	bt_put_be32(rec->handle, rsp->data);
	rsp->data_size = sizeof(uint32_t);

	return 0;

invalid:
	bt_put_be16(SDP_INVALID_SYNTAX, rsp->data);
	rsp->data_size = sizeof(uint16_t);

	return -1;
}