diff options
author | Wu Zheng <wu.zheng@intel.com> | 2013-12-12 04:50:37 -0500 |
---|---|---|
committer | Wu Zheng <wu.zheng@intel.com> | 2013-12-12 04:50:37 -0500 |
commit | 5d363eb448eacca7c3939fd6e8d6ee3c284db7e2 (patch) | |
tree | f48817eba8ed8386a9f9c40801d2b6cb196dddfa /profiles | |
parent | a704ad586e3a3480a8e0c60da2d9b772dbd0c887 (diff) | |
download | bluez-5d363eb448eacca7c3939fd6e8d6ee3c284db7e2.tar.gz bluez-5d363eb448eacca7c3939fd6e8d6ee3c284db7e2.tar.bz2 bluez-5d363eb448eacca7c3939fd6e8d6ee3c284db7e2.zip |
Imported Upstream version 5.12upstream/5.12
Diffstat (limited to 'profiles')
-rw-r--r-- | profiles/audio/a2dp.c | 4 | ||||
-rw-r--r-- | profiles/audio/avctp.c | 22 | ||||
-rw-r--r-- | profiles/audio/avdtp.c | 74 | ||||
-rw-r--r-- | profiles/audio/avdtp.h | 15 | ||||
-rw-r--r-- | profiles/audio/sink.c | 5 | ||||
-rw-r--r-- | profiles/audio/sink.h | 2 | ||||
-rw-r--r-- | profiles/audio/source.c | 5 | ||||
-rw-r--r-- | profiles/audio/source.h | 2 | ||||
-rw-r--r-- | profiles/health/hdp.c | 10 | ||||
-rw-r--r-- | profiles/health/hdp_util.c | 6 | ||||
-rw-r--r-- | profiles/input/device.c | 11 | ||||
-rw-r--r-- | profiles/input/manager.c | 4 | ||||
-rw-r--r-- | profiles/input/server.c | 104 | ||||
-rw-r--r-- | profiles/network/bnep.c (renamed from profiles/network/common.c) | 197 | ||||
-rw-r--r-- | profiles/network/bnep.h (renamed from profiles/network/common.h) | 5 | ||||
-rw-r--r-- | profiles/network/connection.c | 176 | ||||
-rw-r--r-- | profiles/network/manager.c | 2 | ||||
-rw-r--r-- | profiles/network/server.c | 9 | ||||
-rw-r--r-- | profiles/sap/server.c | 3 |
19 files changed, 379 insertions, 277 deletions
diff --git a/profiles/audio/a2dp.c b/profiles/audio/a2dp.c index 864cb188..29a15939 100644 --- a/profiles/audio/a2dp.c +++ b/profiles/audio/a2dp.c @@ -1887,7 +1887,7 @@ static int a2dp_source_disconnect(struct btd_service *service) DBG("path %s", path); - return source_disconnect(service, FALSE); + return source_disconnect(service); } static int a2dp_sink_connect(struct btd_service *service) @@ -1919,7 +1919,7 @@ static int a2dp_sink_disconnect(struct btd_service *service) DBG("path %s", path); - return sink_disconnect(service, FALSE); + return sink_disconnect(service); } static int a2dp_source_server_probe(struct btd_profile *p, diff --git a/profiles/audio/avctp.c b/profiles/audio/avctp.c index dac7a66c..6669ddc0 100644 --- a/profiles/audio/avctp.c +++ b/profiles/audio/avctp.c @@ -1307,11 +1307,11 @@ static void avctp_control_confirm(struct avctp *session, GIOChannel *chan, avctp_set_state(session, AVCTP_STATE_CONNECTING); session->control = avctp_channel_create(session, chan, NULL); - src = adapter_get_address(device_get_adapter(dev)); + src = btd_adapter_get_address(device_get_adapter(dev)); dst = device_get_address(dev); session->auth_id = btd_request_authorization(src, dst, - AVRCP_TARGET_UUID, + AVRCP_REMOTE_UUID, auth_cb, session); if (session->auth_id == 0) goto drop; @@ -1371,7 +1371,7 @@ static void avctp_confirm_cb(GIOChannel *chan, gpointer data) DBG("AVCTP: incoming connect from %s", address); - device = adapter_find_device(adapter_find(&src), &dst); + device = btd_adapter_find_device(adapter_find(&src), &dst); if (!device) return; @@ -1422,7 +1422,7 @@ static GIOChannel *avctp_server_socket(const bdaddr_t *src, gboolean master, int avctp_register(struct btd_adapter *adapter, gboolean master) { struct avctp_server *server; - const bdaddr_t *src = adapter_get_address(adapter); + const bdaddr_t *src = btd_adapter_get_address(adapter); server = g_new0(struct avctp_server, 1); @@ -1488,7 +1488,7 @@ static struct avctp_pending_req *pending_create(struct avctp_channel *chan, tmp = g_slist_copy(chan->processed); /* Find first unused transaction id */ - for (l = tmp; l; l = l->next) { + for (l = tmp; l; l = g_slist_next(l)) { struct avctp_pending_req *req = l->data; if (req->transaction == chan->transaction) { @@ -1937,6 +1937,7 @@ struct avctp *avctp_connect(struct btd_device *device) struct avctp *session; GError *err = NULL; GIOChannel *io; + const bdaddr_t *src; session = avctp_get_internal(device); if (!session) @@ -1947,9 +1948,10 @@ struct avctp *avctp_connect(struct btd_device *device) avctp_set_state(session, AVCTP_STATE_CONNECTING); + src = btd_adapter_get_address(session->server->adapter); + io = bt_io_connect(avctp_connect_cb, session, NULL, &err, - BT_IO_OPT_SOURCE_BDADDR, - adapter_get_address(session->server->adapter), + BT_IO_OPT_SOURCE_BDADDR, src, BT_IO_OPT_DEST_BDADDR, device_get_address(session->device), BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, @@ -1971,6 +1973,7 @@ struct avctp *avctp_connect(struct btd_device *device) int avctp_connect_browsing(struct avctp *session) { + const bdaddr_t *src; GError *err = NULL; GIOChannel *io; @@ -1982,9 +1985,10 @@ int avctp_connect_browsing(struct avctp *session) avctp_set_state(session, AVCTP_STATE_BROWSING_CONNECTING); + src = btd_adapter_get_address(session->server->adapter); + io = bt_io_connect(avctp_connect_browsing_cb, session, NULL, &err, - BT_IO_OPT_SOURCE_BDADDR, - adapter_get_address(session->server->adapter), + BT_IO_OPT_SOURCE_BDADDR, src, BT_IO_OPT_DEST_BDADDR, device_get_address(session->device), BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, diff --git a/profiles/audio/avdtp.c b/profiles/audio/avdtp.c index 93783509..f866b392 100644 --- a/profiles/audio/avdtp.c +++ b/profiles/audio/avdtp.c @@ -394,9 +394,6 @@ struct avdtp { avdtp_session_state_t state; - /* True if the entire device is being disconnected */ - gboolean device_disconnect; - guint auth_id; GIOChannel *io; @@ -1200,11 +1197,6 @@ static void set_disconnect_timer(struct avdtp *session) if (session->dc_timer) remove_disconnect_timer(session); - if (session->device_disconnect) { - session->dc_timer = g_idle_add(disconnect_timeout, session); - return; - } - session->dc_timer = g_timeout_add_seconds(DISCONNECT_TIMEOUT, disconnect_timeout, session); @@ -2475,7 +2467,7 @@ static void avdtp_confirm_cb(GIOChannel *chan, gpointer data) DBG("AVDTP: incoming connect from %s", address); - device = adapter_find_device(adapter_find(&src), &dst); + device = btd_adapter_find_device(adapter_find(&src), &dst); if (!device) goto drop; @@ -2531,11 +2523,13 @@ static GIOChannel *l2cap_connect(struct avdtp *session) { GError *err = NULL; GIOChannel *io; + const bdaddr_t *src; + + src = btd_adapter_get_address(session->server->adapter); io = bt_io_connect(avdtp_connect_cb, session, NULL, &err, - BT_IO_OPT_SOURCE_BDADDR, - adapter_get_address(session->server->adapter), + BT_IO_OPT_SOURCE_BDADDR, src, BT_IO_OPT_DEST_BDADDR, device_get_address(session->device), BT_IO_OPT_PSM, AVDTP_PSM, @@ -3183,8 +3177,8 @@ struct avdtp_service_capability *avdtp_stream_get_codec( return NULL; } -gboolean avdtp_stream_has_capability(struct avdtp_stream *stream, - struct avdtp_service_capability *cap) +static gboolean avdtp_stream_has_capability(struct avdtp_stream *stream, + struct avdtp_service_capability *cap) { GSList *l; struct avdtp_service_capability *stream_cap; @@ -3219,7 +3213,16 @@ gboolean avdtp_stream_has_capabilities(struct avdtp_stream *stream, struct avdtp_remote_sep *avdtp_stream_get_remote_sep( struct avdtp_stream *stream) { - return avdtp_get_remote_sep(stream->session, stream->rseid); + GSList *l; + + for (l = stream->session->seps; l; l = l->next) { + struct avdtp_remote_sep *sep = l->data; + + if (sep->seid == stream->rseid) + return sep; + } + + return NULL; } gboolean avdtp_stream_get_transport(struct avdtp_stream *stream, int *sock, @@ -3268,46 +3271,11 @@ static int process_queue(struct avdtp *session) return send_req(session, FALSE, req); } -struct avdtp_remote_sep *avdtp_get_remote_sep(struct avdtp *session, - uint8_t seid) -{ - GSList *l; - - for (l = session->seps; l; l = l->next) { - struct avdtp_remote_sep *sep = l->data; - - if (sep->seid == seid) - return sep; - } - - return NULL; -} - -uint8_t avdtp_get_seid(struct avdtp_remote_sep *sep) -{ - return sep->seid; -} - -uint8_t avdtp_get_type(struct avdtp_remote_sep *sep) -{ - return sep->type; -} - struct avdtp_service_capability *avdtp_get_codec(struct avdtp_remote_sep *sep) { return sep->codec; } -gboolean avdtp_get_delay_reporting(struct avdtp_remote_sep *sep) -{ - return sep->delay_reporting; -} - -struct avdtp_stream *avdtp_get_stream(struct avdtp_remote_sep *sep) -{ - return sep->stream; -} - struct avdtp_service_capability *avdtp_service_cap_new(uint8_t category, void *data, int length) { @@ -3709,7 +3677,8 @@ static struct avdtp_server *avdtp_server_init(struct btd_adapter *adapter) server = g_new0(struct avdtp_server, 1); - server->io = avdtp_server_socket(adapter_get_address(adapter), TRUE); + server->io = avdtp_server_socket(btd_adapter_get_address(adapter), + TRUE); if (!server->io) { g_free(server); return NULL; @@ -3867,11 +3836,6 @@ gboolean avdtp_has_stream(struct avdtp *session, struct avdtp_stream *stream) return g_slist_find(session->streams, stream) ? TRUE : FALSE; } -void avdtp_set_device_disconnect(struct avdtp *session, gboolean dev_dc) -{ - session->device_disconnect = dev_dc; -} - unsigned int avdtp_add_state_cb(struct btd_device *dev, avdtp_session_state_cb cb, void *user_data) { diff --git a/profiles/audio/avdtp.h b/profiles/audio/avdtp.h index 56065062..390c154e 100644 --- a/profiles/audio/avdtp.h +++ b/profiles/audio/avdtp.h @@ -221,19 +221,8 @@ struct avdtp *avdtp_ref(struct avdtp *session); struct avdtp_service_capability *avdtp_service_cap_new(uint8_t category, void *data, int size); -struct avdtp_remote_sep *avdtp_get_remote_sep(struct avdtp *session, - uint8_t seid); - -uint8_t avdtp_get_seid(struct avdtp_remote_sep *sep); - -uint8_t avdtp_get_type(struct avdtp_remote_sep *sep); - struct avdtp_service_capability *avdtp_get_codec(struct avdtp_remote_sep *sep); -gboolean avdtp_get_delay_reporting(struct avdtp_remote_sep *sep); - -struct avdtp_stream *avdtp_get_stream(struct avdtp_remote_sep *sep); - int avdtp_discover(struct avdtp *session, avdtp_discover_cb_t cb, void *user_data); @@ -251,8 +240,6 @@ gboolean avdtp_stream_get_transport(struct avdtp_stream *stream, int *sock, GSList **caps); struct avdtp_service_capability *avdtp_stream_get_codec( struct avdtp_stream *stream); -gboolean avdtp_stream_has_capability(struct avdtp_stream *stream, - struct avdtp_service_capability *cap); gboolean avdtp_stream_has_capabilities(struct avdtp_stream *stream, GSList *caps); struct avdtp_remote_sep *avdtp_stream_get_remote_sep( @@ -306,5 +293,3 @@ int avdtp_error_posix_errno(struct avdtp_error *err); struct btd_adapter *avdtp_get_adapter(struct avdtp *session); struct btd_device *avdtp_get_device(struct avdtp *session); - -void avdtp_set_device_disconnect(struct avdtp *session, gboolean dev_dc); diff --git a/profiles/audio/sink.c b/profiles/audio/sink.c index 400af061..4f39622e 100644 --- a/profiles/audio/sink.c +++ b/profiles/audio/sink.c @@ -388,16 +388,13 @@ gboolean sink_new_stream(struct btd_service *service, struct avdtp *session, return TRUE; } -int sink_disconnect(struct btd_service *service, gboolean shutdown) +int sink_disconnect(struct btd_service *service) { struct sink *sink = btd_service_get_user_data(service); if (!sink->session) return -ENOTCONN; - if (shutdown) - avdtp_set_device_disconnect(sink->session, TRUE); - /* cancel pending connect */ if (sink->connect_id > 0) { a2dp_cancel(sink->connect_id); diff --git a/profiles/audio/sink.h b/profiles/audio/sink.h index 904a33d4..93c62a20 100644 --- a/profiles/audio/sink.h +++ b/profiles/audio/sink.h @@ -47,4 +47,4 @@ int sink_connect(struct btd_service *service); gboolean sink_new_stream(struct btd_service *service, struct avdtp *session, struct avdtp_stream *stream); gboolean sink_setup_stream(struct btd_service *service, struct avdtp *session); -int sink_disconnect(struct btd_service *service, gboolean shutdown); +int sink_disconnect(struct btd_service *service); diff --git a/profiles/audio/source.c b/profiles/audio/source.c index 24a43536..7b129b76 100644 --- a/profiles/audio/source.c +++ b/profiles/audio/source.c @@ -380,16 +380,13 @@ gboolean source_new_stream(struct btd_service *service, struct avdtp *session, return TRUE; } -int source_disconnect(struct btd_service *service, gboolean shutdown) +int source_disconnect(struct btd_service *service) { struct source *source = btd_service_get_user_data(service); if (!source->session) return -ENOTCONN; - if (shutdown) - avdtp_set_device_disconnect(source->session, TRUE); - /* cancel pending connect */ if (source->connect_id > 0) { a2dp_cancel(source->connect_id); diff --git a/profiles/audio/source.h b/profiles/audio/source.h index c16fb4bc..a014c68d 100644 --- a/profiles/audio/source.h +++ b/profiles/audio/source.h @@ -48,4 +48,4 @@ gboolean source_new_stream(struct btd_service *service, struct avdtp *session, struct avdtp_stream *stream); gboolean source_setup_stream(struct btd_service *service, struct avdtp *session); -int source_disconnect(struct btd_service *service, gboolean shutdown); +int source_disconnect(struct btd_service *service); diff --git a/profiles/health/hdp.c b/profiles/health/hdp.c index 7b4e7995..6203fa8a 100644 --- a/profiles/health/hdp.c +++ b/profiles/health/hdp.c @@ -1205,8 +1205,8 @@ static void mcl_connected(struct mcap_mcl *mcl, gpointer data) struct hdp_adapter *hdp_adapter = data; struct btd_device *device; - device = adapter_get_device(hdp_adapter->btd_adapter, &addr, - BDADDR_BREDR); + device = btd_adapter_get_device(hdp_adapter->btd_adapter, + &addr, BDADDR_BREDR); if (!device) return; hdp_device = create_health_device(device); @@ -1322,6 +1322,7 @@ static void release_adapter_instance(struct hdp_adapter *hdp_adapter) static gboolean update_adapter(struct hdp_adapter *hdp_adapter) { GError *err = NULL; + const bdaddr_t *src; if (applications == NULL) { release_adapter_instance(hdp_adapter); @@ -1331,8 +1332,9 @@ static gboolean update_adapter(struct hdp_adapter *hdp_adapter) if (hdp_adapter->mi != NULL) goto update; - hdp_adapter->mi = mcap_create_instance( - adapter_get_address(hdp_adapter->btd_adapter), + src = btd_adapter_get_address(hdp_adapter->btd_adapter); + + hdp_adapter->mi = mcap_create_instance(src, BT_IO_SEC_MEDIUM, 0, 0, mcl_connected, mcl_reconnected, mcl_disconnected, mcl_uncached, diff --git a/profiles/health/hdp_util.c b/profiles/health/hdp_util.c index 34e4671d..7de87a85 100644 --- a/profiles/health/hdp_util.c +++ b/profiles/health/hdp_util.c @@ -853,7 +853,7 @@ gboolean hdp_get_mdep(struct hdp_device *device, struct hdp_application *app, const bdaddr_t *dst; uuid_t uuid; - src = adapter_get_address(device_get_adapter(device->dev)); + src = btd_adapter_get_address(device_get_adapter(device->dev)); dst = device_get_address(device->dev); mdep_data = g_new0(struct get_mdep_data, 1); @@ -1080,7 +1080,7 @@ gboolean hdp_establish_mcl(struct hdp_device *device, const bdaddr_t *dst; uuid_t uuid; - src = adapter_get_address(device_get_adapter(device->dev)); + src = btd_adapter_get_address(device_get_adapter(device->dev)); dst = device_get_address(device->dev); conn_data = g_new0(struct conn_mcl_data, 1); @@ -1151,7 +1151,7 @@ gboolean hdp_get_dcpsm(struct hdp_device *device, hdp_continue_dcpsm_f func, const bdaddr_t *dst; uuid_t uuid; - src = adapter_get_address(device_get_adapter(device->dev)); + src = btd_adapter_get_address(device_get_adapter(device->dev)); dst = device_get_address(device->dev); dcpsm_data = g_new0(struct get_dcpsm_data, 1); diff --git a/profiles/input/device.c b/profiles/input/device.c index 65231612..62f6dbb2 100644 --- a/profiles/input/device.c +++ b/profiles/input/device.c @@ -667,7 +667,7 @@ static gboolean input_device_auto_reconnect(gpointer user_data) /* Stop the recurrent reconnection attempts if the device is reconnected * or is marked for removal. */ if (device_is_temporary(idev->device) || - device_is_connected(idev->device)) + btd_device_is_connected(idev->device)) return FALSE; /* Only attempt an auto-reconnect for at most 3 minutes (6 * 30s). */ @@ -713,7 +713,7 @@ static void input_device_enter_reconnect_mode(struct input_device *idev) /* If the device is temporary we are not required to reconnect with the * device. This is likely the case of a removing device. */ if (device_is_temporary(idev->device) || - device_is_connected(idev->device)) + btd_device_is_connected(idev->device)) return; if (idev->reconnect_timer > 0) @@ -811,8 +811,11 @@ static struct input_device *input_device_new(struct btd_service *service) struct input_device *idev; char name[HCI_MAX_NAME_LENGTH + 1]; + if (!rec) + return NULL; + idev = g_new0(struct input_device, 1); - bacpy(&idev->src, adapter_get_address(adapter)); + bacpy(&idev->src, btd_adapter_get_address(adapter)); bacpy(&idev->dst, device_get_address(device)); idev->service = btd_service_ref(service); idev->device = btd_device_ref(device); @@ -880,7 +883,7 @@ static struct input_device *find_device(const bdaddr_t *src, struct btd_device *device; struct btd_service *service; - device = adapter_find_device(adapter_find(src), dst); + device = btd_adapter_find_device(adapter_find(src), dst); if (device == NULL) return NULL; diff --git a/profiles/input/manager.c b/profiles/input/manager.c index 689ccddd..660043ee 100644 --- a/profiles/input/manager.c +++ b/profiles/input/manager.c @@ -46,13 +46,13 @@ static int hid_server_probe(struct btd_profile *p, struct btd_adapter *adapter) { - return server_start(adapter_get_address(adapter)); + return server_start(btd_adapter_get_address(adapter)); } static void hid_server_remove(struct btd_profile *p, struct btd_adapter *adapter) { - server_stop(adapter_get_address(adapter)); + server_stop(btd_adapter_get_address(adapter)); } static struct btd_profile input_profile = { diff --git a/profiles/input/server.c b/profiles/input/server.c index 21d4562b..f6f85a0d 100644 --- a/profiles/input/server.c +++ b/profiles/input/server.c @@ -63,6 +63,100 @@ static int server_cmp(gconstpointer s, gconstpointer user_data) return bacmp(&server->src, src); } +struct sixaxis_data { + GIOChannel *chan; + uint16_t psm; +}; + +static void connect_event_cb(GIOChannel *chan, GError *err, gpointer data); + +static void sixaxis_sdp_cb(struct btd_device *dev, int err, void *user_data) +{ + struct sixaxis_data *data = user_data; + struct input_server *server; + GError *gerr = NULL; + const bdaddr_t *src; + GSList *l; + + DBG("err %d (%s)", err, strerror(-err)); + + if (err < 0) + goto fail; + + src = btd_adapter_get_address(device_get_adapter(dev)); + + l = g_slist_find_custom(servers, src, server_cmp); + if (!l) + goto fail; + + server = l->data; + + err = input_device_set_channel(src, device_get_address(dev), + data->psm, data->chan); + if (err < 0) + goto fail; + + if (server->confirm) { + if (!bt_io_accept(server->confirm, connect_event_cb, server, + NULL, &gerr)) { + error("bt_io_accept: %s", gerr->message); + g_error_free(gerr); + goto fail; + } + + g_io_channel_unref(server->confirm); + server->confirm = NULL; + } + + g_io_channel_unref(data->chan); + g_free(data); + + return; + +fail: + g_io_channel_shutdown(data->chan, TRUE, NULL); + g_io_channel_unref(data->chan); + g_free(data); +} + +static void sixaxis_browse_sdp(const bdaddr_t *src, const bdaddr_t *dst, + GIOChannel *chan, uint16_t psm) +{ + struct btd_device *device; + struct sixaxis_data *data; + + if (psm != L2CAP_PSM_HIDP_CTRL) + return; + + device = btd_adapter_find_device(adapter_find(src), dst); + if (!device) + return; + + data = g_new0(struct sixaxis_data, 1); + data->chan = g_io_channel_ref(chan); + data->psm = psm; + + device_discover_services(device); + device_wait_for_svc_complete(device, sixaxis_sdp_cb, data); +} + +static bool dev_is_sixaxis(const bdaddr_t *src, const bdaddr_t *dst) +{ + struct btd_device *device; + + device = btd_adapter_find_device(adapter_find(src), dst); + if (!device) + return false; + + if (btd_device_get_vendor(device) != 0x054c) + return false; + + if (btd_device_get_product(device) != 0x0268) + return false; + + return true; +} + static void connect_event_cb(GIOChannel *chan, GError *err, gpointer data) { uint16_t psm; @@ -95,6 +189,11 @@ static void connect_event_cb(GIOChannel *chan, GError *err, gpointer data) if (ret == 0) return; + if (ret == -ENOENT && dev_is_sixaxis(&src, &dst)) { + sixaxis_browse_sdp(&src, &dst, chan, psm); + return; + } + error("Refusing input device connect: %s (%d)", strerror(-ret), -ret); /* Send unplug virtual cable to unknown devices */ @@ -129,6 +228,9 @@ static void auth_callback(DBusError *derr, void *user_data) goto reject; } + if (!input_device_exists(&src, &dst) && dev_is_sixaxis(&src, &dst)) + return; + if (!bt_io_accept(server->confirm, connect_event_cb, server, NULL, &err)) { error("bt_io_accept: %s", err->message); @@ -175,7 +277,7 @@ static void confirm_event_cb(GIOChannel *chan, gpointer user_data) goto drop; } - if (!input_device_exists(&src, &dst)) { + if (!input_device_exists(&src, &dst) && !dev_is_sixaxis(&src, &dst)) { error("Refusing connection from %s: unknown device", addr); goto drop; } diff --git a/profiles/network/common.c b/profiles/network/bnep.c index 0b291bdb..0a719a2e 100644 --- a/profiles/network/common.c +++ b/profiles/network/bnep.c @@ -43,9 +43,12 @@ #include <glib.h> #include "log.h" -#include "common.h" +#include "bnep.h" #include "lib/uuid.h" +#define CON_SETUP_RETRIES 3 +#define CON_SETUP_TO 9 + static int ctl; static struct { @@ -59,6 +62,35 @@ static struct { { NULL } }; +struct __service_16 { + uint16_t dst; + uint16_t src; +} __attribute__ ((packed)); + +struct bnep_conn { + GIOChannel *io; + uint16_t src; + uint16_t dst; + guint attempts; + guint setup_to; + void *data; + bnep_connect_cb conn_cb; +}; + +static void free_bnep_connect(struct bnep_conn *bc) +{ + if (!bc) + return; + + if (bc->io) { + g_io_channel_unref(bc->io); + bc->io = NULL; + } + + g_free(bc); + bc = NULL; +} + uint16_t bnep_service_id(const char *svc) { int i; @@ -149,9 +181,9 @@ int bnep_connadd(int sk, uint16_t role, char *dev) { struct bnep_connadd_req req; + memset(dev, 0, 16); memset(&req, 0, sizeof(req)); - strncpy(req.device, dev, 16); - req.device[15] = '\0'; + strcpy(req.device, "bnep%d"); req.sock = sk; req.role = role; if (ioctl(ctl, BNEPCONNADD, &req) < 0) { @@ -215,6 +247,165 @@ int bnep_if_down(const char *devname) return 0; } +static gboolean bnep_setup_cb(GIOChannel *chan, GIOCondition cond, + gpointer data) +{ + struct bnep_conn *bc = data; + struct bnep_control_rsp *rsp; + struct timeval timeo; + char pkt[BNEP_MTU]; + char iface[16]; + ssize_t r; + int sk; + + if (cond & G_IO_NVAL) + goto failed; + + if (bc->setup_to > 0) { + g_source_remove(bc->setup_to); + bc->setup_to = 0; + } + + if (cond & (G_IO_HUP | G_IO_ERR)) { + error("Hangup or error on l2cap server socket"); + goto failed; + } + + sk = g_io_channel_unix_get_fd(chan); + memset(pkt, 0, BNEP_MTU); + r = read(sk, pkt, sizeof(pkt) - 1); + if (r < 0) { + error("IO Channel read error"); + goto failed; + } + + if (r == 0) { + error("No packet received on l2cap socket"); + goto failed; + } + + errno = EPROTO; + + if ((size_t) r < sizeof(*rsp)) { + error("Packet received is not bnep type"); + goto failed; + } + + rsp = (void *) pkt; + if (rsp->type != BNEP_CONTROL) { + error("Packet received is not bnep type"); + goto failed; + } + + if (rsp->ctrl != BNEP_SETUP_CONN_RSP) + return TRUE; + + r = ntohs(rsp->resp); + if (r != BNEP_SUCCESS) { + error("bnep failed"); + goto failed; + } + + memset(&timeo, 0, sizeof(timeo)); + timeo.tv_sec = 0; + setsockopt(sk, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo)); + + sk = g_io_channel_unix_get_fd(bc->io); + if (bnep_connadd(sk, bc->src, iface)) { + error("bnep conn could not be added"); + goto failed; + } + + if (bnep_if_up(iface)) { + error("could not up %s", iface); + goto failed; + } + + bc->conn_cb(chan, iface, 0, bc->data); + free_bnep_connect(bc); + + return FALSE; + +failed: + bc->conn_cb(NULL, NULL, -EIO, bc->data); + free_bnep_connect(bc); + + return FALSE; +} + +static int bnep_setup_conn_req(struct bnep_conn *bc) +{ + struct bnep_setup_conn_req *req; + struct __service_16 *s; + unsigned char pkt[BNEP_MTU]; + int fd; + + /* Send request */ + req = (void *) pkt; + req->type = BNEP_CONTROL; + req->ctrl = BNEP_SETUP_CONN_REQ; + req->uuid_size = 2; /* 16bit UUID */ + s = (void *) req->service; + s->src = htons(bc->src); + s->dst = htons(bc->dst); + + fd = g_io_channel_unix_get_fd(bc->io); + if (write(fd, pkt, sizeof(*req) + sizeof(*s)) < 0) { + error("bnep connection req send failed: %s", strerror(errno)); + return -errno; + } + + bc->attempts++; + + return 0; +} + +static gboolean bnep_conn_req_to(gpointer user_data) +{ + struct bnep_conn *bc = user_data; + + if (bc->attempts == CON_SETUP_RETRIES) { + error("Too many bnep connection attempts"); + } else { + error("bnep connection setup TO, retrying..."); + if (bnep_setup_conn_req(bc) == 0) + return TRUE; + } + + bc->conn_cb(NULL, NULL, -ETIMEDOUT, bc->data); + free_bnep_connect(bc); + + return FALSE; +} + +int bnep_connect(int sk, uint16_t src, uint16_t dst, bnep_connect_cb conn_cb, + void *data) +{ + struct bnep_conn *bc; + int err; + + if (!conn_cb) + return -EINVAL; + + bc = g_new0(struct bnep_conn, 1); + bc->io = g_io_channel_unix_new(sk); + bc->attempts = 0; + bc->src = src; + bc->dst = dst; + bc->conn_cb = conn_cb; + bc->data = data; + + err = bnep_setup_conn_req(bc); + if (err < 0) + return err; + + bc->setup_to = g_timeout_add_seconds(CON_SETUP_TO, + bnep_conn_req_to, bc); + g_io_add_watch(bc->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, + bnep_setup_cb, bc); + return 0; +} + int bnep_add_to_bridge(const char *devname, const char *bridge) { int ifindex; diff --git a/profiles/network/common.h b/profiles/network/bnep.h index 9a8caac0..9043e46f 100644 --- a/profiles/network/common.h +++ b/profiles/network/bnep.h @@ -35,3 +35,8 @@ int bnep_if_up(const char *devname); int bnep_if_down(const char *devname); int bnep_add_to_bridge(const char *devname, const char *bridge); int bnep_del_from_bridge(const char *devname, const char *bridge); + +typedef void (*bnep_connect_cb) (GIOChannel *chan, char *iface, int err, + void *data); +int bnep_connect(int sk, uint16_t src, uint16_t dst, bnep_connect_cb conn_cb, + void *data); diff --git a/profiles/network/connection.c b/profiles/network/connection.c index 960a1fe2..9aff3191 100644 --- a/profiles/network/connection.c +++ b/profiles/network/connection.c @@ -47,12 +47,10 @@ #include "service.h" #include "error.h" -#include "common.h" +#include "bnep.h" #include "connection.h" #define NETWORK_PEER_INTERFACE "org.bluez.Network1" -#define CON_SETUP_RETRIES 3 -#define CON_SETUP_TO 9 typedef enum { CONNECTED, @@ -73,16 +71,9 @@ struct network_conn { GIOChannel *io; guint dc_id; struct network_peer *peer; - guint attempt_cnt; - guint timeout_source; DBusMessage *connect; }; -struct __service_16 { - uint16_t dst; - uint16_t src; -} __attribute__ ((packed)); - static GSList *peers = NULL; static uint16_t get_service_id(struct btd_service *service) @@ -163,11 +154,6 @@ static void local_connect_cb(struct network_conn *nc, int err) static void cancel_connection(struct network_conn *nc, int err) { - if (nc->timeout_source > 0) { - g_source_remove(nc->timeout_source); - nc->timeout_source = 0; - } - btd_service_connecting_complete(nc->service, err); if (nc->connect) local_connect_cb(nc, err); @@ -200,83 +186,24 @@ static void disconnect_cb(struct btd_device *device, gboolean removal, connection_destroy(NULL, user_data); } -static gboolean bnep_setup_cb(GIOChannel *chan, GIOCondition cond, - gpointer data) +static void bnep_conn_cb(GIOChannel *chan, char *iface, int err, void *data) { struct network_conn *nc = data; - struct bnep_control_rsp *rsp; - struct timeval timeo; - char pkt[BNEP_MTU]; - ssize_t r; - int sk; const char *path; DBusConnection *conn; - DBG("cond %u", cond); - - if (cond & G_IO_NVAL) - return FALSE; - - if (nc->timeout_source > 0) { - g_source_remove(nc->timeout_source); - nc->timeout_source = 0; - } - - if (cond & (G_IO_HUP | G_IO_ERR)) { - error("Hangup or error on l2cap server socket"); - goto failed; - } - - sk = g_io_channel_unix_get_fd(chan); - - memset(pkt, 0, BNEP_MTU); - r = read(sk, pkt, sizeof(pkt) -1); - if (r < 0) { - error("IO Channel read error"); - goto failed; - } - - if (r == 0) { - error("No packet received on l2cap socket"); - goto failed; - } - - errno = EPROTO; - - if ((size_t) r < sizeof(*rsp)) { - error("Packet received is not bnep type"); - goto failed; - } - - rsp = (void *) pkt; - if (rsp->type != BNEP_CONTROL) { - error("Packet received is not bnep type"); - goto failed; - } - - if (rsp->ctrl != BNEP_SETUP_CONN_RSP) - return TRUE; - - r = ntohs(rsp->resp); - - if (r != BNEP_SUCCESS) { - error("bnep failed"); - goto failed; - } - - memset(&timeo, 0, sizeof(timeo)); - timeo.tv_sec = 0; - - setsockopt(sk, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo)); + DBG(""); - if (bnep_connadd(sk, BNEP_SVC_PANU, nc->dev)) { - error("%s could not be added", nc->dev); + if (err < 0) { + error("connect failed %s", strerror(-err)); goto failed; } - bnep_if_up(nc->dev); + info("%s connected", nc->dev); + memcpy(nc->dev, iface, sizeof(nc->dev)); btd_service_connecting_complete(nc->service, 0); + if (nc->connect) local_connect_cb(nc, 0); @@ -292,101 +219,30 @@ static gboolean bnep_setup_cb(GIOChannel *chan, GIOCondition cond, nc->state = CONNECTED; nc->dc_id = device_add_disconnect_watch(nc->peer->device, disconnect_cb, - nc, NULL); - - info("%s connected", nc->dev); - /* Start watchdog */ + nc, NULL); g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL, - (GIOFunc) bnep_watchdog_cb, nc); + bnep_watchdog_cb, nc); g_io_channel_unref(nc->io); nc->io = NULL; - return FALSE; + return; failed: cancel_connection(nc, -EIO); - - return FALSE; -} - -static int bnep_send_conn_req(struct network_conn *nc) -{ - struct bnep_setup_conn_req *req; - struct __service_16 *s; - unsigned char pkt[BNEP_MTU]; - int fd; - - DBG(""); - - /* Send request */ - req = (void *) pkt; - req->type = BNEP_CONTROL; - req->ctrl = BNEP_SETUP_CONN_REQ; - req->uuid_size = 2; /* 16bit UUID */ - s = (void *) req->service; - s->dst = htons(nc->id); - s->src = htons(BNEP_SVC_PANU); - - fd = g_io_channel_unix_get_fd(nc->io); - if (write(fd, pkt, sizeof(*req) + sizeof(*s)) < 0) { - int err = -errno; - error("bnep connection req send failed: %s", strerror(errno)); - return err; - } - - nc->attempt_cnt++; - - return 0; -} - -static gboolean bnep_conn_req_to(gpointer user_data) -{ - struct network_conn *nc; - - nc = user_data; - if (nc->attempt_cnt == CON_SETUP_RETRIES) { - error("Too many bnep connection attempts"); - } else { - error("bnep connection setup TO, retrying..."); - if (bnep_send_conn_req(nc) == 0) - return TRUE; - } - - cancel_connection(nc, -ETIMEDOUT); - - return FALSE; -} - -static int bnep_connect(struct network_conn *nc) -{ - int err; - - nc->attempt_cnt = 0; - - err = bnep_send_conn_req(nc); - if (err < 0) - return err; - - nc->timeout_source = g_timeout_add_seconds(CON_SETUP_TO, - bnep_conn_req_to, nc); - - g_io_add_watch(nc->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, - bnep_setup_cb, nc); - - return 0; } static void connect_cb(GIOChannel *chan, GError *err, gpointer data) { struct network_conn *nc = data; - int perr; + int sk, perr; if (err) { error("%s", err->message); goto failed; } - perr = bnep_connect(nc); + sk = g_io_channel_unix_get_fd(nc->io); + perr = bnep_connect(sk, BNEP_SVC_PANU, nc->id, bnep_conn_cb, nc); if (perr < 0) { error("bnep connect(): %s (%d)", strerror(-perr), -perr); goto failed; @@ -452,7 +308,7 @@ int connection_connect(struct btd_service *service) if (nc->state != DISCONNECTED) return -EALREADY; - src = adapter_get_address(device_get_adapter(peer->device)); + src = btd_adapter_get_address(device_get_adapter(peer->device)); dst = device_get_address(peer->device); nc->io = bt_io_connect(connect_cb, nc, @@ -692,8 +548,6 @@ int connection_register(struct btd_service *service) nc = g_new0(struct network_conn, 1); nc->id = id; - memset(nc->dev, 0, sizeof(nc->dev)); - strcpy(nc->dev, "bnep%d"); nc->service = btd_service_ref(service); nc->state = DISCONNECTED; nc->peer = peer; diff --git a/profiles/network/manager.c b/profiles/network/manager.c index ab4224de..8ac2decb 100644 --- a/profiles/network/manager.c +++ b/profiles/network/manager.c @@ -43,7 +43,7 @@ #include "device.h" #include "profile.h" #include "service.h" -#include "common.h" +#include "bnep.h" #include "connection.h" #include "server.h" diff --git a/profiles/network/server.c b/profiles/network/server.c index 7b784e54..b3aab118 100644 --- a/profiles/network/server.c +++ b/profiles/network/server.c @@ -48,7 +48,7 @@ #include "error.h" #include "sdpd.h" -#include "common.h" +#include "bnep.h" #include "server.h" #define NETWORK_SERVER_INTERFACE "org.bluez.NetworkServer1" @@ -269,9 +269,6 @@ static int server_connadd(struct network_server *ns, char devname[16]; int err, nsk; - memset(devname, 0, sizeof(devname)); - strcpy(devname, "bnep%d"); - nsk = g_io_channel_unix_get_fd(session->io); err = bnep_connadd(nsk, dst_role, devname); if (err < 0) @@ -765,7 +762,7 @@ static struct network_adapter *create_adapter(struct btd_adapter *adapter) na->io = bt_io_listen(NULL, confirm_event, na, NULL, &err, BT_IO_OPT_SOURCE_BDADDR, - adapter_get_address(adapter), + btd_adapter_get_address(adapter), BT_IO_OPT_PSM, BNEP_PSM, BT_IO_OPT_OMTU, BNEP_MTU, BT_IO_OPT_IMTU, BNEP_MTU, @@ -823,7 +820,7 @@ int server_register(struct btd_adapter *adapter, uint16_t id) path); done: - bacpy(&ns->src, adapter_get_address(adapter)); + bacpy(&ns->src, btd_adapter_get_address(adapter)); ns->id = id; ns->na = na; ns->record_id = 0; diff --git a/profiles/sap/server.c b/profiles/sap/server.c index 63314a77..119862df 100644 --- a/profiles/sap/server.c +++ b/profiles/sap/server.c @@ -1372,7 +1372,8 @@ int sap_server_register(struct btd_adapter *adapter) io = bt_io_listen(NULL, connect_confirm_cb, server, NULL, &gerr, - BT_IO_OPT_SOURCE_BDADDR, adapter_get_address(adapter), + BT_IO_OPT_SOURCE_BDADDR, + btd_adapter_get_address(adapter), BT_IO_OPT_CHANNEL, SAP_SERVER_CHANNEL, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_HIGH, BT_IO_OPT_MASTER, TRUE, |