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; }
static int hidp_add_connection(struct input_device *idev, struct input_conn *iconn) { struct hidp_connadd_req *req; struct fake_hid *fake_hid; struct fake_input *fake; sdp_record_t *rec; char src_addr[18], dst_addr[18]; GError *gerr = NULL; int err; DBG("idev %p", idev); req = g_new0(struct hidp_connadd_req, 1); req->ctrl_sock = g_io_channel_unix_get_fd(iconn->ctrl_io); req->intr_sock = g_io_channel_unix_get_fd(iconn->intr_io); req->flags = 0; req->idle_to = iconn->timeout; ba2str(&idev->src, src_addr); ba2str(&idev->dst, dst_addr); rec = fetch_record(src_addr, dst_addr, idev->handle); if (!rec) { error("Rejected connection from unknown device %s", dst_addr); err = -EPERM; goto cleanup; } extract_hid_record(rec, req); extract_hid_props(idev, rec); sdp_record_free(rec); req->vendor = btd_device_get_vendor(idev->device); req->product = btd_device_get_product(idev->device); req->version = btd_device_get_version(idev->device); fake_hid = get_fake_hid(req->vendor, req->product); if (fake_hid) { err = 0; fake = g_new0(struct fake_input, 1); fake->connect = fake_hid_connect; fake->disconnect = fake_hid_disconnect; fake->priv = fake_hid; fake->idev = idev; fake = fake_hid_connadd(fake, iconn->intr_io, fake_hid); if (fake == NULL) err = -ENOMEM; else fake->flags |= FI_FLAG_CONNECTED; goto cleanup; } if (idev->name) strncpy(req->name, idev->name, sizeof(req->name) - 1); /* Encryption is mandatory for keyboards */ if (req->subclass & 0x40) { struct btd_adapter *adapter = device_get_adapter(idev->device); err = btd_adapter_encrypt_link(adapter, (bdaddr_t *) &idev->dst, encrypt_completed, req); if (err == 0) { /* Waiting async encryption */ return 0; } if (err == -ENOSYS) goto nosys; if (err != -EALREADY) { error("encrypt_link: %s (%d)", strerror(-err), -err); goto cleanup; } } err = ioctl_connadd(req); cleanup: free(req->rd_data); g_free(req); return err; nosys: if (!bt_io_set(iconn->intr_io, BT_IO_L2CAP, &gerr, BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM, BT_IO_OPT_INVALID)) { error("btio: %s", gerr->message); g_error_free(gerr); goto cleanup; } iconn->req = req; iconn->sec_watch = g_io_add_watch(iconn->intr_io, G_IO_OUT, encrypt_notify, iconn); return 0; }