att_db.c (883180d368adc7b0f3f8d7831feca767a652997f) att_db.c (9b49c4f4cec484bb4c6c1c43b43f3fa86593884d)
1/*
2 * Copyright (C) 2014 BlueKitchen GmbH
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright

--- 276 unchanged lines hidden (view full) ---

285static inline uint16_t setup_error_invalid_handle(uint8_t * response_buffer, uint16_t request, uint16_t handle){
286 return setup_error(response_buffer, request, handle, ATT_ERROR_INVALID_HANDLE);
287}
288
289static inline uint16_t setup_error_invalid_offset(uint8_t * response_buffer, uint16_t request, uint16_t handle){
290 return setup_error(response_buffer, request, handle, ATT_ERROR_INVALID_OFFSET);
291}
292
1/*
2 * Copyright (C) 2014 BlueKitchen GmbH
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright

--- 276 unchanged lines hidden (view full) ---

285static inline uint16_t setup_error_invalid_handle(uint8_t * response_buffer, uint16_t request, uint16_t handle){
286 return setup_error(response_buffer, request, handle, ATT_ERROR_INVALID_HANDLE);
287}
288
289static inline uint16_t setup_error_invalid_offset(uint8_t * response_buffer, uint16_t request, uint16_t handle){
290 return setup_error(response_buffer, request, handle, ATT_ERROR_INVALID_OFFSET);
291}
292
293static inline uint16_t setup_error_invalid_pdu(uint8_t *response_buffer, uint16_t request) {
294 return setup_error(response_buffer, request, 0, ATT_ERROR_INVALID_PDU);
295}
296
293static uint8_t att_validate_security(att_connection_t * att_connection, att_operation_t operation, att_iterator_t * it){
294 int required_security_level = 0;
295 int requires_secure_connection = 0;
296 switch (operation){
297 case ATT_READ:
298 if ((it->flags & ATT_PROPERTY_READ_PERMISSION_BIT_0) != 0){
299 required_security_level |= 1;
300 }

--- 50 unchanged lines hidden (view full) ---

351}
352
353//
354// MARK: ATT_EXCHANGE_MTU_REQUEST
355//
356static uint16_t handle_exchange_mtu_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len,
357 uint8_t * response_buffer){
358
297static uint8_t att_validate_security(att_connection_t * att_connection, att_operation_t operation, att_iterator_t * it){
298 int required_security_level = 0;
299 int requires_secure_connection = 0;
300 switch (operation){
301 case ATT_READ:
302 if ((it->flags & ATT_PROPERTY_READ_PERMISSION_BIT_0) != 0){
303 required_security_level |= 1;
304 }

--- 50 unchanged lines hidden (view full) ---

355}
356
357//
358// MARK: ATT_EXCHANGE_MTU_REQUEST
359//
360static uint16_t handle_exchange_mtu_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len,
361 uint8_t * response_buffer){
362
359 UNUSED(request_len);
363 if (request_len != 3) return setup_error_invalid_pdu(response_buffer, ATT_EXCHANGE_MTU_REQUEST);
360
361 uint16_t client_rx_mtu = little_endian_read_16(request_buffer, 1);
362
363 // find min(local max mtu, remote mtu) and use as mtu for this connection
364 if (client_rx_mtu < att_connection->max_mtu){
365 att_connection->mtu = client_rx_mtu;
366 } else {
367 att_connection->mtu = att_connection->max_mtu;

--- 68 unchanged lines hidden (view full) ---

436 }
437
438 response_buffer[0] = ATT_FIND_INFORMATION_REPLY;
439 return offset;
440}
441
442static uint16_t handle_find_information_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len,
443 uint8_t * response_buffer, uint16_t response_buffer_size){
364
365 uint16_t client_rx_mtu = little_endian_read_16(request_buffer, 1);
366
367 // find min(local max mtu, remote mtu) and use as mtu for this connection
368 if (client_rx_mtu < att_connection->max_mtu){
369 att_connection->mtu = client_rx_mtu;
370 } else {
371 att_connection->mtu = att_connection->max_mtu;

--- 68 unchanged lines hidden (view full) ---

440 }
441
442 response_buffer[0] = ATT_FIND_INFORMATION_REPLY;
443 return offset;
444}
445
446static uint16_t handle_find_information_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len,
447 uint8_t * response_buffer, uint16_t response_buffer_size){
444 UNUSED(request_len);
445 return handle_find_information_request2(att_connection, response_buffer, response_buffer_size, little_endian_read_16(request_buffer, 1), little_endian_read_16(request_buffer, 3));
448
449 if (request_len != 5) return setup_error_invalid_pdu(response_buffer, ATT_FIND_INFORMATION_REQUEST);
450
451 uint16_t start_handle = little_endian_read_16(request_buffer, 1);
452 uint16_t end_handle = little_endian_read_16(request_buffer, 3);
453 return handle_find_information_request2(att_connection, response_buffer, response_buffer_size, start_handle, end_handle);
446}
447
448//
449// MARK: ATT_FIND_BY_TYPE_VALUE
450//
451// "Only attributes with attribute handles between and including the Starting Handle parameter
452// and the Ending Handle parameter that match the requested attri- bute type and the attribute
453// value that have sufficient permissions to allow reading will be returned" -> (1)
454//
455// TODO: handle other types then GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID
456//
457// NOTE: doesn't handle DYNAMIC values
458// NOTE: only supports 16 bit UUIDs
459//
460static uint16_t handle_find_by_type_value_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len,
461 uint8_t * response_buffer, uint16_t response_buffer_size){
462 UNUSED(att_connection);
463
454}
455
456//
457// MARK: ATT_FIND_BY_TYPE_VALUE
458//
459// "Only attributes with attribute handles between and including the Starting Handle parameter
460// and the Ending Handle parameter that match the requested attri- bute type and the attribute
461// value that have sufficient permissions to allow reading will be returned" -> (1)
462//
463// TODO: handle other types then GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID
464//
465// NOTE: doesn't handle DYNAMIC values
466// NOTE: only supports 16 bit UUIDs
467//
468static uint16_t handle_find_by_type_value_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len,
469 uint8_t * response_buffer, uint16_t response_buffer_size){
470 UNUSED(att_connection);
471
472 if (request_len < 7) return setup_error_invalid_pdu(response_buffer, ATT_FIND_BY_TYPE_VALUE_REQUEST);
473
464 // parse request
474 // parse request
465 int attribute_len = request_len - 7;
466 uint16_t start_handle = little_endian_read_16(request_buffer, 1);
467 uint16_t end_handle = little_endian_read_16(request_buffer, 3);
468 uint16_t attribute_type = little_endian_read_16(request_buffer, 5);
469 const uint8_t *attribute_value = &request_buffer[7];
475 uint16_t start_handle = little_endian_read_16(request_buffer, 1);
476 uint16_t end_handle = little_endian_read_16(request_buffer, 3);
477 uint16_t attribute_type = little_endian_read_16(request_buffer, 5);
478 const uint8_t *attribute_value = &request_buffer[7];
479 uint16_t attribute_len = request_len - 7;
470
471 log_info("ATT_FIND_BY_TYPE_VALUE_REQUEST: from %04X to %04X, type %04X, value: ", start_handle, end_handle, attribute_type);
472 log_info_hexdump(attribute_value, attribute_len);
473 uint8_t request_type = ATT_FIND_BY_TYPE_VALUE_REQUEST;
474
475 if ((start_handle > end_handle) || (start_handle == 0)){
476 return setup_error_invalid_handle(response_buffer, request_type, start_handle);
477 }

--- 153 unchanged lines hidden (view full) ---

631 }
632
633 // attribute not found
634 return setup_error_atribute_not_found(response_buffer, request_type, start_handle);
635}
636
637static uint16_t handle_read_by_type_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len,
638 uint8_t * response_buffer, uint16_t response_buffer_size){
480
481 log_info("ATT_FIND_BY_TYPE_VALUE_REQUEST: from %04X to %04X, type %04X, value: ", start_handle, end_handle, attribute_type);
482 log_info_hexdump(attribute_value, attribute_len);
483 uint8_t request_type = ATT_FIND_BY_TYPE_VALUE_REQUEST;
484
485 if ((start_handle > end_handle) || (start_handle == 0)){
486 return setup_error_invalid_handle(response_buffer, request_type, start_handle);
487 }

--- 153 unchanged lines hidden (view full) ---

641 }
642
643 // attribute not found
644 return setup_error_atribute_not_found(response_buffer, request_type, start_handle);
645}
646
647static uint16_t handle_read_by_type_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len,
648 uint8_t * response_buffer, uint16_t response_buffer_size){
639 int attribute_type_len;
640 if (request_len <= 7){
641 attribute_type_len = 2;
642 } else {
643 attribute_type_len = 16;
649
650 uint16_t attribute_type_len;
651 switch (request_len){
652 case 7:
653 attribute_type_len = 2;
654 break;
655 case 21:
656 attribute_type_len = 16;
657 break;
658 default:
659 return setup_error_invalid_pdu(response_buffer, ATT_READ_BY_TYPE_REQUEST);
644 }
660 }
645 return handle_read_by_type_request2(att_connection, response_buffer, response_buffer_size, little_endian_read_16(request_buffer, 1), little_endian_read_16(request_buffer, 3), attribute_type_len, &request_buffer[5]);
661
662 uint16_t start_handle = little_endian_read_16(request_buffer, 1);
663 uint16_t end_handle = little_endian_read_16(request_buffer, 3);
664 return handle_read_by_type_request2(att_connection, response_buffer, response_buffer_size, start_handle, end_handle, attribute_type_len, &request_buffer[5]);
646}
647
648//
649// MARK: ATT_READ_BY_TYPE_REQUEST
650//
651static uint16_t handle_read_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t handle){
652
653 log_info("ATT_READ_REQUEST: handle %04x", handle);

--- 33 unchanged lines hidden (view full) ---

687 offset += bytes_copied;
688
689 response_buffer[0] = ATT_READ_RESPONSE;
690 return offset;
691}
692
693static uint16_t handle_read_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len,
694 uint8_t * response_buffer, uint16_t response_buffer_size){
665}
666
667//
668// MARK: ATT_READ_BY_TYPE_REQUEST
669//
670static uint16_t handle_read_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t handle){
671
672 log_info("ATT_READ_REQUEST: handle %04x", handle);

--- 33 unchanged lines hidden (view full) ---

706 offset += bytes_copied;
707
708 response_buffer[0] = ATT_READ_RESPONSE;
709 return offset;
710}
711
712static uint16_t handle_read_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len,
713 uint8_t * response_buffer, uint16_t response_buffer_size){
695 UNUSED(request_len);
696 return handle_read_request2(att_connection, response_buffer, response_buffer_size, little_endian_read_16(request_buffer, 1));
714
715 if (request_len != 3) return setup_error_invalid_pdu(response_buffer, ATT_READ_REQUEST);
716
717 uint16_t handle = little_endian_read_16(request_buffer, 1);
718 return handle_read_request2(att_connection, response_buffer, response_buffer_size, handle);
697}
698
719}
720
699//
721//s
700// MARK: ATT_READ_BLOB_REQUEST 0x0c
701//
702static uint16_t handle_read_blob_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t handle, uint16_t value_offset){
703 log_info("ATT_READ_BLOB_REQUEST: handle %04x, offset %u", handle, value_offset);
704 uint8_t request_type = ATT_READ_BLOB_REQUEST;
705
706 att_iterator_t it;
707 int ok = att_find_handle(&it, handle);

--- 33 unchanged lines hidden (view full) ---

741 offset += bytes_copied;
742
743 response_buffer[0] = ATT_READ_BLOB_RESPONSE;
744 return offset;
745}
746
747static uint16_t handle_read_blob_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len,
748 uint8_t * response_buffer, uint16_t response_buffer_size){
722// MARK: ATT_READ_BLOB_REQUEST 0x0c
723//
724static uint16_t handle_read_blob_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t handle, uint16_t value_offset){
725 log_info("ATT_READ_BLOB_REQUEST: handle %04x, offset %u", handle, value_offset);
726 uint8_t request_type = ATT_READ_BLOB_REQUEST;
727
728 att_iterator_t it;
729 int ok = att_find_handle(&it, handle);

--- 33 unchanged lines hidden (view full) ---

763 offset += bytes_copied;
764
765 response_buffer[0] = ATT_READ_BLOB_RESPONSE;
766 return offset;
767}
768
769static uint16_t handle_read_blob_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len,
770 uint8_t * response_buffer, uint16_t response_buffer_size){
749 UNUSED(request_len);
750 return handle_read_blob_request2(att_connection, response_buffer, response_buffer_size, little_endian_read_16(request_buffer, 1), little_endian_read_16(request_buffer, 3));
771
772 if (request_len != 5) return setup_error_invalid_pdu(response_buffer, ATT_READ_BLOB_REQUEST);
773
774 uint16_t handle = little_endian_read_16(request_buffer, 1);
775 uint16_t value_offset = little_endian_read_16(request_buffer, 3);
776 return handle_read_blob_request2(att_connection, response_buffer, response_buffer_size, handle, value_offset);
751}
752
753//
754// MARK: ATT_READ_MULTIPLE_REQUEST 0x0e
755//
756static uint16_t handle_read_multiple_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t num_handles, uint8_t * handles){
757 log_info("ATT_READ_MULTIPLE_REQUEST: num handles %u", num_handles);
758 uint8_t request_type = ATT_READ_MULTIPLE_REQUEST;

--- 60 unchanged lines hidden (view full) ---

819 return setup_error(response_buffer, request_type, handle, error_code);
820 }
821
822 response_buffer[0] = ATT_READ_MULTIPLE_RESPONSE;
823 return offset;
824}
825static uint16_t handle_read_multiple_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len,
826 uint8_t * response_buffer, uint16_t response_buffer_size){
777}
778
779//
780// MARK: ATT_READ_MULTIPLE_REQUEST 0x0e
781//
782static uint16_t handle_read_multiple_request2(att_connection_t * att_connection, uint8_t * response_buffer, uint16_t response_buffer_size, uint16_t num_handles, uint8_t * handles){
783 log_info("ATT_READ_MULTIPLE_REQUEST: num handles %u", num_handles);
784 uint8_t request_type = ATT_READ_MULTIPLE_REQUEST;

--- 60 unchanged lines hidden (view full) ---

845 return setup_error(response_buffer, request_type, handle, error_code);
846 }
847
848 response_buffer[0] = ATT_READ_MULTIPLE_RESPONSE;
849 return offset;
850}
851static uint16_t handle_read_multiple_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len,
852 uint8_t * response_buffer, uint16_t response_buffer_size){
853
854 // 1 byte opcode + two or more attribute handles (2 bytes each)
855 if ( (request_len < 5) || ((request_len & 1) == 0) ) return setup_error_invalid_pdu(response_buffer,
856 ATT_READ_MULTIPLE_REQUEST);
857
827 int num_handles = (request_len - 1) >> 1;
828 return handle_read_multiple_request2(att_connection, response_buffer, response_buffer_size, num_handles, &request_buffer[1]);
829}
830
831//
832// MARK: ATT_READ_BY_GROUP_TYPE_REQUEST 0x10
833//
834// Only handles GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID

--- 100 unchanged lines hidden (view full) ---

935 return setup_error_atribute_not_found(response_buffer, request_type, start_handle);
936 }
937
938 response_buffer[0] = ATT_READ_BY_GROUP_TYPE_RESPONSE;
939 return offset;
940}
941static uint16_t handle_read_by_group_type_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len,
942 uint8_t * response_buffer, uint16_t response_buffer_size){
858 int num_handles = (request_len - 1) >> 1;
859 return handle_read_multiple_request2(att_connection, response_buffer, response_buffer_size, num_handles, &request_buffer[1]);
860}
861
862//
863// MARK: ATT_READ_BY_GROUP_TYPE_REQUEST 0x10
864//
865// Only handles GATT_PRIMARY_SERVICE_UUID and GATT_SECONDARY_SERVICE_UUID

--- 100 unchanged lines hidden (view full) ---

966 return setup_error_atribute_not_found(response_buffer, request_type, start_handle);
967 }
968
969 response_buffer[0] = ATT_READ_BY_GROUP_TYPE_RESPONSE;
970 return offset;
971}
972static uint16_t handle_read_by_group_type_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len,
973 uint8_t * response_buffer, uint16_t response_buffer_size){
943 int attribute_type_len;
944 if (request_len <= 7){
945 attribute_type_len = 2;
946 } else {
947 attribute_type_len = 16;
974 uint16_t attribute_type_len;
975 switch (request_len){
976 case 7:
977 attribute_type_len = 2;
978 break;
979 case 21:
980 attribute_type_len = 16;
981 break;
982 default:
983 return setup_error_invalid_pdu(response_buffer, ATT_READ_BY_GROUP_TYPE_REQUEST);
948 }
984 }
949 return handle_read_by_group_type_request2(att_connection, response_buffer, response_buffer_size, little_endian_read_16(request_buffer, 1), little_endian_read_16(request_buffer, 3), attribute_type_len, &request_buffer[5]);
985
986 uint16_t start_handle = little_endian_read_16(request_buffer, 1);
987 uint16_t end_handle = little_endian_read_16(request_buffer, 3);
988 return handle_read_by_group_type_request2(att_connection, response_buffer, response_buffer_size, start_handle, end_handle, attribute_type_len, &request_buffer[5]);
950}
951
952//
953// MARK: ATT_WRITE_REQUEST 0x12
954static uint16_t handle_write_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len,
955 uint8_t * response_buffer, uint16_t response_buffer_size){
956
957 UNUSED(response_buffer_size);

--- 38 unchanged lines hidden (view full) ---

996// MARK: ATT_PREPARE_WRITE_REQUEST 0x16
997static uint16_t handle_prepare_write_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len,
998 uint8_t * response_buffer, uint16_t response_buffer_size){
999
1000 UNUSED(response_buffer_size);
1001
1002 uint8_t request_type = ATT_PREPARE_WRITE_REQUEST;
1003
989}
990
991//
992// MARK: ATT_WRITE_REQUEST 0x12
993static uint16_t handle_write_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len,
994 uint8_t * response_buffer, uint16_t response_buffer_size){
995
996 UNUSED(response_buffer_size);

--- 38 unchanged lines hidden (view full) ---

1035// MARK: ATT_PREPARE_WRITE_REQUEST 0x16
1036static uint16_t handle_prepare_write_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len,
1037 uint8_t * response_buffer, uint16_t response_buffer_size){
1038
1039 UNUSED(response_buffer_size);
1040
1041 uint8_t request_type = ATT_PREPARE_WRITE_REQUEST;
1042
1043 if (request_len < 5) return setup_error_invalid_pdu(response_buffer, request_type);
1044
1004 uint16_t handle = little_endian_read_16(request_buffer, 1);
1005 uint16_t offset = little_endian_read_16(request_buffer, 3);
1006 if (att_write_callback == NULL) {
1007 return setup_error_write_not_permitted(response_buffer, request_type, handle);
1008 }
1009 att_iterator_t it;
1010 if (att_find_handle(&it, handle) == 0) {
1011 return setup_error_invalid_handle(response_buffer, request_type, handle);

--- 40 unchanged lines hidden (view full) ---

1052 (*att_write_callback)(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_CANCEL, 0, NULL, 0);
1053}
1054
1055// MARK: ATT_EXECUTE_WRITE_REQUEST 0x18
1056// NOTE: security has been verified by handle_prepare_write_request
1057static uint16_t handle_execute_write_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len,
1058 uint8_t * response_buffer, uint16_t response_buffer_size){
1059
1045 uint16_t handle = little_endian_read_16(request_buffer, 1);
1046 uint16_t offset = little_endian_read_16(request_buffer, 3);
1047 if (att_write_callback == NULL) {
1048 return setup_error_write_not_permitted(response_buffer, request_type, handle);
1049 }
1050 att_iterator_t it;
1051 if (att_find_handle(&it, handle) == 0) {
1052 return setup_error_invalid_handle(response_buffer, request_type, handle);

--- 40 unchanged lines hidden (view full) ---

1093 (*att_write_callback)(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_CANCEL, 0, NULL, 0);
1094}
1095
1096// MARK: ATT_EXECUTE_WRITE_REQUEST 0x18
1097// NOTE: security has been verified by handle_prepare_write_request
1098static uint16_t handle_execute_write_request(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len,
1099 uint8_t * response_buffer, uint16_t response_buffer_size){
1100
1060 UNUSED(request_len);
1061 UNUSED(response_buffer_size);
1101 UNUSED(response_buffer_size);
1062
1102
1063 uint8_t request_type = ATT_EXECUTE_WRITE_REQUEST;
1103 uint8_t request_type = ATT_EXECUTE_WRITE_REQUEST;
1104
1105 if (request_len < 2) return setup_error_invalid_pdu(response_buffer, request_type);
1106
1064 if (request_buffer[1]) {
1065 // validate queued write
1066 if (att_prepare_write_error_code == 0){
1067 att_prepare_write_error_code = (*att_write_callback)(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_VALIDATE, 0, NULL, 0);
1068 }
1069#ifdef ENABLE_ATT_DELAYED_RESPONSE
1070 if (att_prepare_write_error_code == ATT_ERROR_WRITE_RESPONSE_PENDING) return ATT_INTERNAL_WRITE_RESPONSE_PENDING;
1071#endif

--- 13 unchanged lines hidden (view full) ---

1085 return 1;
1086}
1087
1088// MARK: ATT_WRITE_COMMAND 0x52
1089// Core 4.0, vol 3, part F, 3.4.5.3
1090// "No Error Response or Write Response shall be sent in response to this command"
1091static void handle_write_command(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, uint16_t required_flags){
1092
1107 if (request_buffer[1]) {
1108 // validate queued write
1109 if (att_prepare_write_error_code == 0){
1110 att_prepare_write_error_code = (*att_write_callback)(att_connection->con_handle, 0, ATT_TRANSACTION_MODE_VALIDATE, 0, NULL, 0);
1111 }
1112#ifdef ENABLE_ATT_DELAYED_RESPONSE
1113 if (att_prepare_write_error_code == ATT_ERROR_WRITE_RESPONSE_PENDING) return ATT_INTERNAL_WRITE_RESPONSE_PENDING;
1114#endif

--- 13 unchanged lines hidden (view full) ---

1128 return 1;
1129}
1130
1131// MARK: ATT_WRITE_COMMAND 0x52
1132// Core 4.0, vol 3, part F, 3.4.5.3
1133// "No Error Response or Write Response shall be sent in response to this command"
1134static void handle_write_command(att_connection_t * att_connection, uint8_t * request_buffer, uint16_t request_len, uint16_t required_flags){
1135
1136 if (request_len < 3) return;
1137
1093 uint16_t handle = little_endian_read_16(request_buffer, 1);
1094 if (att_write_callback == NULL) return;
1095
1096 att_iterator_t it;
1097 int ok = att_find_handle(&it, handle);
1098 if (!ok) return;
1099 if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) return;
1100 if ((it.flags & required_flags) == 0) return;

--- 311 unchanged lines hidden ---
1138 uint16_t handle = little_endian_read_16(request_buffer, 1);
1139 if (att_write_callback == NULL) return;
1140
1141 att_iterator_t it;
1142 int ok = att_find_handle(&it, handle);
1143 if (!ok) return;
1144 if ((it.flags & ATT_PROPERTY_DYNAMIC) == 0) return;
1145 if ((it.flags & required_flags) == 0) return;

--- 311 unchanged lines hidden ---