/* * Input Device methods */ static DBusMessage *input_device_connect(DBusConnection *conn, DBusMessage *msg, void *data) { struct input_device *idev = data; struct input_conn *iconn; DBusMessage *reply; GError *err = NULL; DBG("idev %p", idev); iconn = find_connection(idev->connections, HID_UUID); if (!iconn) return btd_error_not_supported(msg); if (iconn->pending_connect) return btd_error_in_progress(msg); if (is_connected(iconn)) return btd_error_already_connected(msg); iconn->pending_connect = dbus_message_ref(msg); dev_connect(idev, iconn, &err); if (err == NULL) return NULL; error("%s", err->message); dbus_message_unref(iconn->pending_connect); iconn->pending_connect = NULL; reply = btd_error_failed(msg, err->message); g_error_free(err); return reply; }
static DBusMessage *characteristic_read_value(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct characteristic *chrc = user_data; struct bt_gatt_client *gatt = chrc->service->client->gatt; struct async_dbus_op *op; if (chrc->read_id) return btd_error_in_progress(msg); op = new0(struct async_dbus_op, 1); if (!op) return btd_error_failed(msg, "Failed to initialize request"); op->msg = dbus_message_ref(msg); op->data = chrc; chrc->read_id = bt_gatt_client_read_value(gatt, chrc->value_handle, chrc_read_cb, async_dbus_op_ref(op), async_dbus_op_unref); if (chrc->read_id) return NULL; async_dbus_op_free(op); return btd_error_failed(msg, "Failed to send read request"); }
static DBusMessage *descriptor_read_value(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct descriptor *desc = user_data; struct bt_gatt_client *gatt = desc->chrc->service->client->gatt; struct async_dbus_op *op; if (!gatt) return btd_error_failed(msg, "Not connected"); if (desc->read_id) return btd_error_in_progress(msg); op = new0(struct async_dbus_op, 1); op->msg = dbus_message_ref(msg); op->data = desc; desc->read_id = bt_gatt_client_read_value(gatt, desc->handle, desc_read_cb, async_dbus_op_ref(op), async_dbus_op_unref); if (desc->read_id) return NULL; async_dbus_op_free(op); return btd_error_failed(msg, "Failed to send read request"); }
static DBusMessage *set_cumulative_wheel_rev(DBusConnection *conn, DBusMessage *msg, void *data) { struct csc *csc = data; dbus_uint32_t value; struct controlpoint_req *req; uint8_t att_val[5]; /* uint8 opcode + uint32 value */ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &value, DBUS_TYPE_INVALID)) return btd_error_invalid_args(msg); if (csc->pending_req != NULL) return btd_error_in_progress(msg); req = g_new(struct controlpoint_req, 1); req->csc = csc; req->opcode = SET_CUMULATIVE_VALUE; req->msg = dbus_message_ref(msg); csc->pending_req = req; att_val[0] = SET_CUMULATIVE_VALUE; put_le32(value, att_val + 1); gatt_write_char(csc->attrib, csc->controlpoint_val_handle, att_val, sizeof(att_val), controlpoint_write_cb, req); return NULL; }
static DBusMessage *release(DBusConnection *conn, DBusMessage *msg, void *data) { struct media_transport *transport = data; struct media_owner *owner; const char *accesstype, *sender; struct media_request *req; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &accesstype, DBUS_TYPE_INVALID)) return NULL; sender = dbus_message_get_sender(msg); owner = media_transport_find_owner(transport, sender); if (owner == NULL) return btd_error_not_authorized(msg); if (g_strcmp0(owner->accesstype, accesstype) == 0) { guint id; /* Not the last owner, no need to suspend */ if (g_slist_length(transport->owners) != 1) { media_transport_remove(transport, owner); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } if (owner->pending) { const char *member; member = dbus_message_get_member(owner->pending->msg); /* Cancel Acquire request if that exist */ if (g_str_equal(member, "Acquire")) media_owner_remove(owner); else return btd_error_in_progress(msg); } id = transport->suspend(transport, owner); if (id == 0) { media_transport_remove(transport, owner); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } req = media_request_create(msg, id); media_owner_add(owner, req); return NULL; } else if (g_strstr_len(owner->accesstype, -1, accesstype) != NULL) { media_transport_release(transport, accesstype); g_strdelimit(owner->accesstype, accesstype, ' '); } else return btd_error_not_authorized(msg); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); }
static DBusMessage *descriptor_write_value(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct descriptor *desc = user_data; struct bt_gatt_client *gatt = desc->chrc->service->client->gatt; uint8_t *value = NULL; size_t value_len = 0; if (!gatt) return btd_error_failed(msg, "Not connected"); if (desc->write_id) return btd_error_in_progress(msg); if (!parse_value_arg(msg, &value, &value_len)) return btd_error_invalid_args(msg); /* * Don't allow writing to Client Characteristic Configuration * descriptors. We achieve this through the StartNotify and StopNotify * methods on GattCharacteristic1. */ if (uuid_cmp(&desc->uuid, GATT_CLIENT_CHARAC_CFG_UUID)) return btd_error_not_permitted(msg, "Write not permitted"); /* * Based on the value length and the MTU, either use a write or a long * write. */ if (value_len <= (unsigned) bt_gatt_client_get_mtu(gatt) - 3) desc->write_id = start_write_request(msg, desc->handle, gatt, value, value_len, desc, desc_write_complete); else desc->write_id = start_long_write(msg, desc->handle, gatt, false, value, value_len, desc, desc_write_complete); if (!desc->write_id) return btd_error_failed(msg, "Failed to initiate write"); return NULL; }
static DBusMessage *read_local_data(DBusConnection *conn, DBusMessage *msg, void *data) { struct btd_adapter *adapter = data; struct oob_request *oob_request; if (find_oob_request(adapter)) return btd_error_in_progress(msg); if (btd_adapter_read_local_oob_data(adapter)) return btd_error_failed(msg, "Request failed."); oob_request = g_new(struct oob_request, 1); oob_request->adapter = adapter; oob_requests = g_slist_append(oob_requests, oob_request); oob_request->msg = dbus_message_ref(msg); return NULL; }
static DBusMessage *release(DBusConnection *conn, DBusMessage *msg, void *data) { struct media_transport *transport = data; struct media_owner *owner = transport->owner; const char *sender; struct media_request *req; guint id; sender = dbus_message_get_sender(msg); if (owner == NULL || g_strcmp0(owner->name, sender) != 0) return btd_error_not_authorized(msg); if (owner->pending) { const char *member; member = dbus_message_get_member(owner->pending->msg); /* Cancel Acquire request if that exist */ if (g_str_equal(member, "Acquire")) media_owner_remove(owner); else return btd_error_in_progress(msg); } transport_set_state(transport, TRANSPORT_STATE_SUSPENDING); id = transport->suspend(transport, owner); if (id == 0) { media_transport_remove_owner(transport); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } req = media_request_create(msg, id); media_owner_add(owner, req); return NULL; }
static DBusMessage *ag_connect(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *au_dev = (struct audio_device *) data; struct gateway *gw = au_dev->gateway; int err; if (gw->state == GATEWAY_STATE_CONNECTING) return btd_error_in_progress(msg); else if (gw->state > GATEWAY_STATE_CONNECTING) return btd_error_already_connected(msg); if (!gw->agent) return btd_error_agent_not_available(msg); err = get_records(au_dev); if (err < 0) return btd_error_failed(msg, strerror(-err)); gw->msg = dbus_message_ref(msg); return NULL; }
static DBusMessage *dev_connect(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *dev = data; struct dev_priv *priv = dev->priv; if (priv->state == AUDIO_STATE_CONNECTING) return btd_error_in_progress(msg); else if (priv->state == AUDIO_STATE_CONNECTED) return btd_error_already_connected(msg); dev->auto_connect = TRUE; if (dev->headset) headset_config_stream(dev, FALSE, NULL, NULL); if (priv->state != AUDIO_STATE_CONNECTING && dev->sink) { struct avdtp *session = avdtp_get(&dev->src, &dev->dst); if (!session) return btd_error_failed(msg, "Failed to get AVDTP session"); sink_setup_stream(dev->sink, session); avdtp_unref(session); } /* The previous calls should cause a call to the state callback to * indicate AUDIO_STATE_CONNECTING */ if (priv->state != AUDIO_STATE_CONNECTING) return btd_error_failed(msg, "Connect Failed"); priv->conn_req = dbus_message_ref(msg); return NULL; }
static DBusMessage *characteristic_write_value(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct characteristic *chrc = user_data; struct bt_gatt_client *gatt = chrc->service->client->gatt; uint8_t *value = NULL; size_t value_len = 0; bool supported = false; if (chrc->write_id) return btd_error_in_progress(msg); if (!parse_value_arg(msg, &value, &value_len)) return btd_error_invalid_args(msg); /* * Decide which write to use based on characteristic properties. For now * we don't perform signed writes since gatt-client doesn't support them * and the user can always encrypt the through pairing. The procedure to * use is determined based on the following priority: * * * "reliable-write" property set -> reliable long-write. * * "write" property set -> write request. * - If value is larger than MTU - 3: long-write * * "write-without-response" property set -> write command. */ if ((chrc->ext_props & BT_GATT_CHRC_EXT_PROP_RELIABLE_WRITE)) { supported = true; chrc->write_id = start_long_write(msg, chrc->value_handle, gatt, true, value, value_len, chrc, chrc_write_complete); if (chrc->write_id) return NULL; } if (chrc->props & BT_GATT_CHRC_PROP_WRITE) { uint16_t mtu; supported = true; mtu = bt_gatt_client_get_mtu(gatt); if (!mtu) return btd_error_failed(msg, "No ATT transport"); if (value_len <= (unsigned) mtu - 3) chrc->write_id = start_write_request(msg, chrc->value_handle, gatt, value, value_len, chrc, chrc_write_complete); else chrc->write_id = start_long_write(msg, chrc->value_handle, gatt, false, value, value_len, chrc, chrc_write_complete); if (chrc->write_id) return NULL; } if (!(chrc->props & BT_GATT_CHRC_PROP_WRITE_WITHOUT_RESP)) goto fail; supported = true; chrc->write_id = bt_gatt_client_write_without_response(gatt, chrc->value_handle, false, value, value_len); if (chrc->write_id) return dbus_message_new_method_return(msg); fail: if (supported) return btd_error_failed(msg, "Failed to initiate write"); return btd_error_not_supported(msg); }
/* * Input Device methods */ static DBusMessage *input_device_connect(DBusConnection *conn, DBusMessage *msg, void *data) { //+++ BRCM #ifdef BT_ALT_STACK struct input_device *idev = data; tDTUN_DEVICE_METHOD method; method.hh_open.hdr.id = DTUN_METHOD_HH_OPEN; method.hh_open.hdr.len = sizeof(tDTUN_METHOD_HH_OPEN) - sizeof(tDTUN_HDR); memcpy(&method.hh_open.bdaddr, &idev->dst, 6); read_remote_class(&idev->src, &idev->dst, &method.hh_open.cod); dtun_client_call_method(&method); return NULL; #else struct input_device *idev = data; struct input_conn *iconn; struct fake_input *fake; DBusMessage *reply; GError *err = NULL; iconn = find_connection(idev->connections, "HID"); if (!iconn) return btd_error_not_supported(msg); if (iconn->pending_connect) return btd_error_in_progress(msg); if (is_connected(iconn)) return btd_error_already_connected(msg); iconn->pending_connect = dbus_message_ref(msg); fake = iconn->fake; if (fake) { /* Fake input device */ if (fake->connect(iconn, &err)) fake->flags |= FI_FLAG_CONNECTED; } else { /* HID devices */ GIOChannel *io; io = bt_io_connect(BT_IO_L2CAP, control_connect_cb, iconn, NULL, &err, BT_IO_OPT_SOURCE_BDADDR, &idev->src, BT_IO_OPT_DEST_BDADDR, &idev->dst, BT_IO_OPT_PSM, L2CAP_PSM_HIDP_CTRL, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW, BT_IO_OPT_POWER_ACTIVE, 0, BT_IO_OPT_INVALID); iconn->ctrl_io = io; } if (err == NULL) return NULL; error("%s", err->message); dbus_message_unref(iconn->pending_connect); iconn->pending_connect = NULL; reply = btd_error_failed(msg, err->message); g_error_free(err); return reply; #endif //--- BRCM }
static DBusMessage *characteristic_start_notify(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct characteristic *chrc = user_data; struct bt_gatt_client *gatt = chrc->service->client->gatt; const char *sender = dbus_message_get_sender(msg); struct async_dbus_op *op; struct notify_client *client; if (!(chrc->props & BT_GATT_CHRC_PROP_NOTIFY || chrc->props & BT_GATT_CHRC_PROP_INDICATE)) return btd_error_not_supported(msg); /* Each client can only have one active notify session. */ client = queue_find(chrc->notify_clients, match_notify_sender, sender); if (client) return client->notify_id ? btd_error_failed(msg, "Already notifying") : btd_error_in_progress(msg); client = notify_client_create(chrc, sender); if (!client) return btd_error_failed(msg, "Failed allocate notify session"); queue_push_tail(chrc->notify_clients, client); queue_push_tail(chrc->service->client->all_notify_clients, client); /* * If the device is currently not connected, return success. We will * automatically try and register all clients when a GATT client becomes * ready. */ if (!gatt) { DBusMessage *reply; reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID); if (reply) return reply; /* * Clean up and respond with an error instead of timing out to * avoid any ambiguities. */ error("Failed to construct D-Bus message reply"); goto fail; } op = new0(struct async_dbus_op, 1); op->data = client; op->msg = dbus_message_ref(msg); client->notify_id = bt_gatt_client_register_notify(gatt, chrc->value_handle, register_notify_cb, notify_cb, op, async_dbus_op_free); if (client->notify_id) return NULL; async_dbus_op_free(op); fail: queue_remove(chrc->notify_clients, client); queue_remove(chrc->service->client->all_notify_clients, client); /* Directly free the client */ notify_client_free(client); return btd_error_failed(msg, "Failed to register notify session"); }