Linux bluetooth development
 help / color / mirror / Atom feed
* Re: [RFC 04/16] Bluetooth: add l2cap_state_change_and_error()
From: Anderson Lizardo @ 2012-12-12 13:40 UTC (permalink / raw)
  To: Gustavo Padovan; +Cc: linux-bluetooth, Gustavo Padovan
In-Reply-To: <1355285624-25811-5-git-send-email-gustavo@padovan.org>

Hi Gustavo,

On Wed, Dec 12, 2012 at 12:13 AM, Gustavo Padovan <gustavo@padovan.org> wrote:
> @@ -238,7 +244,7 @@ static inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err)
>         struct sock *sk = chan->sk;
>
>         lock_sock(sk);
> -       __l2cap_chan_set_err(chan, err);
> +       chan->ops->state_change(chan, chan->state, 0);

Why "0" and not "err" ?

>         release_sock(sk);
>  }
>

Regards,
-- 
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil

^ permalink raw reply

* Re: [RFC BlueZ v1] media-api: Add org.bluez.MediaLibrary1
From: Luiz Augusto von Dentz @ 2012-12-12 14:45 UTC (permalink / raw)
  To: Oleksandr.Domin; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <9F89C4B87365E4408446E7FF5C4AE97115A0CB9EAF@SMUCM17V.europe.bmw.corp>

Hi Oleksandr,

On Tue, Dec 11, 2012 at 6:53 PM,  <Oleksandr.Domin@bmw.de> wrote:
> Hi Luiz
>>
>>Hi Oleksandr,
>>
>>On Tue, Dec 11, 2012 at 2:57 PM,  <Oleksandr.Domin@bmw.de> wrote:
>>> Hi Luiz,
>>>
>>>>From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>>>>
>>>>This interface adds support for browsing and searching in the player's
>>>>storage using AVRCP 1.4/1.5.
>>>>
>>>>Some remarks about the design:
>>>>
>>>>  - Exposing UIDCounter and UIDs was considered, but the spec seems to
>>have
>>>>    missed to define the player's id persistency. There are also the fact
>>>>that
>>>>    UIDCounter alone does not guarantee persistency across sessions and do
>>>>not
>>>>    provide what exact items have changed, so in the end exposing these
>>>>    details will bring almost no value.
>>>
>>> In case UIDCounter I agree we have no value, but we need to expose UIDs
>>> for found and browsed media items. I am thinking about IVI use cases like
>>> "search", "file browsing" and "content browsing". In this case you have
>>> not only AVRCP device but also USB and other devices you would like to
>>> run you use cases. And you would like to combine results in to one
>>> global list and initiate playback.
>>
>>If you need to cache any information, which is not recommended, you
>>are in your own to assume the player id or name are persistent, but if
>>you do so you can also assume the folder are persistent as well then
>>just cache them. The important part is that you have to rediscover
>>them to find out what is the current UID for the item.
>>
>>> I know we cannot rely on this UIDs but in case we get UIDCounter changed
>>> application has to delete all UIDs and start from the beginning.
>>
>>Yes, and that would be done automatically by ObjectManager for the
>>current listed items.
>>
>>>>  - Indexing or caching the whole media library is not recommended,
>>>>Bluetooth
>>>>    is too slow for that and even vendors such as Apple do not recommend
>>>>doing
>>>>    it, so the only items keep in cache are the current listed ones.
>>>
>>> Question is why do we need this cache on D-Bus (Object manager)? If we
>>> return this information it's up to the application to do whatever
>>> it wants.
>>
>>To track the item's UID, otherwise we always have to access by path
>>and discover the UID in the background since the UID is unreliable.
>
> So I see. We have the an Item represented as an object. This item has
> internally the UID to be able to send it to the target for playing. In case
> UIDCounter will be updated the object will be deleted. But if UIDCounter
> is unchanged you can use only PlayItem(UID) ignoring the Item object?

Nope, you can't have the UID as they are unreliable and Im quite sure
this would create a lot of other problems that the application
themselves would have to resolve such as the player persistency. The
items filesystem path is probably much more deterministic than the UID
and that is something you can probably use together with Search to
discover the Item UID when you want it to be played or added to now
playing list.

>>
>>>>  - Addressed vs Browsed player is done implicitly when accessed, this was
>>>>done
>>>>    to simplify the API and avoid confusions between applications and
>>>>players.
>>>>---
>>>>v1: Rename to MediaLibrary and add versioning, also rename Properties
>>filter
>>>>to attributes and don't use camel case for values.
>>>>
>>>> doc/media-api.txt | 173
>>>>++++++++++++++++++++++++++++++++++++++++++++++++++++++
>>>> 1 file changed, 173 insertions(+)
>>>>
>>>>diff --git a/doc/media-api.txt b/doc/media-api.txt
>>>>index 1865df9..0926e43 100644
>>>>--- a/doc/media-api.txt
>>>>+++ b/doc/media-api.txt
>>>>@@ -219,6 +219,179 @@ Properties       string Equalizer [readwrite]
>>>>                       possible to signal its end by setting position to
>>the
>>>>                       maximum uint32 value.
>>>
>>> As I see we have properties like "Equalizer", "Repeat" "Shuffle"
>>> and "Scan" per player. But I think from the application point of view
>>> it's good to set it once and to lat BlueZ handle this state's internally.
>>> In this case we would also reduce calls on D-Bus and simplify the logic
>>> in the application above.
>>
>>This is per player, if you want to replicate your status to each
>>player you can do it but I don't think BlueZ should assume all of them
>>have the same setting.
>
> I think we what design our applications as simple as possible. Please think
> about the following use case:
>         1. The customer is changing the player configuration.
>         2. This configuration will be applied for each media source
> Bluetooth AVRCP is in our case one audio source but with several players.
> But still I would expect BlueZ can handle this. I also agree if I
> change the player I can first of all read settings by the upper application
> and set it to the customer settings. But you need to do this every time
> you changing the player ;-)

But AVRCP is not meant to be audio source, it is a player or to be
more precise it is a remote control that can browse the player's media
library, so the behavior of your UI should be consistent with the
player you are controlling which is the opposite of what you are
suggesting which is to reflect the local player settings.

>>If that is useful I can add it no problem, but note that since you can
>>only play items from its own media library Im not sure this will be
>>useful for anything except maybe for filtering what player you display
>>to the user.
>
> I am not sure, but I think this information could be useful.

We can add it latter if we have a use case that does actually use these details.

>>
>>>>+
>>>>+MediaLibrary1 hierarchy
>>>>+=======================
>>>>+
>>>>+Service               unique name (Target role)
>>>>+              org.bluez (Controller role)
>>>>+Interface     org.bluez.MediaLibrary1
>>>>+Object path   freely definable (Target role)
>>>>+              [variable
>>prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/player
>>>
>>> Are you talking about
>>> [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/MediaLibraryX
>>>
>>>>+              (Controller role)
>>>>+
>>>>+Methods               array{objects, properties} Search(string value,
>>dict
>>>>filter)
>>>>+
>>>>+                      Return a list of MediaItem found
>>>
>>> I think in this case we need to return only the number of media items
>>> found by the search method. In the second step you can ask the stack
>>> to list all items (ListItems).
>>
>>Well the underlining protocol is designed like this so to get the
>>number of items you have to search anyway so why not return the items
>>too? Perhaps you are suggesting to join this with ListItems so we
>>could in theory have a search string as filter which will do just the
>>same.
>
> No, in case you are searching you will get the number of items
> found by the search. You need to call getFolderItems and the
> number of items you would like to download. And if you remember our
> discussion, if we have low budget IVI system you could download only
> the first 100 items. If you do it in one call you will return all items.

Then it can search from the last index + 100 items, otherwise we need
a specific folder to map search scope of the items.

> The second reason is if you use only one function to download item
> by calling ListItems you can easily cancel the previous initiated
> ListItems call (canceling previous item download).

Other operations such as ListItems or ChangeFolder could trigger
search to cancel, furthermore there is no cancel for AVRCP Browsing
commands so could just ignore the response but not really stop
anything.

>>
>>>>+
>>>>+              array{objects, properties} ListItems(dict filter)
>>>>+
>>>>+                      Return a list of MediaItem found
>>>
>>> Also here we need a numberOfItems parameter instead of the filter.
>>> If you have to search you would like also to set the filter if you
>>> want to browse (and we are talking about file browsing) we have
>>> to return all results in the folder. We have to use the filter
>>> other in Search or in ListItem but not in both.
>>
>>You can provide Start and End as filter with that you can select how
>>many items you want in the return.
>
> You will know the start and end items only if you know the number of
> items before you start ListItems
>
>>
>>> I am also not a freand of returning objects. I think we need to
>>> return a dict with the media item ID and meta data.
>>
>>The object is an id and the metadata is the properties and they both
>>are returned.
>
> Yes, I agree but I think in our case it's not what we want.
>
>>
>>>>+
>>>>+              void ChangeFolder(string path)
>>>>+
>>>>+                      Change current folder, support both relative or
>>>>+                      absolute paths.
>>>>+
>>>>+Properties    uint32 NumberOfItems:
>>>>+
>>>>+                      Number of items in the current folder
>>>
>>> I think we need this property as a return value. Result of the
>>> Search and ChangeFolder return different values. For example you
>>> do start search and the system will update the number of items
>>> and in the second step you execute ChangeFolder and BleuZ is
>>> updating the number of items. How do you know now how mach items
>>> do you have in search? So we need for Search and ChangeFolder
>>> different properties.
>>
>>What do you mean how many items you have in the search, we return a
>>list which the application will have to iterate, the number of items
>>is only interesting if you are not listen them, we could perhaps even
>>have it as return to ChangeFolder but anyway the property will be
>>updated everytime you change the folder.
>
> No the use case is as followed:
> 1. initiate ChangeFolder "/"
> 2. NumberOfItems will be set to 20
> 3. initiate Search
> 4. NumberOfItems will be set to 50
> 5. How do I get the number of items in the "/" directory know?

Right now Search do not affect the NumberOfItems because you haven't
changed the folder, and you can still request the amount of items you
want via filters, internally we should be able to keep the search
context active if you want more items, the application can also filter
the list itself.

>>
>>>>+
>>>>+              string Path:
>>>>+
>>>>+                      Current path:
>>>>+
>>>>+                      Possible values: "/root/folder" or "/NowPlaying"
>>>>+
>>>>+                      Note: /NowPlaying might not be listed if player is
>>>>+                      stopped
>>>
>>> It's good to have this property but I think we also need
>>> ListNowPlaing method without changing the paht to /NowPlaying.
>>> Requests ChangeFolder and ListNowPlaying are addressed to
>>> different players the one to the browsed and the second to the
>>> addressed player
>>
>>But that is exactly the purpose to expose NowPlaying as a folder, the
>>application has to request it explicitly which may not be there if the
>>player is not addressed and in addition we list the items there. Btw,
>>you can still do browse one player and list NowPlaying on other the
>>only thing that we are limiting is browsing both NowPlaying and
>>filesystem together which anyway is not possible since that would be
>>to the same device and the requests are no done in parallel
>
> This is something I would like to understand. I think you can do
> Change folder "path" for the browsed player and list know playing
> For the addressed player in parallel. But please correct me If I am wrong.

Yes, you can, NowPlaying list is persistent for this reason, you just
have to switch folder to change the scope.

>>
>>>>+
>>>>+Filters               uint32 Start:
>>>>+
>>>>+                      Offset of the first item.
>>>>+
>>>>+                      Default value: 0
>>>>+
>>>>+              uint32 End:
>>>>+
>>>>+                      Offset of the last item.
>>>>+
>>>>+                      Default value: NumbeOfItems
>>>
>>> In case we use NumberOfItems we also need one value not only for the
>>> ChangeFolder but even for Search.
>>
>>Search return a list of items found, NumberOfItems represents the
>>items in the folder just so the application can know in advance how
>>much traffic it would cause and possible download them in windowing
>>mode.
>>
>>>>+
>>>>+              array{string} Attributes
>>>>+
>>>>+                      Item properties that should be included in the
>>list.
>>>>+
>>>>+                      Possible Values:
>>>>+
>>>>+                              "title", "artist", "album", "genre",
>>>>+                              "number-of-tracks", "number", "duration"
>>>>+
>>>>+                      Default Value: All
>>>>+
>>>>+MediaItem1 hierarchy
>>>>+====================
>>>>+
>>>>+Service               unique name (Target role)
>>>>+              org.bluez (Controller role)
>>>>+Interface     org.bluez.MediaItem1
>>>>+Object path   freely definable (Target role)
>>>>+              [variable
>>>>+              prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/playerX/itemX
>>>>+              (Controller role)
>>>
>>> In fact I do not like this Item representation as object in D-Bus.
>>> In this case we have 1000 D-Bus calls and more if you are trying to
>>> remove and add items from D-Bus.
>>
>>You don't remove or add, you list them, if you want to list only 10
>>items you can do that and only 10 objects would be created.
>>
>>> The second limitation is on IVI you cannot create your own lists to
>>> play. And I think the API should be as generic as possible in this
>>> case.
>>
>>You can create your own list, you just have to list them to refresh
>>the UID, btw if you use the NowPlaying list that should be persistent.
>>It the mixing of different sources that would be a problem, since with
>>that you cannot use NowPlaying, or perhaps you can by stopping the
>>playing when switching to another source but this could racy.
>
> I think in IVI do use our own global item list to play and not the
> NowPlaing one from the phone. Because we have already different
> Interpretations of the implementation with Iphone and the Windows 8.

Exactly, and the IVI system should be consistent what the target
player it is controlling, the use case you are trying to implement is
something completely different which perhaps could be possible with
something like OBEX FTP or MTP, but even this protocols are not meant
for indexing but for syncing the library.

> If you select on the Iphone any item in a folder to play all folder
> Items will be added to the NowPlaying list. In case on Windows 8 only
> this item will be added to the NowPlaing list and this item will play
> in a loop.

Yes devices will behave differently, actually even player of the same
device could probably behave completely different and have completely
different feature set.


--
Luiz Augusto von Dentz

^ permalink raw reply

* [PATCH 01/14] device: Retrieve device technology from storage
From: Frédéric Danis @ 2012-12-12 15:47 UTC (permalink / raw)
  To: linux-bluetooth

---
 src/device.c |   68 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 68 insertions(+)

diff --git a/src/device.c b/src/device.c
index e6afe64..d6f8a9a 100644
--- a/src/device.c
+++ b/src/device.c
@@ -246,6 +246,35 @@ static gboolean store_device_info_cb(gpointer user_data)
 		g_key_file_remove_key(key_file, "General", "Class", NULL);
 	}
 
+	switch (device->bdaddr_type) {
+	case BDADDR_BREDR:
+		g_key_file_set_string(key_file, "General",
+					"SupportedTechnologies", "BR/EDR");
+		g_key_file_remove_key(key_file, "General",
+					"AddressType", NULL);
+		break;
+
+	case BDADDR_LE_PUBLIC:
+		g_key_file_set_string(key_file, "General",
+					"SupportedTechnologies", "LE");
+		g_key_file_set_string(key_file, "General",
+					"AddressType", "public");
+		break;
+
+	case BDADDR_LE_RANDOM:
+		g_key_file_set_string(key_file, "General",
+					"SupportedTechnologies", "LE");
+		g_key_file_set_string(key_file, "General",
+					"AddressType", "static");
+		break;
+
+	default:
+		g_key_file_remove_key(key_file, "General",
+					"SupportedTechnologies", NULL);
+		g_key_file_remove_key(key_file, "General",
+					"AddressType", NULL);
+	}
+
 	g_key_file_set_boolean(key_file, "General", "Trusted",
 							device->trusted);
 
@@ -1902,6 +1931,9 @@ static void load_info(struct btd_device *device, const gchar *local,
 	gboolean store_needed = FALSE;
 	gboolean blocked;
 	int source, vendor, product, version;
+	char **techno, **t;
+	gboolean bredr = FALSE;
+	gboolean le = FALSE;
 
 	snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", local, peer);
 	filename[PATH_MAX] = '\0';
@@ -1938,6 +1970,42 @@ static void load_info(struct btd_device *device, const gchar *local,
 		g_free(str);
 	}
 
+	/* Load device technology */
+	techno = g_key_file_get_string_list(key_file, "General",
+					"SupportedTechnologies", NULL, NULL);
+	if (!techno)
+		goto next;
+
+	for (t = techno; *t; t++) {
+		if (g_str_equal(*t, "BR/EDR"))
+			bredr = TRUE;
+		else if (g_str_equal(*t, "LE"))
+			le = TRUE;
+		else
+			error("Unknown device technology");
+	}
+
+	if (bredr && le) {
+		/* TODO: Add correct type for dual mode device */
+	} else if (bredr) {
+		device->bdaddr_type = BDADDR_BREDR;
+	} else if (le) {
+		str = g_key_file_get_string(key_file, "General",
+						"AddressType", NULL);
+
+		if (str && g_str_equal(str, "public"))
+			device->bdaddr_type = BDADDR_LE_PUBLIC;
+		else if (str && g_str_equal(str, "static"))
+			device->bdaddr_type = BDADDR_LE_RANDOM;
+		else
+			error("Unknown LE device technology");
+
+		g_free(str);
+	}
+
+	g_strfreev(techno);
+
+next:
 	/* Load trust */
 	device->trusted = g_key_file_get_boolean(key_file, "General",
 							"Trusted", NULL);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 02/14] device: Add device_create_from_storage() function
From: Frédéric Danis @ 2012-12-12 15:47 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1355327283-1558-1-git-send-email-frederic.danis@linux.intel.com>

This function is used from load_devices() of adapter.c
during bluetoothd start-up to re-load known devices from
storage key file.

device_create() is used to create new devices for which
no storage exists, but until all device load during start-up
has been converted we should continue to call load_info().
---
 src/adapter.c |   10 +++++----
 src/device.c  |   69 ++++++++++++++++++++++++++++++++++++++++++++-------------
 src/device.h  |    2 ++
 3 files changed, 61 insertions(+), 20 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index 34af063..7fcd42c 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1888,8 +1888,6 @@ static void load_devices(struct btd_adapter *adapter)
 		if (ltk_info)
 			ltks.keys = g_slist_append(ltks.keys, ltk_info);
 
-		g_key_file_free(key_file);
-
 		l = g_slist_find_custom(adapter->devices, entry->d_name,
 					(GCompareFunc) device_address_cmp);
 		if (l) {
@@ -1897,9 +1895,10 @@ static void load_devices(struct btd_adapter *adapter)
 			goto device_exist;
 		}
 
-		device = device_create(adapter, entry->d_name, BDADDR_BREDR);
+		device = device_create_from_storage(adapter, entry->d_name,
+							key_file);
 		if (!device)
-			continue;
+			goto free;
 
 		device_set_temporary(device, FALSE);
 		adapter->devices = g_slist_append(adapter->devices, device);
@@ -1909,6 +1908,9 @@ device_exist:
 			device_set_paired(device, TRUE);
 			device_set_bonded(device, TRUE);
 		}
+
+free:
+		g_key_file_free(key_file);
 	}
 
 	closedir(dir);
diff --git a/src/device.c b/src/device.c
index d6f8a9a..99ef77c 100644
--- a/src/device.c
+++ b/src/device.c
@@ -1923,10 +1923,8 @@ failed:
 }
 
 static void load_info(struct btd_device *device, const gchar *local,
-			const gchar *peer)
+			const gchar *peer, GKeyFile *key_file)
 {
-	char filename[PATH_MAX + 1];
-	GKeyFile *key_file;
 	char *str;
 	gboolean store_needed = FALSE;
 	gboolean blocked;
@@ -1935,12 +1933,6 @@ static void load_info(struct btd_device *device, const gchar *local,
 	gboolean bredr = FALSE;
 	gboolean le = FALSE;
 
-	snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", local, peer);
-	filename[PATH_MAX] = '\0';
-
-	key_file = g_key_file_new();
-	g_key_file_load_from_file(key_file, filename, 0, NULL);
-
 	/* Load device name from storage info file, if that fails fall back to
 	 * the cache.
 	 */
@@ -2035,18 +2027,14 @@ next:
 
 	if (store_needed)
 		store_device_info(device);
-
-	g_key_file_free(key_file);
 }
 
-struct btd_device *device_create(struct btd_adapter *adapter,
-				const gchar *address, uint8_t bdaddr_type)
+static struct btd_device *device_new(struct btd_adapter *adapter,
+				const gchar *address)
 {
 	gchar *address_up;
 	struct btd_device *device;
 	const gchar *adapter_path = adapter_get_path(adapter);
-	const bdaddr_t *src;
-	char srcaddr[18];
 
 	device = g_try_malloc0(sizeof(struct btd_device));
 	if (device == NULL)
@@ -2070,11 +2058,60 @@ struct btd_device *device_create(struct btd_adapter *adapter,
 
 	str2ba(address, &device->bdaddr);
 	device->adapter = adapter;
+
+	return btd_device_ref(device);
+}
+
+struct btd_device *device_create_from_storage(struct btd_adapter *adapter,
+				const char *address, GKeyFile *key_file)
+{
+	struct btd_device *device;
+	const bdaddr_t *src;
+	char srcaddr[18];
+
+	device = device_new(adapter, address);
+	if (device == NULL)
+		return NULL;
+
+	src = adapter_get_address(adapter);
+	ba2str(src, srcaddr);
+
+	load_info(device, srcaddr, address, key_file);
+
+	return device;
+}
+
+struct btd_device *device_create(struct btd_adapter *adapter,
+				const gchar *address, uint8_t bdaddr_type)
+{
+	struct btd_device *device;
+	const bdaddr_t *src;
+	char srcaddr[18];
+	char filename[PATH_MAX + 1];
+	GKeyFile *key_file;
+
+	device = device_new(adapter, address);
+	if (device == NULL)
+		return NULL;
+
 	device->bdaddr_type = bdaddr_type;
 	src = adapter_get_address(adapter);
 	ba2str(src, srcaddr);
 
-	load_info(device, srcaddr, address);
+	/*TODO: after all device load during start-up has been converted to
+	 * new key file structure, this should be replaced by :
+	 *	str = load_cached_name(device, srcaddr, address);
+	 *	if (str) {
+	 *		strcpy(device->name, str);
+	 *		g_free(str);
+	 *	}
+	 */
+	snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", srcaddr,
+			address);
+	key_file = g_key_file_new();
+	g_key_file_load_from_file(key_file, filename, 0, NULL);
+	load_info(device, srcaddr, address, key_file);
+	g_key_file_free(key_file);
 
 	return btd_device_ref(device);
 }
diff --git a/src/device.h b/src/device.h
index 1987a80..5c55b35 100644
--- a/src/device.h
+++ b/src/device.h
@@ -28,6 +28,8 @@ struct btd_device;
 
 struct btd_device *device_create(struct btd_adapter *adapter,
 				const char *address, uint8_t bdaddr_type);
+struct btd_device *device_create_from_storage(struct btd_adapter *adapter,
+				const char *address, GKeyFile *key_file);
 
 void device_set_name(struct btd_device *device, const char *name);
 void device_get_name(struct btd_device *device, char *name, size_t len);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 03/14] adapter: Convert device profiles list
From: Frédéric Danis @ 2012-12-12 15:47 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1355327283-1558-1-git-send-email-frederic.danis@linux.intel.com>

---
 src/adapter.c |    9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/src/adapter.c b/src/adapter.c
index 7fcd42c..7ab2389 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2556,6 +2556,12 @@ static void convert_ltk_entry(GKeyFile *key_file, void *value)
 	g_free(str);
 }
 
+static void convert_profiles_entry(GKeyFile *key_file, void *value)
+{
+	g_strdelimit(value, " ", ';');
+	g_key_file_set_string(key_file, "General", "Profiles", value);
+}
+
 static void convert_entry(char *key, char *value, void *user_data)
 {
 	struct device_converter *converter = user_data;
@@ -2663,6 +2669,9 @@ static void convert_device_storage(struct btd_adapter *adapter)
 	/* Convert blocked */
 	convert_file("blocked", address, convert_blocked_entry, TRUE);
 
+	/* Convert profiles */
+	convert_file("profiles", address, convert_profiles_entry, TRUE);
+
 	/* Convert linkkeys */
 	convert_file("linkkeys", address, convert_linkkey_entry, TRUE);
 
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 04/14] device: Load profiles from storage
From: Frédéric Danis @ 2012-12-12 15:47 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1355327283-1558-1-git-send-email-frederic.danis@linux.intel.com>

Add device_get_uuids() to retrieve UUIDs list.
It will allow to call device_probe_profiles() from
load_devices() of adapter.c after device creation.

Remove write_device_profiles from storage.[ch].
---
 src/device.c  |   89 ++++++++++++++++++++++++++++++---------------------------
 src/device.h  |    1 +
 src/storage.c |   18 ------------
 src/storage.h |    2 --
 4 files changed, 48 insertions(+), 62 deletions(-)

diff --git a/src/device.c b/src/device.c
index 99ef77c..242313d 100644
--- a/src/device.c
+++ b/src/device.c
@@ -218,6 +218,7 @@ static gboolean store_device_info_cb(gpointer user_data)
 	char device_addr[18];
 	char *str;
 	char class[9];
+	gchar **uuids = NULL;
 	gsize length = 0;
 
 	device->store_id = 0;
@@ -281,6 +282,19 @@ static gboolean store_device_info_cb(gpointer user_data)
 	g_key_file_set_boolean(key_file, "General", "Blocked",
 							device->blocked);
 
+	if (device->uuids) {
+		GSList *l;
+		int i;
+
+		uuids = g_new0(gchar *, g_slist_length(device->uuids) + 1);
+		for (i = 0, l = device->uuids; l; l = g_slist_next(l), i++)
+			uuids[i] = l->data;
+		g_key_file_set_string_list(key_file, "General", "Profiles",
+						(const gchar **)uuids, i);
+	} else {
+		g_key_file_remove_key(key_file, "General", "Profiles", NULL);
+	}
+
 	if (device->vendor_src) {
 		g_key_file_set_integer(key_file, "DeviceID", "Source",
 					device->vendor_src);
@@ -301,6 +315,7 @@ static gboolean store_device_info_cb(gpointer user_data)
 	g_free(str);
 
 	g_key_file_free(key_file);
+	g_free(uuids);
 
 	return FALSE;
 }
@@ -1928,6 +1943,7 @@ static void load_info(struct btd_device *device, const gchar *local,
 	char *str;
 	gboolean store_needed = FALSE;
 	gboolean blocked;
+	gchar **uuids;
 	int source, vendor, product, version;
 	char **techno, **t;
 	gboolean bredr = FALSE;
@@ -2007,6 +2023,27 @@ next:
 	if (blocked)
 		device_block(device, FALSE);
 
+	/* Load device profile list */
+	uuids = g_key_file_get_string_list(key_file, "General", "Profiles",
+						NULL, NULL);
+	if (uuids) {
+		gchar **uuid;
+
+		for (uuid = uuids; *uuid; uuid++) {
+			GSList *match;
+
+			match = g_slist_find_custom(device->uuids, *uuid,
+							bt_uuid_strcmp);
+			if (match)
+				continue;
+
+			device->uuids = g_slist_insert_sorted(device->uuids,
+								g_strdup(*uuid),
+								bt_uuid_strcmp);
+		}
+		g_strfreev(uuids);
+	}
+
 	/* Load device id */
 	source = g_key_file_get_integer(key_file, "DeviceID", "Source", NULL);
 	if (source) {
@@ -2316,6 +2353,11 @@ static gboolean record_has_uuid(const sdp_record_t *rec,
 	return FALSE;
 }
 
+GSList *device_get_uuids(struct btd_device *device)
+{
+	return device->uuids;
+}
+
 static GSList *device_match_profile(struct btd_device *device,
 					struct btd_profile *profile,
 					GSList *uuids)
@@ -2455,35 +2497,16 @@ add_uuids:
 static void device_remove_profiles(struct btd_device *device, GSList *uuids)
 {
 	char srcaddr[18], dstaddr[18];
-	sdp_list_t *records;
 	GSList *l, *next;
 
 	ba2str(adapter_get_address(device->adapter), srcaddr);
 	ba2str(&device->bdaddr, dstaddr);
 
-	records = read_records(adapter_get_address(device->adapter),
-							&device->bdaddr);
-
 	DBG("Removing profiles for %s", dstaddr);
 
-	for (l = uuids; l != NULL; l = g_slist_next(l)) {
-		sdp_record_t *rec;
-
-		device->uuids = g_slist_remove(device->uuids, l->data);
-
-		rec = find_record_in_list(records, l->data);
-		if (!rec)
-			continue;
-
-		delete_record(srcaddr, dstaddr, device->bdaddr_type,
-							rec->handle);
-
-		records = sdp_list_remove(records, rec);
-		sdp_record_free(rec);
-	}
-
-	if (records)
-		sdp_list_free(records, (sdp_free_func_t) sdp_record_free);
+	g_slist_free(device->uuids);
+	device->uuids = NULL;
+	store_device_info(device);
 
 	for (l = device->profiles; l != NULL; l = next) {
 		struct btd_profile *profile = l->data;
@@ -2652,24 +2675,6 @@ static void update_gatt_services(struct browse_req *req, GSList *current,
 	g_slist_free(left);
 }
 
-static void store_profiles(struct btd_device *device)
-{
-	struct btd_adapter *adapter = device->adapter;
-	char *str;
-
-	if (!device->uuids) {
-		write_device_profiles(adapter_get_address(adapter),
-					&device->bdaddr, device->bdaddr_type,
-					"");
-		return;
-	}
-
-	str = bt_list2string(device->uuids);
-	write_device_profiles(adapter_get_address(adapter), &device->bdaddr,
-						device->bdaddr_type, str);
-	g_free(str);
-}
-
 GSList *device_services_from_record(struct btd_device *device, GSList *profiles)
 {
 	GSList *l, *prim_list = NULL;
@@ -2759,7 +2764,7 @@ send_reply:
 	device_svc_resolved(device, err);
 
 	if (!device->temporary)
-		store_profiles(device);
+		store_device_info(device);
 
 	browse_request_free(req);
 }
@@ -4023,7 +4028,7 @@ void btd_device_add_uuid(struct btd_device *device, const char *uuid)
 	g_free(new_uuid);
 	g_slist_free(uuid_list);
 
-	store_profiles(device);
+	store_device_info(device);
 	uuids_changed(device);
 }
 
diff --git a/src/device.h b/src/device.h
index 5c55b35..1785a75 100644
--- a/src/device.h
+++ b/src/device.h
@@ -42,6 +42,7 @@ uint16_t btd_device_get_version(struct btd_device *device);
 void device_remove(struct btd_device *device, gboolean remove_stored);
 gint device_address_cmp(struct btd_device *device, const gchar *address);
 gint device_bdaddr_cmp(struct btd_device *device, bdaddr_t *bdaddr);
+GSList *device_get_uuids(struct btd_device *device);
 void device_probe_profiles(struct btd_device *device, GSList *profiles);
 const sdp_record_t *btd_device_get_record(struct btd_device *device,
 						const char *uuid);
diff --git a/src/storage.c b/src/storage.c
index 5798ccd..17dfc21 100644
--- a/src/storage.c
+++ b/src/storage.c
@@ -263,24 +263,6 @@ ssize_t read_pin_code(const bdaddr_t *local, const bdaddr_t *peer, char *pin)
 	return len;
 }
 
-int write_device_profiles(const bdaddr_t *src, const bdaddr_t *dst,
-					uint8_t dst_type, const char *profiles)
-{
-	char filename[PATH_MAX + 1], key[20];
-
-	if (!profiles)
-		return -EINVAL;
-
-	create_filename(filename, PATH_MAX, src, "profiles");
-
-	create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
-	ba2str(dst, key);
-	sprintf(&key[17], "#%hhu", dst_type);
-
-	return textfile_put(filename, key, profiles);
-}
-
 int delete_entry(const bdaddr_t *src, const char *storage, const bdaddr_t *dst,
 							uint8_t dst_type)
 {
diff --git a/src/storage.h b/src/storage.h
index c8ae6b0..fdee61c 100644
--- a/src/storage.h
+++ b/src/storage.h
@@ -36,8 +36,6 @@ int read_remote_appearance(const bdaddr_t *local, const bdaddr_t *peer,
 int write_lastused_info(const bdaddr_t *local, const bdaddr_t *peer,
 					uint8_t peer_type, struct tm *tm);
 ssize_t read_pin_code(const bdaddr_t *local, const bdaddr_t *peer, char *pin);
-int write_device_profiles(const bdaddr_t *src, const bdaddr_t *dst,
-				uint8_t dst_type, const char *profiles);
 int delete_entry(const bdaddr_t *src, const char *storage, const bdaddr_t *dst,
 							uint8_t dst_type);
 int store_record(const gchar *src, const gchar *dst, uint8_t dst_type,
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 05/14] adapter: Probe profiles after device creation
From: Frédéric Danis @ 2012-12-12 15:47 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1355327283-1558-1-git-send-email-frederic.danis@linux.intel.com>

---
 src/adapter.c |   40 ++++------------------------------------
 1 file changed, 4 insertions(+), 36 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index 7ab2389..10aacbf 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1631,38 +1631,6 @@ static const GDBusPropertyTable adapter_properties[] = {
 	{ }
 };
 
-static void create_stored_device_from_profiles(char *key, char *value,
-						void *user_data)
-{
-	char address[18];
-	uint8_t bdaddr_type;
-	struct btd_adapter *adapter = user_data;
-	GSList *list, *uuids = bt_string2list(value);
-	struct btd_device *device;
-
-	if (sscanf(key, "%17s#%hhu", address, &bdaddr_type) < 2)
-		bdaddr_type = BDADDR_BREDR;
-
-	if (g_slist_find_custom(adapter->devices,
-				address, (GCompareFunc) device_address_cmp))
-		return;
-
-	device = device_create(adapter, address, bdaddr_type);
-	if (!device)
-		return;
-
-	device_set_temporary(device, FALSE);
-	adapter->devices = g_slist_append(adapter->devices, device);
-
-	list = device_services_from_record(device, uuids);
-	if (list)
-		device_register_services(device, list, ATT_PSM);
-
-	device_probe_profiles(device, uuids);
-
-	g_slist_free_full(uuids, g_free);
-}
-
 struct adapter_keys {
 	struct btd_adapter *adapter;
 	GSList *keys;
@@ -1846,10 +1814,6 @@ static void load_devices(struct btd_adapter *adapter)
 
 	ba2str(&adapter->bdaddr, srcaddr);
 
-	create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "profiles");
-	textfile_foreach(filename, create_stored_device_from_profiles,
-								adapter);
-
 	create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "primaries");
 	textfile_foreach(filename, create_stored_device_from_primaries,
 								adapter);
@@ -1903,6 +1867,10 @@ static void load_devices(struct btd_adapter *adapter)
 		device_set_temporary(device, FALSE);
 		adapter->devices = g_slist_append(adapter->devices, device);
 
+		l = device_get_uuids(device);
+		if (l)
+			device_probe_profiles(device, l);
+
 device_exist:
 		if (key_info || ltk_info) {
 			device_set_paired(device, TRUE);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 06/14] device: Delete storage device recursively
From: Frédéric Danis @ 2012-12-12 15:47 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1355327283-1558-1-git-send-email-frederic.danis@linux.intel.com>

Device storage directory may contain multiple files like info or
attributes but also files stored by plug-ins or profiles,
so completely delete directory.
---
 src/device.c |   36 ++++++++++++++++++++++++++++++------
 1 file changed, 30 insertions(+), 6 deletions(-)

diff --git a/src/device.c b/src/device.c
index 242313d..da868b8 100644
--- a/src/device.c
+++ b/src/device.c
@@ -34,6 +34,7 @@
 #include <sys/stat.h>
 #include <sys/ioctl.h>
 #include <errno.h>
+#include <dirent.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/uuid.h>
@@ -2219,6 +2220,34 @@ uint16_t btd_device_get_version(struct btd_device *device)
 	return device->version;
 }
 
+static void delete_folder_tree(const char *dirname)
+{
+	DIR *dir;
+	struct dirent *entry;
+	char filename[PATH_MAX + 1];
+
+	dir = opendir(dirname);
+	if (dir == NULL)
+		return;
+
+	while ((entry = readdir(dir)) != NULL) {
+		if (g_str_equal(entry->d_name, ".") ||
+				g_str_equal(entry->d_name, ".."))
+			continue;
+
+		snprintf(filename, PATH_MAX, "%s/%s", dirname, entry->d_name);
+		filename[PATH_MAX] = '\0';
+
+		if (entry->d_type == DT_DIR)
+			delete_folder_tree(filename);
+		else
+			unlink(filename);
+	}
+	closedir(dir);
+
+	rmdir(dirname);
+}
+
 static void device_remove_stored(struct btd_device *device)
 {
 	const bdaddr_t *src = adapter_get_address(device->adapter);
@@ -2250,15 +2279,10 @@ static void device_remove_stored(struct btd_device *device)
 	ba2str(src, adapter_addr);
 	ba2str(&device->bdaddr, device_addr);
 
-	snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", adapter_addr,
-			device_addr);
-	filename[PATH_MAX] = '\0';
-	remove(filename);
-
 	snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s", adapter_addr,
 			device_addr);
 	filename[PATH_MAX] = '\0';
-	remove(filename);
+	delete_folder_tree(filename);
 }
 
 void device_remove(struct btd_device *device, gboolean remove_stored)
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 07/14] adapter: Convert device sdp file
From: Frédéric Danis @ 2012-12-12 15:47 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1355327283-1558-1-git-send-email-frederic.danis@linux.intel.com>

Parse sdp file to retrieve services, i.e. sdp records with attribute
uuid.
Create device attributes file based on this.
---
 src/adapter.c |  134 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 134 insertions(+)

diff --git a/src/adapter.c b/src/adapter.c
index 10aacbf..baeae79 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2607,6 +2607,127 @@ static void convert_file(char *file, char *address,
 	free(str);
 }
 
+static gboolean record_has_uuid(const sdp_record_t *rec,
+				const char *profile_uuid)
+{
+	sdp_list_t *pat;
+
+	for (pat = rec->pattern; pat != NULL; pat = pat->next) {
+		char *uuid;
+		int ret;
+
+		uuid = bt_uuid2string(pat->data);
+		if (!uuid)
+			continue;
+
+		ret = strcasecmp(uuid, profile_uuid);
+
+		g_free(uuid);
+
+		if (ret == 0)
+			return TRUE;
+	}
+
+	return FALSE;
+}
+
+static void store_attribute_uuid(GKeyFile *key_file, uint16_t start,
+					char *att_uuid, uuid_t uuid)
+{
+	char handle[6], uuid_str[33];
+	int i;
+
+	switch (uuid.type) {
+	case SDP_UUID16:
+		sprintf(uuid_str, "%4.4X", uuid.value.uuid16);
+		break;
+	case SDP_UUID32:
+		sprintf(uuid_str, "%8.8X", uuid.value.uuid32);
+		break;
+	case SDP_UUID128:
+		for (i = 0; i < 16; i++)
+			sprintf(uuid_str + (i * 2), "%2.2X",
+					uuid.value.uuid128.data[i]);
+		break;
+	default:
+		uuid_str[0] = '\0';
+	}
+
+	sprintf(handle, "%hd", start);
+	g_key_file_set_string(key_file, handle, "UUID", att_uuid);
+	g_key_file_set_string(key_file, handle, "Value", uuid_str);
+}
+
+static void convert_sdp_entry(char *key, char *value, void *user_data)
+{
+	char *address = user_data;
+	char filename[PATH_MAX + 1];
+	GKeyFile *key_file;
+	struct stat st;
+	sdp_record_t *rec;
+	uuid_t uuid;
+	char *att_uuid, *prim_uuid;
+	uint16_t start = 0, end = 0, psm = 0;
+	char *str;
+	gsize length = 0;
+	int err;
+
+	if (key[17] == '#')
+		key[17] = '\0';
+
+	if (bachk(key) != 0)
+		return;
+
+	/* Check if the device directory has been created as records should
+	 * only be converted for known devices */
+	snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s", address, key);
+	filename[PATH_MAX] = '\0';
+
+	err = stat(filename, &st);
+	if (err || !S_ISDIR(st.st_mode))
+		return;
+
+	sdp_uuid16_create(&uuid, ATT_UUID);
+	att_uuid = bt_uuid2string(&uuid);
+
+	sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
+	prim_uuid = bt_uuid2string(&uuid);
+
+	/* Retrieve device record and check if there is an
+	 * attribute entry in it */
+	rec = record_from_string(value);
+
+	if (!record_has_uuid(rec, att_uuid))
+		goto failed;
+
+	if (!gatt_parse_record(rec, &uuid, &psm, &start, &end))
+		goto failed;
+
+	snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/attributes", address,
+									key);
+	filename[PATH_MAX] = '\0';
+
+	key_file = g_key_file_new();
+	g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+	store_attribute_uuid(key_file, start, prim_uuid, uuid);
+
+	str = g_key_file_to_data(key_file, &length, NULL);
+	if (length > 0) {
+		create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+		g_file_set_contents(filename, str, length, NULL);
+	}
+
+	g_free(str);
+
+	g_key_file_free(key_file);
+
+failed:
+	sdp_record_free(rec);
+	g_free(prim_uuid);
+	g_free(att_uuid);
+}
+
 static void convert_device_storage(struct btd_adapter *adapter)
 {
 	char filename[PATH_MAX + 1];
@@ -2651,6 +2772,19 @@ static void convert_device_storage(struct btd_adapter *adapter)
 
 	/* Convert device ids */
 	convert_file("did", address, convert_did_entry, FALSE);
+
+	/* Convert sdp */
+	snprintf(filename, PATH_MAX, STORAGEDIR "/%s/sdp", address);
+	filename[PATH_MAX] = '\0';
+
+	str = textfile_get(filename, "converted");
+	if (str && strcmp(str, "yes") == 0) {
+		DBG("Legacy %s file already converted", filename);
+	} else {
+		textfile_foreach(filename, convert_sdp_entry, address);
+		textfile_put(filename, "converted", "yes");
+	}
+	free(str);
 }
 
 static void convert_config(struct btd_adapter *adapter, const char *filename,
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 08/14] device: Load services from storage
From: Frédéric Danis @ 2012-12-12 15:47 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1355327283-1558-1-git-send-email-frederic.danis@linux.intel.com>

Parse device attributes file for primary services, then add UUID service
to device pimaries list.
---
 src/device.c |   77 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 77 insertions(+)

diff --git a/src/device.c b/src/device.c
index da868b8..a515266 100644
--- a/src/device.c
+++ b/src/device.c
@@ -2067,6 +2067,82 @@ next:
 		store_device_info(device);
 }
 
+static void load_att_info(struct btd_device *device, const gchar *local,
+				const gchar *peer)
+{
+	char filename[PATH_MAX + 1];
+	GKeyFile *key_file;
+	char *prim_uuid, *str;
+	char **groups, **handle, *service_uuid;
+	struct gatt_primary *prim;
+	uuid_t uuid;
+	char tmp[3];
+	int i;
+
+	sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
+	prim_uuid = bt_uuid2string(&uuid);
+
+	snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/attributes", local,
+			peer);
+	filename[PATH_MAX] = '\0';
+
+	key_file = g_key_file_new();
+	g_key_file_load_from_file(key_file, filename, 0, NULL);
+	groups = g_key_file_get_groups(key_file, NULL);
+
+	for (handle = groups; *handle; handle++) {
+		str = g_key_file_get_string(key_file, *handle, "UUID", NULL);
+		if (!str)
+			continue;
+
+		if (!g_str_equal(str, prim_uuid))
+			continue;
+
+		g_free(str);
+
+		prim = g_new0(struct gatt_primary, 1);
+		prim->range.start = atoi(*handle);
+		str = g_key_file_get_string(key_file, *handle, "Value", NULL);
+		if (!str) {
+			g_free(prim);
+			continue;
+		}
+
+		switch (strlen(str)) {
+		case 4:
+			uuid.type = SDP_UUID16;
+			sscanf(str, "%04hx", &uuid.value.uuid16);
+		break;
+		case 8:
+			uuid.type = SDP_UUID32;
+			sscanf(str, "%08x", &uuid.value.uuid32);
+			break;
+		case 32:
+			uuid.type = SDP_UUID128;
+			memset(tmp, 0, sizeof(tmp));
+			for (i = 0; i < 16; i++) {
+				memcpy(tmp, str + (i * 2), 2);
+				uuid.value.uuid128.data[i] =
+						(uint8_t) strtol(tmp, NULL, 16);
+			}
+			break;
+		default:
+			continue;
+		}
+
+		service_uuid = bt_uuid2string(&uuid);
+		memcpy(prim->uuid, service_uuid, MAX_LEN_UUID_STR + 1);
+		g_free(service_uuid);
+		g_free(str);
+
+		device->primaries = g_slist_append(device->primaries, prim);
+	}
+
+	g_strfreev(groups);
+	g_key_file_free(key_file);
+	g_free(prim_uuid);
+}
+
 static struct btd_device *device_new(struct btd_adapter *adapter,
 				const gchar *address)
 {
@@ -2115,6 +2191,7 @@ struct btd_device *device_create_from_storage(struct btd_adapter *adapter,
 	ba2str(src, srcaddr);
 
 	load_info(device, srcaddr, address, key_file);
+	load_att_info(device, srcaddr, address);
 
 	return device;
 }
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 09/14] device: Update services from SDP records
From: Frédéric Danis @ 2012-12-12 15:47 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1355327283-1558-1-git-send-email-frederic.danis@linux.intel.com>

Update attributes file with primary services retrieved from attributes
entry in SDP records.

Remove store_record() from storage.[ch].
---
 src/device.c  |   75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/storage.c |   33 -------------------------
 src/storage.h |    2 --
 3 files changed, 74 insertions(+), 36 deletions(-)

diff --git a/src/device.c b/src/device.c
index a515266..6c3d5e8 100644
--- a/src/device.c
+++ b/src/device.c
@@ -2643,6 +2643,52 @@ static void uuids_changed(struct btd_device *device)
 	g_free(uuids);
 }
 
+static void store_primaries_from_sdp_record(GKeyFile *key_file,
+						sdp_record_t *rec)
+{
+	uuid_t uuid;
+	char *att_uuid, *prim_uuid;
+	uint16_t start = 0, end = 0, psm = 0;
+	char handle[6], uuid_str[33];
+	int i;
+
+	sdp_uuid16_create(&uuid, ATT_UUID);
+	att_uuid = bt_uuid2string(&uuid);
+
+	sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
+	prim_uuid = bt_uuid2string(&uuid);
+
+	if (!record_has_uuid(rec, att_uuid))
+		goto done;
+
+	if (!gatt_parse_record(rec, &uuid, &psm, &start, &end))
+		goto done;
+
+	sprintf(handle, "%hd", start);
+	switch (uuid.type) {
+	case SDP_UUID16:
+		sprintf(uuid_str, "%4.4X", uuid.value.uuid16);
+		break;
+	case SDP_UUID32:
+		sprintf(uuid_str, "%8.8X", uuid.value.uuid32);
+		break;
+	case SDP_UUID128:
+		for (i = 0; i < 16; i++)
+			sprintf(uuid_str + (i * 2), "%2.2X",
+					uuid.value.uuid128.data[i]);
+		break;
+	default:
+		uuid_str[0] = '\0';
+	}
+
+	g_key_file_set_string(key_file, handle, "UUID", prim_uuid);
+	g_key_file_set_string(key_file, handle, "Value", uuid_str);
+
+done:
+	g_free(prim_uuid);
+	g_free(att_uuid);
+}
+
 static int rec_cmp(const void *a, const void *b)
 {
 	const sdp_record_t *r1 = a;
@@ -2656,10 +2702,23 @@ static void update_bredr_services(struct browse_req *req, sdp_list_t *recs)
 	struct btd_device *device = req->device;
 	sdp_list_t *seq;
 	char srcaddr[18], dstaddr[18];
+	char filename[PATH_MAX + 1];
+	GKeyFile *key_file = NULL;
+	char *data;
+	gsize length = 0;
 
 	ba2str(adapter_get_address(device->adapter), srcaddr);
 	ba2str(&device->bdaddr, dstaddr);
 
+	if (!device->temporary) {
+		snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/attributes",
+							srcaddr, dstaddr);
+		filename[PATH_MAX] = '\0';
+
+		key_file = g_key_file_new();
+		g_key_file_load_from_file(key_file, filename, 0, NULL);
+	}
+
 	for (seq = recs; seq; seq = seq->next) {
 		sdp_record_t *rec = (sdp_record_t *) seq->data;
 		sdp_list_t *svcclass = NULL;
@@ -2713,7 +2772,8 @@ static void update_bredr_services(struct browse_req *req, sdp_list_t *recs)
 			continue;
 		}
 
-		store_record(srcaddr, dstaddr, device->bdaddr_type, rec);
+		if (key_file)
+			store_primaries_from_sdp_record(key_file, rec);
 
 		/* Copy record */
 		req->records = sdp_list_append(req->records,
@@ -2734,6 +2794,19 @@ static void update_bredr_services(struct browse_req *req, sdp_list_t *recs)
 
 		sdp_list_free(svcclass, free);
 	}
+
+	if (!key_file)
+		return;
+
+	data = g_key_file_to_data(key_file, &length, NULL);
+	if (length > 0) {
+		create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+		g_file_set_contents(filename, data, length, NULL);
+	}
+
+	g_free(data);
+
+	g_key_file_free(key_file);
 }
 
 static gint primary_cmp(gconstpointer a, gconstpointer b)
diff --git a/src/storage.c b/src/storage.c
index 17dfc21..5dfb8ea 100644
--- a/src/storage.c
+++ b/src/storage.c
@@ -288,39 +288,6 @@ int delete_entry(const bdaddr_t *src, const char *storage, const bdaddr_t *dst,
 	return err;
 }
 
-int store_record(const gchar *src, const gchar *dst, uint8_t dst_type,
-							sdp_record_t *rec)
-{
-	char filename[PATH_MAX + 1], key[30];
-	sdp_buf_t buf;
-	int err, size, i;
-	char *str;
-
-	create_name(filename, PATH_MAX, STORAGEDIR, src, "sdp");
-
-	create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
-	snprintf(key, sizeof(key), "%17s#%hhu#%08X", dst, dst_type,
-								rec->handle);
-
-	if (sdp_gen_record_pdu(rec, &buf) < 0)
-		return -1;
-
-	size = buf.data_size;
-
-	str = g_malloc0(size*2+1);
-
-	for (i = 0; i < size; i++)
-		sprintf(str + (i * 2), "%02X", buf.data[i]);
-
-	err = textfile_put(filename, key, str);
-
-	free(buf.data);
-	g_free(str);
-
-	return err;
-}
-
 sdp_record_t *record_from_string(const gchar *str)
 {
 	sdp_record_t *rec;
diff --git a/src/storage.h b/src/storage.h
index fdee61c..c390e46 100644
--- a/src/storage.h
+++ b/src/storage.h
@@ -38,8 +38,6 @@ int write_lastused_info(const bdaddr_t *local, const bdaddr_t *peer,
 ssize_t read_pin_code(const bdaddr_t *local, const bdaddr_t *peer, char *pin);
 int delete_entry(const bdaddr_t *src, const char *storage, const bdaddr_t *dst,
 							uint8_t dst_type);
-int store_record(const gchar *src, const gchar *dst, uint8_t dst_type,
-							sdp_record_t *rec);
 sdp_record_t *record_from_string(const gchar *str);
 sdp_record_t *fetch_record(const gchar *src, const gchar *dst,
 			   uint8_t dst_type, const uint32_t handle);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 10/14] adapter: Convert device primaries list
From: Frédéric Danis @ 2012-12-12 15:47 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1355327283-1558-1-git-send-email-frederic.danis@linux.intel.com>

---
 src/adapter.c |   95 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 95 insertions(+)

diff --git a/src/adapter.c b/src/adapter.c
index baeae79..754bc2a 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2728,6 +2728,88 @@ failed:
 	g_free(att_uuid);
 }
 
+static void convert_primaries_entry(char *key, char *value, void *user_data)
+{
+	char *address = user_data;
+	char device_type = -1;
+	uuid_t uuid;
+	char **services, **service, *prim_uuid;
+	char filename[PATH_MAX + 1];
+	GKeyFile *key_file;
+	int ret;
+	uint16_t start, end;
+	char uuid_str[MAX_LEN_UUID_STR + 1];
+	char *data;
+	gsize length = 0;
+
+	if (key[17] == '#') {
+		key[17] = '\0';
+		device_type = key[18] - '0';
+	}
+
+	if (bachk(key) != 0)
+		return;
+
+	services = g_strsplit(value, " ", 0);
+	if (services == NULL)
+		return;
+
+	sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
+	prim_uuid = bt_uuid2string(&uuid);
+
+	snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/attributes", address,
+									key);
+	filename[PATH_MAX] = '\0';
+
+	key_file = g_key_file_new();
+	g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+	for (service = services; *service; service++) {
+		ret = sscanf(*service, "%04hX#%04hX#%s", &start, &end,
+								uuid_str);
+		if (ret < 3)
+			continue;
+
+		bt_string2uuid(&uuid, uuid_str);
+		sdp_uuid128_to_uuid(&uuid);
+
+		store_attribute_uuid(key_file, start, prim_uuid, uuid);
+	}
+
+	g_strfreev(services);
+
+	data = g_key_file_to_data(key_file, &length, NULL);
+	if (length == 0)
+		goto end;
+
+	create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+	g_file_set_contents(filename, data, length, NULL);
+
+	if (device_type < 0)
+		goto end;
+
+	g_free(data);
+	g_key_file_free(key_file);
+
+	snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", address, key);
+	filename[PATH_MAX] = '\0';
+
+	key_file = g_key_file_new();
+	g_key_file_load_from_file(key_file, filename, 0, NULL);
+	set_device_type(key_file, device_type);
+
+	data = g_key_file_to_data(key_file, &length, NULL);
+	if (length > 0) {
+		create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+		g_file_set_contents(filename, data, length, NULL);
+	}
+
+end:
+	g_free(data);
+	g_free(prim_uuid);
+	g_key_file_free(key_file);
+}
+
 static void convert_device_storage(struct btd_adapter *adapter)
 {
 	char filename[PATH_MAX + 1];
@@ -2761,6 +2843,19 @@ static void convert_device_storage(struct btd_adapter *adapter)
 	/* Convert profiles */
 	convert_file("profiles", address, convert_profiles_entry, TRUE);
 
+	/* Convert primaries */
+	snprintf(filename, PATH_MAX, STORAGEDIR "/%s/primaries", address);
+	filename[PATH_MAX] = '\0';
+
+	str = textfile_get(filename, "converted");
+	if (str && strcmp(str, "yes") == 0) {
+		DBG("Legacy %s file already converted", filename);
+	} else {
+		textfile_foreach(filename, convert_primaries_entry, address);
+		textfile_put(filename, "converted", "yes");
+	}
+	free(str);
+
 	/* Convert linkkeys */
 	convert_file("linkkeys", address, convert_linkkey_entry, TRUE);
 
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 11/14] adapter: Register services after device creation
From: Frédéric Danis @ 2012-12-12 15:48 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1355327283-1558-1-git-send-email-frederic.danis@linux.intel.com>

Add device_register_services_from_primaries() to device.c to allow
to register from device->primaries pre-loaded during device creation
from storage.

As all device load during start-up has been converted, we can remove
temporary hack in device_create().
---
 src/adapter.c |   80 ++-------------------------------------------------------
 src/device.c  |   28 +++++++++-----------
 src/device.h  |    1 +
 3 files changed, 15 insertions(+), 94 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index 754bc2a..1a220cf 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -1728,80 +1728,6 @@ failed:
 	return ltk;
 }
 
-static GSList *string_to_primary_list(char *str)
-{
-	GSList *l = NULL;
-	char **services;
-	int i;
-
-	if (str == NULL)
-		return NULL;
-
-	services = g_strsplit(str, " ", 0);
-	if (services == NULL)
-		return NULL;
-
-	for (i = 0; services[i]; i++) {
-		struct gatt_primary *prim;
-		int ret;
-
-		prim = g_new0(struct gatt_primary, 1);
-
-		ret = sscanf(services[i], "%04hX#%04hX#%s", &prim->range.start,
-							&prim->range.end, prim->uuid);
-
-		if (ret < 3) {
-			g_free(prim);
-			continue;
-		}
-
-		l = g_slist_append(l, prim);
-	}
-
-	g_strfreev(services);
-
-	return l;
-}
-
-static void create_stored_device_from_primaries(char *key, char *value,
-							void *user_data)
-{
-	struct btd_adapter *adapter = user_data;
-	struct btd_device *device;
-	GSList *services, *uuids, *l;
-	char address[18];
-	uint8_t bdaddr_type;
-
-	if (sscanf(key, "%17s#%hhu", address, &bdaddr_type) < 2)
-		return;
-
-	if (g_slist_find_custom(adapter->devices,
-			address, (GCompareFunc) device_address_cmp))
-		return;
-
-	device = device_create(adapter, address, bdaddr_type);
-	if (!device)
-		return;
-
-	device_set_temporary(device, FALSE);
-	adapter->devices = g_slist_append(adapter->devices, device);
-
-	services = string_to_primary_list(value);
-	if (services == NULL)
-		return;
-
-	for (l = services, uuids = NULL; l; l = l->next) {
-		struct gatt_primary *prim = l->data;
-		uuids = g_slist_append(uuids, prim->uuid);
-	}
-
-	device_register_services(device, services, -1);
-
-	device_probe_profiles(device, uuids);
-
-	g_slist_free(uuids);
-}
-
 static void load_devices(struct btd_adapter *adapter)
 {
 	char filename[PATH_MAX + 1];
@@ -1814,10 +1740,6 @@ static void load_devices(struct btd_adapter *adapter)
 
 	ba2str(&adapter->bdaddr, srcaddr);
 
-	create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "primaries");
-	textfile_foreach(filename, create_stored_device_from_primaries,
-								adapter);
-
 	snprintf(filename, PATH_MAX, STORAGEDIR "/%s", srcaddr);
 	filename[PATH_MAX] = '\0';
 
@@ -1867,6 +1789,8 @@ static void load_devices(struct btd_adapter *adapter)
 		device_set_temporary(device, FALSE);
 		adapter->devices = g_slist_append(adapter->devices, device);
 
+		device_register_services_from_primaries(device);
+
 		l = device_get_uuids(device);
 		if (l)
 			device_probe_profiles(device, l);
diff --git a/src/device.c b/src/device.c
index 6c3d5e8..9c3211c 100644
--- a/src/device.c
+++ b/src/device.c
@@ -2202,8 +2202,7 @@ struct btd_device *device_create(struct btd_adapter *adapter,
 	struct btd_device *device;
 	const bdaddr_t *src;
 	char srcaddr[18];
-	char filename[PATH_MAX + 1];
-	GKeyFile *key_file;
+	char *str;
 
 	device = device_new(adapter, address);
 	if (device == NULL)
@@ -2213,24 +2212,21 @@ struct btd_device *device_create(struct btd_adapter *adapter,
 	src = adapter_get_address(adapter);
 	ba2str(src, srcaddr);
 
-	/*TODO: after all device load during start-up has been converted to
-	 * new key file structure, this should be replaced by :
-	 *	str = load_cached_name(device, srcaddr, address);
-	 *	if (str) {
-	 *		strcpy(device->name, str);
-	 *		g_free(str);
-	 *	}
-	 */
-	snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", srcaddr,
-			address);
-	key_file = g_key_file_new();
-	g_key_file_load_from_file(key_file, filename, 0, NULL);
-	load_info(device, srcaddr, address, key_file);
-	g_key_file_free(key_file);
+	str = load_cached_name(device, srcaddr, address);
+	if (str) {
+		strcpy(device->name, str);
+		g_free(str);
+	}
 
 	return btd_device_ref(device);
 }
 
+void device_register_services_from_primaries(struct btd_device *device)
+{
+	device->services = attrib_client_register(device, -1, NULL,
+							device->primaries);
+}
+
 void device_set_name(struct btd_device *device, const char *name)
 {
 	if (strncmp(name, device->name, MAX_NAME_LENGTH) == 0)
diff --git a/src/device.h b/src/device.h
index 1785a75..750b1ea 100644
--- a/src/device.h
+++ b/src/device.h
@@ -30,6 +30,7 @@ struct btd_device *device_create(struct btd_adapter *adapter,
 				const char *address, uint8_t bdaddr_type);
 struct btd_device *device_create_from_storage(struct btd_adapter *adapter,
 				const char *address, GKeyFile *key_file);
+void device_register_services_from_primaries(struct btd_device *device);
 
 void device_set_name(struct btd_device *device, const char *name);
 void device_get_name(struct btd_device *device, char *name, size_t len);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 12/14] device: Add device_get_storage_path()
From: Frédéric Danis @ 2012-12-12 15:48 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1355327283-1558-1-git-send-email-frederic.danis@linux.intel.com>

---
 src/device.c |   15 +++++++++++++++
 src/device.h |    2 ++
 2 files changed, 17 insertions(+)

diff --git a/src/device.c b/src/device.c
index 9c3211c..6cec4a0 100644
--- a/src/device.c
+++ b/src/device.c
@@ -2227,6 +2227,21 @@ void device_register_services_from_primaries(struct btd_device *device)
 							device->primaries);
 }
 
+char *device_get_storage_path(struct btd_device *device,
+				const char *filename)
+{
+	char srcaddr[18], dstaddr[18];
+
+	ba2str(adapter_get_address(device->adapter), srcaddr);
+	ba2str(&device->bdaddr, dstaddr);
+
+	if (!filename)
+		return g_strdup_printf(STORAGEDIR "/%s/%s", srcaddr, dstaddr);
+
+	return g_strdup_printf(STORAGEDIR "/%s/%s/%s", srcaddr, dstaddr,
+							filename);
+}
+
 void device_set_name(struct btd_device *device, const char *name)
 {
 	if (strncmp(name, device->name, MAX_NAME_LENGTH) == 0)
diff --git a/src/device.h b/src/device.h
index 750b1ea..94adaa3 100644
--- a/src/device.h
+++ b/src/device.h
@@ -31,6 +31,8 @@ struct btd_device *device_create(struct btd_adapter *adapter,
 struct btd_device *device_create_from_storage(struct btd_adapter *adapter,
 				const char *address, GKeyFile *key_file);
 void device_register_services_from_primaries(struct btd_device *device);
+char *device_get_storage_path(struct btd_device *device,
+				const char *filename);
 
 void device_set_name(struct btd_device *device, const char *name);
 void device_get_name(struct btd_device *device, char *name, size_t len);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 13/14] device: Retrieve records from tmp_records only
From: Frédéric Danis @ 2012-12-12 15:48 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1355327283-1558-1-git-send-email-frederic.danis@linux.intel.com>

SDP records are no more stored, so they can only be retrieved
from remote device (tmp_records during bonding).
---
 src/device.c |   24 ++++++++++--------------
 1 file changed, 10 insertions(+), 14 deletions(-)

diff --git a/src/device.c b/src/device.c
index 6cec4a0..a7f85d1 100644
--- a/src/device.c
+++ b/src/device.c
@@ -4220,24 +4220,20 @@ void btd_device_add_uuid(struct btd_device *device, const char *uuid)
 const sdp_record_t *btd_device_get_record(struct btd_device *device,
 							const char *uuid)
 {
-	if (device->tmp_records) {
-		const sdp_record_t *record;
+	const sdp_record_t *record;
 
-		record = find_record_in_list(device->tmp_records, uuid);
-		if (record != NULL)
-			return record;
-
-		sdp_list_free(device->tmp_records,
-					(sdp_free_func_t) sdp_record_free);
-		device->tmp_records = NULL;
-	}
-
-	device->tmp_records = read_records(adapter_get_address(device->adapter),
-							&device->bdaddr);
 	if (!device->tmp_records)
 		return NULL;
 
-	return find_record_in_list(device->tmp_records, uuid);
+	record = find_record_in_list(device->tmp_records, uuid);
+	if (record != NULL)
+		return record;
+
+	sdp_list_free(device->tmp_records,
+				(sdp_free_func_t) sdp_record_free);
+	device->tmp_records = NULL;
+
+	return NULL;
 }
 
 struct btd_device *btd_device_ref(struct btd_device *device)
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 14/14] input: Use new storage architecture
From: Frédéric Danis @ 2012-12-12 15:48 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1355327283-1558-1-git-send-email-frederic.danis@linux.intel.com>

When an input device is probed, it tries to retrieve its SDP record
from "input" file in storage directory.
If this fails, during bonding phase, records is vailable from device
object.

During connection, retrieve SDP record from "input" file.
---
 profiles/input/device.c  |   17 ++++++++---
 profiles/input/manager.c |   75 +++++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 84 insertions(+), 8 deletions(-)

diff --git a/profiles/input/device.c b/profiles/input/device.c
index 2d8077a..5eba0be 100644
--- a/profiles/input/device.c
+++ b/profiles/input/device.c
@@ -316,7 +316,8 @@ static gboolean encrypt_notify(GIOChannel *io, GIOCondition condition,
 static int hidp_add_connection(struct input_device *idev)
 {
 	struct hidp_connadd_req *req;
-	uint8_t dst_type;
+	char *filename, *data;
+	GKeyFile *key_file = NULL;
 	sdp_record_t *rec;
 	char src_addr[18], dst_addr[18];
 	GError *gerr = NULL;
@@ -331,15 +332,23 @@ static int hidp_add_connection(struct input_device *idev)
 	ba2str(&idev->src, src_addr);
 	ba2str(&idev->dst, dst_addr);
 
-	dst_type = device_get_addr_type(idev->device);
+	filename = device_get_storage_path(idev->device, "input");
 
-	rec = fetch_record(src_addr, dst_addr, dst_type, idev->handle);
-	if (!rec) {
+	key_file = g_key_file_new();
+	g_key_file_load_from_file(key_file, filename, 0, NULL);
+	data = g_key_file_get_string(key_file, "SDP", "Record", NULL);
+	g_key_file_free(key_file);
+	g_free(filename);
+
+	if (!data) {
 		error("Rejected connection from unknown device %s", dst_addr);
 		err = -EPERM;
 		goto cleanup;
 	}
 
+	rec = record_from_string(data);
+	g_free(data);
+
 	extract_hid_record(rec, req);
 	sdp_record_free(rec);
 
diff --git a/profiles/input/manager.c b/profiles/input/manager.c
index 622e24b..db42c34 100644
--- a/profiles/input/manager.c
+++ b/profiles/input/manager.c
@@ -27,6 +27,8 @@
 
 #include <errno.h>
 #include <stdbool.h>
+#include <stdlib.h>
+#include <fcntl.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/sdp.h>
@@ -42,6 +44,7 @@
 #include "device.h"
 #include "server.h"
 #include "manager.h"
+#include "storage.h"
 
 static int idle_timeout = 0;
 
@@ -54,19 +57,83 @@ static void input_remove(struct btd_device *device, const char *uuid)
 	input_device_unregister(path, uuid);
 }
 
+static void store_hid_record(char *filename, const sdp_record_t *rec)
+{
+	sdp_buf_t buf;
+	int size, i;
+	char *str, *data;
+	GKeyFile *key_file = NULL;
+	gsize length = 0;
+
+	if (sdp_gen_record_pdu(rec, &buf) < 0)
+		return;
+
+	size = buf.data_size;
+	str = g_malloc0(size*2+1);
+
+	for (i = 0; i < size; i++)
+		sprintf(str + (i * 2), "%02X", buf.data[i]);
+
+	free(buf.data);
+
+	key_file = g_key_file_new();
+	g_key_file_set_string(key_file, "SDP", "Record", str);
+
+	data = g_key_file_to_data(key_file, &length, NULL);
+	if (length > 0) {
+		create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+		g_file_set_contents(filename, data, length, NULL);
+	}
+
+	g_free(data);
+	g_free(str);
+
+	g_key_file_free(key_file);
+}
+
 static int hid_device_probe(struct btd_profile *p, struct btd_device *device,
 								GSList *uuids)
 {
 	const gchar *path = device_get_path(device);
 	const sdp_record_t *rec = btd_device_get_record(device, uuids->data);
+	sdp_record_t *stored_rec;
+	char *filename, *data;
+	GKeyFile *key_file = NULL;
+	int err;
 
 	DBG("path %s", path);
 
-	if (!rec)
-		return -1;
+	filename = device_get_storage_path(device, "input");
+
+	if (rec) {
+		store_hid_record(filename, rec);
+
+		err = input_device_register(device, path, HID_UUID, rec,
+						idle_timeout * 60);
+		goto end;
+	}
+
+	key_file = g_key_file_new();
+	g_key_file_load_from_file(key_file, filename, 0, NULL);
+	data = g_key_file_get_string(key_file, "SDP", "Record", NULL);
+	g_key_file_free(key_file);
+
+	if (!data) {
+		err = -1;
+		goto end;
+	}
+
+	stored_rec = record_from_string(data);
+	g_free(data);
+
+	err = input_device_register(device, path, HID_UUID, stored_rec,
+						idle_timeout * 60);
+	sdp_record_free(stored_rec);
+
+end:
+	g_free(filename);
 
-	return input_device_register(device, path, HID_UUID, rec,
-							idle_timeout * 60);
+	return err;
 }
 
 static void hid_device_remove(struct btd_profile *p, struct btd_device *device)
-- 
1.7.9.5


^ permalink raw reply related

* Re: [PATCH BlueZ 01/11] obexd: Port bluetooth plugin to use external profile support
From: Mikel Astiz @ 2012-12-12 16:38 UTC (permalink / raw)
  To: Luiz Augusto von Dentz, linux-bluetooth
In-Reply-To: <20121212120236.GA11264@x220.ger.corp.intel.com>

Hi Johan, Luiz,

On Wed, Dec 12, 2012 at 1:02 PM, Johan Hedberg <johan.hedberg@gmail.com> wrote:
> Hi Luiz,
>
> On Wed, Dec 12, 2012, Luiz Augusto von Dentz wrote:
>> This changes obexd to use ProfileManager.RegisterProfile
>> ---
>>  obexd/plugins/bluetooth.c | 696 ++++++++++++++--------------------------------
>>  1 file changed, 212 insertions(+), 484 deletions(-)
>
> All patches in this set have been applied. I also removed the service
> plugin in the same go as now all known users of it are gone.

I'm a bit confused with these recent changes. I haven't been following
this closely so I guess I'm missing the Big Plan but let me start with
the basics: both bluetoothd and obexd repositories were merged but I
believe both daemons are still going to be separate daemons, is this
correct?

If yes, it makes sense that obexd makes use of the "external profile"
infrastructure.

But in that case, why would we add any obex-specific code into
bluetoothd? My understanding was that, if a profile is implemented as
an external profile, the bluetoothd core would not be aware of it.

Cheers,
Mikel

^ permalink raw reply

* Rayson BTM-112 support
From: Wojciech Kazubski @ 2012-12-12 16:49 UTC (permalink / raw)
  To: linux-bluetooth

Hello

I am trying to make Rayson BTM-112 module working with Linux. This is the BT 
module designed to use with microcontolers  and supports SPP profile. It works 
out of the box with Windows (creating two seriarial ports - COM8 and COM 9 or 
so) and I can pair it under Linux but no serial port is created.

Have I missed anything? (any bluez modules that have to be installed 
separately? modprobe entries?)

I am using Fedora 17 and openSUSE 12.2 and the module is not working in both 
distributions. 

Wojciech Kazubski



^ permalink raw reply

* Re: [PATCH BlueZ 01/11] obexd: Port bluetooth plugin to use external profile support
From: Johan Hedberg @ 2012-12-12 18:55 UTC (permalink / raw)
  To: Mikel Astiz; +Cc: Luiz Augusto von Dentz, linux-bluetooth
In-Reply-To: <CANT-zCWrF=xz-ud=tKbds9Fag5uH+ryLL3ZiQG=APqcZgEq0ug@mail.gmail.com>

Hi Mikel,

On Wed, Dec 12, 2012, Mikel Astiz wrote:
> I'm a bit confused with these recent changes. I haven't been following
> this closely so I guess I'm missing the Big Plan but let me start with
> the basics: both bluetoothd and obexd repositories were merged but I
> believe both daemons are still going to be separate daemons, is this
> correct?
> 
> If yes, it makes sense that obexd makes use of the "external profile"
> infrastructure.
> 
> But in that case, why would we add any obex-specific code into
> bluetoothd? My understanding was that, if a profile is implemented as
> an external profile, the bluetoothd core would not be aware of it.

No, bluetoothd still takes care of SDP record registration,
server/client socket handling, authorization, etc. Some external
profiles (like HFP implemented through oFono) also take part in the
Device.Connect connection procedure (this is particularly important for
HFP since it needs to be the first of the audio profiles to be
connected).

>From the L2CAP/RFCOMM connection establishment onwards the external
profile takes over though through the NewConnection method.

Johan

^ permalink raw reply

* Re: [RFC 04/16] Bluetooth: add l2cap_state_change_and_error()
From: Gustavo Padovan @ 2012-12-12 19:26 UTC (permalink / raw)
  To: Anderson Lizardo; +Cc: linux-bluetooth, Gustavo Padovan
In-Reply-To: <CAJdJm_PMBC8nivsJuYDp-wW5ei1WF7m3SJzh78RScUyQu5ApJQ@mail.gmail.com>

* Anderson Lizardo <anderson.lizardo@openbossa.org> [2012-12-12 09:40:06 -0400]:

> Hi Gustavo,
> 
> On Wed, Dec 12, 2012 at 12:13 AM, Gustavo Padovan <gustavo@padovan.org> wrote:
> > @@ -238,7 +244,7 @@ static inline void l2cap_chan_set_err(struct l2cap_chan *chan, int err)
> >         struct sock *sk = chan->sk;
> >
> >         lock_sock(sk);
> > -       __l2cap_chan_set_err(chan, err);
> > +       chan->ops->state_change(chan, chan->state, 0);
> 
> Why "0" and not "err" ?

Yes, it is "err" here. I fixed both issues you reported.

	Gustavo

^ permalink raw reply

* Re: [RFC 12/16] Bluetooth: Use abstract chan->data in comparison
From: Gustavo Padovan @ 2012-12-12 19:57 UTC (permalink / raw)
  To: Andrei Emeltchenko, linux-bluetooth, Gustavo Padovan
In-Reply-To: <20121212082009.GA7034@aemeltch-MOBL1>

Hi Andrei,

* Andrei Emeltchenko <andrei.emeltchenko.news@gmail.com> [2012-12-12 10:20:11 +0200]:

> Hi Gustavo,
> 
> On Wed, Dec 12, 2012 at 02:13:40AM -0200, Gustavo Padovan wrote:
> > From: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
> > 
> > If the L2CAP user is l2cap_sock.c chan->data is a pointer to the l2cap
> > socket so chan->sk and chan->data are the same thing. Then we can just
> > compare with chan->data instead.
> > 
> > Non-socket users will have skb->sk = NULL, thus this change does not
> > interfere in other users.
> > 
> > Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
> > ---
> >  net/bluetooth/l2cap_core.c | 3 +--
> >  1 file changed, 1 insertion(+), 2 deletions(-)
> > 
> > diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> > index 934ac1b..92936db 100644
> > --- a/net/bluetooth/l2cap_core.c
> > +++ b/net/bluetooth/l2cap_core.c
> > @@ -2682,12 +2682,11 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
> >  	mutex_lock(&conn->chan_lock);
> >  
> >  	list_for_each_entry(chan, &conn->chan_l, list) {
> > -		struct sock *sk = chan->sk;
> >  		if (chan->chan_type != L2CAP_CHAN_RAW)
> >  			continue;
> >  
> >  		/* Don't send frame to the socket it came from */
> > -		if (skb->sk == sk)
> > +		if (skb->sk && skb->sk == chan->data)
> 
> In the other patch you delete chan->sk pointer and then we have only
> chan->data which points to sk. What is the reason for that? This would
> confuse people reading chan->data guessing what the hell is this.
> 
> I really think we can leave chan->sk if it is needed and it is better to
> remove chan->data.

chan->data is the generic data pointer for l2cap users, l2cap_sock.c puts an
struct sock while a2mp.c puts struct amp_mgr there. I'll better add a comment
to struct l2cap_chan saying what it is for instead of re-adding struct sock.

	Gustavo

^ permalink raw reply

* RE: [BLE] org.bluez.Device1.Connect() returns org.bluez.Error.NotAvailable
From: Ting Chou @ 2012-12-13  2:33 UTC (permalink / raw)
  To: Anderson Lizardo; +Cc: Johan Hedberg, linux-bluetooth@vger.kernel.org
In-Reply-To: <CAJdJm_PPnSmEV0nmjeka6vLa9qG9-FvZTvhypi9mfVyw+KxH+Q@mail.gmail.com>

Hi Anderson,

> > I'm not sure if I understand correctly. But do you mean the GCEP you
> > mentioned above is applied while "reconnecting" to a supported device?
> 
> Yes, all GAP connection procedures are applicable for re-connection.
> There is no "reconnection" procedure as per GAP (as far as I know).
> But note that each GATT profile can specify reconnection procedures in
> case of disconnection due to link loss (most of those that I read have
> this). For instance, in HTP:
> 
> "5.2.4 Link Loss Reconnection Procedure
> When a connection is terminated due to link loss, a Collector should
> attempt to reconnect to the Thermometer using any of the GAP connection
> procedures with the parameters in Table 5.2."
> 
> This is what BlueZ is doing for profiles implemented internally, except
> that the parameters we use are not the ones recommended on the profile
> specs (that could be implemented in future, but for now GCEP uses fixed
> connection parameters).
> 

So I should exercise the D-Bus API like following for LE device:

  Adapter1.StartDiscovery
  Device1.Pair
  ...
  ...
  // link loss
  ...
  // auto reconnect
  ...
  Adapter1.RemoveDevice

Is my understanding correct?

Thank you,
Ting

^ permalink raw reply

* Re: [BLE] org.bluez.Device1.Connect() returns org.bluez.Error.NotAvailable
From: Johan Hedberg @ 2012-12-13  7:48 UTC (permalink / raw)
  To: Ting Chou; +Cc: Anderson Lizardo, linux-bluetooth@vger.kernel.org
In-Reply-To: <ADCBF04BB97EBF4AAE65663F8478B61CA99E65AC43@Luna.iaSolution.net>

Hi Ting,

On Thu, Dec 13, 2012, Ting Chou wrote:
> > > I'm not sure if I understand correctly. But do you mean the GCEP you
> > > mentioned above is applied while "reconnecting" to a supported device?
> > 
> > Yes, all GAP connection procedures are applicable for re-connection.
> > There is no "reconnection" procedure as per GAP (as far as I know).
> > But note that each GATT profile can specify reconnection procedures in
> > case of disconnection due to link loss (most of those that I read have
> > this). For instance, in HTP:
> > 
> > "5.2.4 Link Loss Reconnection Procedure
> > When a connection is terminated due to link loss, a Collector should
> > attempt to reconnect to the Thermometer using any of the GAP connection
> > procedures with the parameters in Table 5.2."
> > 
> > This is what BlueZ is doing for profiles implemented internally, except
> > that the parameters we use are not the ones recommended on the profile
> > specs (that could be implemented in future, but for now GCEP uses fixed
> > connection parameters).
> > 
> 
> So I should exercise the D-Bus API like following for LE device:
> 
>   Adapter1.StartDiscovery
>   Device1.Pair
>   ...
>   ...
>   // link loss
>   ...
>   // auto reconnect
>   ...
>   Adapter1.RemoveDevice
> 
> Is my understanding correct?

Yes, except that you should call Adapter1.StopDiscovery before calling
Device1.Pair.

Johan

^ permalink raw reply

* [PATCH BlueZ] build: Remove obexd usb plugin
From: Luiz Augusto von Dentz @ 2012-12-13 12:03 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This plugin is not longer maintained and used to work only in meego
times.
---
 Makefile.obexd      |   5 -
 obexd/plugins/usb.c | 299 ----------------------------------------------------
 2 files changed, 304 deletions(-)
 delete mode 100644 obexd/plugins/usb.c

diff --git a/Makefile.obexd b/Makefile.obexd
index 9498ac1..e6536bc 100644
--- a/Makefile.obexd
+++ b/Makefile.obexd
@@ -11,11 +11,6 @@ obexd_builtin_sources += obexd/plugins/filesystem.c obexd/plugins/filesystem.h
 obexd_builtin_modules += bluetooth
 obexd_builtin_sources += obexd/plugins/bluetooth.c
 
-if USB
-obexd_builtin_modules += usb
-obexd_builtin_sources += obexd/plugins/usb.c
-endif
-
 if EXPERIMENTAL
 obexd_builtin_modules += pcsuite
 obexd_builtin_sources += obexd/plugins/pcsuite.c
diff --git a/obexd/plugins/usb.c b/obexd/plugins/usb.c
deleted file mode 100644
index 1c3da3e..0000000
--- a/obexd/plugins/usb.c
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- *
- *  OBEX Server
- *
- *  Copyright (C) 2007-2010  Nokia Corporation
- *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <termios.h>
-#include <inttypes.h>
-
-#include <glib.h>
-#include <gdbus/gdbus.h>
-
-#include "obexd.h"
-#include "plugin.h"
-#include "server.h"
-#include "obex.h"
-#include "transport.h"
-#include "service.h"
-#include "log.h"
-
-static GIOChannel *usb_io = NULL;
-static guint usb_reconnecting = 0;
-static guint usb_watch = 0;
-static DBusConnection *connection = NULL;
-
-#define USB_RX_MTU 65535
-#define USB_TX_MTU 65535
-#define USB_DEVNODE "/dev/ttyGS0"
-
-static int usb_connect(struct obex_server *server);
-
-static void usb_disconnect(struct obex_server *server)
-{
-	if (usb_reconnecting > 0) {
-		g_source_remove(usb_reconnecting);
-		usb_reconnecting = 0;
-	}
-
-	if (usb_watch > 0) {
-		g_source_remove(usb_watch);
-		usb_watch = 0;
-	}
-
-	/* already disconnected */
-	if (usb_io == NULL)
-		return;
-
-	g_io_channel_shutdown(usb_io, TRUE, NULL);
-	g_io_channel_unref(usb_io);
-	usb_io = NULL;
-	DBG("disconnected");
-}
-
-static gboolean usb_reconnect(void *data)
-{
-	struct obex_server *server = data;
-
-	DBG("reconnecting");
-	usb_reconnecting = 0;
-	usb_connect(server);
-
-	return FALSE;
-}
-
-static gboolean usb_watchdog(GIOChannel *io, GIOCondition cond,
-				void *user_data)
-{
-	struct obex_server *server = user_data;
-
-	usb_watch = 0;
-	usb_disconnect(server);
-
-	if ((cond & G_IO_NVAL) == FALSE)
-		usb_reconnecting = g_idle_add(usb_reconnect, server);
-
-	return FALSE;
-}
-
-static int usb_connect(struct obex_server *server)
-{
-	struct termios options;
-	int fd, err, arg;
-	glong flags;
-
-	if (usb_reconnecting > 0) {
-		g_source_remove(usb_reconnecting);
-		usb_reconnecting = 0;
-	}
-
-	/* already connected */
-	if (usb_io != NULL)
-		return 0;
-
-	fd = open(USB_DEVNODE, O_RDWR | O_NOCTTY);
-	if (fd < 0)
-		return fd;
-
-	flags = fcntl(fd, F_GETFL);
-	fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
-
-	tcgetattr(fd, &options);
-	cfmakeraw(&options);
-	options.c_oflag &= ~ONLCR;
-	tcsetattr(fd, TCSANOW, &options);
-
-	arg = fcntl(fd, F_GETFL);
-	if (arg < 0) {
-		err = -errno;
-		goto failed;
-	}
-
-	arg |= O_NONBLOCK;
-	if (fcntl(fd, F_SETFL, arg) < 0) {
-		err = -errno;
-		goto failed;
-	}
-
-	usb_io = g_io_channel_unix_new(fd);
-	g_io_channel_set_close_on_unref(usb_io, TRUE);
-
-	err = obex_server_new_connection(server, usb_io, USB_TX_MTU,
-							USB_RX_MTU, TRUE);
-	if (err < 0)
-		goto failed;
-
-	usb_watch = g_io_add_watch(usb_io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-					usb_watchdog, server);
-
-	DBG("Successfully opened %s", USB_DEVNODE);
-
-	return 0;
-
-failed:
-	error("usb: %s (%d)", strerror(-err), -err);
-	if (usb_io == NULL)
-		close(fd);
-	else
-		usb_disconnect(server);
-	return err;
-}
-
-static void sig_usb(int sig)
-{
-}
-
-static void usb_set_mode(struct obex_server *server, const char *mode)
-{
-	DBG("%s", mode);
-
-	if (g_str_equal(mode, "ovi_suite") == TRUE)
-		usb_connect(server);
-	else if (g_str_equal(mode, "USB disconnected") == TRUE)
-		usb_disconnect(server);
-}
-
-static gboolean handle_signal(DBusConnection *connection,
-				DBusMessage *message, void *user_data)
-{
-	struct obex_server *server = user_data;
-	const char *mode;
-
-	dbus_message_get_args(message, NULL,
-				DBUS_TYPE_STRING, &mode,
-				DBUS_TYPE_INVALID);
-
-	usb_set_mode(server, mode);
-
-	return TRUE;
-}
-
-static void usb_stop(void *data)
-{
-	guint id = GPOINTER_TO_UINT(data);
-	g_dbus_remove_watch(connection, id);
-}
-
-static void mode_request_reply(DBusPendingCall *call, void *user_data)
-{
-	struct obex_server *server = user_data;
-	DBusMessage *reply = dbus_pending_call_steal_reply(call);
-	DBusError derr;
-
-	dbus_error_init(&derr);
-	if (dbus_set_error_from_message(&derr, reply)) {
-		error("usb: Replied with an error: %s, %s",
-				derr.name, derr.message);
-		dbus_error_free(&derr);
-	} else {
-		const char *mode;
-		dbus_message_get_args(reply, NULL,
-				DBUS_TYPE_STRING, &mode,
-				DBUS_TYPE_INVALID);
-
-		usb_set_mode(server, mode);
-	}
-
-	dbus_message_unref(reply);
-}
-
-static void *usb_start(struct obex_server *server, int *err)
-{
-	guint id;
-	DBusMessage *msg;
-	DBusPendingCall *call;
-
-	msg = dbus_message_new_method_call("com.meego.usb_moded",
-						"/com/meego/usb_moded",
-						"com.meego.usb_moded",
-						"mode_request");
-
-	if (dbus_connection_send_with_reply(connection,
-					msg, &call, -1) == FALSE) {
-		error("usb: unable to send mode_request");
-		dbus_message_unref(msg);
-		goto fail;
-	}
-
-	dbus_pending_call_set_notify(call, mode_request_reply, server, NULL);
-	dbus_pending_call_unref(call);
-	dbus_message_unref(msg);
-
-	id = g_dbus_add_signal_watch(connection, NULL, NULL,
-					"com.meego.usb_moded",
-					"sig_usb_state_ind",
-					handle_signal, server, NULL);
-
-	if (err != NULL)
-		*err = 0;
-
-	return GUINT_TO_POINTER(id);
-
-fail:
-	if (err != NULL)
-		*err = -1;
-
-	return NULL;
-}
-
-static struct obex_transport_driver driver = {
-	.name = "usb",
-	.service = OBEX_PCSUITE,
-	.start = usb_start,
-	.stop = usb_stop
-};
-
-static int usb_init(void)
-{
-	struct sigaction sa;
-
-	memset(&sa, 0, sizeof(sa));
-	sa.sa_handler = sig_usb;
-	sigaction(SIGUSR1, &sa, NULL);
-	sigaction(SIGHUP, &sa, NULL);
-
-	connection = g_dbus_setup_private(DBUS_BUS_SYSTEM, NULL, NULL);
-	if (connection == NULL)
-		return -EPERM;
-
-	return obex_transport_driver_register(&driver);
-}
-
-static void usb_exit(void)
-{
-	if (connection)
-		dbus_connection_unref(connection);
-
-	obex_transport_driver_unregister(&driver);
-}
-
-OBEX_PLUGIN_DEFINE(usb, usb_init, usb_exit)
-- 
1.7.11.7


^ permalink raw reply related

* Re: [PATCH BlueZ] build: Remove obexd usb plugin
From: Johan Hedberg @ 2012-12-13 12:27 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <1355400231-25205-1-git-send-email-luiz.dentz@gmail.com>

Hi Luiz,

On Thu, Dec 13, 2012, Luiz Augusto von Dentz wrote:
> This plugin is not longer maintained and used to work only in meego
> times.
> ---
>  Makefile.obexd      |   5 -
>  obexd/plugins/usb.c | 299 ----------------------------------------------------
>  2 files changed, 304 deletions(-)
>  delete mode 100644 obexd/plugins/usb.c

Applied. Thanks.

Johan

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox