Ejemplo n.º 1
0
static int cmd_set_sec_level(char *level)
{
  BtIOSecLevel sec_level;
  GError *gerr = NULL;

  if (strcasecmp(level, "low") == 0) {
    sec_level = BT_IO_SEC_LOW;
  } else if (strcasecmp(level, "medium") == 0) {
    sec_level = BT_IO_SEC_MEDIUM;
  } else if (strcasecmp(level, "high") == 0) {
    sec_level = BT_IO_SEC_HIGH;
  } else {
    printf("Invalid security level\n");
    return -1;
  }

  if (get_state() != STATE_CONNECTED) {
    printf("Device not connected\n");
    return -2;
  }

  bt_io_set(iochannel, &gerr, BT_IO_OPT_SEC_LEVEL, sec_level, BT_IO_OPT_INVALID);

  if (gerr) {
    printf("Error: %s\n", gerr->message);
    g_error_free(gerr);
    return -3;
  }
  return 0;
}
Ejemplo n.º 2
0
static void confirm_cb(GIOChannel *io, gpointer user_data)
{
	char addr[18];
	struct io_data *data = user_data;
	GError *err = NULL;

	if (!bt_io_get(io, &err, BT_IO_OPT_DEST, addr, BT_IO_OPT_INVALID)) {
		printf("bt_io_get(OPT_DEST): %s\n", err->message);
		g_clear_error(&err);
	} else
		printf("Got confirmation request for %s\n", addr);

	if (data->accept < 0 && data->reject < 0)
		return;

	if (data->reject == 0) {
		printf("Rejecting connection\n");
		g_io_channel_shutdown(io, TRUE, NULL);
		return;
	}

	if (data->voice) {
		if (!bt_io_set(io, &err, BT_IO_OPT_VOICE, data->voice,
							BT_IO_OPT_INVALID)) {
			printf("bt_io_set(OPT_VOICE): %s\n", err->message);
			g_clear_error(&err);
		}
	}

	data->io = g_io_channel_ref(io);
	io_data_ref(data);

	if (data->accept == 0) {
		if (!bt_io_accept(io, connect_cb, data,
					(GDestroyNotify) io_data_unref,
					&err)) {
			printf("bt_io_accept() failed: %s\n", err->message);
			g_clear_error(&err);
			io_data_unref(data);
			return;
		}
	} else {
		int seconds = (data->reject > 0) ?
						data->reject : data->accept;
		g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, seconds,
					confirm_timeout, data,
					(GDestroyNotify) io_data_unref);
	}
}
Ejemplo n.º 3
0
static void cmd_sec_level(int argcp, char **argvp)
{
    GError *gerr = NULL;
    BtIOSecLevel sec_level;

    if (argcp < 2) {
        printf("sec-level: %s\n", opt_sec_level);
        goto done;
    }

    if (strcasecmp(argvp[1], "medium") == 0)
        sec_level = BT_IO_SEC_MEDIUM;
    else if (strcasecmp(argvp[1], "high") == 0)
        sec_level = BT_IO_SEC_HIGH;
    else if (strcasecmp(argvp[1], "low") == 0)
        sec_level = BT_IO_SEC_LOW;
    else {
        printf("Allowed values: low | medium | high\n");
        goto done;
    }

    g_free(opt_sec_level);
    opt_sec_level = g_strdup(argvp[1]);

    if (conn_state != STATE_CONNECTED)
        goto done;

    if (opt_psm) {
        printf("It must be reconnected to this change take effect\n");
        goto done;
    }

    bt_io_set(iochannel, BT_IO_L2CAP, &gerr,
              BT_IO_OPT_SEC_LEVEL, sec_level,
              BT_IO_OPT_INVALID);

    if (gerr) {
        printf("Error: %s\n", gerr->message);
        g_error_free(gerr);
    }
    return;

done:
    printf("\r%s", get_prompt());
    fflush(stdout);
}
Ejemplo n.º 4
0
static void update_char_desc(guint8 status, const guint8 *pdu, guint16 len,
							gpointer user_data)
{
	struct query_data *current = user_data;
	struct gatt_service *gatt = current->gatt;
	struct characteristic *chr = current->chr;
	INFO("%s",chr->path);

	if (status == 0) {

		g_free(chr->desc);

		chr->desc = g_malloc(len);
		memcpy(chr->desc, pdu + 1, len - 1);
		chr->desc[len - 1] = '\0';

		store_attribute(gatt, current->handle,
				GATT_CHARAC_USER_DESC_UUID,
				(void *) chr->desc, len);
	} else if (status == ATT_ECODE_INSUFF_ENC) {
		GIOChannel *io = g_attrib_get_channel(gatt->attrib);
		BtIOSecLevel level = BT_IO_SEC_HIGH;

		bt_io_get(io, BT_IO_L2CAP, NULL,
				BT_IO_OPT_SEC_LEVEL, &level,
				BT_IO_OPT_INVALID);

		if (level < BT_IO_SEC_HIGH)
			level++;

		if (bt_io_set(io, BT_IO_L2CAP, NULL,
				BT_IO_OPT_SEC_LEVEL, level,
				BT_IO_OPT_INVALID)) {
			gatt_read_char(gatt->attrib, current->handle, 0,
					update_char_desc, current);
			return;
		}
	}

	add_characteristic_descriptor(current, GATT_CHARAC_USER_DESC_UUID);
	query_list_remove(gatt, current);
	g_free(current);
}
Ejemplo n.º 5
0
gboolean g_attrib_set_mtu(GAttrib *attrib, int mtu)
{
	if (mtu < ATT_DEFAULT_LE_MTU)
		mtu = ATT_DEFAULT_LE_MTU;

	if (mtu > ATT_MAX_MTU)
		mtu = ATT_MAX_MTU;

	if (!bt_io_set(attrib->io, BT_IO_L2CAP, NULL,
			BT_IO_OPT_OMTU, mtu,
			BT_IO_OPT_INVALID))
		return FALSE;

	attrib->buf = g_realloc(attrib->buf, mtu);

	attrib->buflen = mtu;

	return TRUE;
}
Ejemplo n.º 6
0
static void cmd_sec_level(int argcp, char **argvp)
{
    GError *gerr = NULL;
    BtIOSecLevel sec_level;

    if (argcp < 2) {
        resp_error(err_BAD_PARAM);;
        return;
    }

    if (strcasecmp(argvp[1], "medium") == 0)
        sec_level = BT_IO_SEC_MEDIUM;
    else if (strcasecmp(argvp[1], "high") == 0)
        sec_level = BT_IO_SEC_HIGH;
    else if (strcasecmp(argvp[1], "low") == 0)
        sec_level = BT_IO_SEC_LOW;
    else {
        resp_error(err_BAD_PARAM);;
        return;
    }

    g_free(opt_sec_level);
    opt_sec_level = g_strdup(argvp[1]);

    if (conn_state != STATE_CONNECTED)
        return;

    assert(!opt_psm);

    bt_io_set(iochannel, &gerr,
            BT_IO_OPT_SEC_LEVEL, sec_level,
            BT_IO_OPT_INVALID);
    if (gerr) {
        printf("# Error: %s\n", gerr->message);
        resp_error(err_PROTO_ERR);
        g_error_free(gerr);
    }
    else {
        /* Tell bluepy the security level
         * has been changed successfuly */
        cmd_status(0, NULL);
    }
}
Ejemplo n.º 7
0
static void cmd_sec_level(int argcp, char **argvp)
{
	GError *gerr = NULL;
	BtIOSecLevel sec_level;

	if (argcp < 2) {
		rl_printf("sec-level: %s\n", opt_sec_level);
		return;
	}

	if (strcasecmp(argvp[1], "medium") == 0)
		sec_level = BT_IO_SEC_MEDIUM;
	else if (strcasecmp(argvp[1], "high") == 0)
		sec_level = BT_IO_SEC_HIGH;
	else if (strcasecmp(argvp[1], "low") == 0)
		sec_level = BT_IO_SEC_LOW;
	else {
		rl_printf("Allowed values: low | medium | high\n");
		return;
	}

	g_free(opt_sec_level);
	opt_sec_level = g_strdup(argvp[1]);

	if (conn_state != STATE_CONNECTED)
		return;

	if (opt_psm) {
		rl_printf("Change will take effect on reconnection\n");
		return;
	}

	bt_io_set(iochannel, &gerr,
			BT_IO_OPT_SEC_LEVEL, sec_level,
			BT_IO_OPT_INVALID);
	if (gerr) {
		error("%s\n", gerr->message);
		g_error_free(gerr);
	}
}
Ejemplo n.º 8
0
static void update_sec_level(struct io_data *data)
{
	GError *err = NULL;
	int sec_level;

	if (!bt_io_get(data->io, &err, BT_IO_OPT_SEC_LEVEL, &sec_level,
							BT_IO_OPT_INVALID)) {
		printf("bt_io_get(OPT_SEC_LEVEL): %s\n", err->message);
		g_clear_error(&err);
		return;
	}

	printf("sec_level=%d\n", sec_level);

	if (opt_update_sec == sec_level)
		return;

	if (!bt_io_set(data->io, &err, BT_IO_OPT_SEC_LEVEL, opt_update_sec,
							BT_IO_OPT_INVALID)) {
		printf("bt_io_set(OPT_SEC_LEVEL): %s\n", err->message);
		g_clear_error(&err);
	}
}
Ejemplo n.º 9
0
static void update_char_value(guint8 status, const guint8 *pdu,
					guint16 len, gpointer user_data)
{
	struct query_data *current = user_data;
	struct gatt_service *gatt = current->gatt;
	struct characteristic *chr = current->chr;

	if (status == 0)
		characteristic_set_value(chr, pdu + 1, len - 1);
	else if (status == ATT_ECODE_INSUFF_ENC) {
		GIOChannel *io = g_attrib_get_channel(gatt->attrib);

		if (bt_io_set(io, BT_IO_L2CAP, NULL,
				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_HIGH,
				BT_IO_OPT_INVALID)) {
			gatt_read_char(gatt->attrib, chr->handle, 0,
					update_char_value, current);
			return;
		}
	}

	query_list_remove(gatt, current);
	g_free(current);
}
Ejemplo n.º 10
0
static int hidp_add_connection(struct input_device *idev)
{
    struct hidp_connadd_req *req;
    sdp_record_t *rec;
    char src_addr[18], dst_addr[18];
    char filename[PATH_MAX + 1];
    GKeyFile *key_file;
    char handle[11], *str;
    GError *gerr = NULL;
    int err;

    req = g_new0(struct hidp_connadd_req, 1);
    req->ctrl_sock = g_io_channel_unix_get_fd(idev->ctrl_io);
    req->intr_sock = g_io_channel_unix_get_fd(idev->intr_io);
    req->flags     = 0;
    req->idle_to   = idle_timeout;

    ba2str(&idev->src, src_addr);
    ba2str(&idev->dst, dst_addr);

    snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", src_addr,
             dst_addr);
    filename[PATH_MAX] = '\0';
    sprintf(handle, "0x%8.8X", idev->handle);

    key_file = g_key_file_new();
    g_key_file_load_from_file(key_file, filename, 0, NULL);
    str = g_key_file_get_string(key_file, "ServiceRecords", handle, NULL);
    g_key_file_free(key_file);

    if (!str) {
        error("Rejected connection from unknown device %s", dst_addr);
        err = -EPERM;
        goto cleanup;
    }

    rec = record_from_string(str);
    g_free(str);

    err = extract_hid_record(rec, req);
    sdp_record_free(rec);
    if (err < 0) {
        error("Could not parse HID SDP record: %s (%d)", strerror(-err),
              -err);
        goto cleanup;
    }

    req->vendor = btd_device_get_vendor(idev->device);
    req->product = btd_device_get_product(idev->device);
    req->version = btd_device_get_version(idev->device);

    if (idev->name)
        strncpy(req->name, idev->name, sizeof(req->name) - 1);

    /* Encryption is mandatory for keyboards */
    if (req->subclass & 0x40) {
        if (!bt_io_set(idev->intr_io, &gerr,
                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
                       BT_IO_OPT_INVALID)) {
            error("btio: %s", gerr->message);
            g_error_free(gerr);
            err = -EFAULT;
            goto cleanup;
        }

        idev->req = req;
        idev->sec_watch = g_io_add_watch(idev->intr_io, G_IO_OUT,
                                         encrypt_notify, idev);

        return 0;
    }

    err = ioctl_connadd(req);

cleanup:
    g_free(req->rd_data);
    g_free(req);

    return err;
}
Ejemplo n.º 11
0
static void confirm_sco_cb(GIOChannel *chan, gpointer user_data)
{
	char address[18];
	bdaddr_t bdaddr;
	GError *err = NULL;
	struct bt_sco *sco = user_data;
	uint16_t voice_settings;

	DBG("");

	bt_io_get(chan, &err,
			BT_IO_OPT_DEST, address,
			BT_IO_OPT_DEST_BDADDR, &bdaddr,
			BT_IO_OPT_INVALID);
	if (err) {
		error("sco: audio confirm failed (%s)", err->message);
		g_error_free(err);
		goto drop;
	}

	if (!sco->confirm_cb || !sco->connect_cb) {
		error("sco: Connect and/or confirm callback not registered ");
		goto drop;
	}

	/* Check if there is SCO */
	if (sco->io) {
		error("sco: SCO is in progress");
		goto drop;
	}

	if (!sco->confirm_cb(&bdaddr, &voice_settings)) {
		error("sco: Audio connection from %s rejected", address);
		goto drop;
	}

	bacpy(&sco->remote_addr, &bdaddr);

	DBG("Incoming SCO connection from %s, voice settings 0x%x", address,
								voice_settings);

	err = NULL;
	bt_io_set(chan, &err, BT_IO_OPT_VOICE, voice_settings,
							BT_IO_OPT_INVALID);
	if (err) {
		error("sco: Could not set voice settings (%s)", err->message);
		g_error_free(err);
		goto drop;
	}

	if (!bt_io_accept(chan, connect_sco_cb, sco, NULL, NULL)) {
		error("sco: Failed to accept audio connection");
		goto drop;
	}

	sco->io = g_io_channel_ref(chan);

	return;

drop:
	g_io_channel_shutdown(chan, TRUE, NULL);
}
Ejemplo n.º 12
0
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;
}