static DBusMessage *media_folder_list_items(DBusConnection *conn, DBusMessage *msg, void *data) { struct media_player *mp = data; struct media_folder *folder = mp->scope; struct player_callback *cb = mp->cb; DBusMessageIter iter; uint32_t start, end; int err; dbus_message_iter_init(msg, &iter); if (parse_filters(mp, &iter, &start, &end) < 0) return btd_error_invalid_args(msg); if (cb->cbs->list_items == NULL) return btd_error_not_supported(msg); if (folder->msg != NULL) return btd_error_failed(msg, strerror(EBUSY)); err = cb->cbs->list_items(mp, folder->item->name, start, end, cb->user_data); if (err < 0) return btd_error_failed(msg, strerror(-err)); folder->msg = dbus_message_ref(msg); return NULL; }
static DBusMessage *sink_connect(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *dev = data; struct sink *sink = dev->sink; struct pending_request *pending; if (!sink->session) sink->session = avdtp_get(&dev->src, &dev->dst); if (!sink->session) return btd_error_failed(msg, "Unable to get a session"); if (sink->connect || sink->disconnect) return btd_error_busy(msg); if (sink->stream_state >= AVDTP_STATE_OPEN) return btd_error_already_connected(msg); if (!sink_setup_stream(sink, NULL)) return btd_error_failed(msg, "Failed to create a stream"); dev->auto_connect = FALSE; pending = sink->connect; pending->conn = dbus_connection_ref(conn); pending->msg = dbus_message_ref(msg); DBG("stream creation in progress"); return NULL; }
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 void controlpoint_method_reply(struct controlpoint_req *req, uint8_t code) { DBusMessage *reply; switch (code) { case RSP_SUCCESS: reply = dbus_message_new_method_return(req->msg); break; case RSP_NOT_SUPPORTED: reply = btd_error_not_supported(req->msg); break; case RSP_INVALID_PARAM: reply = btd_error_invalid_args(req->msg); break; case RSP_FAILED: reply = btd_error_failed(req->msg, "Failed"); break; default: reply = btd_error_failed(req->msg, "Unknown error"); break; } g_dbus_send_message(btd_get_dbus_connection(), reply); dbus_message_unref(req->msg); }
static DBusMessage *register_server(DBusConnection *conn, DBusMessage *msg, void *data) { struct network_server *ns = data; DBusMessage *reply; const char *uuid, *bridge; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &uuid, DBUS_TYPE_STRING, &bridge, DBUS_TYPE_INVALID)) return NULL; if (g_strcmp0(uuid, "nap")) return btd_error_failed(msg, "Invalid UUID"); if (ns->record_id) return btd_error_already_exists(msg); reply = dbus_message_new_method_return(msg); if (!reply) return NULL; ns->record_id = register_server_record(ns); if (!ns->record_id) return btd_error_failed(msg, "SDP record registration failed"); g_free(ns->bridge); ns->bridge = g_strdup(bridge); ns->watch_id = g_dbus_add_disconnect_watch(conn, dbus_message_get_sender(msg), server_disconnect, ns, NULL); return reply; }
static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data) { struct serial_port *port = user_data; struct serial_device *device = port->device; sdp_record_t *record = NULL; sdp_list_t *protos; DBusMessage *reply; GError *gerr = NULL; if (!port->listener_id) { reply = NULL; goto failed; } if (err < 0) { error("Unable to get service record: %s (%d)", strerror(-err), -err); reply = btd_error_failed(port->msg, strerror(-err)); goto failed; } if (!recs || !recs->data) { error("No record found"); reply = btd_error_failed(port->msg, "No record found"); goto failed; } record = recs->data; if (sdp_get_access_protos(record, &protos) < 0) { error("Unable to get access protos from port record"); reply = btd_error_failed(port->msg, "Invalid channel"); goto failed; } port->channel = sdp_get_proto_port(protos, RFCOMM_UUID); sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL); sdp_list_free(protos, NULL); port->io = bt_io_connect(BT_IO_RFCOMM, rfcomm_connect_cb, port, NULL, &gerr, BT_IO_OPT_SOURCE_BDADDR, &device->src, BT_IO_OPT_DEST_BDADDR, &device->dst, BT_IO_OPT_CHANNEL, port->channel, BT_IO_OPT_INVALID); if (!port->io) { error("%s", gerr->message); reply = btd_error_failed(port->msg, gerr->message); g_error_free(gerr); goto failed; } return; failed: g_dbus_remove_watch(device->conn, port->listener_id); port->listener_id = 0; g_dbus_send_message(device->conn, reply); }
static DBusMessage *media_folder_search(DBusConnection *conn, DBusMessage *msg, void *data) { struct media_player *mp = data; struct media_folder *folder = mp->scope; struct player_callback *cb = mp->cb; DBusMessageIter iter; const char *string; int err; dbus_message_iter_init(msg, &iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) return btd_error_invalid_args(msg); dbus_message_iter_get_basic(&iter, &string); if (!mp->searchable || folder != mp->folder || !cb->cbs->search) return btd_error_not_supported(msg); if (folder->msg != NULL) return btd_error_failed(msg, strerror(EINVAL)); err = cb->cbs->search(mp, string, cb->user_data); if (err < 0) return btd_error_failed(msg, strerror(-err)); folder->msg = dbus_message_ref(msg); return NULL; }
static void write_result_cb(bool success, bool reliable_error, uint8_t att_ecode, void *user_data) { struct async_dbus_op *op = user_data; DBusMessage *reply; if (op->complete && !op->complete(op->data)) { reply = btd_error_failed(op->msg, "Operation failed"); goto done; } if (!success) { if (reliable_error) reply = btd_error_failed(op->msg, "Reliable write failed"); else reply = create_gatt_dbus_error(op->msg, att_ecode); goto done; } reply = g_dbus_create_reply(op->msg, DBUS_TYPE_INVALID); if (!reply) { error("Failed to allocate D-Bus message reply"); return; } done: g_dbus_send_message(btd_get_dbus_connection(), reply); }
static void rfcomm_connect_cb(GIOChannel *chan, GError *conn_err, gpointer user_data) { struct serial_port *port = user_data; struct serial_device *device = port->device; struct rfcomm_dev_req req; int sk, fd; DBusMessage *reply; /* Owner exited? */ if (!port->listener_id) return; if (conn_err) { error("%s", conn_err->message); reply = btd_error_failed(port->msg, conn_err->message); goto fail; } memset(&req, 0, sizeof(req)); req.dev_id = -1; req.flags = (1 << RFCOMM_REUSE_DLC); bacpy(&req.src, &device->src); bacpy(&req.dst, &device->dst); req.channel = port->channel; g_io_channel_unref(port->io); port->io = NULL; sk = g_io_channel_unix_get_fd(chan); port->id = ioctl(sk, RFCOMMCREATEDEV, &req); if (port->id < 0) { int err = -errno; error("ioctl(RFCOMMCREATEDEV): %s (%d)", strerror(-err), -err); reply = btd_error_failed(port->msg, strerror(-err)); g_io_channel_shutdown(chan, TRUE, NULL); goto fail; } port->dev = g_strdup_printf("/dev/rfcomm%d", port->id); DBG("Serial port %s created", port->dev); g_io_channel_shutdown(chan, TRUE, NULL); /* Addressing connect port */ fd = port_open(port); if (fd < 0) /* Open in progress: Wait the callback */ return; open_notify(fd, 0, port); return; fail: g_dbus_send_message(device->conn, reply); g_dbus_remove_watch(device->conn, port->listener_id); port->listener_id = 0; }
static DBusMessage *refresh_advertisement(struct advertisement *ad) { struct mgmt_cp_add_advertising *cp; uint8_t param_len; uint8_t *adv_data; size_t adv_data_len; uint32_t flags = 0; DBG("Refreshing advertisement: %s", ad->path); if (ad->type == AD_TYPE_PERIPHERAL) flags = MGMT_ADV_FLAG_CONNECTABLE | MGMT_ADV_FLAG_DISCOV; if (ad->include_tx_power) flags |= MGMT_ADV_FLAG_TX_POWER; adv_data = bt_ad_generate(ad->data, &adv_data_len); if (!adv_data || (adv_data_len > calc_max_adv_len(ad, flags))) { error("Advertising data too long or couldn't be generated."); return g_dbus_create_error(ad->reg, ERROR_INTERFACE ".InvalidLength", "Advertising data too long."); } param_len = sizeof(struct mgmt_cp_add_advertising) + adv_data_len; cp = malloc0(param_len); if (!cp) { error("Couldn't allocate for MGMT!"); free(adv_data); return btd_error_failed(ad->reg, "Failed"); } cp->flags = flags; cp->instance = ad->instance; cp->adv_data_len = adv_data_len; memcpy(cp->data, adv_data, adv_data_len); free(adv_data); if (!mgmt_send(ad->manager->mgmt, MGMT_OP_ADD_ADVERTISING, ad->manager->mgmt_index, param_len, cp, add_advertising_callback, ad, NULL)) { error("Failed to add Advertising Data"); free(cp); return btd_error_failed(ad->reg, "Failed"); } free(cp); return NULL; }
static DBusMessage *media_folder_change_folder(DBusConnection *conn, DBusMessage *msg, void *data) { struct media_player *mp = data; struct media_folder *folder = mp->scope; struct player_callback *cb = mp->cb; const char *path; int err; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID)) return btd_error_invalid_args(msg); if (folder->msg != NULL) return btd_error_failed(msg, strerror(EBUSY)); folder = media_player_find_folder(mp, path); if (folder == NULL) return btd_error_invalid_args(msg); if (mp->scope == folder) return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); if (folder == mp->playlist || folder == mp->folder || folder == mp->search) { media_player_change_scope(mp, folder); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); } /* * ChangePath can only navigate one level up/down so check if folder * is direct child or parent of the current folder otherwise fail. */ if (!g_slist_find(mp->folder->subfolders, folder) && !g_slist_find(folder->subfolders, mp->folder)) return btd_error_invalid_args(msg); if (cb->cbs->change_folder == NULL) return btd_error_not_supported(msg); err = cb->cbs->change_folder(mp, folder->item->name, folder->item->uid, cb->user_data); if (err < 0) return btd_error_failed(msg, strerror(-err)); mp->scope->msg = dbus_message_ref(msg); return NULL; }
static void control_connect_cb(GIOChannel *chan, GError *conn_err, gpointer user_data) { struct input_conn *iconn = user_data; struct input_device *idev = iconn->idev; DBusMessage *reply = NULL; GIOChannel *io; GError *err = NULL; DBG(""); if (conn_err) { error("%s", conn_err->message); if (iconn->pending_connect) reply = btd_error_failed(iconn->pending_connect, conn_err->message); goto failed; } /* Connect to the HID interrupt channel */ io = bt_io_connect(BT_IO_L2CAP, interrupt_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_INTR, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW, BT_IO_OPT_INVALID); if (!io) { error("%s", err->message); if (iconn->pending_connect) reply = btd_error_failed(iconn->pending_connect, err->message); g_error_free(err); goto failed; } iconn->intr_io = io; return; failed: g_io_channel_unref(iconn->ctrl_io); iconn->ctrl_io = NULL; if (reply) g_dbus_send_message(idev->conn, reply); if (iconn->pending_connect) { dbus_message_unref(iconn->pending_connect); iconn->pending_connect = NULL; } }
static DBusMessage *register_advertisement(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct btd_advertising *manager = user_data; DBusMessageIter args; struct advertisement *ad; struct dbus_obj_match match; uint8_t instance; DBG("RegisterAdvertisement"); if (!dbus_message_iter_init(msg, &args)) return btd_error_invalid_args(msg); if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH) return btd_error_invalid_args(msg); dbus_message_iter_get_basic(&args, &match.path); match.owner = dbus_message_get_sender(msg); if (queue_find(manager->ads, match_advertisement, &match)) return btd_error_already_exists(msg); instance = util_get_uid(&manager->instance_bitmap, manager->max_ads); if (!instance) return btd_error_failed(msg, "Maximum advertisements reached"); dbus_message_iter_next(&args); if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY) return btd_error_invalid_args(msg); ad = advertisement_create(conn, msg, match.path); if (!ad) return btd_error_failed(msg, "Failed to register advertisement"); DBG("Registered advertisement at path %s", match.path); ad->instance = instance; ad->manager = manager; queue_push_tail(manager->ads, ad); return NULL; }
static DBusMessage *port_connect(DBusConnection *conn, DBusMessage *msg, void *user_data) { struct serial_device *device = user_data; struct serial_port *port; const char *pattern; int err; if (dbus_message_has_member(msg, "ConnectFD") && DBUS_TYPE_UNIX_FD < 0) return btd_error_not_supported(msg); if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &pattern, DBUS_TYPE_INVALID) == FALSE) return NULL; port = find_port(device->ports, pattern); if (!port) { char *endptr = NULL; int channel; channel = strtol(pattern, &endptr, 10); if ((endptr && *endptr != '\0') || channel < 1 || channel > 30) return btd_error_does_not_exist(msg); port = create_port(device, NULL, channel); } if (port->listener_id) return btd_error_failed(msg, "Port already in use"); port->listener_id = g_dbus_add_disconnect_watch(conn, dbus_message_get_sender(msg), port_owner_exited, port, NULL); port->msg = dbus_message_ref(msg); err = connect_port(port); if (err < 0) { error("%s", strerror(-err)); g_dbus_remove_watch(conn, port->listener_id); port->listener_id = 0; return btd_error_failed(msg, strerror(-err)); } return NULL; }
static DBusMessage *create_gatt_dbus_error(DBusMessage *msg, uint8_t att_ecode) { switch (att_ecode) { case BT_ATT_ERROR_READ_NOT_PERMITTED: return btd_error_not_permitted(msg, "Read not permitted"); case BT_ATT_ERROR_WRITE_NOT_PERMITTED: return btd_error_not_permitted(msg, "Write not permitted"); case BT_ATT_ERROR_AUTHENTICATION: case BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION: case BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION_KEY_SIZE: return btd_error_not_permitted(msg, "Not paired"); case BT_ATT_ERROR_INVALID_OFFSET: return btd_error_invalid_args_str(msg, "Invalid offset"); case BT_ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LEN: return btd_error_invalid_args_str(msg, "Invalid Length"); case BT_ATT_ERROR_AUTHORIZATION: return btd_error_not_authorized(msg); case BT_ATT_ERROR_REQUEST_NOT_SUPPORTED: return btd_error_not_supported(msg); case 0: return btd_error_failed(msg, "Operation failed"); default: return g_dbus_create_error(msg, ERROR_INTERFACE, "Operation failed with ATT error: 0x%02x", att_ecode); } return NULL; }
static DBusMessage *input_device_disconnect(DBusConnection *conn, DBusMessage *msg, void *data) { //+++ BRCM #ifdef BT_ALT_STACK struct input_device *idev = data; tDTUN_DEVICE_METHOD method; method.hh_bdaddr.hdr.id = DTUN_METHOD_HH_CLOSE; method.hh_bdaddr.hdr.len = sizeof(tDTUN_METHOD_HH_BDADDR) - sizeof(tDTUN_HDR); memcpy(&method.hh_bdaddr.bdaddr, &idev->dst, 6); dtun_client_call_method(&method); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); #else struct input_device *idev = data; int err; err = disconnect(idev, 0); if (err < 0) return btd_error_failed(msg, strerror(-err)); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); #endif //--- BRCM }
static DBusMessage *add_remote_data(DBusConnection *conn, DBusMessage *msg, void *data) { struct btd_adapter *adapter = data; uint8_t *hash, *randomizer; int32_t hlen, rlen; const char *addr; bdaddr_t bdaddr; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &addr, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &hash, &hlen, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &randomizer, &rlen, DBUS_TYPE_INVALID)) return btd_error_invalid_args(msg); if (hlen != 16 || rlen != 16 || bachk(addr)) return btd_error_invalid_args(msg); str2ba(addr, &bdaddr); if (btd_adapter_add_remote_oob_data(adapter, &bdaddr, hash, randomizer)) return btd_error_failed(msg, "Request failed"); return g_dbus_create_reply(msg, DBUS_TYPE_INVALID); }
static DBusMessage *unregister_server(DBusConnection *conn, DBusMessage *msg, void *data) { struct network_adapter *na = data; struct network_server *ns; DBusMessage *reply; const char *uuid; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &uuid, DBUS_TYPE_INVALID)) return btd_error_invalid_args(msg); ns = find_server_by_uuid(na->servers, uuid); if (!ns) return btd_error_failed(msg, "Invalid UUID"); reply = dbus_message_new_method_return(msg); if (!reply) return NULL; g_dbus_remove_watch(conn, ns->watch_id); server_disconnect(conn, ns); return reply; }
static DBusMessage *add_service_record(DBusConnection *conn, DBusMessage *msg, void *data) { struct service_adapter *serv_adapter = data; DBusMessage *reply; const char *sender, *record; dbus_uint32_t handle; int err; if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &record, DBUS_TYPE_INVALID) == FALSE) return NULL; sender = dbus_message_get_sender(msg); err = add_xml_record(conn, sender, serv_adapter, record, &handle); if (err < 0) return btd_error_failed(msg, strerror(-err)); reply = dbus_message_new_method_return(msg); if (!reply) return NULL; dbus_message_append_args(reply, DBUS_TYPE_UINT32, &handle, DBUS_TYPE_INVALID); return reply; }
static DBusMessage *update_xml_record(DBusConnection *conn, DBusMessage *msg, struct service_adapter *serv_adapter) { struct record_data *user_record; sdp_record_t *sdp_record; const char *record; dbus_uint32_t handle; int len; if (dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &handle, DBUS_TYPE_STRING, &record, DBUS_TYPE_INVALID) == FALSE) return NULL; len = (record ? strlen(record) : 0); if (len == 0) return btd_error_invalid_args(msg); user_record = find_record(serv_adapter, handle, dbus_message_get_sender(msg)); if (!user_record) return btd_error_not_available(msg); sdp_record = sdp_xml_parse_record(record, len); if (!sdp_record) { error("Parsing of XML service record failed"); return btd_error_failed(msg, "Parsing of XML service record failed"); } return update_record(conn, msg, serv_adapter, handle, sdp_record); }
static DBusMessage *update_record(DBusConnection *conn, DBusMessage *msg, struct service_adapter *serv_adapter, dbus_uint32_t handle, sdp_record_t *sdp_record) { bdaddr_t src; int err; if (remove_record_from_server(handle) < 0) { sdp_record_free(sdp_record); return btd_error_not_available(msg); } if (serv_adapter->adapter) adapter_get_address(serv_adapter->adapter, &src); else bacpy(&src, BDADDR_ANY); sdp_record->handle = handle; err = add_record_to_server(&src, sdp_record); if (err < 0) { sdp_record_free(sdp_record); error("Failed to update the service record"); return btd_error_failed(msg, strerror(-err)); } return dbus_message_new_method_return(msg); }
static void attio_disconnected(gpointer user_data) { struct gatt_service *gatt = user_data; if (gatt->query && gatt->query->msg) { DBusMessage *reply; reply = btd_error_failed(gatt->query->msg, "ATT IO channel was disconnected"); g_dbus_send_message(gatt->conn, reply); dbus_message_unref(gatt->query->msg); gatt->query->msg = NULL; } if (gatt->query) { g_slist_free_full(gatt->query->list, g_free); gatt->query = NULL; } if (gatt->attrib) { g_attrib_cancel_all(gatt->attrib); g_attrib_unref(gatt->attrib); gatt->attrib = NULL; } }
static void read_local_data_complete(struct btd_adapter *adapter, uint8_t *hash, uint8_t *randomizer) { struct DBusMessage *reply; struct oob_request *oob_request; oob_request = find_oob_request(adapter); if (!oob_request) return; if (hash && randomizer) reply = g_dbus_create_reply(oob_request->msg, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &hash, 16, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &randomizer, 16, DBUS_TYPE_INVALID); else reply = btd_error_failed(oob_request->msg, "Failed to read local OOB data."); oob_requests = g_slist_remove(oob_requests, oob_request); dbus_message_unref(oob_request->msg); g_free(oob_request); if (!reply) { error("Couldn't allocate D-Bus message"); return; } if (!g_dbus_send_message(connection, reply)) error("D-Bus send failed"); }
/* * 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 void cancel_connection(struct network_conn *nc, const char *err_msg) { DBusMessage *reply; if (nc->timeout_source > 0) { g_source_remove(nc->timeout_source); nc->timeout_source = 0; } if (nc->watch) { g_dbus_remove_watch(connection, nc->watch); nc->watch = 0; } if (nc->msg && err_msg) { reply = btd_error_failed(nc->msg, err_msg); g_dbus_send_message(connection, reply); } g_io_channel_shutdown(nc->io, TRUE, NULL); g_io_channel_unref(nc->io); nc->io = NULL; nc->state = DISCONNECTED; }
static DBusMessage *disconnect_device(DBusConnection *conn, DBusMessage *msg, void *data) { DBusMessage *reply; struct network_server *ns = data; struct network_session *session; const char *addr, *devname; bdaddr_t dst_addr; if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &addr, DBUS_TYPE_STRING, &devname, DBUS_TYPE_INVALID)) return NULL; str2ba(addr, &dst_addr); session = find_session_by_addr(ns->sessions, dst_addr); if (!session) return btd_error_failed(msg, "No active session"); if (session->io) { bnep_if_down(devname); bnep_kill_connection(&dst_addr); } else return btd_error_not_connected(msg); reply = dbus_message_new_method_return(msg); if (!reply) return NULL; return reply; }
static DBusMessage *sink_disconnect(DBusConnection *conn, DBusMessage *msg, void *data) { struct audio_device *device = data; struct sink *sink = device->sink; struct pending_request *pending; int err; if (!sink->session) return btd_error_not_connected(msg); if (sink->connect || sink->disconnect) return btd_error_busy(msg); if (sink->stream_state < AVDTP_STATE_OPEN) { DBusMessage *reply = dbus_message_new_method_return(msg); if (!reply) return NULL; avdtp_unref(sink->session); sink->session = NULL; return reply; } err = avdtp_close(sink->session, sink->stream, FALSE); if (err < 0) return btd_error_failed(msg, strerror(-err)); pending = g_new0(struct pending_request, 1); pending->conn = dbus_connection_ref(conn); pending->msg = dbus_message_ref(msg); sink->disconnect = pending; return NULL; }
static void controlpoint_write_cb(guint8 status, const guint8 *pdu, guint16 len, gpointer user_data) { struct controlpoint_req *req = user_data; if (status == 0) { req->timeout = g_timeout_add_seconds(ATT_TIMEOUT, controlpoint_timeout, req); return; } error("SC Control Point write failed (opcode=%d)", req->opcode); if (req->opcode == UPDATE_SENSOR_LOC) { g_dbus_pending_property_error(req->reply_id, ERROR_INTERFACE ".Failed", "Operation failed (%d)", status); } else if (req->opcode == SET_CUMULATIVE_VALUE) { DBusMessage *reply; reply = btd_error_failed(req->msg, "Operation failed"); g_dbus_send_message(btd_get_dbus_connection(), reply); dbus_message_unref(req->msg); } req->csc->pending_req = NULL; g_free(req); }
static void rfcomm_connect_cb(GIOChannel *chan, GError *err, gpointer user_data) { struct input_conn *iconn = user_data; struct input_device *idev = iconn->idev; struct fake_input *fake = iconn->fake; DBusMessage *reply; if (err) { reply = btd_error_failed(iconn->pending_connect, err->message); goto failed; } fake->rfcomm = g_io_channel_unix_get_fd(chan); /* * FIXME: Some headsets required a sco connection * first to report volume gain key events */ fake->uinput = uinput_create(idev->name); if (fake->uinput < 0) { int err = fake->uinput; g_io_channel_shutdown(chan, TRUE, NULL); reply = btd_error_failed(iconn->pending_connect, strerror(-err)); goto failed; } fake->io = g_io_channel_unix_new(fake->rfcomm); g_io_channel_set_close_on_unref(fake->io, TRUE); g_io_add_watch(fake->io, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, (GIOFunc) rfcomm_io_cb, fake); /* Replying to the requestor */ reply = dbus_message_new_method_return(iconn->pending_connect); g_dbus_send_message(idev->conn, reply); dbus_message_unref(iconn->pending_connect); iconn->pending_connect = NULL; return; failed: g_dbus_send_message(idev->conn, reply); dbus_message_unref(iconn->pending_connect); iconn->pending_connect = NULL; }