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