diff options
-rw-r--r-- | audio/device.h | 2 | ||||
-rw-r--r-- | audio/headset.c | 20 | ||||
-rw-r--r-- | audio/headset.h | 7 | ||||
-rw-r--r-- | audio/manager.c | 95 | ||||
-rw-r--r-- | input/manager.c | 10 | ||||
-rw-r--r-- | network/manager.c | 15 | ||||
-rw-r--r-- | serial/manager.c | 23 | ||||
-rw-r--r-- | src/adapter.c | 8 | ||||
-rw-r--r-- | src/device.c | 78 | ||||
-rw-r--r-- | src/device.h | 6 | ||||
-rw-r--r-- | src/storage.c | 22 | ||||
-rw-r--r-- | src/storage.h | 2 |
12 files changed, 172 insertions, 116 deletions
diff --git a/audio/device.h b/audio/device.h index bdcba754..80e1b107 100644 --- a/audio/device.h +++ b/audio/device.h @@ -50,6 +50,8 @@ struct headset; struct gateway; struct audio_device { + struct btd_device *btd_dev; + DBusConnection *conn; char *path; bdaddr_t src; diff --git a/audio/headset.c b/audio/headset.c index ca7cc189..6599e1d7 100644 --- a/audio/headset.c +++ b/audio/headset.c @@ -59,6 +59,8 @@ #include "headset.h" #include "glib-helper.h" #include "dbus-common.h" +#include "../src/adapter.h" +#include "../src/device.h" #define DC_TIMEOUT 3000 @@ -1810,8 +1812,8 @@ static GDBusSignalTable headset_signals[] = { { NULL, NULL } }; -static void headset_set_channel(struct headset *headset, sdp_record_t *record, - uint16_t svc) +static void headset_set_channel(struct headset *headset, + const sdp_record_t *record, uint16_t svc) { int ch; sdp_list_t *protos; @@ -1835,9 +1837,15 @@ static void headset_set_channel(struct headset *headset, sdp_record_t *record, error("Unable to get RFCOMM channel from Headset record"); } -void headset_update(struct audio_device *dev, sdp_record_t *record, uint16_t svc) +void headset_update(struct audio_device *dev, uint16_t svc, + const char *uuidstr) { struct headset *headset = dev->headset; + const sdp_record_t *record; + + record = btd_device_get_record(dev->btd_dev, uuidstr); + if (!record) + return; switch (svc) { case HANDSFREE_SVCLASS_ID: @@ -1918,10 +1926,11 @@ void headset_unregister(struct audio_device *dev) AUDIO_HEADSET_INTERFACE); } -struct headset *headset_init(struct audio_device *dev, sdp_record_t *record, - uint16_t svc) +struct headset *headset_init(struct audio_device *dev, uint16_t svc, + const char *uuidstr) { struct headset *hs; + const sdp_record_t *record; hs = g_new0(struct headset, 1); hs->rfcomm_ch = -1; @@ -1931,6 +1940,7 @@ struct headset *headset_init(struct audio_device *dev, sdp_record_t *record, hs->hfp_active = FALSE; hs->cli_active = FALSE; + record = btd_device_get_record(dev->btd_dev, uuidstr); if (!record) goto register_iface; diff --git a/audio/headset.h b/audio/headset.h index 9152401d..c8d63b9b 100644 --- a/audio/headset.h +++ b/audio/headset.h @@ -42,14 +42,15 @@ typedef enum { typedef void (*headset_stream_cb_t) (struct audio_device *dev, void *user_data); -struct headset *headset_init(struct audio_device *dev, sdp_record_t *record, - uint16_t svc); +struct headset *headset_init(struct audio_device *dev, uint16_t svc, + const char *uuidstr); void headset_unregister(struct audio_device *dev); uint32_t headset_config_init(GKeyFile *config); -void headset_update(struct audio_device *dev, sdp_record_t *record, uint16_t svc); +void headset_update(struct audio_device *dev, uint16_t svc, + const char *uuidstr); unsigned int headset_request_stream(struct audio_device *dev, headset_stream_cb_t cb, void *user_data); diff --git a/audio/manager.c b/audio/manager.c index f7058649..bb7a457a 100644 --- a/audio/manager.c +++ b/audio/manager.c @@ -139,40 +139,6 @@ static struct audio_adapter *find_adapter_by_address(GSList *list, return NULL; } -static uint16_t get_service_uuid(const sdp_record_t *record) -{ - sdp_list_t *classes; - uuid_t uuid; - uint16_t uuid16 = 0; - - if (sdp_get_service_classes(record, &classes) < 0) { - error("Unable to get service classes from record"); - return 0; - } - - memcpy(&uuid, classes->data, sizeof(uuid)); - - if (!sdp_uuid128_to_uuid(&uuid)) { - error("Not a 16 bit UUID"); - sdp_list_free(classes, free); - return 0; - } - - if (uuid.type == SDP_UUID32) { - if (uuid.value.uuid32 > 0xFFFF) { - error("Not a 16 bit UUID"); - goto done; - } - uuid16 = (uint16_t) uuid.value.uuid32; - } else - uuid16 = uuid.value.uuid16; - -done: - sdp_list_free(classes, free); - - return uuid16; -} - gboolean server_is_enabled(bdaddr_t *src, uint16_t svc) { struct audio_adapter *adp; @@ -208,23 +174,37 @@ gboolean server_is_enabled(bdaddr_t *src, uint16_t svc) return ret; } -static void handle_record(sdp_record_t *record, struct audio_device *device) +static void handle_uuid(const char *uuidstr, struct audio_device *device) { + uuid_t uuid; uint16_t uuid16; - uuid16 = get_service_uuid(record); + if (bt_string2uuid(&uuid, uuidstr) < 0) { + error("%s not detected as an UUID-128", uuidstr); + return; + } + + if (!sdp_uuid128_to_uuid(&uuid) && uuid.type != SDP_UUID16) { + error("Could not convert %s to a UUID-16", uuidstr); + return; + } + + uuid16 = uuid.value.uuid16; - if (!server_is_enabled(&device->src, uuid16)) + if (!server_is_enabled(&device->src, uuid16)) { + debug("audio handle_uuid: server not enabled for %s (0x%04x)", + uuidstr, uuid16); return; + } switch (uuid16) { case HEADSET_SVCLASS_ID: debug("Found Headset record"); if (device->headset) - headset_update(device, record, uuid16); + headset_update(device, uuid16, uuidstr); else - device->headset = headset_init(device, - record, uuid16); + device->headset = headset_init(device, uuid16, + uuidstr); break; case HEADSET_AGW_SVCLASS_ID: debug("Found Headset AG record"); @@ -232,10 +212,10 @@ static void handle_record(sdp_record_t *record, struct audio_device *device) case HANDSFREE_SVCLASS_ID: debug("Found Handsfree record"); if (device->headset) - headset_update(device, record, uuid16); + headset_update(device, uuid16, uuidstr); else - device->headset = headset_init(device, - record, uuid16); + device->headset = headset_init(device, uuid16, + uuidstr); break; case HANDSFREE_AGW_SVCLASS_ID: debug("Found Handsfree AG record"); @@ -474,7 +454,8 @@ static void ag_io_cb(GIOChannel *chan, int err, const bdaddr_t *src, const bdaddr_t *dst, gpointer data) { struct audio_adapter *adapter = data; - const char *uuid; + const char *server_uuid, *remote_uuid; + uint16_t svclass; struct audio_device *device; gboolean hfp_active; @@ -485,10 +466,14 @@ static void ag_io_cb(GIOChannel *chan, int err, const bdaddr_t *src, if (chan == adapter->hsp_ag_server) { hfp_active = FALSE; - uuid = HSP_AG_UUID; + server_uuid = HSP_AG_UUID; + remote_uuid = HSP_HS_UUID; + svclass = HEADSET_SVCLASS_ID; } else { hfp_active = TRUE; - uuid = HFP_AG_UUID; + server_uuid = HFP_AG_UUID; + remote_uuid = HFP_HS_UUID; + svclass = HANDSFREE_SVCLASS_ID; } device = manager_get_device(src, dst, NULL); @@ -496,7 +481,7 @@ static void ag_io_cb(GIOChannel *chan, int err, const bdaddr_t *src, goto drop; if (!device->headset) - device->headset = headset_init(device, NULL, 0); + device->headset = headset_init(device, svclass, remote_uuid); if (headset_get_state(device) > HEADSET_STATE_DISCONNECTED) { debug("Refusing new connection since one already exists"); @@ -512,8 +497,8 @@ static void ag_io_cb(GIOChannel *chan, int err, const bdaddr_t *src, headset_set_state(device, HEADSET_STATE_CONNECT_IN_PROGRESS); - err = btd_request_authorization(&device->src, &device->dst, uuid, - auth_cb, device); + err = btd_request_authorization(&device->src, &device->dst, + server_uuid, auth_cb, device); if (err < 0) { debug("Authorization denied: %s", strerror(-err)); headset_set_state(device, HEADSET_STATE_DISCONNECTED); @@ -678,23 +663,25 @@ static int gateway_server_init(struct audio_adapter *adapter) return 0; } -static int audio_probe(struct btd_device *device, GSList *records) +static int audio_probe(struct btd_device *device, GSList *uuids) { struct btd_adapter *adapter = device_get_adapter(device); const gchar *path = device_get_path(device); bdaddr_t src, dst; - struct audio_device *dev; + struct audio_device *audio_dev; adapter_get_address(adapter, &src); device_get_address(device, &dst); - dev = manager_get_device(&src, &dst, path); - if (!dev) { + audio_dev = manager_get_device(&src, &dst, path); + if (!audio_dev) { debug("audio_probe: unable to get a device object"); return -1; } - g_slist_foreach(records, (GFunc) handle_record, dev); + audio_dev->btd_dev = device; + + g_slist_foreach(uuids, (GFunc) handle_uuid, audio_dev); return 0; } diff --git a/input/manager.c b/input/manager.c index 9e548369..51634e3d 100644 --- a/input/manager.c +++ b/input/manager.c @@ -54,11 +54,11 @@ static void input_remove(struct btd_device *device, const char *uuid) input_device_unregister(path, uuid); } -static int hid_device_probe(struct btd_device *device, GSList *records) +static int hid_device_probe(struct btd_device *device, GSList *uuids) { struct btd_adapter *adapter = device_get_adapter(device); const gchar *path = device_get_path(device); - sdp_record_t *rec = records->data; + const sdp_record_t *rec = btd_device_get_record(device, uuids->data); sdp_data_t *pdlist; bdaddr_t src, dst; uint32_t handle; @@ -82,18 +82,18 @@ static void hid_device_remove(struct btd_device *device) input_remove(device, HID_UUID); } -static int headset_probe(struct btd_device *device, GSList *records) +static int headset_probe(struct btd_device *device, GSList *uuids) { struct btd_adapter *adapter = device_get_adapter(device); const gchar *path = device_get_path(device); - sdp_record_t *record = records->data; + const sdp_record_t *record = btd_device_get_record(device, uuids->data); sdp_list_t *protos; uint8_t ch; bdaddr_t src, dst; DBG("path %s", path); - if (sdp_get_access_protos(record, &protos) < 0) { + if (!record || sdp_get_access_protos(record, &protos) < 0) { error("Invalid record"); return -EINVAL; } diff --git a/network/manager.c b/network/manager.c index 25c95837..564af2ad 100644 --- a/network/manager.c +++ b/network/manager.c @@ -191,8 +191,7 @@ done: conf.security ? "true" : "false"); } -static int network_probe(struct btd_device *device, GSList *records, - uint16_t id) +static int network_probe(struct btd_device *device, GSList *uuids, uint16_t id) { struct btd_adapter *adapter = device_get_adapter(device); const gchar *path = device_get_path(device); @@ -215,9 +214,9 @@ static void network_remove(struct btd_device *device, uint16_t id) connection_unregister(path, id); } -static int panu_probe(struct btd_device *device, GSList *records) +static int panu_probe(struct btd_device *device, GSList *uuids) { - return network_probe(device, records, BNEP_SVC_PANU); + return network_probe(device, uuids, BNEP_SVC_PANU); } static void panu_remove(struct btd_device *device) @@ -225,9 +224,9 @@ static void panu_remove(struct btd_device *device) network_remove(device, BNEP_SVC_PANU); } -static int gn_probe(struct btd_device *device, GSList *records) +static int gn_probe(struct btd_device *device, GSList *uuids) { - return network_probe(device, records, BNEP_SVC_GN); + return network_probe(device, uuids, BNEP_SVC_GN); } static void gn_remove(struct btd_device *device) @@ -235,9 +234,9 @@ static void gn_remove(struct btd_device *device) network_remove(device, BNEP_SVC_GN); } -static int nap_probe(struct btd_device *device, GSList *records) +static int nap_probe(struct btd_device *device, GSList *uuids) { - return network_probe(device, records, BNEP_SVC_NAP); + return network_probe(device, uuids, BNEP_SVC_NAP); } static void nap_remove(struct btd_device *device) diff --git a/serial/manager.c b/serial/manager.c index 235b2534..e9166504 100644 --- a/serial/manager.c +++ b/serial/manager.c @@ -74,7 +74,7 @@ static DBusConnection *connection = NULL; -static int serial_probe(struct btd_device *device, sdp_record_t *rec, +static int serial_probe(struct btd_device *device, const sdp_record_t *rec, const char *name, const char *uuid) { struct btd_adapter *adapter = device_get_adapter(device); @@ -114,9 +114,15 @@ static void serial_remove(struct btd_device *device, const char *uuid) } -static int port_probe(struct btd_device *device, GSList *records) +static int port_probe(struct btd_device *device, GSList *uuids) { - return serial_probe(device, records->data, SERIAL_PORT_NAME, + const sdp_record_t *record; + + record = btd_device_get_record(device, uuids->data); + if (!record) + return -1; + + return serial_probe(device, record, SERIAL_PORT_NAME, SERIAL_PORT_UUID); } @@ -125,10 +131,15 @@ static void port_remove(struct btd_device *device) return serial_remove(device, SERIAL_PORT_UUID); } -static int dialup_probe(struct btd_device *device, GSList *records) +static int dialup_probe(struct btd_device *device, GSList *uuids) { - return serial_probe(device, records->data, DIALUP_NET_NAME, - DIALUP_NET_UUID); + const sdp_record_t *record; + + record = btd_device_get_record(device, uuids->data); + if (!record) + return -1; + + return serial_probe(device, record, DIALUP_NET_NAME, DIALUP_NET_UUID); } static void dialup_remove(struct btd_device *device) diff --git a/src/adapter.c b/src/adapter.c index 1e22b4b3..f983069e 100644 --- a/src/adapter.c +++ b/src/adapter.c @@ -2274,7 +2274,6 @@ static void create_stored_device_from_profiles(char *key, char *value, struct btd_adapter *adapter = user_data; GSList *uuids = bt_string2list(value); struct btd_device *device; - sdp_list_t *records; bdaddr_t dst; char srcaddr[18], dstaddr[18]; @@ -2294,12 +2293,7 @@ static void create_stored_device_from_profiles(char *key, char *value, device_get_address(device, &dst); ba2str(&dst, dstaddr); - records = read_records(srcaddr, dstaddr); - - device_probe_drivers(device, uuids, records); - - if (records) - sdp_list_free(records, (sdp_free_func_t) sdp_record_free); + device_probe_drivers(device, uuids); g_slist_free(uuids); } diff --git a/src/device.c b/src/device.c index 1e7747d6..3f70e647 100644 --- a/src/device.c +++ b/src/device.c @@ -87,6 +87,8 @@ struct btd_device { /* Whether were creating a security mode 3 connection */ gboolean secmode3; + + sdp_list_t *tmp_records; }; struct browse_req { @@ -616,7 +618,7 @@ gint device_address_cmp(struct btd_device *device, const gchar *address) return strcasecmp(addr, address); } -void device_probe_drivers(struct btd_device *device, GSList *uuids, sdp_list_t *recs) +void device_probe_drivers(struct btd_device *device, GSList *uuids) { GSList *list; const char **uuid; @@ -626,62 +628,70 @@ void device_probe_drivers(struct btd_device *device, GSList *uuids, sdp_list_t * for (list = device_drivers; list; list = list->next) { struct btd_device_driver *driver = list->data; - GSList *records = NULL; + GSList *probe_uuids = NULL; for (uuid = driver->uuids; *uuid; uuid++) { - sdp_record_t *rec; + GSList *match; - if (!g_slist_find_custom(uuids, *uuid, - (GCompareFunc) strcasecmp)) - continue; - - rec = find_record_in_list(recs, *uuid); - if (!rec) + match = g_slist_find_custom(uuids, *uuid, + (GCompareFunc) strcasecmp); + if (!match) continue; - records = g_slist_append(records, rec); + probe_uuids = g_slist_append(probe_uuids, match->data); } - if (records) { + if (probe_uuids) { struct btd_driver_data *driver_data = g_new0(struct btd_driver_data, 1); - err = driver->probe(device, records); + err = driver->probe(device, probe_uuids); if (err < 0) { error("probe failed for driver %s", driver->name); g_free(driver_data); + g_slist_free(probe_uuids); continue; } driver_data->driver = driver; device->drivers = g_slist_append(device->drivers, driver_data); + g_slist_free(probe_uuids); } } for (list = uuids; list; list = list->next) { GSList *l = g_slist_find_custom(device->uuids, list->data, - (GCompareFunc) strcmp); + (GCompareFunc) strcasecmp); if (l) continue; device->uuids = g_slist_insert_sorted(device->uuids, - list->data, (GCompareFunc) strcmp); + list->data, (GCompareFunc) strcasecmp); + } + + if (device->tmp_records) { + sdp_list_free(device->tmp_records, + (sdp_free_func_t) sdp_record_free); + device->tmp_records = NULL; } } -void device_remove_drivers(struct btd_device *device, GSList *uuids, sdp_list_t *recs) +void device_remove_drivers(struct btd_device *device, GSList *uuids) { struct btd_adapter *adapter = device_get_adapter(device); GSList *list, *next; char srcaddr[18], dstaddr[18]; bdaddr_t src; + sdp_list_t *records; adapter_get_address(adapter, &src); ba2str(&src, srcaddr); ba2str(&device->bdaddr, dstaddr); + records = read_records(&src, &device->bdaddr); + debug("Remove drivers for %s", device->path); for (list = device->drivers; list; list = next) { @@ -698,20 +708,29 @@ void device_remove_drivers(struct btd_device *device, GSList *uuids, sdp_list_t (GCompareFunc) strcasecmp)) continue; + debug("UUID %s was removed from device %s", dstaddr); + driver->remove(device); device->drivers = g_slist_remove(device->drivers, driver_data); g_free(driver_data); - rec = find_record_in_list(recs, *uuid); + + rec = find_record_in_list(records, *uuid); if (!rec) continue; delete_record(srcaddr, dstaddr, 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); + for (list = uuids; list; list = list->next) device->uuids = g_slist_remove(device->uuids, list->data); } @@ -994,13 +1013,19 @@ static void search_cb(sdp_list_t *recs, int err, gpointer user_data) goto proceed; } + if (device->tmp_records && req->records) { + sdp_list_free(device->tmp_records, (sdp_free_func_t) sdp_record_free); + device->tmp_records = req->records; + req->records = NULL; + } + /* Probe matching drivers for services added */ if (req->uuids_added) - device_probe_drivers(device, req->uuids_added, req->records); + device_probe_drivers(device, req->uuids_added); /* Remove drivers for services removed */ if (req->uuids_removed) - device_remove_drivers(device, req->uuids_removed, req->records); + device_remove_drivers(device, req->uuids_removed); /* Propagate services changes */ services_changed(req); @@ -1314,6 +1339,23 @@ int device_set_paired(DBusConnection *conn, struct btd_device *device, return 0; } +const sdp_record_t *btd_device_get_record(struct btd_device *device, + const char *uuid) +{ + bdaddr_t src; + + if (device->tmp_records) + return find_record_in_list(device->tmp_records, uuid); + + adapter_get_address(device->adapter, &src); + + device->tmp_records = read_records(&src, &device->bdaddr); + if (!device->tmp_records) + return NULL; + + return find_record_in_list(device->tmp_records, uuid); +} + int btd_register_device_driver(struct btd_device_driver *driver) { device_drivers = g_slist_append(device_drivers, driver); diff --git a/src/device.h b/src/device.h index a1fa15ab..e0d334f6 100644 --- a/src/device.h +++ b/src/device.h @@ -30,7 +30,9 @@ void device_remove(DBusConnection *conn, struct btd_device *device); gint device_address_cmp(struct btd_device *device, const gchar *address); int device_browse(struct btd_device *device, DBusConnection *conn, DBusMessage *msg, uuid_t *search, gboolean reverse); -void device_probe_drivers(struct btd_device *device, GSList *uuids, sdp_list_t *recs); +void device_probe_drivers(struct btd_device *device, GSList *uuids); +const sdp_record_t *btd_device_get_record(struct btd_device *device, + const char *uuid); struct btd_adapter *device_get_adapter(struct btd_device *device); void device_get_address(struct btd_device *adapter, bdaddr_t *bdaddr); const gchar *device_get_path(struct btd_device *device); @@ -54,7 +56,7 @@ void device_set_secmode3_conn(struct btd_device *device, gboolean enable); struct btd_device_driver { const char *name; const char **uuids; - int (*probe) (struct btd_device *device, GSList *records); + int (*probe) (struct btd_device *device, GSList *uuids); void (*remove) (struct btd_device *device); }; diff --git a/src/storage.c b/src/storage.c index d048ddb4..d99fb33c 100644 --- a/src/storage.c +++ b/src/storage.c @@ -845,15 +845,19 @@ static void create_stored_records_from_keys(char *key, char *value, rec_list->recs = sdp_list_append(rec_list->recs, rec); } -sdp_list_t *read_records(const gchar *src, const gchar *dst) +sdp_list_t *read_records(bdaddr_t *src, bdaddr_t *dst) { char filename[PATH_MAX + 1]; struct record_list rec_list; + char srcaddr[18], dstaddr[18]; - rec_list.addr = dst; + ba2str(src, srcaddr); + ba2str(dst, dstaddr); + + rec_list.addr = dstaddr; rec_list.recs = NULL; - create_name(filename, PATH_MAX, STORAGEDIR, src, "sdp"); + create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "sdp"); textfile_foreach(filename, create_stored_records_from_keys, &rec_list); return rec_list.recs; @@ -952,16 +956,17 @@ static int read_device_id_from_did(const gchar *src, const gchar *dst, return 0; } -int read_device_id(const gchar *src, const gchar *dst, +int read_device_id(const gchar *srcaddr, const gchar *dstaddr, uint16_t *source, uint16_t *vendor, uint16_t *product, uint16_t *version) { uint16_t lsource, lvendor, lproduct, lversion; sdp_list_t *recs; sdp_record_t *rec; + bdaddr_t src, dst; int err; - err = read_device_id_from_did(src, dst, &lsource, + err = read_device_id_from_did(srcaddr, dstaddr, &lsource, vendor, product, version); if (!err) { if (lsource == 0xffff) @@ -970,7 +975,10 @@ int read_device_id(const gchar *src, const gchar *dst, return err; } - recs = read_records(src, dst); + str2ba(srcaddr, &src); + str2ba(dstaddr, &dst); + + recs = read_records(&src, &dst); rec = find_record_in_list(recs, PNP_UUID); if (rec) { @@ -1004,7 +1012,7 @@ int read_device_id(const gchar *src, const gchar *dst, lversion = 0x0000; } - store_device_id(src, dst, lsource, lvendor, lproduct, lversion); + store_device_id(srcaddr, dstaddr, lsource, lvendor, lproduct, lversion); if (err) return err; diff --git a/src/storage.h b/src/storage.h index d6008a40..bff36a7c 100644 --- a/src/storage.h +++ b/src/storage.h @@ -59,7 +59,7 @@ int delete_entry(bdaddr_t *src, const char *storage, const char *key); int store_record(const gchar *src, const gchar *dst, sdp_record_t *rec); sdp_record_t *fetch_record(const gchar *src, const gchar *dst, const uint32_t handle); int delete_record(const gchar *src, const gchar *dst, const uint32_t handle); -sdp_list_t *read_records(const gchar *src, const gchar *dst); +sdp_list_t *read_records(bdaddr_t *src, bdaddr_t *dst); sdp_record_t *find_record_in_list(sdp_list_t *recs, const char *uuid); int store_device_id(const gchar *src, const gchar *dst, const uint16_t source, const uint16_t vendor, |