3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2011 Nokia Corporation
6 * Copyright (C) 2011 Marcel Holtmann <marcel@holtmann.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 #include <bluetooth/uuid.h>
34 #include <dbus/dbus.h>
39 #include "dbus-common.h"
46 #include "att-database.h"
47 #include "attrib-server.h"
52 #define BLUEZ_SERVICE "org.bluez"
54 struct reporter_adapter {
56 struct btd_adapter *adapter;
60 static GSList *reporter_adapters;
62 static int radapter_cmp(gconstpointer a, gconstpointer b)
64 const struct reporter_adapter *radapter = a;
65 const struct btd_adapter *adapter = b;
67 if (radapter->adapter == adapter)
73 static struct reporter_adapter *
74 find_reporter_adapter(struct btd_adapter *adapter)
76 GSList *l = g_slist_find_custom(reporter_adapters, adapter,
84 const char *get_alert_level_string(uint8_t level)
98 static void register_tx_power(struct btd_adapter *adapter)
100 uint16_t start_handle, h;
101 const int svc_size = 4;
105 bt_uuid16_create(&uuid, TX_POWER_SVC_UUID);
106 start_handle = attrib_db_find_avail(adapter, &uuid, svc_size);
107 if (start_handle == 0) {
108 error("Not enough free handles to register service");
112 DBG("start_handle=0x%04x", start_handle);
116 /* Primary service definition */
117 bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
118 att_put_u16(TX_POWER_SVC_UUID, &atval[0]);
119 attrib_db_add(adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 2);
121 /* Power level characteristic */
122 bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
123 atval[0] = ATT_CHAR_PROPER_READ | ATT_CHAR_PROPER_NOTIFY;
124 att_put_u16(h + 1, &atval[1]);
125 att_put_u16(POWER_LEVEL_CHR_UUID, &atval[3]);
126 attrib_db_add(adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 5);
128 /* Power level value */
129 bt_uuid16_create(&uuid, POWER_LEVEL_CHR_UUID);
130 att_put_u8(0x00, &atval[0]);
131 attrib_db_add(adapter, h++, &uuid, ATT_NONE, ATT_NOT_PERMITTED, atval, 1);
133 /* Client characteristic configuration */
134 bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
137 attrib_db_add(adapter, h++, &uuid, ATT_NONE, ATT_NONE, atval, 2);
139 g_assert(h - start_handle == svc_size);
142 static DBusMessage *get_properties(DBusConnection *conn,
143 DBusMessage *msg, void *data)
145 DBusMessageIter iter;
146 DBusMessageIter dict;
147 DBusMessage *reply = NULL;
148 const char *linkloss_level, *immalert_level;
149 struct btd_device *device = data;
151 reply = dbus_message_new_method_return(msg);
155 linkloss_level = link_loss_get_alert_level(device);
156 immalert_level = imm_alert_get_level(device);
158 dbus_message_iter_init_append(reply, &iter);
160 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
161 DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
162 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
163 DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict))
166 dict_append_entry(&dict, "LinkLossAlertLevel", DBUS_TYPE_STRING,
168 dict_append_entry(&dict, "ImmediateAlertLevel", DBUS_TYPE_STRING,
171 if (!dbus_message_iter_close_container(&iter, &dict))
178 dbus_message_unref(reply);
179 return btd_error_failed(msg, "not enough memory");
182 static const GDBusMethodTable reporter_methods[] = {
183 { GDBUS_METHOD("GetProperties",
184 NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
189 static const GDBusSignalTable reporter_signals[] = {
190 { GDBUS_SIGNAL("PropertyChanged",
191 GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
195 static void unregister_reporter_device(gpointer data, gpointer user_data)
197 struct btd_device *device = data;
198 struct reporter_adapter *radapter = user_data;
199 const char *path = device_get_path(device);
201 DBG("unregister on device %s", path);
203 g_dbus_unregister_interface(radapter->conn, path,
204 PROXIMITY_REPORTER_INTERFACE);
206 radapter->devices = g_slist_remove(radapter->devices, device);
207 btd_device_unref(device);
210 static void register_reporter_device(struct btd_device *device,
211 struct reporter_adapter *radapter)
213 const char *path = device_get_path(device);
215 DBG("register on device %s", path);
217 g_dbus_register_interface(radapter->conn, path,
218 PROXIMITY_REPORTER_INTERFACE,
219 reporter_methods, reporter_signals,
222 btd_device_ref(device);
223 radapter->devices = g_slist_prepend(radapter->devices, device);
226 static int reporter_device_probe(struct btd_device *device, GSList *uuids)
228 struct reporter_adapter *radapter;
229 struct btd_adapter *adapter = device_get_adapter(device);
231 radapter = find_reporter_adapter(adapter);
235 register_reporter_device(device, radapter);
239 static void reporter_device_remove(struct btd_device *device)
241 struct reporter_adapter *radapter;
242 struct btd_adapter *adapter = device_get_adapter(device);
244 radapter = find_reporter_adapter(adapter);
248 unregister_reporter_device(device, radapter);
251 /* device driver for tracking remote GATT client devices */
252 static struct btd_device_driver reporter_device_driver = {
253 .name = "Proximity GATT Reporter Device Tracker Driver",
254 .uuids = BTD_UUIDS(GATT_UUID),
255 .probe = reporter_device_probe,
256 .remove = reporter_device_remove,
259 int reporter_init(struct btd_adapter *adapter)
261 struct reporter_adapter *radapter;
262 DBusConnection *conn;
264 if (!main_opts.gatt_enabled) {
265 DBG("GATT is disabled");
269 conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
273 radapter = g_new0(struct reporter_adapter, 1);
274 radapter->adapter = adapter;
275 radapter->conn = conn;
277 link_loss_register(adapter, radapter->conn);
278 register_tx_power(adapter);
279 imm_alert_register(adapter, radapter->conn);
281 btd_register_device_driver(&reporter_device_driver);
283 reporter_adapters = g_slist_prepend(reporter_adapters, radapter);
284 DBG("Proximity Reporter for adapter %p", adapter);
289 void reporter_exit(struct btd_adapter *adapter)
291 struct reporter_adapter *radapter = find_reporter_adapter(adapter);
295 btd_unregister_device_driver(&reporter_device_driver);
297 g_slist_foreach(radapter->devices, unregister_reporter_device,
300 link_loss_unregister(adapter);
301 imm_alert_unregister(adapter);
302 dbus_connection_unref(radapter->conn);
304 reporter_adapters = g_slist_remove(reporter_adapters, radapter);