int avctp_register(struct btd_adapter *adapter, gboolean master) { struct avctp_server *server; const bdaddr_t *src = btd_adapter_get_address(adapter); server = g_new0(struct avctp_server, 1); server->control_io = avctp_server_socket(src, master, L2CAP_MODE_BASIC, AVCTP_CONTROL_PSM); if (!server->control_io) { g_free(server); return -1; } server->browsing_io = avctp_server_socket(src, master, L2CAP_MODE_ERTM, AVCTP_BROWSING_PSM); if (!server->browsing_io) { if (server->control_io) { g_io_channel_shutdown(server->control_io, TRUE, NULL); g_io_channel_unref(server->control_io); server->control_io = NULL; } g_free(server); return -1; } server->adapter = btd_adapter_ref(adapter); servers = g_slist_append(servers, server); return 0; }
static struct input_device *input_device_new(struct btd_service *service) { struct btd_device *device = btd_service_get_device(service); struct btd_profile *p = btd_service_get_profile(service); const char *path = device_get_path(device); const sdp_record_t *rec = btd_device_get_record(device, p->remote_uuid); struct btd_adapter *adapter = device_get_adapter(device); struct input_device *idev; char name[HCI_MAX_NAME_LENGTH + 1]; idev = g_new0(struct input_device, 1); 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); idev->path = g_strdup(path); idev->handle = rec->handle; idev->disable_sdp = is_device_sdp_disable(rec); device_get_name(device, name, HCI_MAX_NAME_LENGTH); if (strlen(name) > 0) idev->name = g_strdup(name); /* Initialize device properties */ extract_hid_props(idev, rec); return idev; }
gboolean hdp_get_mdep(struct hdp_device *device, struct hdp_application *app, hdp_continue_mdep_f func, gpointer data, GDestroyNotify destroy, GError **err) { struct get_mdep_data *mdep_data; const bdaddr_t *src; const bdaddr_t *dst; uuid_t uuid; 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); mdep_data->app = hdp_application_ref(app); mdep_data->func = func; mdep_data->data = data; mdep_data->destroy = destroy; bt_string2uuid(&uuid, HDP_UUID); if (bt_search_service(src, dst, &uuid, get_mdep_cb, mdep_data, free_mdep_data, 0) < 0) { g_set_error(err, HDP_ERROR, HDP_CONNECTION_ERROR, "Can't get remote SDP record"); g_free(mdep_data); return FALSE; } return TRUE; }
static void sixaxis_sdp_cb(struct btd_device *dev, int err, void *user_data) { struct sixaxis_data *data = user_data; const bdaddr_t *src; DBG("err %d (%s)", err, strerror(-err)); if (err < 0) goto fail; src = btd_adapter_get_address(device_get_adapter(dev)); if (input_device_set_channel(src, device_get_address(dev), data->psm, data->chan) < 0) goto fail; 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); }
gboolean hdp_establish_mcl(struct hdp_device *device, hdp_continue_proc_f func, gpointer data, GDestroyNotify destroy, GError **err) { struct conn_mcl_data *conn_data; const bdaddr_t *src; const bdaddr_t *dst; uuid_t uuid; 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); conn_data->refs = 1; conn_data->func = func; conn_data->data = data; conn_data->destroy = destroy; conn_data->dev = health_device_ref(device); bt_string2uuid(&uuid, HDP_UUID); if (bt_search_service(src, dst, &uuid, search_cb, conn_data, destroy_con_mcl_data, 0) < 0) { g_set_error(err, HDP_ERROR, HDP_CONNECTION_ERROR, "Can't get remote SDP record"); g_free(conn_data); return FALSE; } return TRUE; }
static struct network_adapter *create_adapter(struct btd_adapter *adapter) { struct network_adapter *na; GError *err = NULL; na = g_new0(struct network_adapter, 1); na->adapter = btd_adapter_ref(adapter); na->io = bt_io_listen(NULL, confirm_event, na, NULL, &err, BT_IO_OPT_SOURCE_BDADDR, btd_adapter_get_address(adapter), BT_IO_OPT_PSM, BNEP_PSM, BT_IO_OPT_OMTU, BNEP_MTU, BT_IO_OPT_IMTU, BNEP_MTU, BT_IO_OPT_SEC_LEVEL, security ? BT_IO_SEC_MEDIUM : BT_IO_SEC_LOW, BT_IO_OPT_INVALID); if (!na->io) { error("%s", err->message); g_error_free(err); adapter_free(na); return NULL; } return na; }
/* Connect and initiate BNEP session */ int connection_connect(struct btd_service *service) { struct network_conn *nc = btd_service_get_user_data(service); struct network_peer *peer = nc->peer; uint16_t id = get_service_id(service); GError *err = NULL; const bdaddr_t *src; const bdaddr_t *dst; DBG("id %u", id); if (nc->state != DISCONNECTED) return -EALREADY; src = btd_adapter_get_address(device_get_adapter(peer->device)); dst = device_get_address(peer->device); nc->io = bt_io_connect(connect_cb, nc, NULL, &err, BT_IO_OPT_SOURCE_BDADDR, src, BT_IO_OPT_DEST_BDADDR, dst, BT_IO_OPT_PSM, BNEP_PSM, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, BT_IO_OPT_OMTU, BNEP_MTU, BT_IO_OPT_IMTU, BNEP_MTU, BT_IO_OPT_INVALID); if (!nc->io) return -EIO; nc->state = CONNECTING; return 0; }
static bool setup_device(int fd, int index, struct btd_adapter *adapter) { char device_addr[18], master_addr[18], adapter_addr[18]; bdaddr_t device_bdaddr, master_bdaddr; const bdaddr_t *adapter_bdaddr; struct btd_device *device; if (get_device_bdaddr(fd, &device_bdaddr) < 0) return false; if (get_master_bdaddr(fd, &master_bdaddr) < 0) return false; /* This can happen if controller was plugged while already connected * eg. to charge up battery. * Don't set LEDs in that case, hence return false */ device = btd_adapter_find_device(adapter, &device_bdaddr, BDADDR_BREDR); if (device && btd_device_is_connected(device)) return false; adapter_bdaddr = btd_adapter_get_address(adapter); if (bacmp(adapter_bdaddr, &master_bdaddr)) { if (set_master_bdaddr(fd, adapter_bdaddr) < 0) return false; } ba2str(&device_bdaddr, device_addr); ba2str(&master_bdaddr, master_addr); ba2str(adapter_bdaddr, adapter_addr); DBG("remote %s old_master %s new_master %s", device_addr, master_addr, adapter_addr); device = btd_adapter_get_device(adapter, &device_bdaddr, BDADDR_BREDR); if (g_slist_find_custom(btd_device_get_uuids(device), HID_UUID, (GCompareFunc)strcasecmp)) { DBG("device %s already known, skipping", device_addr); return true; } info("sixaxis: setting up new device"); btd_device_device_set_name(device, devices[index].name); btd_device_set_pnpid(device, devices[index].source, devices[index].vid, devices[index].pid, devices[index].version); btd_device_set_temporary(device, FALSE); return true; }
int server_register(struct btd_adapter *adapter, uint16_t id) { struct network_adapter *na; struct network_server *ns; const char *path; na = find_adapter(adapters, adapter); if (!na) { na = create_adapter(adapter); if (!na) return -EINVAL; adapters = g_slist_append(adapters, na); } ns = find_server(na->servers, id); if (ns) return 0; ns = g_new0(struct network_server, 1); ns->name = g_strdup("Network service"); path = adapter_get_path(adapter); if (g_slist_length(na->servers) > 0) goto done; if (!g_dbus_register_interface(btd_get_dbus_connection(), path, NETWORK_SERVER_INTERFACE, server_methods, NULL, NULL, na, path_unregister)) { error("D-Bus failed to register %s interface", NETWORK_SERVER_INTERFACE); server_free(ns); return -1; } DBG("Registered interface %s on path %s", NETWORK_SERVER_INTERFACE, path); done: bacpy(&ns->src, btd_adapter_get_address(adapter)); ns->id = id; ns->na = na; ns->record_id = 0; na->servers = g_slist_append(na->servers, ns); return 0; }
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) return NULL; if (session->state > AVCTP_STATE_DISCONNECTED) return session; avctp_set_state(session, AVCTP_STATE_CONNECTING, 0); src = btd_adapter_get_address(session->server->adapter); io = bt_io_connect(avctp_connect_cb, session, NULL, &err, 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, BT_IO_OPT_PSM, AVCTP_CONTROL_PSM, BT_IO_OPT_INVALID); if (err) { avctp_set_state(session, AVCTP_STATE_DISCONNECTED, -EIO); error("%s", err->message); g_error_free(err); return NULL; } session->control = avctp_channel_create(session, io, 2, NULL); session->initiator = true; g_io_channel_unref(io); return session; }
static void avctp_control_confirm(struct avctp *session, GIOChannel *chan, struct btd_device *dev) { const bdaddr_t *src; const bdaddr_t *dst; if (session->control != NULL) { error("Control: Refusing unexpected connect"); g_io_channel_shutdown(chan, TRUE, NULL); /* * Close AVCTP channel if remote tried connect * at the same time * AVRCP SPEC V1.5 4.1.1 Connection Establishment */ avctp_set_state(session, AVCTP_STATE_DISCONNECTED, -EAGAIN); return; } avctp_set_state(session, AVCTP_STATE_CONNECTING, 0); session->control = avctp_channel_create(session, chan, 2, NULL); src = btd_adapter_get_address(device_get_adapter(dev)); dst = device_get_address(dev); session->auth_id = btd_request_authorization(src, dst, AVRCP_REMOTE_UUID, auth_cb, session); if (session->auth_id == 0) goto drop; session->control->watch = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL, session_cb, session); return; drop: avctp_set_state(session, AVCTP_STATE_DISCONNECTED, -EIO); }
static ssize_t wii_pincb(struct btd_adapter *adapter, struct btd_device *device, char *pinbuf, bool *display, unsigned int attempt) { uint16_t vendor, product; char addr[18], name[25]; unsigned int i; /* Only try the pin code once per device. If it's not correct then it's * an unknown device. */ if (attempt > 1) return 0; ba2str(device_get_address(device), addr); vendor = btd_device_get_vendor(device); product = btd_device_get_product(device); device_get_name(device, name, sizeof(name)); for (i = 0; i < G_N_ELEMENTS(wii_ids); ++i) { if (vendor == wii_ids[i][0] && product == wii_ids[i][1]) goto found; } for (i = 0; i < G_N_ELEMENTS(wii_names); ++i) { if (g_str_equal(name, wii_names[i])) goto found; } return 0; found: DBG("Forcing fixed pin on detected wiimote %s", addr); memcpy(pinbuf, btd_adapter_get_address(adapter), 6); return 6; }
int avctp_connect_browsing(struct avctp *session) { const bdaddr_t *src; GError *err = NULL; GIOChannel *io; if (session->state != AVCTP_STATE_CONNECTED) return -ENOTCONN; if (session->browsing != NULL) return 0; avctp_set_state(session, AVCTP_STATE_BROWSING_CONNECTING, 0); src = btd_adapter_get_address(session->server->adapter); io = bt_io_connect(avctp_connect_browsing_cb, session, NULL, &err, 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, BT_IO_OPT_PSM, AVCTP_BROWSING_PSM, BT_IO_OPT_MODE, L2CAP_MODE_ERTM, BT_IO_OPT_INVALID); if (err) { error("%s", err->message); g_error_free(err); return -EIO; } session->browsing = avctp_channel_create(session, io, 1, avctp_destroy_browsing); g_io_channel_unref(io); return 0; }
int sap_server_register(struct btd_adapter *adapter) { sdp_record_t *record = NULL; GError *gerr = NULL; GIOChannel *io; struct sap_server *server; if (sap_init() < 0) { error("Sap driver initialization failed."); return -1; } record = create_sap_record(SAP_SERVER_CHANNEL); if (!record) { error("Creating SAP SDP record failed."); goto sdp_err; } if (adapter_service_add(adapter, record) < 0) { error("Adding SAP SDP record to the SDP server failed."); sdp_record_free(record); goto sdp_err; } server = g_new0(struct sap_server, 1); server->adapter = btd_adapter_ref(adapter); server->record_id = record->handle; io = bt_io_listen(NULL, connect_confirm_cb, server, NULL, &gerr, 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, BT_IO_OPT_INVALID); if (!io) { error("Can't listen at channel %d.", SAP_SERVER_CHANNEL); g_error_free(gerr); goto server_err; } server->listen_io = io; if (!g_dbus_register_interface(btd_get_dbus_connection(), adapter_get_path(server->adapter), SAP_SERVER_INTERFACE, server_methods, NULL, server_properties, server, destroy_sap_interface)) { error("D-Bus failed to register %s interface", SAP_SERVER_INTERFACE); goto server_err; } DBG("server %p, listen socket 0x%02x", server, g_io_channel_unix_get_fd(io)); return 0; server_err: server_remove(server); sdp_err: sap_exit(); return -1; }
static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen, gpointer user_data) { struct hog_device *hogdev = user_data; struct btd_adapter *adapter = device_get_adapter(hogdev->device); uint8_t value[HOG_REPORT_MAP_MAX_SIZE]; struct uhid_event ev; uint16_t vendor_src, vendor, product, version; ssize_t vlen; char itemstr[20]; /* 5x3 (data) + 4 (continuation) + 1 (null) */ int i, err; if (status != 0) { error("Report Map read failed: %s", att_ecode2str(status)); return; } vlen = dec_read_resp(pdu, plen, value, sizeof(value)); if (vlen < 0) { error("ATT protocol error"); return; } DBG("Report MAP:"); for (i = 0; i < vlen;) { ssize_t ilen = 0; bool long_item = false; if (get_descriptor_item_info(&value[i], vlen - i, &ilen, &long_item)) { /* Report ID is short item with prefix 100001xx */ if (!long_item && (value[i] & 0xfc) == 0x84) hogdev->has_report_id = TRUE; DBG("\t%s", item2string(itemstr, &value[i], ilen)); i += ilen; } else { error("Report Map parsing failed at %d", i); /* Just print remaining items at once and break */ DBG("\t%s", item2string(itemstr, &value[i], vlen - i)); break; } } vendor_src = btd_device_get_vendor_src(hogdev->device); vendor = btd_device_get_vendor(hogdev->device); product = btd_device_get_product(hogdev->device); version = btd_device_get_version(hogdev->device); DBG("DIS information: vendor_src=0x%X, vendor=0x%X, product=0x%X, " "version=0x%X", vendor_src, vendor, product, version); /* create uHID device */ memset(&ev, 0, sizeof(ev)); ev.type = UHID_CREATE; if (device_name_known(hogdev->device)) device_get_name(hogdev->device, (char *) ev.u.create.name, sizeof(ev.u.create.name)); else strcpy((char *) ev.u.create.name, "bluez-hog-device"); ba2str(btd_adapter_get_address(adapter), (char *) ev.u.create.phys); ba2str(device_get_address(hogdev->device), (char *) ev.u.create.uniq); ev.u.create.vendor = vendor; ev.u.create.product = product; ev.u.create.version = version; ev.u.create.country = hogdev->bcountrycode; ev.u.create.bus = BUS_BLUETOOTH; ev.u.create.rd_data = value; ev.u.create.rd_size = vlen; err = bt_uhid_send(hogdev->uhid, &ev); if (err < 0) { error("bt_uhid_send: %s", strerror(-err)); return; } bt_uhid_register(hogdev->uhid, UHID_OUTPUT, forward_report, hogdev); bt_uhid_register(hogdev->uhid, UHID_SET_REPORT, set_report, hogdev); bt_uhid_register(hogdev->uhid, UHID_GET_REPORT, get_report, hogdev); }
static void hid_server_remove(struct btd_profile *p, struct btd_adapter *adapter) { server_stop(btd_adapter_get_address(adapter)); }
static int hid_server_probe(struct btd_profile *p, struct btd_adapter *adapter) { return server_start(btd_adapter_get_address(adapter)); }