static void handle_open_req(struct unix_client *client, struct bt_open_req *req) { struct audio_device *dev; bdaddr_t src, dst; int err = 0; if (!check_nul(req->source) || !check_nul(req->destination) || !check_nul(req->object)) { err = EINVAL; goto failed; } str2ba(req->source, &src); str2ba(req->destination, &dst); if (req->seid > BT_A2DP_SEID_RANGE) { err = handle_sco_open(client, req); if (err < 0) { err = -err; goto failed; } } else { err = handle_a2dp_open(client, req); if (err < 0) { err = -err; goto failed; } } if (!manager_find_device(req->object, &src, &dst, NULL, FALSE)) goto failed; dev = manager_find_device(req->object, &src, &dst, client->interface, TRUE); if (!dev) dev = manager_find_device(req->object, &src, &dst, client->interface, FALSE); if (!dev) goto failed; client->seid = req->seid; client->lock = req->lock; start_open(dev, client); return; failed: unix_ipc_error(client, BT_OPEN, err ? : EIO); }
static struct audio_device *a2dp_get_dev(struct avdtp *session) { bdaddr_t src, dst; avdtp_get_peers(session, &src, &dst); return manager_find_device(NULL, &src, &dst, NULL, FALSE); }
static void audio_remove(struct btd_device *device) { struct audio_device *dev; const char *path; path = device_get_path(device); dev = manager_find_device(path, NULL, NULL, NULL, FALSE); if (!dev) return; devices = g_slist_remove(devices, dev); audio_device_unregister(dev); }
struct audio_device *manager_get_device(const bdaddr_t *src, const bdaddr_t *dst, gboolean create) { struct audio_device *dev; struct btd_adapter *adapter; struct btd_device *device; char addr[18]; const char *path; dev = manager_find_device(NULL, src, dst, NULL, FALSE); if (dev) return dev; if (!create) return NULL; ba2str(src, addr); adapter = manager_find_adapter(src); if (!adapter) { error("Unable to get a btd_adapter object for %s", addr); return NULL; } ba2str(dst, addr); device = adapter_get_device(connection, adapter, addr); if (!device) { error("Unable to get btd_device object for %s", addr); return NULL; } path = device_get_path(device); dev = audio_device_register(connection, device, path, src, dst); if (!dev) return NULL; devices = g_slist_append(devices, dev); return dev; }
static void sco_server_cb(GIOChannel *chan, GError *err, gpointer data) { int sk; struct audio_device *device; char addr[18]; bdaddr_t src, dst; if (err) { error("sco_server_cb: %s", err->message); return; } bt_io_get(chan, BT_IO_SCO, &err, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_DEST, addr, BT_IO_OPT_INVALID); if (err) { error("bt_io_get: %s", err->message); goto drop; } device = manager_find_device(NULL, &src, &dst, AUDIO_HEADSET_INTERFACE, FALSE); if (!device) device = manager_find_device(NULL, &src, &dst, AUDIO_GATEWAY_INTERFACE, FALSE); if (!device) goto drop; if (device->headset) { if (headset_get_state(device) < HEADSET_STATE_CONNECTED) { DBG("Refusing SCO from non-connected headset"); goto drop; } if (!get_hfp_active(device)) { error("Refusing non-HFP SCO connect attempt from %s", addr); goto drop; } if (headset_connect_sco(device, chan) < 0) goto drop; headset_set_state(device, HEADSET_STATE_PLAYING); } else if (device->gateway) { if (!gateway_is_connected(device)) { DBG("Refusing SCO from non-connected AG"); goto drop; } if (gateway_connect_sco(device, chan) < 0) goto drop; } else goto drop; sk = g_io_channel_unix_get_fd(chan); fcntl(sk, F_SETFL, 0); DBG("Accepted SCO connection from %s", addr); return; drop: g_io_channel_shutdown(chan, TRUE, NULL); }
static void handle_getcapabilities_req(struct unix_client *client, struct bt_get_capabilities_req *req) { struct audio_device *dev; bdaddr_t src, dst; int err = EIO; const char *interface; if (!check_nul(req->source) || !check_nul(req->destination) || !check_nul(req->object)) { err = EINVAL; goto failed; } str2ba(req->source, &src); str2ba(req->destination, &dst); if (!manager_find_device(req->object, &src, &dst, NULL, FALSE)) goto failed; if (req->transport == BT_CAPABILITIES_TRANSPORT_SCO) interface = AUDIO_HEADSET_INTERFACE; else if (req->transport == BT_CAPABILITIES_TRANSPORT_A2DP) interface = AUDIO_SINK_INTERFACE; else interface = client->interface; dev = manager_find_device(req->object, &src, &dst, interface, TRUE); if (!dev && (req->flags & BT_FLAG_AUTOCONNECT)) dev = manager_find_device(req->object, &src, &dst, interface, FALSE); if (!dev) { if (req->transport == BT_CAPABILITIES_TRANSPORT_SCO) interface = AUDIO_GATEWAY_INTERFACE; else if (req->transport == BT_CAPABILITIES_TRANSPORT_A2DP) interface = AUDIO_SOURCE_INTERFACE; else interface = NULL; dev = manager_find_device(req->object, &src, &dst, interface, TRUE); if (!dev && (req->flags & BT_FLAG_AUTOCONNECT)) dev = manager_find_device(req->object, &src, &dst, interface, FALSE); } if (!dev) { error("Unable to find a matching device"); goto failed; } client->type = select_service(dev, interface); if (client->type == TYPE_NONE) { error("No matching service found"); goto failed; } if (g_strcmp0(interface, client->interface) != 0) { g_free(client->interface); client->interface = g_strdup(interface); } client->seid = req->seid; start_discovery(dev, client); return; failed: unix_ipc_error(client, BT_GET_CAPABILITIES, err); }
static void avctp_server_cb(GIOChannel *chan, int err, const bdaddr_t *src, const bdaddr_t *dst, gpointer data) { socklen_t size; struct l2cap_options l2o; struct avctp *session; GIOCondition flags = G_IO_ERR | G_IO_HUP | G_IO_NVAL; struct audio_device *dev; char address[18]; if (err < 0) { error("AVCTP server socket: %s (%d)", strerror(-err), -err); return; } session = avctp_get(src, dst); if (!session) { error("Unable to create new AVCTP session"); goto drop; } if (session->sock >= 0) { error("Refusing unexpected connect from %s", address); goto drop; } dev = manager_find_device(&session->dst, AUDIO_CONTROL_INTERFACE, FALSE); if (!dev) { error("Unable to get audio device object for %s", address); goto drop; } if (!dev->control) dev->control = control_init(dev); device_remove_control_timer(dev); session->state = AVCTP_STATE_CONNECTING; session->sock = g_io_channel_unix_get_fd(chan); memset(&l2o, 0, sizeof(l2o)); size = sizeof(l2o); if (getsockopt(session->sock, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &size) < 0) { err = errno; error("getsockopt(L2CAP_OPTIONS): %s (%d)", strerror(err), err); avctp_unref(session); goto drop; } session->mtu = l2o.imtu; if (session->io) g_source_remove(session->io); session->io = g_io_add_watch(chan, flags, (GIOFunc) session_cb, session); g_io_channel_unref(chan); if (avdtp_is_connected(src, dst)) goto proceed; if (service_req_auth(src, dst, AVRCP_TARGET_UUID, auth_cb, session) < 0) goto drop; return; proceed: avctp_connect_session(session); return; drop: close(session->sock); }