static void connect_cb(GIOChannel *io, GError *err, gpointer user_data) { uint16_t mtu; uint16_t cid; GError *gerr = NULL; DBG("io = %p, err = %p", io, err); if (err) { DBG("err = %s", err->message); set_state(STATE_DISCONNECTED); resp_error(err_CONN_FAIL); printf("# Connect error: %s\n", err->message); return; } bt_io_get(io, &gerr, BT_IO_OPT_IMTU, &mtu, BT_IO_OPT_CID, &cid, BT_IO_OPT_INVALID); if (gerr) { printf("# Can't detect MTU, using default"); g_error_free(gerr); mtu = ATT_DEFAULT_LE_MTU; } else if (cid == ATT_CID) mtu = ATT_DEFAULT_LE_MTU; attrib = g_attrib_new(iochannel, mtu); g_attrib_register(attrib, ATT_OP_HANDLE_NOTIFY, GATTRIB_ALL_HANDLES, events_handler, attrib, NULL); g_attrib_register(attrib, ATT_OP_HANDLE_IND, GATTRIB_ALL_HANDLES, events_handler, attrib, NULL); g_attrib_register(attrib, ATT_OP_FIND_INFO_REQ, GATTRIB_ALL_HANDLES, req_gatts, NULL, NULL); g_attrib_register(attrib, ATT_OP_FIND_BY_TYPE_REQ, GATTRIB_ALL_HANDLES, req_gatts, NULL, NULL); g_attrib_register(attrib, ATT_OP_READ_BY_TYPE_REQ, GATTRIB_ALL_HANDLES, req_gatts, NULL, NULL); g_attrib_register(attrib, ATT_OP_READ_REQ, GATTRIB_ALL_HANDLES, req_gatts, NULL, NULL); g_attrib_register(attrib, ATT_OP_READ_BLOB_REQ, GATTRIB_ALL_HANDLES, req_gatts, NULL, NULL); g_attrib_register(attrib, ATT_OP_READ_MULTI_REQ, GATTRIB_ALL_HANDLES, req_gatts, NULL, NULL); g_attrib_register(attrib, ATT_OP_READ_BY_GROUP_REQ, GATTRIB_ALL_HANDLES, req_gatts, NULL, NULL); g_attrib_register(attrib, ATT_OP_WRITE_REQ, GATTRIB_ALL_HANDLES, req_gatts, NULL, NULL); g_attrib_register(attrib, ATT_OP_WRITE_CMD, GATTRIB_ALL_HANDLES, req_gatts, NULL, NULL); g_attrib_register(attrib, ATT_OP_SIGNED_WRITE_CMD, GATTRIB_ALL_HANDLES, req_gatts, NULL, NULL); g_attrib_register(attrib, ATT_OP_PREP_WRITE_REQ, GATTRIB_ALL_HANDLES, req_gatts, NULL, NULL); g_attrib_register(attrib, ATT_OP_EXEC_WRITE_REQ, GATTRIB_ALL_HANDLES, req_gatts, NULL, NULL); set_state(STATE_CONNECTED); }
static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data) { uint16_t imtu, omtu; GError *gerr = NULL; int fd; if (err) { printf("%s\n", err->message); g_main_loop_quit(mainloop); return; } bt_io_get(chan, &gerr, BT_IO_OPT_IMTU, &imtu, BT_IO_OPT_OMTU, &omtu, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_INVALID); if (gerr) { printf("%s\n", gerr->message); g_main_loop_quit(mainloop); return; } printf("Connected (imtu=%d omtu=%d)\n", imtu, omtu); fd = g_io_channel_unix_get_fd(chan); if (avdtp && avdtp_stream) { if (!avdtp_stream_set_transport(avdtp_stream, fd, imtu, omtu)) { printf("avdtp_stream_set_transport: failed\n"); g_main_loop_quit(mainloop); } g_io_channel_set_close_on_unref(chan, FALSE); send_command(); return; } avdtp = avdtp_new(fd, imtu, omtu, version); if (!avdtp) { printf("Failed to create avdtp instance\n"); g_main_loop_quit(mainloop); return; } avdtp_add_disconnect_cb(avdtp, disconnect_cb, NULL); if (preconf) { int ret; ret = avdtp_discover(avdtp, discover_cb, NULL); if (ret < 0) { printf("avdtp_discover failed: %s", strerror(-ret)); g_main_loop_quit(mainloop); } } }
static void avctp_connect_browsing_cb(GIOChannel *chan, GError *err, gpointer data) { struct avctp *session = data; struct avctp_channel *browsing = session->browsing; char address[18]; uint16_t imtu, omtu; GError *gerr = NULL; if (err) { error("Browsing: %s", err->message); goto fail; } bt_io_get(chan, &gerr, BT_IO_OPT_DEST, &address, BT_IO_OPT_IMTU, &imtu, BT_IO_OPT_OMTU, &omtu, BT_IO_OPT_INVALID); if (gerr) { error("%s", gerr->message); g_io_channel_shutdown(chan, TRUE, NULL); g_io_channel_unref(chan); g_error_free(gerr); goto fail; } DBG("AVCTP Browsing: connected to %s", address); if (browsing == NULL) { browsing = avctp_channel_create(session, chan, avctp_destroy_browsing); session->browsing = browsing; } browsing->imtu = imtu; browsing->omtu = omtu; browsing->buffer = g_malloc0(MAX(imtu, omtu)); browsing->watch = g_io_add_watch(session->browsing->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) session_browsing_cb, session); avctp_set_state(session, AVCTP_STATE_BROWSING_CONNECTED); /* Process any request that was pending the connection to complete */ if (browsing->process_id == 0 && !g_queue_is_empty(browsing->queue)) browsing->process_id = g_idle_add(process_queue, browsing); return; fail: avctp_set_state(session, AVCTP_STATE_CONNECTED); if (session->browsing) { avctp_channel_destroy(session->browsing); session->browsing = NULL; } }
static void connect_confirm_cb(GIOChannel *io, gpointer data) { struct sap_server *server = data; struct sap_connection *conn = server->conn; GError *gerr = NULL; bdaddr_t src, dst; char dstaddr[18]; int err; DBG("conn %p io %p", conn, io); if (!io) return; if (conn) { DBG("Another SAP connection already exists."); g_io_channel_shutdown(io, TRUE, NULL); return; } conn = g_try_new0(struct sap_connection, 1); if (!conn) { error("Can't allocate memory for incoming SAP connection."); g_io_channel_shutdown(io, TRUE, NULL); return; } g_io_channel_set_encoding(io, NULL, NULL); g_io_channel_set_buffered(io, FALSE); server->conn = conn; conn->io = g_io_channel_ref(io); conn->state = SAP_STATE_DISCONNECTED; bt_io_get(io, BT_IO_RFCOMM, &gerr, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_INVALID); if (gerr) { error("%s", gerr->message); g_error_free(gerr); sap_server_remove_conn(server); return; } ba2str(&dst, dstaddr); err = btd_request_authorization(&src, &dst, SAP_UUID, connect_auth_cb, server); if (err < 0) { error("Authorization failure (err %d)", err); sap_server_remove_conn(server); return; } DBG("Authorizing incoming SAP connection from %s", dstaddr); }
static void hf_io_cb(GIOChannel *chan, gpointer data) { bdaddr_t src, dst; GError *err = NULL; uint8_t ch; const char *server_uuid, *remote_uuid; struct audio_device *device; int perr; bt_io_get(chan, BT_IO_RFCOMM, &err, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_CHANNEL, &ch, BT_IO_OPT_INVALID); if (err) { error("%s", err->message); g_error_free(err); return; } server_uuid = HFP_AG_UUID; remote_uuid = HFP_HS_UUID; device = manager_get_device(&src, &dst, TRUE); if (!device) goto drop; if (!device->gateway) { btd_device_add_uuid(device->btd_dev, remote_uuid); if (!device->gateway) goto drop; } if (gateway_is_connected(device)) { DBG("Refusing new connection since one already exists"); goto drop; } if (gateway_connect_rfcomm(device, chan) < 0) { error("Allocating new GIOChannel failed!"); goto drop; } perr = audio_device_request_authorization(device, server_uuid, gateway_auth_cb, device); if (perr < 0) { DBG("Authorization denied!"); goto drop; } return; drop: g_io_channel_shutdown(chan, TRUE, NULL); }
static void avctp_confirm_cb(GIOChannel *chan, gpointer data) { struct control *control = NULL; struct audio_device *dev; char address[18]; bdaddr_t src, dst; GError *err = NULL; bt_io_get(chan, BT_IO_L2CAP, &err, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_DEST, address, BT_IO_OPT_INVALID); if (err) { error("%s", err->message); g_error_free(err); g_io_channel_shutdown(chan, TRUE, NULL); return; } dev = manager_get_device(&src, &dst, TRUE); if (!dev) { error("Unable to get audio device object for %s", address); goto drop; } if (!dev->control) { btd_device_add_uuid(dev->btd_dev, AVRCP_REMOTE_UUID); if (!dev->control) goto drop; } control = dev->control; if (control->io) { error("Refusing unexpected connect from %s", address); goto drop; } avctp_set_state(control, AVCTP_STATE_CONNECTING); control->io = g_io_channel_ref(chan); if (audio_device_request_authorization(dev, AVRCP_TARGET_UUID, auth_cb, dev->control) < 0) goto drop; control->io_id = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL, control_cb, control); return; drop: if (!control || !control->io) g_io_channel_shutdown(chan, TRUE, NULL); if (control) avctp_set_state(control, AVCTP_STATE_DISCONNECTED); }
static void confirm_event(GIOChannel *chan, gpointer user_data) { struct network_adapter *na = user_data; struct network_server *ns; int perr; bdaddr_t src, dst; char address[18]; GError *err = NULL; bt_io_get(chan, BT_IO_L2CAP, &err, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_DEST, address, BT_IO_OPT_INVALID); if (err) { error("%s", err->message); g_error_free(err); goto drop; } DBG("BNEP: incoming connect from %s", address); if (na->setup) { error("Refusing connect from %s: setup in progress", address); goto drop; } ns = find_server(na->servers, BNEP_SVC_NAP); if (!ns) goto drop; if (!ns->record_id) goto drop; if (!ns->bridge) goto drop; na->setup = g_new0(struct network_session, 1); bacpy(&na->setup->dst, &dst); na->setup->io = g_io_channel_ref(chan); perr = btd_request_authorization(&src, &dst, BNEP_SVC_UUID, auth_cb, na); if (perr < 0) { error("Refusing connect from %s: %s (%d)", address, strerror(-perr), -perr); setup_destroy(na); goto drop; } return; drop: g_io_channel_shutdown(chan, TRUE, NULL); }
static void signaling_connect_cb(GIOChannel *chan, GError *err, gpointer user_data) { struct a2dp_device *dev = user_data; uint16_t imtu, omtu; GError *gerr = NULL; int fd; if (err) { bt_a2dp_notify_state(dev, HAL_A2DP_STATE_DISCONNECTED); error("%s", err->message); return; } bt_io_get(chan, &gerr, BT_IO_OPT_IMTU, &imtu, BT_IO_OPT_OMTU, &omtu, BT_IO_OPT_INVALID); if (gerr) { error("%s", gerr->message); g_error_free(gerr); goto failed; } fd = g_io_channel_unix_get_fd(chan); /* FIXME: Add proper version */ dev->session = avdtp_new(fd, imtu, omtu, 0x0100); if (!dev->session) goto failed; avdtp_add_disconnect_cb(dev->session, disconnect_cb, dev); /* Proceed to stream setup if initiator */ if (dev->io) { int perr; g_io_channel_unref(dev->io); dev->io = NULL; perr = avdtp_discover(dev->session, discover_cb, dev); if (perr < 0) { error("avdtp_discover: %s", strerror(-perr)); goto failed; } bt_avrcp_connect(&dev->dst); } else /* Init idle timeout to discover */ dev->idle_id = g_timeout_add_seconds(IDLE_TIMEOUT, idle_timeout, dev); return; failed: bt_a2dp_notify_state(dev, HAL_A2DP_STATE_DISCONNECTED); }
static DBusMessage *proxy_enable(DBusConnection *conn, DBusMessage *msg, void *data) { struct serial_proxy *prx = data; sdp_record_t *record; GError *err = NULL; DBusMessage *reply; if (prx->io) return failed(msg, "Already enabled"); /* Listen */ prx->io = bt_io_listen(BT_IO_RFCOMM, NULL, confirm_event_cb, prx, NULL, &err, BT_IO_OPT_SOURCE_BDADDR, &prx->src, BT_IO_OPT_INVALID); if (!prx->io) goto failed; bt_io_get(prx->io, BT_IO_RFCOMM, &err, BT_IO_OPT_CHANNEL, &prx->channel, BT_IO_OPT_INVALID); if (err) { g_io_channel_unref(prx->io); prx->io = NULL; goto failed; } debug("Allocated channel %d", prx->channel); g_io_channel_set_close_on_unref(prx->io, TRUE); record = proxy_record_new(prx->uuid128, prx->channel); if (!record) { g_io_channel_unref(prx->io); return failed(msg, "Unable to allocate new service record"); } if (add_record_to_server(&prx->src, record) < 0) { sdp_record_free(record); g_io_channel_unref(prx->io); return failed(msg, "Service registration failed"); } prx->record_id = record->handle; return dbus_message_new_method_return(msg); failed: error("%s", err->message); reply = failed(msg, err->message); g_error_free(err); return reply; }
static void ctrl_confirm_event_cb(GIOChannel *chan, gpointer user_data) { struct input_server *server = user_data; bdaddr_t src, dst; GError *err = NULL; struct btd_device *device = NULL; DBG(""); bt_io_get(chan, BT_IO_L2CAP, &err, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_INVALID); if (err) { error("%s", err->message); g_error_free(err); goto drop; } device = device_for_connection(&src, &dst); if (!device) { DBG("No device."); goto drop; } if (device_has_service_records(device)) { DBG("Device has service records"); server->pending_accept.chan = chan; if (server_accept(server)) return; DBG("Accept failed"); goto drop; } if (server->pending_accept.timer) { DBG("Accept already pending."); goto drop; } DBG("Device has no service records, pending accept."); server->pending_accept.chan = chan; g_io_channel_ref(server->pending_accept.chan); server->pending_accept.retries = 0; server->pending_accept.src = src; server->pending_accept.dst = dst; server->pending_accept.timer = g_timeout_add_seconds(1, retry_server_accept, server); return; drop: g_io_channel_shutdown(chan, TRUE, NULL); }
static void avctp_connect_cb(GIOChannel *chan, GError *err, gpointer data) { struct avctp *session = data; char address[18]; uint16_t imtu, omtu; GError *gerr = NULL; if (err) { avctp_set_state(session, AVCTP_STATE_DISCONNECTED); error("%s", err->message); return; } bt_io_get(chan, &gerr, BT_IO_OPT_DEST, &address, BT_IO_OPT_IMTU, &imtu, BT_IO_OPT_IMTU, &omtu, BT_IO_OPT_INVALID); if (gerr) { avctp_set_state(session, AVCTP_STATE_DISCONNECTED); error("%s", gerr->message); g_error_free(gerr); return; } DBG("AVCTP: connected to %s", address); if (session->control == NULL) session->control = avctp_channel_create(session, chan, NULL); session->control->imtu = imtu; session->control->omtu = omtu; session->control->buffer = g_malloc0(MAX(imtu, omtu)); session->control->watch = g_io_add_watch(session->control->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) session_cb, session); session->passthrough_id = avctp_register_pdu_handler(session, AVC_OP_PASSTHROUGH, handle_panel_passthrough, NULL); session->unit_id = avctp_register_pdu_handler(session, AVC_OP_UNITINFO, handle_unit_info, NULL); session->subunit_id = avctp_register_pdu_handler(session, AVC_OP_SUBUNITINFO, handle_subunit_info, NULL); init_uinput(session); avctp_set_state(session, AVCTP_STATE_CONNECTED); }
gboolean g_attrib_is_encrypted(GAttrib *attrib) { BtIOSecLevel sec_level; if (!bt_io_get(attrib->io, BT_IO_L2CAP, NULL, BT_IO_OPT_SEC_LEVEL, &sec_level, BT_IO_OPT_INVALID)) return FALSE; return sec_level > BT_IO_SEC_LOW; }
static int enable_proxy(struct serial_proxy *prx) { sdp_record_t *record; GError *gerr = NULL; int err; if (prx->io) return -EALREADY; /* Listen */ prx->io = bt_io_listen(BT_IO_RFCOMM, NULL, confirm_event_cb, prx, NULL, &gerr, BT_IO_OPT_SOURCE_BDADDR, &prx->src, BT_IO_OPT_INVALID); if (!prx->io) goto failed; bt_io_get(prx->io, BT_IO_RFCOMM, &gerr, BT_IO_OPT_CHANNEL, &prx->channel, BT_IO_OPT_INVALID); if (gerr) { g_io_channel_unref(prx->io); prx->io = NULL; goto failed; } debug("Allocated channel %d", prx->channel); g_io_channel_set_close_on_unref(prx->io, TRUE); record = proxy_record_new(prx->uuid128, prx->channel); if (!record) { g_io_channel_unref(prx->io); return -ENOMEM; } err = add_record_to_server(&prx->src, record); if (err < 0) { sdp_record_free(record); g_io_channel_unref(prx->io); return err; } prx->record_id = record->handle; return 0; failed: error("%s", gerr->message); g_error_free(gerr); return -EIO; }
static void rfcomm_listen(const char *src, uint8_t ch, gboolean defer, gint reject, gint disconn, gint accept, gint sec, gboolean master) { struct io_data *data; BtIOConnect conn; BtIOConfirm cfm; GIOChannel *rc_srv; GError *err = NULL; if (defer) { conn = NULL; cfm = confirm_cb; } else { conn = connect_cb; cfm = NULL; } data = io_data_new(NULL, BT_IO_RFCOMM, reject, disconn, accept); if (src) rc_srv = bt_io_listen(BT_IO_RFCOMM, conn, cfm, data, (GDestroyNotify) io_data_unref, &err, BT_IO_OPT_SOURCE, src, BT_IO_OPT_CHANNEL, ch, BT_IO_OPT_SEC_LEVEL, sec, BT_IO_OPT_MASTER, master, BT_IO_OPT_INVALID); else rc_srv = bt_io_listen(BT_IO_RFCOMM, conn, cfm, data, (GDestroyNotify) io_data_unref, &err, BT_IO_OPT_CHANNEL, ch, BT_IO_OPT_SEC_LEVEL, sec, BT_IO_OPT_MASTER, master, BT_IO_OPT_INVALID); if (!rc_srv) { printf("Listening failed: %s\n", err->message); g_error_free(err); exit(EXIT_FAILURE); } bt_io_get(rc_srv, BT_IO_RFCOMM, &err, BT_IO_OPT_CHANNEL, &ch, BT_IO_OPT_INVALID); printf("Listening on RFCOMM channel %u\n", ch); g_io_channel_unref(rc_srv); }
static void avctp_confirm_cb(GIOChannel *chan, gpointer data) { struct avctp *session; char address[18]; bdaddr_t src, dst; GError *err = NULL; uint16_t psm; struct btd_device *device; bt_io_get(chan, &err, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_DEST, address, BT_IO_OPT_PSM, &psm, BT_IO_OPT_INVALID); if (err) { error("%s", err->message); g_error_free(err); g_io_channel_shutdown(chan, TRUE, NULL); return; } DBG("AVCTP: incoming connect from %s", address); device = btd_adapter_find_device(adapter_find(&src), &dst, BDADDR_BREDR); if (!device) return; session = avctp_get_internal(device); if (session == NULL) return; if (btd_device_get_service(device, AVRCP_REMOTE_UUID) == NULL) btd_device_add_uuid(device, AVRCP_REMOTE_UUID); if (btd_device_get_service(device, AVRCP_TARGET_UUID) == NULL) btd_device_add_uuid(device, AVRCP_TARGET_UUID); switch (psm) { case AVCTP_CONTROL_PSM: avctp_control_confirm(session, chan, device); break; case AVCTP_BROWSING_PSM: avctp_browsing_confirm(session, chan, device); break; } return; }
static void confirm_cb(GIOChannel *io, gpointer user_data) { char addr[18]; struct io_data *data = user_data; GError *err = NULL; if (!bt_io_get(io, &err, BT_IO_OPT_DEST, addr, BT_IO_OPT_INVALID)) { printf("bt_io_get(OPT_DEST): %s\n", err->message); g_clear_error(&err); } else printf("Got confirmation request for %s\n", addr); if (data->accept < 0 && data->reject < 0) return; if (data->reject == 0) { printf("Rejecting connection\n"); g_io_channel_shutdown(io, TRUE, NULL); return; } if (data->voice) { if (!bt_io_set(io, &err, BT_IO_OPT_VOICE, data->voice, BT_IO_OPT_INVALID)) { printf("bt_io_set(OPT_VOICE): %s\n", err->message); g_clear_error(&err); } } data->io = g_io_channel_ref(io); io_data_ref(data); if (data->accept == 0) { if (!bt_io_accept(io, connect_cb, data, (GDestroyNotify) io_data_unref, &err)) { printf("bt_io_accept() failed: %s\n", err->message); g_clear_error(&err); io_data_unref(data); return; } } else { int seconds = (data->reject > 0) ? data->reject : data->accept; g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, seconds, confirm_timeout, data, (GDestroyNotify) io_data_unref); } }
static void connect_event_cb(GIOChannel *chan, GError *err, gpointer data) { uint16_t psm; bdaddr_t src, dst; char address[18]; GError *gerr = NULL; int ret; if (err) { error("%s", err->message); return; } bt_io_get(chan, &gerr, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_PSM, &psm, BT_IO_OPT_INVALID); if (gerr) { error("%s", gerr->message); g_error_free(gerr); g_io_channel_shutdown(chan, TRUE, NULL); return; } ba2str(&dst, address); DBG("Incoming connection from %s on PSM %d", address, psm); ret = input_device_set_channel(&src, &dst, psm, chan); 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 */ if (ret == -ENOENT && psm == L2CAP_PSM_HIDP_CTRL) { unsigned char unplug = 0x15; int sk = g_io_channel_unix_get_fd(chan); if (write(sk, &unplug, sizeof(unplug)) < 0) error("Unable to send virtual cable unplug"); } g_io_channel_shutdown(chan, TRUE, NULL); }
static void confirm_event_cb(GIOChannel *chan, gpointer user_data) { struct input_server *server = user_data; bdaddr_t src, dst; GError *err = NULL; char addr[18]; guint ret; DBG(""); bt_io_get(chan, &err, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_INVALID); if (err) { error("%s", err->message); g_error_free(err); goto drop; } ba2str(&dst, addr); if (server->confirm) { error("Refusing connection from %s: setup in progress", addr); goto drop; } if (!input_device_exists(&src, &dst) && !dev_is_sixaxis(&src, &dst)) { error("Refusing connection from %s: unknown device", addr); goto drop; } server->confirm = g_io_channel_ref(chan); ret = btd_request_authorization(&src, &dst, HID_UUID, auth_callback, server); if (ret != 0) return; error("input: authorization for device %s failed", addr); g_io_channel_unref(server->confirm); server->confirm = NULL; drop: input_device_close_channels(&src, &dst); g_io_channel_shutdown(chan, TRUE, NULL); }
static int bluetooth_getpeername(GIOChannel *io, char **name) { GError *gerr = NULL; char address[18]; bt_io_get(io, &gerr, BT_IO_OPT_DEST, address, BT_IO_OPT_INVALID); if (gerr) { error("%s", gerr->message); g_error_free(gerr); return -EINVAL; } *name = g_strdup(address); return 0; }
static void transport_connect_cb(GIOChannel *chan, GError *err, gpointer user_data) { struct a2dp_device *dev = user_data; struct a2dp_setup *setup; uint16_t imtu, omtu; GError *gerr = NULL; int fd; if (err) { error("%s", err->message); return; } setup = find_setup_by_device(dev); if (!setup) { error("Unable to find stream setup"); return; } bt_io_get(chan, &gerr, BT_IO_OPT_IMTU, &imtu, BT_IO_OPT_OMTU, &omtu, BT_IO_OPT_INVALID); if (gerr) { error("%s", gerr->message); g_error_free(gerr); return; } fd = g_io_channel_unix_get_fd(chan); if (!avdtp_stream_set_transport(setup->stream, fd, imtu, omtu)) { error("avdtp_stream_set_transport: failed"); return; } g_io_channel_set_close_on_unref(chan, FALSE); if (dev->io) { g_io_channel_unref(dev->io); dev->io = NULL; } bt_a2dp_notify_state(dev, HAL_A2DP_STATE_CONNECTED); }
static void confirm_event_cb(GIOChannel *chan, gpointer user_data) { struct input_server *server = user_data; bdaddr_t src, dst; GError *err = NULL; char addr[18]; int ret; bt_io_get(chan, BT_IO_L2CAP, &err, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_INVALID); if (err) { error("%s", err->message); g_error_free(err); goto drop; } if (server->confirm) { char address[18]; ba2str(&dst, address); error("Refusing connection from %s: setup in progress", address); goto drop; } server->confirm = g_io_channel_ref(chan); ret = btd_request_authorization(&src, &dst, HID_UUID, auth_callback, server); if (ret == 0) return; ba2str(&src, addr); error("input: authorization for %s failed: %s (%d)", addr, strerror(-ret), ret); g_io_channel_unref(server->confirm); server->confirm = NULL; drop: input_device_close_channels(&src, &dst); g_io_channel_shutdown(chan, TRUE, NULL); }
bool bt_sco_get_fd_and_mtu(struct bt_sco *sco, int *fd, uint16_t *mtu) { GError *err; if (!sco->io || !fd || !mtu) return false; err = NULL; if (!bt_io_get(sco->io, &err, BT_IO_OPT_MTU, mtu, BT_IO_OPT_INVALID)) { error("Unable to get MTU: %s\n", err->message); g_clear_error(&err); return false; } *fd = g_io_channel_unix_get_fd(sco->io); return true; }
static void nap_confirm_cb(GIOChannel *chan, gpointer data) { struct pan_device *dev; bdaddr_t dst; char address[18]; GError *err = NULL; DBG(""); bt_io_get(chan, &err, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_DEST, address, BT_IO_OPT_INVALID); if (err) { error("%s", err->message); g_error_free(err); return; } DBG("incoming connect request from %s", address); dev = g_new0(struct pan_device, 1); bacpy(&dev->dst, &dst); local_role = HAL_PAN_ROLE_NAP; dev->role = HAL_PAN_ROLE_PANU; strncpy(dev->iface, BNEP_NAP_INTERFACE, 16); dev->iface[15] = '\0'; dev->io = g_io_channel_ref(chan); g_io_channel_set_close_on_unref(dev->io, TRUE); if (!bt_io_accept(dev->io, nap_connect_cb, dev, NULL, &err)) { error("bt_io_accept: %s", err->message); g_error_free(err); goto failed; } devices = g_slist_append(devices, dev); bt_pan_notify_conn_state(dev, HAL_PAN_STATE_CONNECTING); return; failed: bt_pan_notify_conn_state(dev, HAL_PAN_STATE_DISCONNECTED); }
static void ext_connect(GIOChannel *io, GError *err, gpointer user_data) { struct ext_io *conn = user_data; struct ext_profile *ext = conn->ext; struct btd_device *device; bdaddr_t src; char addr[18]; if (!bt_io_get(io, NULL, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_DEST, addr, BT_IO_OPT_INVALID)) { error("Unable to get connect data for %s", ext->name); goto drop; } if (err != NULL) { error("%s failed to connect to %s: %s", ext->name, addr, err->message); goto drop; } DBG("%s connected to %s", ext->name, addr); device = get_btd_dev(&src, addr); if (!device) { error("%s: Unable to get dev object for %s", ext->name, addr); goto drop; } if (conn->io_id == 0) { GIOCondition cond = G_IO_HUP | G_IO_ERR | G_IO_NVAL; conn->io_id = g_io_add_watch(io, cond, ext_io_disconnected, conn); } if (send_new_connection(ext, conn, device)) return; drop: ext->conns = g_slist_remove(ext->conns, conn); ext_io_destroy(conn); }
static void update_char_desc(guint8 status, const guint8 *pdu, guint16 len, gpointer user_data) { struct query_data *current = user_data; struct gatt_service *gatt = current->gatt; struct characteristic *chr = current->chr; INFO("%s",chr->path); if (status == 0) { g_free(chr->desc); chr->desc = g_malloc(len); memcpy(chr->desc, pdu + 1, len - 1); chr->desc[len - 1] = '\0'; store_attribute(gatt, current->handle, GATT_CHARAC_USER_DESC_UUID, (void *) chr->desc, len); } else if (status == ATT_ECODE_INSUFF_ENC) { GIOChannel *io = g_attrib_get_channel(gatt->attrib); BtIOSecLevel level = BT_IO_SEC_HIGH; bt_io_get(io, BT_IO_L2CAP, NULL, BT_IO_OPT_SEC_LEVEL, &level, BT_IO_OPT_INVALID); if (level < BT_IO_SEC_HIGH) level++; if (bt_io_set(io, BT_IO_L2CAP, NULL, BT_IO_OPT_SEC_LEVEL, level, BT_IO_OPT_INVALID)) { gatt_read_char(gatt->attrib, current->handle, 0, update_char_desc, current); return; } } add_characteristic_descriptor(current, GATT_CHARAC_USER_DESC_UUID); query_list_remove(gatt, current); g_free(current); }
static void auth_callback(DBusError *derr, void *user_data) { struct input_server *server = user_data; bdaddr_t src, dst; GError *err = NULL; bt_io_get(server->confirm, &err, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_INVALID); if (err) { error("%s", err->message); g_error_free(err); goto reject; } if (derr) { error("Access denied: %s", derr->message); 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); g_error_free(err); goto reject; } g_io_channel_unref(server->confirm); server->confirm = NULL; return; reject: g_io_channel_shutdown(server->confirm, TRUE, NULL); g_io_channel_unref(server->confirm); server->confirm = NULL; input_device_close_channels(&src, &dst); }
static void confirm_event_cb(GIOChannel *chan, gpointer user_data) { struct serial_proxy *prx = user_data; int perr; char address[18]; GError *err = NULL; bt_io_get(chan, BT_IO_RFCOMM, &err, BT_IO_OPT_DEST_BDADDR, &prx->dst, BT_IO_OPT_DEST, address, BT_IO_OPT_INVALID); if (err) { error("%s", err->message); g_error_free(err); goto drop; } if (prx->rfcomm) { error("Refusing connect from %s: Proxy already in use", address); goto drop; } debug("Serial Proxy: incoming connect from %s", address); prx->rfcomm = g_io_channel_ref(chan); perr = btd_request_authorization(&prx->src, &prx->dst, prx->uuid128, auth_cb, prx); if (perr < 0) { error("Refusing connect from %s: %s (%d)", address, strerror(-perr), -perr); g_io_channel_unref(prx->rfcomm); prx->rfcomm = NULL; goto drop; } return; drop: g_io_channel_shutdown(chan, TRUE, NULL); }
GAttrib *g_attrib_new(GIOChannel *io) { struct _GAttrib *attrib; uint16_t imtu; uint16_t att_mtu; uint16_t cid; GError *gerr = NULL; g_io_channel_set_encoding(io, NULL, NULL); g_io_channel_set_buffered(io, FALSE); bt_io_get(io, BT_IO_L2CAP, &gerr, BT_IO_OPT_IMTU, &imtu, BT_IO_OPT_CID, &cid, BT_IO_OPT_INVALID); if (gerr) { error("%s", gerr->message); g_error_free(gerr); return NULL; } attrib = g_try_new0(struct _GAttrib, 1); if (attrib == NULL) return NULL; att_mtu = (cid == ATT_CID) ? ATT_DEFAULT_LE_MTU : imtu; attrib->buf = g_malloc0(att_mtu); attrib->buflen = att_mtu; attrib->io = g_io_channel_ref(io); attrib->requests = g_queue_new(); attrib->responses = g_queue_new(); attrib->read_watch = g_io_add_watch(attrib->io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, received_data, attrib); return g_attrib_ref(attrib); }
static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data) { struct avrcp_device *dev = user_data; uint16_t imtu, omtu; char address[18]; GError *gerr = NULL; int fd; if (err) { error("%s", err->message); return; } bt_io_get(chan, &gerr, BT_IO_OPT_DEST, address, BT_IO_OPT_IMTU, &imtu, BT_IO_OPT_OMTU, &omtu, BT_IO_OPT_INVALID); if (gerr) { error("%s", gerr->message); g_error_free(gerr); g_io_channel_shutdown(chan, TRUE, NULL); return; } fd = g_io_channel_unix_get_fd(chan); if (avrcp_device_add_session(dev, fd, imtu, omtu) < 0) { avrcp_device_free(dev); return; } g_io_channel_set_close_on_unref(chan, FALSE); if (dev->io) { g_io_channel_unref(dev->io); dev->io = NULL; } DBG("%s connected", address); }
static void connect_event_cb(GIOChannel *chan, GError *err, gpointer data) { uint16_t psm; bdaddr_t src, dst; GError *gerr = NULL; int ret; if (err) { error("%s", err->message); return; } bt_io_get(chan, BT_IO_L2CAP, &gerr, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_PSM, &psm, BT_IO_OPT_INVALID); if (gerr) { error("%s", gerr->message); g_error_free(gerr); g_io_channel_shutdown(chan, TRUE, NULL); return; } DBG("Incoming connection on PSM %d", psm); ret = input_device_set_channel(&src, &dst, psm, chan); if (ret == 0) return; /* Send unplug virtual cable to unknown devices */ if (ret == -ENOENT && psm == L2CAP_PSM_HIDP_CTRL) { unsigned char unplug = 0x15; int err, sk = g_io_channel_unix_get_fd(chan); err = write(sk, &unplug, sizeof(unplug)); } g_io_channel_shutdown(chan, TRUE, NULL); }