Beispiel #1
0
uint16_t dec_read_blob_req(const uint8_t *pdu, size_t len, uint16_t *handle,
							uint16_t *offset)
{
	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle) +
							sizeof(*offset);

	if (pdu == NULL)
		return 0;

	if (handle == NULL)
		return 0;

	if (offset == NULL)
		return 0;

	if (len < min_len)
		return 0;

	if (pdu[0] != ATT_OP_READ_BLOB_REQ)
		return 0;

	*handle = att_get_u16(&pdu[1]);
	*offset = att_get_u16(&pdu[3]);

	return min_len;
}
Beispiel #2
0
uint16_t dec_read_by_type_req(const uint8_t *pdu, size_t len, uint16_t *start,
						uint16_t *end, bt_uuid_t *uuid)
{
	const size_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end);

	if (pdu == NULL)
		return 0;

	if (start == NULL || end == NULL || uuid == NULL)
		return 0;

	if (len < min_len + 2)
		return 0;

	if (pdu[0] != ATT_OP_READ_BY_TYPE_REQ)
		return 0;

	*start = att_get_u16(&pdu[1]);
	*end = att_get_u16(&pdu[3]);

	if (len == min_len + 2)
		*uuid = att_get_uuid16(&pdu[5]);
	else
		*uuid = att_get_uuid128(&pdu[5]);

	return len;
}
Beispiel #3
0
uint16_t dec_find_by_type_req(const uint8_t *pdu, size_t len, uint16_t *start,
						uint16_t *end, bt_uuid_t *uuid,
						uint8_t *value, size_t *vlen)
{
	if (pdu == NULL)
		return 0;

	if (len < 7)
		return 0;

	/* Attribute Opcode (1 octet) */
	if (pdu[0] != ATT_OP_FIND_BY_TYPE_REQ)
		return 0;

	/* First requested handle number (2 octets) */
	*start = att_get_u16(&pdu[1]);
	/* Last requested handle number (2 octets) */
	*end = att_get_u16(&pdu[3]);
	/* 16-bit UUID to find (2 octets) */
	*uuid = att_get_uuid16(&pdu[5]);

	/* Attribute value to find */
	*vlen = len - 7;
	if (*vlen > 0)
		memcpy(value, pdu + 7, *vlen);

	return len;
}
Beispiel #4
0
GSList *dec_find_by_type_resp(const uint8_t *pdu, size_t len)
{
	struct att_range *range;
	GSList *matches;
	off_t offset;

	/* PDU should contain at least:
	 * - Attribute Opcode (1 octet)
	 * - Handles Information List (at least one entry):
	 *   - Found Attribute Handle (2 octets)
	 *   - Group End Handle (2 octets) */
	if (pdu == NULL || len < 5)
		return NULL;

	if (pdu[0] != ATT_OP_FIND_BY_TYPE_RESP)
		return NULL;

	/* Reject incomplete Handles Information List */
	if ((len - 1) % 4)
		return NULL;

	for (offset = 1, matches = NULL;
				len >= (offset + sizeof(uint16_t) * 2);
				offset += sizeof(uint16_t) * 2) {
		range = g_new0(struct att_range, 1);
		range->start = att_get_u16(&pdu[offset]);
		range->end = att_get_u16(&pdu[offset + 2]);

		matches = g_slist_append(matches, range);
	}

	return matches;
}
Beispiel #5
0
uint16_t dec_read_by_grp_req(const uint8_t *pdu, int len, uint16_t *start,
						uint16_t *end, uuid_t *uuid)
{
	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end);

	if (pdu == NULL)
		return 0;

	if (start == NULL || end == NULL || uuid == NULL)
		return 0;

	if (pdu[0] != ATT_OP_READ_BY_GROUP_REQ)
		return 0;

	if (len < min_len + 2)
		return 0;

	*start = att_get_u16(&pdu[1]);
	*end = att_get_u16(&pdu[3]);
	if (len == min_len + 2)
		sdp_uuid16_create(uuid, att_get_u16(&pdu[5]));
	else
		sdp_uuid128_create(uuid, &pdu[5]);

	return len;
}
static void read_pnpid_cb(guint8 status, const guint8 *pdu, guint16 len,
							gpointer user_data)
{
	struct characteristic *ch = user_data;
	uint8_t value[PNP_ID_SIZE];
	ssize_t vlen;

	if (status != 0) {
		error("Error reading PNP_ID value: %s", att_ecode2str(status));
		return;
	}

	vlen = dec_read_resp(pdu, len, value, sizeof(value));
	if (vlen < 0) {
		error("Error reading PNP_ID: Protocol error");
		return;
	}

	if (vlen < 7) {
		error("Error reading PNP_ID: Invalid pdu length received");
		return;
	}

	btd_device_set_pnpid(ch->d->dev, value[0], att_get_u16(&value[1]),
				att_get_u16(&value[3]), att_get_u16(&value[5]));
}
Beispiel #7
0
uint16_t dec_prep_write_resp(const uint8_t *pdu, size_t len, uint16_t *handle,
				uint16_t *offset, uint8_t *value, size_t *vlen)
{
	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle) +
								sizeof(*offset);

	if (pdu == NULL)
		return 0;

	if (handle == NULL || offset == NULL || value == NULL || vlen == NULL)
		return 0;

	if (len < min_len)
		return 0;

	if (pdu[0] != ATT_OP_PREP_WRITE_REQ)
		return 0;

	*handle = att_get_u16(&pdu[1]);
	*offset = att_get_u16(&pdu[3]);
	*vlen = len - min_len;
	if (*vlen > 0)
		memcpy(value, pdu + min_len, *vlen);

	return len;
}
static void discover_ccc_cb(guint8 status, const guint8 *pdu,
						guint16 len, gpointer user_data)
{
	struct heartrate *hr = user_data;
	struct att_data_list *list;
	uint8_t format;
	int i;

	if (status != 0) {
		error("Discover Heart Rate Measurement descriptors failed: %s",
							att_ecode2str(status));
		return;
	}

	list = dec_find_info_resp(pdu, len, &format);
	if (list == NULL)
		return;

	if (format != ATT_FIND_INFO_RESP_FMT_16BIT)
		goto done;

	for (i = 0; i < list->num; i++) {
		uint8_t *value;
		uint16_t handle, uuid;
		char *msg;
		uint8_t attr_val[2];

		value = list->data[i];
		handle = att_get_u16(value);
		uuid = att_get_u16(value + 2);

		if (uuid != GATT_CLIENT_CHARAC_CFG_UUID)
			continue;

		hr->measurement_ccc_handle = handle;

		if (g_slist_length(hr->hradapter->watchers) == 0) {
			att_put_u16(0x0000, attr_val);
			msg = g_strdup("Disable measurement");
		} else {
			att_put_u16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, attr_val);
			msg = g_strdup("Enable measurement");
		}

		gatt_write_char(hr->attrib, handle, attr_val,
					sizeof(attr_val), char_write_cb, msg);

		break;
	}

done:
	att_data_list_free(list);
}
Beispiel #9
0
static void discover_descriptor_cb(guint8 status, const guint8 *pdu,
					guint16 len, gpointer user_data)
{
	struct report *report;
	struct hog_device *hogdev;
	struct att_data_list *list;
	uint8_t format;
	int i;

	if (status != 0) {
		error("Discover all characteristic descriptors failed: %s",
							att_ecode2str(status));
		return;
	}

	list = dec_find_info_resp(pdu, len, &format);
	if (list == NULL)
		return;

	if (format != ATT_FIND_INFO_RESP_FMT_16BIT)
		goto done;

	for (i = 0; i < list->num; i++) {
		uint16_t uuid16, handle;
		uint8_t *value;

		value = list->data[i];
		handle = att_get_u16(value);
		uuid16 = att_get_u16(&value[2]);

		switch (uuid16) {
		case GATT_CLIENT_CHARAC_CFG_UUID:
			report = user_data;
			write_ccc(handle, report->hogdev);
			break;
		case GATT_REPORT_REFERENCE:
			report = user_data;
			gatt_read_char(report->hogdev->attrib, handle,
						report_reference_cb, report);
			break;
		case GATT_EXTERNAL_REPORT_REFERENCE:
			hogdev = user_data;
			gatt_read_char(hogdev->attrib, handle,
					external_report_reference_cb, hogdev);
			break;
		}
	}

done:
	att_data_list_free(list);
}
Beispiel #10
0
static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
{
    uint8_t opdu[ATT_MAX_MTU];
    uint16_t handle, i, olen;

    handle = att_get_u16(&pdu[1]);

    printf("\r");
    switch (pdu[0]) {
    case ATT_OP_HANDLE_NOTIFY:
        printf("Notification handle = 0x%04x value: ", handle);
        break;
    case ATT_OP_HANDLE_IND:
        printf("Indication   handle = 0x%04x value: ", handle);
        break;
    default:
        printf("Invalid opcode\n");
        goto done;
    }

    for (i = 3; i < len; i++)
        printf("%02x ", pdu[i]);

    if (pdu[0] == ATT_OP_HANDLE_NOTIFY)
        goto done;

    olen = enc_confirmation(opdu, sizeof(opdu));

    if (olen > 0)
        g_attrib_send(attrib, 0, opdu[0], opdu, olen, NULL, NULL, NULL);

done:
    printf("\r%s", get_prompt());
    fflush(stdout);
}
Beispiel #11
0
static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
{
	GAttrib *attrib = user_data;
	uint8_t *opdu;
	uint16_t handle, i, olen = 0;
	size_t plen;

	handle = att_get_u16(&pdu[1]);

	switch (pdu[0]) {
	case ATT_OP_HANDLE_NOTIFY:
		g_print("Notification handle = 0x%04x value: ", handle);
		break;
	case ATT_OP_HANDLE_IND:
		g_print("Indication   handle = 0x%04x value: ", handle);
		break;
	default:
		g_print("Invalid opcode\n");
		return;
	}

	for (i = 3; i < len; i++)
		g_print("%02x ", pdu[i]);

	g_print("\n");

	if (pdu[0] == ATT_OP_HANDLE_NOTIFY)
		return;

	opdu = g_attrib_get_buffer(attrib, &plen);
	olen = enc_confirmation(opdu, plen);

	if (olen > 0)
		g_attrib_send(attrib, 0, opdu, olen, NULL, NULL, NULL);
}
static void char_read_by_uuid_cb(guint8 status, const guint8 *pdu,
                                 guint16 plen, gpointer user_data)
{
    struct att_data_list *list;
    int i;
    GString *s;

    if (status != 0) {
        error("Read characteristics by UUID failed: %s\n",
              att_ecode2str(status));
        return;
    }

    list = dec_read_by_type_resp(pdu, plen);
    if (list == NULL)
        return;

    s = g_string_new(NULL);
    for (i = 0; i < list->num; i++) {
        uint8_t *value = list->data[i];
        int j;

        g_string_printf(s, "handle: 0x%04x \t value: ",
                        att_get_u16(value));
        value += 2;
        for (j = 0; j < list->len - 2; j++, value++)
            g_string_append_printf(s, "%02x ", *value);

        rl_printf("%s\n", s->str);
    }

    att_data_list_free(list);
    g_string_free(s, TRUE);
}
Beispiel #13
0
struct attribute *dec_indication(const uint8_t *pdu, int len)
{
	const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t);

	struct attribute *a;

	if (pdu == NULL)
		return NULL;

	if (pdu[0] != ATT_OP_HANDLE_IND)
		return NULL;

	if (len < min_len)
		return NULL;

	a = malloc(sizeof(struct attribute) + len - min_len);
	if (a == NULL)
		return NULL;

	a->len = len - min_len;

	a->handle = att_get_u16(&pdu[1]);
	memcpy(a->data, &pdu[3], a->len);

	return a;
}
Beispiel #14
0
static void info_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
							gpointer user_data)
{
	struct hog_device *hogdev = user_data;
	uint8_t value[HID_INFO_SIZE];
	ssize_t vlen;

	if (status != 0) {
		error("HID Information read failed: %s",
						att_ecode2str(status));
		return;
	}

	vlen = dec_read_resp(pdu, plen, value, sizeof(value));
	if (vlen != 4) {
		error("ATT protocol error");
		return;
	}

	hogdev->bcdhid = att_get_u16(&value[0]);
	hogdev->bcountrycode = value[2];
	hogdev->flags = value[3];

	DBG("bcdHID: 0x%04X bCountryCode: 0x%02X Flags: 0x%02X",
			hogdev->bcdhid, hogdev->bcountrycode, hogdev->flags);
}
Beispiel #15
0
static void external_report_reference_cb(guint8 status, const guint8 *pdu,
					guint16 plen, gpointer user_data)
{
	struct hog_device *hogdev = user_data;
	uint16_t uuid16;
	bt_uuid_t uuid;

	if (status != 0) {
		error("Read External Report Reference descriptor failed: %s",
							att_ecode2str(status));
		return;
	}

	if (plen != 3) {
		error("Malformed ATT read response");
		return;
	}

	uuid16 = att_get_u16(&pdu[1]);
	DBG("External report reference read, external report characteristic "
						"UUID: 0x%04x", uuid16);
	bt_uuid16_create(&uuid, uuid16);
	gatt_discover_char(hogdev->attrib, 0x00, 0xff, &uuid,
					external_service_char_cb, hogdev);
}
Beispiel #16
0
static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data) {
	gatt_connection_t *conn = user_data;
	uint8_t opdu[ATT_MAX_MTU];
	uint16_t handle, i, olen = 0;

	handle = att_get_u16(&pdu[1]);
	// printf("0x%02x\n", handle);

	switch (pdu[0]) {
	case ATT_OP_HANDLE_NOTIFY:
		if (conn->notification_handler) {
			conn->notification_handler(handle, &pdu[3], len, conn->notification_user_data);
		}
		break;
	case ATT_OP_HANDLE_IND:
		if (conn->indication_handler) {
			conn->indication_handler(handle, &pdu[3], len, conn->indication_user_data);
		}
		break;
	default:
		g_print("Invalid opcode\n");
		return;
	}

	if (pdu[0] == ATT_OP_HANDLE_NOTIFY)
		return;

	olen = enc_confirmation(opdu, sizeof(opdu));

	if (olen > 0)
		g_attrib_send(conn->attrib, 0, opdu[0], opdu, olen, NULL, NULL, NULL);
}
Beispiel #17
0
void read_by_uuid_cb(guint8 status, const guint8 *pdu, guint16 plen,
                     gpointer user_data)
{
    struct att_data_list *list;
    GSList               *bl_value_list = NULL;
    cb_ctx_t             *cb_ctx = user_data;

    printf_dbg("[CB] IN read_by_uuid_cb\n");
    if (status) {
        cb_ctx->cb_ret_val = BL_REQUEST_FAIL_ERROR;
        sprintf(cb_ctx->cb_ret_msg, "Read by uuid callback: Failure: %s\n",
                att_ecode2str(status));
        goto error;
    }

    list = dec_read_by_type_resp(pdu, plen);
    if (list == NULL) {
        strcpy(cb_ctx->cb_ret_msg, "Read by uuid callback: Nothing found\n");
        cb_ctx->cb_ret_val = BL_NO_ERROR;
        goto error;
    }

    for (int i = 0; i < list->num; i++) {
        bl_value_t *bl_value = bl_value_new(NULL, att_get_u16(list->data[i]),
                                            list->len - 2, list->data[i] + 2);
        if (bl_value == NULL) {
            cb_ctx->cb_ret_val = BL_MALLOC_ERROR;
            strcpy(cb_ctx->cb_ret_msg,
                   "Read by uuid callback: Malloc error\n");
            goto error;
        }

        // Add it to the value list
        if (bl_value_list == NULL) {
            bl_value_list = g_slist_alloc();
            if (bl_value_list == NULL) {
                cb_ctx->cb_ret_val = BL_MALLOC_ERROR;
                strcpy(cb_ctx->cb_ret_msg,
                       "Read by uuid callback: Malloc error\n");
                goto error;
            }
            bl_value_list->data = bl_value;
        } else {
            bl_value_list = g_slist_append(bl_value_list, bl_value);
        }
    }

    att_data_list_free(list);

    cb_ctx->cb_ret_pointer = bl_value_list;
    cb_ctx->cb_ret_val     = BL_NO_ERROR;
    goto exit;

error:
    if (bl_value_list)
        bl_value_list_free(bl_value_list);
exit:
    g_mutex_unlock(&cb_ctx->pending_cb_mtx);
    printf_dbg("[CB] OUT read_by_uuid_cb\n");
}
static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
{
	uint8_t opdu[ATT_MAX_MTU];
	uint16_t handle, i, olen;

	handle = att_get_u16(&pdu[1]);

	printf("\n");
	switch (pdu[0]) {
	case ATT_OP_HANDLE_NOTIFY:
		printf("Notification handle = 0x%04x value: ", handle);
		break;
	case ATT_OP_HANDLE_IND:
		printf("Indication   handle = 0x%04x value: ", handle);
		break;
	default:
		printf("Invalid opcode\n");
		return;
	}

	for (i = 3; i < len; i++)
		printf("%02x ", pdu[i]);

	printf("\n");
	rl_forced_update_display();

	if (pdu[0] == ATT_OP_HANDLE_NOTIFY)
		return;

	olen = enc_confirmation(opdu, sizeof(opdu));

	if (olen > 0)
		g_attrib_send(attrib, 0, opdu[0], opdu, olen, NULL, NULL, NULL);
}
Beispiel #19
0
static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
{
	uint8_t *opdu;
        uint8_t evt;
	uint16_t handle, i, olen;
	size_t plen;

        evt = pdu[0];

        if ( evt != ATT_OP_HANDLE_NOTIFY && evt != ATT_OP_HANDLE_IND )
        {
          printf("#Invalid opcode %02X in event handler??\n", evt);
          return;
        }

        assert( len >= 3 );
	handle = att_get_u16(&pdu[1]);

        resp_begin( evt==ATT_OP_HANDLE_NOTIFY ? rsp_NOTIFY : rsp_IND );
        send_uint( tag_HANDLE, handle );
        send_data( pdu+3, len-3 );
        resp_end();

	if (evt == ATT_OP_HANDLE_NOTIFY)
		return;

	opdu = g_attrib_get_buffer(attrib, &plen);
	olen = enc_confirmation(opdu, plen);

	if (olen > 0)
		g_attrib_send(attrib, 0, opdu, olen, NULL, NULL, NULL);
}
Beispiel #20
0
static void char_read_by_uuid_cb(guint8 status, const guint8 *pdu,
					guint16 plen, gpointer user_data)
{
	struct characteristic_data *char_data = user_data;
	struct att_data_list *list;
	int i;

	if (status == ATT_ECODE_ATTR_NOT_FOUND &&
					char_data->start != opt_start)
		goto done;

	if (status != 0) {
		g_printerr("Read characteristics by UUID failed: %s\n",
							att_ecode2str(status));
		goto done;
	}

	list = dec_read_by_type_resp(pdu, plen);
	if (list == NULL)
		goto done;

	for (i = 0; i < list->num; i++) {
		uint8_t *value = list->data[i];
		int j;

		char_data->start = att_get_u16(value) + 1;

		g_print("handle: 0x%04x \t value: ", att_get_u16(value));
		value += 2;
		for (j = 0; j < list->len - 2; j++, value++)
			g_print("%02x ", *value);
		g_print("\n");
	}

	att_data_list_free(list);

	gatt_read_char_by_uuid(char_data->attrib, char_data->start,
					char_data->end, opt_uuid,
					char_read_by_uuid_cb,
					char_data);

	return;
done:
	g_free(char_data);
	g_main_loop_quit(event_loop);
}
Beispiel #21
0
static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
{
	uint16_t handle = att_get_u16(&pdu[1]);

	if (pdu[0] == ATT_OP_HANDLE_NOTIFY) {
                uint16_t handle = att_get_u16(&pdu[1]);
                if (handle != vehicle.read_char.value_handle) {
                        error("Invalid vehicle read handle: 0x%04x\n", handle);
                        return;
                }
                const uint8_t *data = &pdu[3];
                const uint16_t datalen = len-3;
                
                handle_vehicle_msg_response(data, datalen);
		return;
        }
}
Beispiel #22
0
static struct gatt_included *included_from_buf(const uint8_t *buf, gsize len)
{
	struct gatt_included *incl = g_new0(struct gatt_included, 1);

	incl->handle = att_get_u16(&buf[0]);
	incl->range.start = att_get_u16(&buf[2]);
	incl->range.end = att_get_u16(&buf[4]);

	if (len == 8) {
		bt_uuid_t uuid128;
		bt_uuid_t uuid16 = att_get_uuid16(&buf[6]);

		bt_uuid_to_uuid128(&uuid16, &uuid128);
		bt_uuid_to_string(&uuid128, incl->uuid, sizeof(incl->uuid));
	}

	return incl;
}
Beispiel #23
0
static void char_read_by_uuid_cb(guint8 status, const guint8 *pdu,
					guint16 plen, gpointer user_data)
{
	struct characteristic_data *char_data = user_data;
	struct att_data_list *list;
	int i;

	if (status == ATT_ECODE_ATTR_NOT_FOUND &&
				char_data->start != char_data->orig_start)
        {
		printf("# TODO case in char_read_by_uuid_cb\n");
		goto done;
        }

	if (status != 0) {
		resp_error(err_COMM_ERR); // Todo: status
		goto done;
	}

	list = dec_read_by_type_resp(pdu, plen);

	resp_begin(rsp_READ);
        if (list == NULL)
		goto nolist;

	for (i = 0; i < list->num; i++) {
		uint8_t *value = list->data[i];
		int j;

		char_data->start = att_get_u16(value) + 1;

		send_uint(tag_HANDLE, att_get_u16(value));
                send_data(value+2, list->len-2); // All the same length??
	}

	att_data_list_free(list);
nolist:
	resp_end();

done:
	g_free(char_data);
}
Beispiel #24
0
static void char_read_by_uuid_cb(guint8 status, const guint8 *pdu,
                                 guint16 plen, gpointer user_data)
{
    struct characteristic_data *char_data = user_data;
    struct att_data_list *list;
    int i;

    if (status == ATT_ECODE_ATTR_NOT_FOUND &&
            char_data->start != char_data->orig_start)
        goto done;

    if (status != 0) {
        printf("Read characteristics by UUID failed: %s\n",
               att_ecode2str(status));
        goto done;
    }

    list = dec_read_by_type_resp(pdu, plen);
    if (list == NULL)
        goto done;

    for (i = 0; i < list->num; i++) {
        uint8_t *value = list->data[i];
        int j;

        char_data->start = att_get_u16(value) + 1;

        printf("\nhandle: 0x%04x \t value: ", att_get_u16(value));
        value += 2;
        for (j = 0; j < list->len - 2; j++, value++)
            printf("%02x ", *value);
        printf("\n");
    }

    att_data_list_free(list);

done:
    printf("\n%s", get_prompt());
    fflush(stdout);

    g_free(char_data);
}
Beispiel #25
0
uint16_t dec_find_by_type_req(const uint8_t *pdu, size_t len, uint16_t *start,
						uint16_t *end, bt_uuid_t *uuid,
						uint8_t *value, size_t *vlen)
{
	size_t valuelen;
	uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) +
						sizeof(*end) + sizeof(uint16_t);

	if (pdu == NULL)
		return 0;

	if (len < min_len)
		return 0;

	if (pdu[0] != ATT_OP_FIND_BY_TYPE_REQ)
		return 0;

	/* First requested handle number */
	if (start)
		*start = att_get_u16(&pdu[1]);

	/* Last requested handle number */
	if (end)
		*end = att_get_u16(&pdu[3]);

	/* Always UUID16 */
	if (uuid)
		*uuid = att_get_uuid16(&pdu[5]);

	valuelen = len - min_len;

	/* Attribute value to find */
	if (valuelen > 0 && value)
		memcpy(value, pdu + min_len, valuelen);

	if (vlen)
		*vlen = valuelen;

	return len;
}
Beispiel #26
0
uint16_t dec_find_info_req(const uint8_t *pdu, size_t len, uint16_t *start,
								uint16_t *end)
{
	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end);

	if (pdu == NULL)
		return 0;

	if (len < min_len)
		return 0;

	if (start == NULL || end == NULL)
		return 0;

	if (pdu[0] != ATT_OP_FIND_INFO_REQ)
		return 0;

	*start = att_get_u16(&pdu[1]);
	*end = att_get_u16(&pdu[3]);

	return min_len;
}
Beispiel #27
0
GSList *dec_find_by_type_resp(const uint8_t *pdu, int len)
{
	struct att_range *range;
	GSList *matches;
	int offset;

	if (pdu == NULL || len < 5)
		return NULL;

	if (pdu[0] != ATT_OP_FIND_BY_TYPE_RESP)
		return NULL;

	for (offset = 1, matches = NULL; len >= (offset + 4); offset += 4) {
		range = g_new0(struct att_range, 1);
		range->start = att_get_u16(&pdu[offset]);
		range->end = att_get_u16(&pdu[offset + 2]);

		matches = g_slist_append(matches, range);
	}

	return matches;
}
Beispiel #28
0
static void report_value_cb(const uint8_t *pdu, uint16_t len,
							gpointer user_data)
{
	struct hog_device *hogdev = user_data;
	struct uhid_event ev;
	uint16_t report_size = len - 3;
	guint handle;
	GSList *l;
	struct report *report;
	uint8_t *buf;

	if (len < 3) { /* 1-byte opcode + 2-byte handle */
		error("Malformed ATT notification");
		return;
	}

	handle = att_get_u16(&pdu[1]);

	l = g_slist_find_custom(hogdev->reports, GUINT_TO_POINTER(handle),
							report_handle_cmp);
	if (!l) {
		error("Invalid report");
		return;
	}

	report = l->data;

	memset(&ev, 0, sizeof(ev));
	ev.type = UHID_INPUT;
	ev.u.input.size = MIN(report_size, UHID_DATA_MAX);

	buf = ev.u.input.data;
	if (hogdev->prepend_id) {
		*buf = report->id;
		buf++;
		ev.u.input.size++;
	}

	memcpy(buf, &pdu[3], MIN(report_size, UHID_DATA_MAX));

	if (write(hogdev->uhid_fd, &ev, sizeof(ev)) < 0)
		error("uHID write failed: %s", strerror(errno));
	else
		DBG("Report from HoG device 0x%04X written to uHID fd %d",
						hogdev->id, hogdev->uhid_fd);
}
Beispiel #29
0
static void events_handler(const uint8_t *pdu, uint16_t len,
							gpointer user_data)
{
	struct gatt_service *gatt = user_data;
	struct characteristic *chr;
	GSList *l;
	uint8_t opdu[ATT_MAX_MTU];
	guint handle;
	uint16_t olen;

	if (len < 3) {
		DBG("Malformed notification/indication packet (opcode 0x%02x)",
									pdu[0]);
		return;
	}

	handle = att_get_u16(&pdu[1]);

	l = g_slist_find_custom(gatt->chars, GUINT_TO_POINTER(handle),
						characteristic_handle_cmp);

	if (!l)
		return;

	chr = l->data;

	if (chr == NULL) {
		DBG("Attribute handle 0x%02x not found", handle);
		return;
	}

	switch (pdu[0]) {
	case ATT_OP_HANDLE_IND:
		olen = enc_confirmation(opdu, sizeof(opdu));
		g_attrib_send(gatt->attrib, 0, opdu[0], opdu, olen,
						NULL, NULL, NULL);

	case ATT_OP_HANDLE_NOTIFY:
		if (characteristic_set_value(chr, &pdu[3], len - 3) < 0)
			DBG("Can't change Characteristic 0x%02x", handle);

		g_slist_foreach(gatt->watchers, update_watchers_valuechange, chr);
		break;
	}
}
Beispiel #30
0
static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen,
							gpointer user_data)
{
	struct att_data_list *list;
	guint8 format;
	uint16_t handle = 0xffff;
	int i;

	if (status != 0) {
		resp_error(err_COMM_ERR); // Todo: status
		return;
	}

	list = dec_find_info_resp(pdu, plen, &format);
	if (list == NULL) {
		resp_error(err_NOT_FOUND); // Todo: what does this mean?
		return;
	}

	resp_begin(rsp_DESCRIPTORS);
	for (i = 0; i < list->num; i++) {
		char uuidstr[MAX_LEN_UUID_STR];
		uint8_t *value;
		bt_uuid_t uuid;

		value = list->data[i];
		handle = att_get_u16(value);

		if (format == 0x01)
			uuid = att_get_uuid16(&value[2]);
		else
			uuid = att_get_uuid128(&value[2]);

		bt_uuid_to_string(&uuid, uuidstr, MAX_LEN_UUID_STR);
		send_uint(tag_HANDLE, handle);
                send_str (tag_UUID, uuidstr);
	}
        resp_end();

	att_data_list_free(list);

	if (handle != 0xffff && handle < end)
		gatt_discover_char_desc(attrib, handle + 1, end, char_desc_cb, NULL);
}