Some PTS testcase explicitly require to send prepare write request with offset and number of bytes to be written less than mtu size. Currently, gatttool implicitly converts a write request to prepare write request if data size more than mtu size. But it cannot send prepare write request if data size is less than mtu size. --- attrib/gatt.c | 26 ++++++++++++++++++++ attrib/interactive.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++ attrib/utils.c | 17 +++++++++++++ 3 files changed, 109 insertions(+) diff --git a/attrib/gatt.c b/attrib/gatt.c index 480f874..b674623 100644 --- a/attrib/gatt.c +++ b/attrib/gatt.c @@ -946,6 +946,32 @@ static guint prepare_write(struct write_long_data *long_write) NULL); } +guint gatt_write_long(GAttrib *attrib, uint16_t handle, + uint16_t offset, const uint8_t *value, + size_t vlen, GAttribResultFunc func, gpointer user_data) +{ + uint8_t *buf; + size_t buflen; + struct write_long_data *long_write; + + buf = g_attrib_get_buffer(attrib, &buflen); + + /* Write Long Characteristic Values */ + long_write = g_try_new0(struct write_long_data, 1); + if (long_write == NULL) + return 0; + + long_write->attrib = attrib; + long_write->func = func; + long_write->user_data = user_data; + long_write->handle = handle; + long_write->offset = offset; + long_write->value = g_memdup(value, vlen); + long_write->vlen = vlen; + + return prepare_write(long_write); +} + guint gatt_write_char(GAttrib *attrib, uint16_t handle, const uint8_t *value, size_t vlen, GAttribResultFunc func, gpointer user_data) { diff --git a/attrib/interactive.c b/attrib/interactive.c index 7d4786a..12ed148 100644 --- a/attrib/interactive.c +++ b/attrib/interactive.c @@ -457,6 +457,19 @@ static int strtohandle(const char *src) return dst; } +static int strtooffset(const char *src) +{ + char *e; + int dst; + + errno = 0; + dst = strtoll(src, &e, 10); + if (errno != 0 || *e != '\0') + return -EINVAL; + + return dst; +} + static void cmd_included(int argcp, char **argvp) { int start = 0x0001; @@ -637,6 +650,57 @@ static void char_write_req_cb(guint8 status, const guint8 *pdu, guint16 plen, rl_printf("Characteristic value was written successfully\n"); } +static void cmd_queued_write(int argcp, char **argvp) +{ + uint8_t *value; + size_t plen; + int handle; + int offset = 0; + + if (conn_state != STATE_CONNECTED) { + failed("Disconnected\n"); + return; + } + + if (argcp < 3 || argcp > 4) { + rl_printf("Usage: %s <handle> <new value> [offest]\n", + argvp[0]); + return; + } + + handle = strtohandle(argvp[1]); + if (handle <= 0) { + error("A valid handle is required\n"); + return; + } + + plen = gatt_attr_data_from_string(argvp[2], &value); + if (plen == 0) { + error("Invalid value\n"); + return; + } + + if (argcp >= 4) { + offset = strtooffset(argvp[3]); + if (offset < 0) { + error("A valid offset is required\n"); + g_free(value); + return; + } + + plen = gatt_attr_data_offset_padding(offset, plen, &value); + if (plen == 0) { + error("Invalid value\n"); + g_free(value); + return; + } + } + + gatt_write_long(attrib, handle, offset, value, plen, + char_write_req_cb, NULL); + g_free(value); +} + static void cmd_char_write(int argcp, char **argvp) { uint8_t *value; @@ -802,6 +866,8 @@ static struct { "Characteristics Value/Descriptor Read by UUID" }, { "char-write-req", cmd_char_write, "<handle> <new value>", "Characteristic Value Write (Write Request)" }, + { "char-prep-write", cmd_queued_write, "<handle> <value> [offset]", + "Characteristic Value Long Write (Write Request)" }, { "char-write-cmd", cmd_char_write, "<handle> <new value>", "Characteristic Value Write (No response)" }, { "sec-level", cmd_sec_level, "[low | medium | high]", diff --git a/attrib/utils.c b/attrib/utils.c index 8e2fc1a..af6682d 100644 --- a/attrib/utils.c +++ b/attrib/utils.c @@ -120,3 +120,20 @@ size_t gatt_attr_data_from_string(const char *str, uint8_t **data) return size; } + +size_t gatt_attr_data_offset_padding(size_t offset, size_t len, uint8_t **data) +{ + size_t size; + uint8_t *temp; + + size = offset + len; + temp = g_try_malloc0(size); + if (temp == NULL) + return 0; + + memcpy(temp + offset, *data, len); + g_free(*data); + *data = temp; + + return size; +} -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html