diff options
| -rw-r--r-- | hcid/dbus-adapter.c | 9 | ||||
| -rw-r--r-- | hcid/dbus-sdp.c | 180 | ||||
| -rw-r--r-- | hcid/dbus-sdp.h | 2 | 
3 files changed, 189 insertions, 2 deletions
diff --git a/hcid/dbus-adapter.c b/hcid/dbus-adapter.c index 0f6d680a..b32569f6 100644 --- a/hcid/dbus-adapter.c +++ b/hcid/dbus-adapter.c @@ -1265,6 +1265,13 @@ static DBusHandlerResult adapter_get_remote_svc_handles(DBusConnection *conn,  	return get_remote_svc_handles(conn, msg, data);  } +static DBusHandlerResult adapter_get_remote_svc_identifiers(DBusConnection *conn, +								DBusMessage *msg, +								void *data) +{ +	return get_remote_svc_identifiers(conn, msg, data); +} +  static DBusHandlerResult adapter_finish_sdp_transact(DBusConnection *conn,  							DBusMessage *msg,  							void *data) @@ -3138,6 +3145,8 @@ static DBusMethodVTable adapter_methods[] = {  		"su",	"s"	},  	{ "GetRemoteServiceHandles",		adapter_get_remote_svc_handles,  		"ss",	"au"	}, +	{ "GetRemoteServiceIdentifiers",	adapter_get_remote_svc_identifiers, +		"s",	"as"	},  	{ "FinishRemoteServiceTransaction",	adapter_finish_sdp_transact,  		"s",	""	}, diff --git a/hcid/dbus-sdp.c b/hcid/dbus-sdp.c index d6dd16ef..8fb8dbf6 100644 --- a/hcid/dbus-sdp.c +++ b/hcid/dbus-sdp.c @@ -676,7 +676,7 @@ static void remote_svc_handles_completed_cb(uint8_t type, uint16_t err,  	reply = dbus_message_new_method_return(ctxt->rq);  	dbus_message_iter_init_append(reply, &iter);  	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, -			DBUS_TYPE_UINT32_AS_STRING, &array_iter); +				DBUS_TYPE_UINT32_AS_STRING, &array_iter);  	pdata = rsp; @@ -697,7 +697,7 @@ static void remote_svc_handles_completed_cb(uint8_t type, uint16_t err,  		pdata += sizeof(uint32_t);  		dbus_message_iter_append_basic(&array_iter, -				DBUS_TYPE_UINT32, &handle); +						DBUS_TYPE_UINT32, &handle);  	} while (--tsrc); @@ -709,6 +709,123 @@ failed:  	transaction_context_free(ctxt, TRUE);  } +static const char *extract_service_class(sdp_data_t *d) +{ +	sdp_data_t *seq; +	uuid_t *uuid; +	static char uuid_str[37]; + +	/* Expected sequence of UUID16 */ +	if (d->attrId != SDP_ATTR_SVCLASS_ID_LIST || d->dtd != SDP_SEQ8) +		return NULL; + +	if (!d->val.dataseq) +		return NULL; + +	seq = d->val.dataseq; +	if (!SDP_IS_UUID(seq->dtd)) +		return NULL; + +	uuid = &seq->val.uuid; +	if (uuid->type != SDP_UUID16) +		return NULL; + +	sprintf(uuid_str, "0000%04X-0000-1000-8000-00805F9B34FB", +							uuid->value.uuid16); + +	return uuid_str; +} + +static void remote_svc_identifiers_completed_cb(uint8_t type, uint16_t err, +			uint8_t *rsp, size_t size, void *udata) +{ +	struct transaction_context *ctxt = udata; +	DBusMessage *reply; +	DBusMessageIter iter, array_iter; +	int scanned, n, attrlen, extracted = 0, len = 0; +	uint8_t dtd = 0; + +	if (!ctxt) +		return; + +	if (err == 0xffff) { +		/* Check for protocol error or I/O error */ +		int sdp_err = sdp_get_error(ctxt->session); +		if (sdp_err < 0) { +			error("search failed: Invalid session!"); +			error_failed(ctxt->conn, ctxt->rq, EINVAL); +			goto failed; +		} + +		error("search failed: %s (%d)", strerror(sdp_err), sdp_err); +		error_failed(ctxt->conn, ctxt->rq, sdp_err); +		goto failed; +	} + +	if (type == SDP_ERROR_RSP) { +		error_sdp_failed(ctxt->conn, ctxt->rq, err); +		goto failed; +	} + +	/* Check response PDU ID */ +	if (type != SDP_SVC_SEARCH_ATTR_RSP) { +		error("SDP error: %s (%d)", strerror(EPROTO), EPROTO); +		error_failed(ctxt->conn, ctxt->rq, EPROTO); +		goto failed; +	} + +	reply = dbus_message_new_method_return(ctxt->rq); +	dbus_message_iter_init_append(reply, &iter); +	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, +				DBUS_TYPE_STRING_AS_STRING, &array_iter); + +	/* Expected sequence of service class id list */ +	scanned = sdp_extract_seqtype(rsp, &dtd, &len); +	if (!scanned || !len) +		goto done; + +	rsp += scanned; +	while (extracted < len) { +		const char *puuid; +		sdp_data_t *d; +		int seqlen; +		uint16_t attr; + +		seqlen = 0; +		scanned = sdp_extract_seqtype(rsp, &dtd, &seqlen); +		if (!scanned || !seqlen) +			goto done; + +		extracted += (seqlen + scanned); + +		n = sizeof(uint8_t); +		attrlen = 0; + +		rsp += scanned; +		attr = ntohs(bt_get_unaligned((uint16_t *) (rsp + n))); +		n += sizeof(uint16_t); +		d = sdp_extract_attr(rsp + n, &attrlen, NULL); +		if (!d) +			break; + +		d->attrId = attr; +		puuid = extract_service_class(d); +		if (puuid) +			dbus_message_iter_append_basic(&array_iter, +						DBUS_TYPE_STRING, &puuid); +		sdp_data_free(d); + +		n += attrlen; +		rsp += n; +	} +done: +	dbus_message_iter_close_container(&iter, &array_iter); +	send_message_and_unref(ctxt->conn, reply); + +failed: +	transaction_context_free(ctxt, TRUE); +} +  static gboolean sdp_client_connect_cb(GIOChannel *chan,  					GIOCondition cond, void *udata)  { @@ -941,6 +1058,39 @@ static int remote_svc_handles_conn_cb(struct transaction_context *ctxt)  	return 0;  } +static int remote_svc_identifiers_conn_cb(struct transaction_context *ctxt) +{ +	sdp_list_t *attrids, *search; +	uuid_t uuid; +	uint16_t attr; + +	if (sdp_set_notify(ctxt->session, +			remote_svc_identifiers_completed_cb, ctxt) < 0) +		return -EINVAL; + +	sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP); +	search = sdp_list_append(0, &uuid); + +	attr = SDP_ATTR_SVCLASS_ID_LIST; +	attrids = sdp_list_append(NULL, &attr); + +	/* +	 * Create/send the search request and set the +	 * callback to indicate the request completion +	 */ +	if (sdp_service_search_attr_async(ctxt->session, search, +				SDP_ATTR_REQ_INDIVIDUAL, attrids) < 0) { +		sdp_list_free(search, NULL); +		sdp_list_free(attrids, NULL); +		return -sdp_get_error(ctxt->session); +	} + +	sdp_list_free(search, NULL); +	sdp_list_free(attrids, NULL); + +	return 0; +} +  DBusHandlerResult get_remote_svc_handles(DBusConnection *conn, DBusMessage *msg, void *data)  {  	struct adapter *adapter = data; @@ -977,6 +1127,32 @@ DBusHandlerResult get_remote_svc_handles(DBusConnection *conn, DBusMessage *msg,  	return DBUS_HANDLER_RESULT_HANDLED;  } +DBusHandlerResult get_remote_svc_identifiers(DBusConnection *conn, DBusMessage *msg, void *data) +{ +	struct adapter *adapter = data; +	const char *dst; +	int err; + +	if (!adapter->up) +		return error_not_ready(conn, msg); + +	if (!dbus_message_get_args(msg, NULL, +			DBUS_TYPE_STRING, &dst, +			DBUS_TYPE_INVALID)) +		return error_invalid_arguments(conn, msg); + +	if (find_pending_connect(dst)) +		return error_service_search_in_progress(conn, msg); + +	if (!connect_request(conn, msg, adapter->dev_id, +				dst, remote_svc_identifiers_conn_cb, &err)) { +		error("Search request failed: %s (%d)", strerror(err), err); +		return error_failed(conn, msg, err); +	} + +	return DBUS_HANDLER_RESULT_HANDLED; +} +  DBusHandlerResult finish_remote_svc_transact(DBusConnection *conn,  						DBusMessage *msg, void *data)  { diff --git a/hcid/dbus-sdp.h b/hcid/dbus-sdp.h index d34f2fa1..c1a7382d 100644 --- a/hcid/dbus-sdp.h +++ b/hcid/dbus-sdp.h @@ -35,6 +35,8 @@ typedef enum {  DBusHandlerResult get_remote_svc_handles(DBusConnection *conn, DBusMessage *msg, void *data); +DBusHandlerResult get_remote_svc_identifiers(DBusConnection *conn, DBusMessage *msg, void *data); +  DBusHandlerResult get_remote_svc_rec(DBusConnection *conn, DBusMessage *msg, void *data, sdp_format_t format);  DBusHandlerResult finish_remote_svc_transact(DBusConnection *conn, DBusMessage *msg, void *data);  | 
