Home | History | Annotate | Download | only in attrib
      1 /*
      2  *
      3  *  BlueZ - Bluetooth protocol stack for Linux
      4  *
      5  *  Copyright (C) 2010  Nokia Corporation
      6  *  Copyright (C) 2010  Marcel Holtmann <marcel (at) holtmann.org>
      7  *
      8  *
      9  *  This program is free software; you can redistribute it and/or modify
     10  *  it under the terms of the GNU General Public License as published by
     11  *  the Free Software Foundation; either version 2 of the License, or
     12  *  (at your option) any later version.
     13  *
     14  *  This program is distributed in the hope that it will be useful,
     15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17  *  GNU General Public License for more details.
     18  *
     19  *  You should have received a copy of the GNU General Public License
     20  *  along with this program; if not, write to the Free Software
     21  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     22  *
     23  */
     24 
     25 #include <errno.h>
     26 #include <stdint.h>
     27 #include <stdlib.h>
     28 
     29 #include <bluetooth/bluetooth.h>
     30 #include <bluetooth/uuid.h>
     31 
     32 #include <glib.h>
     33 
     34 #include "att.h"
     35 
     36 const char *att_ecode2str(uint8_t status)
     37 {
     38 	switch (status)  {
     39 	case ATT_ECODE_INVALID_HANDLE:
     40 		return "Invalid handle";
     41 	case ATT_ECODE_READ_NOT_PERM:
     42 		return "Atribute can't be read";
     43 	case ATT_ECODE_WRITE_NOT_PERM:
     44 		return "Attribute can't be written";
     45 	case ATT_ECODE_INVALID_PDU:
     46 		return "Attribute PDU was invalid";
     47 	case ATT_ECODE_AUTHENTICATION:
     48 		return "Attribute requires authentication before read/write";
     49 	case ATT_ECODE_REQ_NOT_SUPP:
     50 		return "Server doesn't support the request received";
     51 	case ATT_ECODE_INVALID_OFFSET:
     52 		return "Offset past the end of the attribute";
     53 	case ATT_ECODE_AUTHORIZATION:
     54 		return "Attribute requires authorization before read/write";
     55 	case ATT_ECODE_PREP_QUEUE_FULL:
     56 		return "Too many prepare writes have been queued";
     57 	case ATT_ECODE_ATTR_NOT_FOUND:
     58 		return "No attribute found within the given range";
     59 	case ATT_ECODE_ATTR_NOT_LONG:
     60 		return "Attribute can't be read/written using Read Blob Req";
     61 	case ATT_ECODE_INSUFF_ENCR_KEY_SIZE:
     62 		return "Encryption Key Size is insufficient";
     63 	case ATT_ECODE_INVAL_ATTR_VALUE_LEN:
     64 		return "Attribute value length is invalid";
     65 	case ATT_ECODE_UNLIKELY:
     66 		return "Request attribute has encountered an unlikely error";
     67 	case ATT_ECODE_INSUFF_ENC:
     68 		return "Encryption required before read/write";
     69 	case ATT_ECODE_UNSUPP_GRP_TYPE:
     70 		return "Attribute type is not a supported grouping attribute";
     71 	case ATT_ECODE_INSUFF_RESOURCES:
     72 		return "Insufficient Resources to complete the request";
     73 	case ATT_ECODE_IO:
     74 		return "Internal application error: I/O";
     75 	default:
     76 		return "Unexpected error code";
     77 	}
     78 }
     79 
     80 void att_data_list_free(struct att_data_list *list)
     81 {
     82 	if (list == NULL)
     83 		return;
     84 
     85 	if (list->data) {
     86 		int i;
     87 		for (i = 0; i < list->num; i++)
     88 			g_free(list->data[i]);
     89 	}
     90 
     91 	g_free(list->data);
     92 	g_free(list);
     93 }
     94 
     95 struct att_data_list *att_data_list_alloc(uint16_t num, uint16_t len)
     96 {
     97 	struct att_data_list *list;
     98 	int i;
     99 
    100 	list = g_new0(struct att_data_list, 1);
    101 	list->len = len;
    102 	list->num = num;
    103 
    104 	list->data = g_malloc0(sizeof(uint8_t *) * num);
    105 
    106 	for (i = 0; i < num; i++)
    107 		list->data[i] = g_malloc0(sizeof(uint8_t) * len);
    108 
    109 	return list;
    110 }
    111 
    112 uint16_t enc_read_by_grp_req(uint16_t start, uint16_t end, bt_uuid_t *uuid,
    113 							uint8_t *pdu, int len)
    114 {
    115 	const uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end);
    116 	uint16_t length;
    117 
    118 	if (!uuid)
    119 		return 0;
    120 
    121 	if (uuid->type == BT_UUID16)
    122 		length = 2;
    123 	else if (uuid->type == BT_UUID128)
    124 		length = 16;
    125 	else
    126 		return 0;
    127 
    128 	if (len < min_len + length)
    129 		return 0;
    130 
    131 	pdu[0] = ATT_OP_READ_BY_GROUP_REQ;
    132 	att_put_u16(start, &pdu[1]);
    133 	att_put_u16(end, &pdu[3]);
    134 
    135 	att_put_uuid(*uuid, &pdu[5]);
    136 
    137 	return min_len + length;
    138 }
    139 
    140 uint16_t dec_read_by_grp_req(const uint8_t *pdu, int len, uint16_t *start,
    141 						uint16_t *end, bt_uuid_t *uuid)
    142 {
    143 	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end);
    144 
    145 	if (pdu == NULL)
    146 		return 0;
    147 
    148 	if (start == NULL || end == NULL || uuid == NULL)
    149 		return 0;
    150 
    151 	if (pdu[0] != ATT_OP_READ_BY_GROUP_REQ)
    152 		return 0;
    153 
    154 	if (len < min_len + 2)
    155 		return 0;
    156 
    157 	*start = att_get_u16(&pdu[1]);
    158 	*end = att_get_u16(&pdu[3]);
    159 	if (len == min_len + 2)
    160 		*uuid = att_get_uuid16(&pdu[5]);
    161 	else
    162 		*uuid = att_get_uuid128(&pdu[5]);
    163 
    164 	return len;
    165 }
    166 
    167 uint16_t enc_read_by_grp_resp(struct att_data_list *list, uint8_t *pdu,
    168 								int len)
    169 {
    170 	int i;
    171 	uint16_t w;
    172 	uint8_t *ptr;
    173 
    174 	if (list == NULL)
    175 		return 0;
    176 
    177 	if (len < list->len + 2)
    178 		return 0;
    179 
    180 	pdu[0] = ATT_OP_READ_BY_GROUP_RESP;
    181 	pdu[1] = list->len;
    182 
    183 	ptr = &pdu[2];
    184 
    185 	for (i = 0, w = 2; i < list->num && w + list->len <= len; i++) {
    186 		memcpy(ptr, list->data[i], list->len);
    187 		ptr += list->len;
    188 		w += list->len;
    189 	}
    190 
    191 	return w;
    192 }
    193 
    194 struct att_data_list *dec_read_by_grp_resp(const uint8_t *pdu, int len)
    195 {
    196 	struct att_data_list *list;
    197 	const uint8_t *ptr;
    198 	uint16_t elen, num;
    199 	int i;
    200 
    201 	if (pdu[0] != ATT_OP_READ_BY_GROUP_RESP)
    202 		return NULL;
    203 
    204 	elen = pdu[1];
    205 	num = (len - 2) / elen;
    206 	list = att_data_list_alloc(num, elen);
    207 
    208 	ptr = &pdu[2];
    209 
    210 	for (i = 0; i < num; i++) {
    211 		memcpy(list->data[i], ptr, list->len);
    212 		ptr += list->len;
    213 	}
    214 
    215 	return list;
    216 }
    217 
    218 uint16_t enc_find_by_type_req(uint16_t start, uint16_t end, bt_uuid_t *uuid,
    219 			const uint8_t *value, int vlen, uint8_t *pdu, int len)
    220 {
    221 	uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end) +
    222 							sizeof(uint16_t);
    223 
    224 	if (pdu == NULL)
    225 		return 0;
    226 
    227 	if (!uuid)
    228 		return 0;
    229 
    230 	if (uuid->type != BT_UUID16)
    231 		return 0;
    232 
    233 	if (len < min_len)
    234 		return 0;
    235 
    236 	if (vlen > len - min_len)
    237 		vlen = len - min_len;
    238 
    239 	pdu[0] = ATT_OP_FIND_BY_TYPE_REQ;
    240 	att_put_u16(start, &pdu[1]);
    241 	att_put_u16(end, &pdu[3]);
    242 	att_put_uuid16(*uuid, &pdu[5]);
    243 
    244 	if (vlen > 0) {
    245 		memcpy(&pdu[7], value, vlen);
    246 		return min_len + vlen;
    247 	}
    248 
    249 	return min_len;
    250 }
    251 
    252 uint16_t dec_find_by_type_req(const uint8_t *pdu, int len, uint16_t *start,
    253 		uint16_t *end, bt_uuid_t *uuid, uint8_t *value, int *vlen)
    254 {
    255 	int valuelen;
    256 	uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) +
    257 						sizeof(*end) + sizeof(uint16_t);
    258 
    259 	if (pdu == NULL)
    260 		return 0;
    261 
    262 	if (len < min_len)
    263 		return 0;
    264 
    265 	if (pdu[0] != ATT_OP_FIND_BY_TYPE_REQ)
    266 		return 0;
    267 
    268 	/* First requested handle number */
    269 	if (start)
    270 		*start = att_get_u16(&pdu[1]);
    271 
    272 	/* Last requested handle number */
    273 	if (end)
    274 		*end = att_get_u16(&pdu[3]);
    275 
    276 	/* Always UUID16 */
    277 	if (uuid)
    278 		*uuid = att_get_uuid16(&pdu[5]);
    279 
    280 	valuelen = len - min_len;
    281 
    282 	/* Attribute value to find */
    283 	if (valuelen > 0 && value)
    284 		memcpy(value, pdu + min_len, valuelen);
    285 
    286 	if (vlen)
    287 		*vlen = valuelen;
    288 
    289 	return len;
    290 }
    291 
    292 uint16_t enc_find_by_type_resp(GSList *matches, uint8_t *pdu, int len)
    293 {
    294 	GSList *l;
    295 	uint16_t offset;
    296 
    297 	if (pdu == NULL || len < 5)
    298 		return 0;
    299 
    300 	pdu[0] = ATT_OP_FIND_BY_TYPE_RESP;
    301 
    302 	for (l = matches, offset = 1; l && len >= (offset + 4);
    303 					l = l->next, offset += 4) {
    304 		struct att_range *range = l->data;
    305 
    306 		att_put_u16(range->start, &pdu[offset]);
    307 		att_put_u16(range->end, &pdu[offset + 2]);
    308 	}
    309 
    310 	return offset;
    311 }
    312 
    313 GSList *dec_find_by_type_resp(const uint8_t *pdu, int len)
    314 {
    315 	struct att_range *range;
    316 	GSList *matches;
    317 	int offset;
    318 
    319 	if (pdu == NULL || len < 5)
    320 		return NULL;
    321 
    322 	if (pdu[0] != ATT_OP_FIND_BY_TYPE_RESP)
    323 		return NULL;
    324 
    325 	for (offset = 1, matches = NULL; len >= (offset + 4); offset += 4) {
    326 		range = g_new0(struct att_range, 1);
    327 		range->start = att_get_u16(&pdu[offset]);
    328 		range->end = att_get_u16(&pdu[offset + 2]);
    329 
    330 		matches = g_slist_append(matches, range);
    331 	}
    332 
    333 	return matches;
    334 }
    335 
    336 uint16_t enc_read_by_type_req(uint16_t start, uint16_t end, bt_uuid_t *uuid,
    337 							uint8_t *pdu, int len)
    338 {
    339 	const uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end);
    340 	uint16_t length;
    341 
    342 	if (!uuid)
    343 		return 0;
    344 
    345 	if (uuid->type == BT_UUID16)
    346 		length = 2;
    347 	else if (uuid->type == BT_UUID128)
    348 		length = 16;
    349 	else
    350 		return 0;
    351 
    352 	if (len < min_len + length)
    353 		return 0;
    354 
    355 	pdu[0] = ATT_OP_READ_BY_TYPE_REQ;
    356 	att_put_u16(start, &pdu[1]);
    357 	att_put_u16(end, &pdu[3]);
    358 
    359 	att_put_uuid(*uuid, &pdu[5]);
    360 
    361 	return min_len + length;
    362 }
    363 
    364 uint16_t dec_read_by_type_req(const uint8_t *pdu, int len, uint16_t *start,
    365 						uint16_t *end, bt_uuid_t *uuid)
    366 {
    367 	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end);
    368 
    369 	if (pdu == NULL)
    370 		return 0;
    371 
    372 	if (start == NULL || end == NULL || uuid == NULL)
    373 		return 0;
    374 
    375 	if (len < min_len + 2)
    376 		return 0;
    377 
    378 	if (pdu[0] != ATT_OP_READ_BY_TYPE_REQ)
    379 		return 0;
    380 
    381 	*start = att_get_u16(&pdu[1]);
    382 	*end = att_get_u16(&pdu[3]);
    383 
    384 	if (len == min_len + 2)
    385 		*uuid = att_get_uuid16(&pdu[5]);
    386 	else
    387 		*uuid = att_get_uuid128(&pdu[5]);
    388 
    389 	return len;
    390 }
    391 
    392 uint16_t enc_read_by_type_resp(struct att_data_list *list, uint8_t *pdu, int len)
    393 {
    394 	uint8_t *ptr;
    395 	int i, w, l;
    396 
    397 	if (list == NULL)
    398 		return 0;
    399 
    400 	if (pdu == NULL)
    401 		return 0;
    402 
    403 	l = MIN(len - 2, list->len);
    404 
    405 	pdu[0] = ATT_OP_READ_BY_TYPE_RESP;
    406 	pdu[1] = l;
    407 	ptr = &pdu[2];
    408 
    409 	for (i = 0, w = 2; i < list->num && w + l <= len; i++) {
    410 		memcpy(ptr, list->data[i], l);
    411 		ptr += l;
    412 		w += l;
    413 	}
    414 
    415 	return w;
    416 }
    417 
    418 struct att_data_list *dec_read_by_type_resp(const uint8_t *pdu, int len)
    419 {
    420 	struct att_data_list *list;
    421 	const uint8_t *ptr;
    422 	uint16_t elen, num;
    423 	int i;
    424 
    425 	if (pdu[0] != ATT_OP_READ_BY_TYPE_RESP)
    426 		return NULL;
    427 
    428 	elen = pdu[1];
    429 	num = (len - 2) / elen;
    430 	list = att_data_list_alloc(num, elen);
    431 
    432 	ptr = &pdu[2];
    433 
    434 	for (i = 0; i < num; i++) {
    435 		memcpy(list->data[i], ptr, list->len);
    436 		ptr += list->len;
    437 	}
    438 
    439 	return list;
    440 }
    441 
    442 uint16_t enc_write_cmd(uint16_t handle, const uint8_t *value, int vlen,
    443 							uint8_t *pdu, int len)
    444 {
    445 	const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle);
    446 
    447 	if (pdu == NULL)
    448 		return 0;
    449 
    450 	if (len < min_len)
    451 		return 0;
    452 
    453 	if (vlen > len - min_len)
    454 		vlen = len - min_len;
    455 
    456 	pdu[0] = ATT_OP_WRITE_CMD;
    457 	att_put_u16(handle, &pdu[1]);
    458 
    459 	if (vlen > 0) {
    460 		memcpy(&pdu[3], value, vlen);
    461 		return min_len + vlen;
    462 	}
    463 
    464 	return min_len;
    465 }
    466 
    467 uint16_t dec_write_cmd(const uint8_t *pdu, int len, uint16_t *handle,
    468 						uint8_t *value, int *vlen)
    469 {
    470 	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle);
    471 
    472 	if (pdu == NULL)
    473 		return 0;
    474 
    475 	if (value == NULL || vlen == NULL || handle == NULL)
    476 		return 0;
    477 
    478 	if (len < min_len)
    479 		return 0;
    480 
    481 	if (pdu[0] != ATT_OP_WRITE_CMD)
    482 		return 0;
    483 
    484 	*handle = att_get_u16(&pdu[1]);
    485 	memcpy(value, pdu + min_len, len - min_len);
    486 	*vlen = len - min_len;
    487 
    488 	return len;
    489 }
    490 
    491 uint16_t enc_write_req(uint16_t handle, const uint8_t *value, int vlen,
    492 							uint8_t *pdu, int len)
    493 {
    494 	const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle);
    495 
    496 	if (pdu == NULL)
    497 		return 0;
    498 
    499 	if (len < min_len)
    500 		return 0;
    501 
    502 	if (vlen > len - min_len)
    503 		vlen = len - min_len;
    504 
    505 	pdu[0] = ATT_OP_WRITE_REQ;
    506 	att_put_u16(handle, &pdu[1]);
    507 
    508 	if (vlen > 0) {
    509 		memcpy(&pdu[3], value, vlen);
    510 		return min_len + vlen;
    511 	}
    512 
    513 	return min_len;
    514 }
    515 
    516 uint16_t dec_write_req(const uint8_t *pdu, int len, uint16_t *handle,
    517 						uint8_t *value, int *vlen)
    518 {
    519 	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle);
    520 
    521 	if (pdu == NULL)
    522 		return 0;
    523 
    524 	if (value == NULL || vlen == NULL || handle == NULL)
    525 		return 0;
    526 
    527 	if (len < min_len)
    528 		return 0;
    529 
    530 	if (pdu[0] != ATT_OP_WRITE_REQ)
    531 		return 0;
    532 
    533 	*handle = att_get_u16(&pdu[1]);
    534 	*vlen = len - min_len;
    535 	if (*vlen > 0)
    536 		memcpy(value, pdu + min_len, *vlen);
    537 
    538 	return len;
    539 }
    540 
    541 uint16_t enc_write_resp(uint8_t *pdu, int len)
    542 {
    543 	if (pdu == NULL)
    544 		return 0;
    545 
    546 	pdu[0] = ATT_OP_WRITE_RESP;
    547 
    548 	return sizeof(pdu[0]);
    549 }
    550 
    551 uint16_t dec_write_resp(const uint8_t *pdu, int len)
    552 {
    553 	if (pdu == NULL)
    554 		return 0;
    555 
    556 	if (pdu[0] != ATT_OP_WRITE_RESP)
    557 		return 0;
    558 
    559 	return len;
    560 }
    561 
    562 uint16_t enc_read_req(uint16_t handle, uint8_t *pdu, int len)
    563 {
    564 	const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle);
    565 
    566 	if (pdu == NULL)
    567 		return 0;
    568 
    569 	if (len < min_len)
    570 		return 0;
    571 
    572 	pdu[0] = ATT_OP_READ_REQ;
    573 	att_put_u16(handle, &pdu[1]);
    574 
    575 	return min_len;
    576 }
    577 
    578 uint16_t enc_read_blob_req(uint16_t handle, uint16_t offset, uint8_t *pdu,
    579 									int len)
    580 {
    581 	const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle) +
    582 							sizeof(offset);
    583 
    584 	if (pdu == NULL)
    585 		return 0;
    586 
    587 	if (len < min_len)
    588 		return 0;
    589 
    590 	pdu[0] = ATT_OP_READ_BLOB_REQ;
    591 	att_put_u16(handle, &pdu[1]);
    592 	att_put_u16(offset, &pdu[3]);
    593 
    594 	return min_len;
    595 }
    596 
    597 uint16_t dec_read_req(const uint8_t *pdu, int len, uint16_t *handle)
    598 {
    599 	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle);
    600 
    601 	if (pdu == NULL)
    602 		return 0;
    603 
    604 	if (handle == NULL)
    605 		return 0;
    606 
    607 	if (len < min_len)
    608 		return 0;
    609 
    610 	if (pdu[0] != ATT_OP_READ_REQ)
    611 		return 0;
    612 
    613 	*handle = att_get_u16(&pdu[1]);
    614 
    615 	return min_len;
    616 }
    617 
    618 uint16_t dec_read_blob_req(const uint8_t *pdu, int len, uint16_t *handle,
    619 							uint16_t *offset)
    620 {
    621 	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle) +
    622 							sizeof(*offset);
    623 
    624 	if (pdu == NULL)
    625 		return 0;
    626 
    627 	if (handle == NULL)
    628 		return 0;
    629 
    630 	if (offset == NULL)
    631 		return 0;
    632 
    633 	if (len < min_len)
    634 		return 0;
    635 
    636 	if (pdu[0] != ATT_OP_READ_BLOB_REQ)
    637 		return 0;
    638 
    639 	*handle = att_get_u16(&pdu[1]);
    640 	*offset = att_get_u16(&pdu[3]);
    641 
    642 	return min_len;
    643 }
    644 
    645 uint16_t enc_read_resp(uint8_t *value, int vlen, uint8_t *pdu, int len)
    646 {
    647 	if (pdu == NULL)
    648 		return 0;
    649 
    650 	/* If the attribute value length is longer than the allowed PDU size,
    651 	 * send only the octets that fit on the PDU. The remaining octets can
    652 	 * be requested using the Read Blob Request. */
    653 	if (vlen > len - 1)
    654 		vlen = len - 1;
    655 
    656 	pdu[0] = ATT_OP_READ_RESP;
    657 
    658 	memcpy(pdu + 1, value, vlen);
    659 
    660 	return vlen + 1;
    661 }
    662 
    663 uint16_t enc_read_blob_resp(uint8_t *value, int vlen, uint16_t offset,
    664 							uint8_t *pdu, int len)
    665 {
    666 	if (pdu == NULL)
    667 		return 0;
    668 
    669 	vlen -= offset;
    670 	if (vlen > len - 1)
    671 		vlen = len - 1;
    672 
    673 	pdu[0] = ATT_OP_READ_BLOB_RESP;
    674 
    675 	memcpy(pdu + 1, &value[offset], vlen);
    676 
    677 	return vlen + 1;
    678 }
    679 
    680 uint16_t dec_read_resp(const uint8_t *pdu, int len, uint8_t *value, int *vlen)
    681 {
    682 	if (pdu == NULL)
    683 		return 0;
    684 
    685 	if (value == NULL || vlen == NULL)
    686 		return 0;
    687 
    688 	if (pdu[0] != ATT_OP_READ_RESP)
    689 		return 0;
    690 
    691 	memcpy(value, pdu + 1, len - 1);
    692 
    693 	*vlen = len - 1;
    694 
    695 	return len;
    696 }
    697 
    698 uint16_t enc_error_resp(uint8_t opcode, uint16_t handle, uint8_t status,
    699 							uint8_t *pdu, int len)
    700 {
    701 	const uint16_t min_len = sizeof(pdu[0]) + sizeof(opcode) +
    702 						sizeof(handle) + sizeof(status);
    703 	uint16_t u16;
    704 
    705 	if (len < min_len)
    706 		return 0;
    707 
    708 	u16 = htobs(handle);
    709 	pdu[0] = ATT_OP_ERROR;
    710 	pdu[1] = opcode;
    711 	memcpy(&pdu[2], &u16, sizeof(u16));
    712 	pdu[4] = status;
    713 
    714 	return min_len;
    715 }
    716 
    717 uint16_t enc_find_info_req(uint16_t start, uint16_t end, uint8_t *pdu, int len)
    718 {
    719 	const uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end);
    720 
    721 	if (pdu == NULL)
    722 		return 0;
    723 
    724 	if (len < min_len)
    725 		return 0;
    726 
    727 	pdu[0] = ATT_OP_FIND_INFO_REQ;
    728 	att_put_u16(start, &pdu[1]);
    729 	att_put_u16(end, &pdu[3]);
    730 
    731 	return min_len;
    732 }
    733 
    734 uint16_t dec_find_info_req(const uint8_t *pdu, int len, uint16_t *start,
    735 								uint16_t *end)
    736 {
    737 	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end);
    738 
    739 	if (pdu == NULL)
    740 		return 0;
    741 
    742 	if (len < min_len)
    743 		return 0;
    744 
    745 	if (start == NULL || end == NULL)
    746 		return 0;
    747 
    748 	if (pdu[0] != ATT_OP_FIND_INFO_REQ)
    749 		return 0;
    750 
    751 	*start = att_get_u16(&pdu[1]);
    752 	*end = att_get_u16(&pdu[3]);
    753 
    754 	return min_len;
    755 }
    756 
    757 uint16_t enc_find_info_resp(uint8_t format, struct att_data_list *list,
    758 							uint8_t *pdu, int len)
    759 {
    760 	uint8_t *ptr;
    761 	int i, w;
    762 
    763 	if (pdu == NULL)
    764 		return 0;
    765 
    766 	if (list == NULL)
    767 		return 0;
    768 
    769 	if (len < list->len + 2)
    770 		return 0;
    771 
    772 	pdu[0] = ATT_OP_FIND_INFO_RESP;
    773 	pdu[1] = format;
    774 	ptr = (void *) &pdu[2];
    775 
    776 	for (i = 0, w = 2; i < list->num && w + list->len <= len; i++) {
    777 		memcpy(ptr, list->data[i], list->len);
    778 		ptr += list->len;
    779 		w += list->len;
    780 	}
    781 
    782 	return w;
    783 }
    784 
    785 struct att_data_list *dec_find_info_resp(const uint8_t *pdu, int len,
    786 							uint8_t *format)
    787 {
    788 	struct att_data_list *list;
    789 	uint8_t *ptr;
    790 	uint16_t elen, num;
    791 	int i;
    792 
    793 	if (pdu == NULL)
    794 		return 0;
    795 
    796 	if (format == NULL)
    797 		return 0;
    798 
    799 	if (pdu[0] != ATT_OP_FIND_INFO_RESP)
    800 		return 0;
    801 
    802 	*format = pdu[1];
    803 	elen = sizeof(pdu[0]) + sizeof(*format);
    804 	if (*format == 0x01)
    805 		elen += 2;
    806 	else if (*format == 0x02)
    807 		elen += 16;
    808 
    809 	num = (len - 2) / elen;
    810 
    811 	ptr = (void *) &pdu[2];
    812 
    813 	list = att_data_list_alloc(num, elen);
    814 
    815 	for (i = 0; i < num; i++) {
    816 		memcpy(list->data[i], ptr, list->len);
    817 		ptr += list->len;
    818 	}
    819 
    820 	return list;
    821 }
    822 
    823 uint16_t enc_notification(struct attribute *a, uint8_t *pdu, int len)
    824 {
    825 	const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t);
    826 
    827 	if (pdu == NULL)
    828 		return 0;
    829 
    830 	if (len < (a->len + min_len))
    831 		return 0;
    832 
    833 	pdu[0] = ATT_OP_HANDLE_NOTIFY;
    834 	att_put_u16(a->handle, &pdu[1]);
    835 	memcpy(&pdu[3], a->data, a->len);
    836 
    837 	return a->len + min_len;
    838 }
    839 
    840 uint16_t enc_indication(struct attribute *a, uint8_t *pdu, int len)
    841 {
    842 	const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t);
    843 
    844 	if (pdu == NULL)
    845 		return 0;
    846 
    847 	if (len < (a->len + min_len))
    848 		return 0;
    849 
    850 	pdu[0] = ATT_OP_HANDLE_IND;
    851 	att_put_u16(a->handle, &pdu[1]);
    852 	memcpy(&pdu[3], a->data, a->len);
    853 
    854 	return a->len + min_len;
    855 }
    856 
    857 struct attribute *dec_indication(const uint8_t *pdu, int len)
    858 {
    859 	const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t);
    860 
    861 	struct attribute *a;
    862 
    863 	if (pdu == NULL)
    864 		return NULL;
    865 
    866 	if (pdu[0] != ATT_OP_HANDLE_IND)
    867 		return NULL;
    868 
    869 	if (len < min_len)
    870 		return NULL;
    871 
    872 	a = g_malloc0(sizeof(struct attribute) + len - min_len);
    873 	a->len = len - min_len;
    874 
    875 	a->handle = att_get_u16(&pdu[1]);
    876 	memcpy(a->data, &pdu[3], a->len);
    877 
    878 	return a;
    879 }
    880 
    881 uint16_t enc_confirmation(uint8_t *pdu, int len)
    882 {
    883 	const uint16_t min_len = sizeof(pdu[0]);
    884 
    885 	if (pdu == NULL)
    886 		return 0;
    887 
    888 	if (len < min_len)
    889 		return 0;
    890 
    891 	pdu[0] = ATT_OP_HANDLE_CNF;
    892 
    893 	return min_len;
    894 }
    895 
    896 uint16_t enc_mtu_req(uint16_t mtu, uint8_t *pdu, int len)
    897 {
    898 	const uint16_t min_len = sizeof(pdu[0]) + sizeof(mtu);
    899 
    900 	if (pdu == NULL)
    901 		return 0;
    902 
    903 	if (len < min_len)
    904 		return 0;
    905 
    906 	pdu[0] = ATT_OP_MTU_REQ;
    907 	att_put_u16(mtu, &pdu[1]);
    908 
    909 	return min_len;
    910 }
    911 
    912 uint16_t dec_mtu_req(const uint8_t *pdu, int len, uint16_t *mtu)
    913 {
    914 	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*mtu);
    915 
    916 	if (pdu == NULL)
    917 		return 0;
    918 
    919 	if (mtu == NULL)
    920 		return 0;
    921 
    922 	if (len < min_len)
    923 		return 0;
    924 
    925 	if (pdu[0] != ATT_OP_MTU_REQ)
    926 		return 0;
    927 
    928 	*mtu = att_get_u16(&pdu[1]);
    929 
    930 	return min_len;
    931 }
    932 
    933 uint16_t enc_mtu_resp(uint16_t mtu, uint8_t *pdu, int len)
    934 {
    935 	const uint16_t min_len = sizeof(pdu[0]) + sizeof(mtu);
    936 
    937 	if (pdu == NULL)
    938 		return 0;
    939 
    940 	if (len < min_len)
    941 		return 0;
    942 
    943 	pdu[0] = ATT_OP_MTU_RESP;
    944 	att_put_u16(mtu, &pdu[1]);
    945 
    946 	return min_len;
    947 }
    948 
    949 uint16_t dec_mtu_resp(const uint8_t *pdu, int len, uint16_t *mtu)
    950 {
    951 	const uint16_t min_len = sizeof(pdu[0]) + sizeof(*mtu);
    952 
    953 	if (pdu == NULL)
    954 		return 0;
    955 
    956 	if (mtu == NULL)
    957 		return 0;
    958 
    959 	if (len < min_len)
    960 		return 0;
    961 
    962 	if (pdu[0] != ATT_OP_MTU_RESP)
    963 		return 0;
    964 
    965 	*mtu = att_get_u16(&pdu[1]);
    966 
    967 	return min_len;
    968 }
    969