1 use log::warn; 2 3 use crate::{ 4 gatt::ids::AttHandle, 5 packets::{ 6 AttChild, AttErrorCode, AttErrorResponseBuilder, AttFindByTypeValueRequestView, 7 AttFindInformationRequestView, AttOpcode, AttReadByGroupTypeRequestView, 8 AttReadByTypeRequestView, AttReadRequestView, AttView, AttWriteRequestView, Packet, 9 ParseError, 10 }, 11 }; 12 13 use super::{ 14 att_database::AttDatabase, 15 transactions::{ 16 find_by_type_value::handle_find_by_type_value_request, 17 find_information_request::handle_find_information_request, 18 read_by_group_type_request::handle_read_by_group_type_request, 19 read_by_type_request::handle_read_by_type_request, read_request::handle_read_request, 20 write_request::handle_write_request, 21 }, 22 }; 23 24 /// This struct handles all requests needing ACKs. Only ONE should exist per 25 /// bearer per database, to ensure serialization. 26 pub struct AttRequestHandler<Db: AttDatabase> { 27 db: Db, 28 } 29 30 impl<Db: AttDatabase> AttRequestHandler<Db> { new(db: Db) -> Self31 pub fn new(db: Db) -> Self { 32 Self { db } 33 } 34 35 // Runs a task to process an incoming packet. Takes an exclusive reference to 36 // ensure that only one request is outstanding at a time (notifications + 37 // commands should take a different path) process_packet(&mut self, packet: AttView<'_>, mtu: usize) -> AttChild38 pub async fn process_packet(&mut self, packet: AttView<'_>, mtu: usize) -> AttChild { 39 match self.try_parse_and_process_packet(packet, mtu).await { 40 Ok(result) => result, 41 Err(_) => { 42 // parse error, assume it's an unsupported request 43 // TODO(aryarahul): distinguish between REQUEST_NOT_SUPPORTED and INVALID_PDU 44 AttErrorResponseBuilder { 45 opcode_in_error: packet.get_opcode(), 46 handle_in_error: AttHandle(0).into(), 47 error_code: AttErrorCode::REQUEST_NOT_SUPPORTED, 48 } 49 .into() 50 } 51 } 52 } 53 try_parse_and_process_packet( &mut self, packet: AttView<'_>, mtu: usize, ) -> Result<AttChild, ParseError>54 async fn try_parse_and_process_packet( 55 &mut self, 56 packet: AttView<'_>, 57 mtu: usize, 58 ) -> Result<AttChild, ParseError> { 59 let snapshotted_db = self.db.snapshot(); 60 match packet.get_opcode() { 61 AttOpcode::READ_REQUEST => { 62 Ok(handle_read_request(AttReadRequestView::try_parse(packet)?, mtu, &self.db).await) 63 } 64 AttOpcode::READ_BY_GROUP_TYPE_REQUEST => { 65 handle_read_by_group_type_request( 66 AttReadByGroupTypeRequestView::try_parse(packet)?, 67 mtu, 68 &snapshotted_db, 69 ) 70 .await 71 } 72 AttOpcode::READ_BY_TYPE_REQUEST => { 73 handle_read_by_type_request( 74 AttReadByTypeRequestView::try_parse(packet)?, 75 mtu, 76 &snapshotted_db, 77 ) 78 .await 79 } 80 AttOpcode::FIND_INFORMATION_REQUEST => Ok(handle_find_information_request( 81 AttFindInformationRequestView::try_parse(packet)?, 82 mtu, 83 &snapshotted_db, 84 )), 85 AttOpcode::FIND_BY_TYPE_VALUE_REQUEST => Ok(handle_find_by_type_value_request( 86 AttFindByTypeValueRequestView::try_parse(packet)?, 87 mtu, 88 &snapshotted_db, 89 ) 90 .await), 91 AttOpcode::WRITE_REQUEST => { 92 Ok(handle_write_request(AttWriteRequestView::try_parse(packet)?, &self.db).await) 93 } 94 _ => { 95 warn!("Dropping unsupported opcode {:?}", packet.get_opcode()); 96 Err(ParseError::InvalidEnumValue) 97 } 98 } 99 } 100 } 101 102 #[cfg(test)] 103 mod test { 104 use super::*; 105 106 use crate::{ 107 core::uuid::Uuid, 108 gatt::server::{ 109 att_database::{AttAttribute, AttPermissions}, 110 request_handler::AttRequestHandler, 111 test::test_att_db::TestAttDatabase, 112 }, 113 packets::{ 114 AttAttributeDataChild, AttReadRequestBuilder, AttReadResponseBuilder, 115 AttWriteResponseBuilder, 116 }, 117 utils::packet::{build_att_data, build_att_view_or_crash}, 118 }; 119 120 #[test] test_read_request()121 fn test_read_request() { 122 // arrange 123 let db = TestAttDatabase::new(vec![( 124 AttAttribute { 125 handle: AttHandle(3), 126 type_: Uuid::new(0x1234), 127 permissions: AttPermissions::READABLE, 128 }, 129 vec![1, 2, 3], 130 )]); 131 let mut handler = AttRequestHandler { db }; 132 let att_view = build_att_view_or_crash(AttReadRequestBuilder { 133 attribute_handle: AttHandle(3).into(), 134 }); 135 136 // act 137 let response = tokio_test::block_on(handler.process_packet(att_view.view(), 31)); 138 139 // assert 140 assert_eq!( 141 response, 142 AttChild::AttReadResponse(AttReadResponseBuilder { 143 value: build_att_data(AttAttributeDataChild::RawData([1, 2, 3].into())) 144 }) 145 ); 146 } 147 148 #[test] test_unsupported_request()149 fn test_unsupported_request() { 150 // arrange 151 let db = TestAttDatabase::new(vec![( 152 AttAttribute { 153 handle: AttHandle(3), 154 type_: Uuid::new(0x1234), 155 permissions: AttPermissions::READABLE, 156 }, 157 vec![1, 2, 3], 158 )]); 159 let mut handler = AttRequestHandler { db }; 160 let att_view = build_att_view_or_crash(AttWriteResponseBuilder {}); 161 162 // act 163 let response = tokio_test::block_on(handler.process_packet(att_view.view(), 31)); 164 165 // assert 166 assert_eq!( 167 response, 168 AttChild::AttErrorResponse(AttErrorResponseBuilder { 169 opcode_in_error: AttOpcode::WRITE_RESPONSE, 170 handle_in_error: AttHandle(0).into(), 171 error_code: AttErrorCode::REQUEST_NOT_SUPPORTED 172 }) 173 ); 174 } 175 } 176