1 #/usr/bin/env python3.4 2 # 3 # Copyright (C) 2016 The Android Open Source Project 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); you may not 6 # use this file except in compliance with the License. You may obtain a copy of 7 # the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 # License for the specific language governing permissions and limitations under 15 # the License. 16 """ 17 Test suite for GATT over BR/EDR. 18 """ 19 20 import time 21 22 from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest 23 from acts.test_utils.bt.bt_test_utils import reset_bluetooth 24 from acts.test_utils.bt.GattEnum import GattCharacteristic 25 from acts.test_utils.bt.GattEnum import GattDescriptor 26 from acts.test_utils.bt.GattEnum import GattService 27 from acts.test_utils.bt.GattEnum import MtuSize 28 from acts.test_utils.bt.GattEnum import GattCbStrings 29 from acts.test_utils.bt.bt_gatt_utils import disconnect_gatt_connection 30 from acts.test_utils.bt.bt_gatt_utils import orchestrate_gatt_connection 31 from acts.test_utils.bt.bt_gatt_utils import setup_gatt_characteristics 32 from acts.test_utils.bt.bt_gatt_utils import setup_gatt_connection 33 from acts.test_utils.bt.bt_gatt_utils import setup_gatt_descriptors 34 from acts.test_utils.bt.bt_test_utils import get_advanced_droid_list 35 from acts.test_utils.bt.bt_test_utils import log_energy_info 36 from acts.test_utils.bt.bt_test_utils import setup_multiple_devices_for_bt_test 37 from acts.test_utils.bt.bt_test_utils import take_btsnoop_logs 38 39 40 class GattOverBrEdrTest(BluetoothBaseTest): 41 default_timeout = 10 42 default_discovery_timeout = 3 43 droid_list = () 44 per_droid_mac_address = None 45 46 def __init__(self, controllers): 47 BluetoothBaseTest.__init__(self, controllers) 48 self.droid_list = get_advanced_droid_list(self.android_devices) 49 self.cen_ad = self.android_devices[0] 50 self.per_ad = self.android_devices[1] 51 52 def setup_class(self): 53 self.log.info("Setting up devices for bluetooth testing.") 54 if not setup_multiple_devices_for_bt_test(self.android_devices): 55 return False 56 self.per_droid_mac_address = self.per_ad.droid.bluetoothGetLocalAddress( 57 ) 58 if not self.per_droid_mac_address: 59 return False 60 return True 61 62 def on_fail(self, test_name, begin_time): 63 take_btsnoop_logs(self.android_devices, self, test_name) 64 reset_bluetooth(self.android_devices) 65 66 def _setup_characteristics_and_descriptors(self, droid): 67 characteristic_input = [ 68 { 69 'uuid': "aa7edd5a-4d1d-4f0e-883a-d145616a1630", 70 'property': GattCharacteristic.PROPERTY_WRITE.value 71 | GattCharacteristic.PROPERTY_WRITE_NO_RESPONSE.value, 72 'permission': GattCharacteristic.PROPERTY_WRITE.value 73 }, 74 { 75 'uuid': "21c0a0bf-ad51-4a2d-8124-b74003e4e8c8", 76 'property': GattCharacteristic.PROPERTY_NOTIFY.value 77 | GattCharacteristic.PROPERTY_READ.value, 78 'permission': GattCharacteristic.PERMISSION_READ.value 79 }, 80 { 81 'uuid': "6774191f-6ec3-4aa2-b8a8-cf830e41fda6", 82 'property': GattCharacteristic.PROPERTY_NOTIFY.value 83 | GattCharacteristic.PROPERTY_READ.value, 84 'permission': GattCharacteristic.PERMISSION_READ.value 85 }, 86 ] 87 descriptor_input = [ 88 { 89 'uuid': "aa7edd5a-4d1d-4f0e-883a-d145616a1630", 90 'property': GattDescriptor.PERMISSION_READ.value 91 | GattDescriptor.PERMISSION_WRITE.value, 92 }, { 93 'uuid': "76d5ed92-ca81-4edb-bb6b-9f019665fb32", 94 'property': GattDescriptor.PERMISSION_READ.value 95 | GattCharacteristic.PERMISSION_WRITE.value, 96 } 97 ] 98 characteristic_list = setup_gatt_characteristics(droid, 99 characteristic_input) 100 descriptor_list = setup_gatt_descriptors(droid, descriptor_input) 101 return characteristic_list, descriptor_list 102 103 def _orchestrate_gatt_disconnection(self, bluetooth_gatt, gatt_callback): 104 self.log.info("Disconnecting from peripheral device.") 105 test_result = disconnect_gatt_connection(self.cen_ad, bluetooth_gatt, 106 gatt_callback) 107 if not test_result: 108 self.log.info("Failed to disconnect from peripheral device.") 109 return False 110 return True 111 112 def _iterate_attributes(self, discovered_services_index): 113 services_count = self.cen_ad.droid.gattClientGetDiscoveredServicesCount( 114 discovered_services_index) 115 for i in range(services_count): 116 service = self.cen_ad.droid.gattClientGetDiscoveredServiceUuid( 117 discovered_services_index, i) 118 self.log.info("Discovered service uuid {}".format(service)) 119 characteristic_uuids = ( 120 self.cen_ad.droid.gattClientGetDiscoveredCharacteristicUuids( 121 discovered_services_index, i)) 122 for characteristic in characteristic_uuids: 123 self.log.info("Discovered characteristic uuid {}".format( 124 characteristic)) 125 descriptor_uuids = ( 126 self.cen_ad.droid.gattClientGetDiscoveredDescriptorUuids( 127 discovered_services_index, i, characteristic)) 128 for descriptor in descriptor_uuids: 129 self.log.info("Discovered descriptor uuid {}".format( 130 descriptor)) 131 132 def _find_service_added_event(self, gatt_server_callback, uuid): 133 event = self.per_ad.ed.pop_event( 134 GattCbStrings.SERV_ADDED.value.format(gatt_server_callback), 135 self.default_timeout) 136 if event['data']['serviceUuid'].lower() != uuid.lower(): 137 self.log.info("Uuid mismatch. Found: {}, Expected {}.".format( 138 event['data']['serviceUuid'], uuid)) 139 return False 140 return True 141 142 def _setup_multiple_services(self): 143 gatt_server_callback = ( 144 self.per_ad.droid.gattServerCreateGattServerCallback()) 145 gatt_server = self.per_ad.droid.gattServerOpenGattServer( 146 gatt_server_callback) 147 characteristic_list, descriptor_list = ( 148 self._setup_characteristics_and_descriptors(self.per_ad.droid)) 149 self.per_ad.droid.gattServerCharacteristicAddDescriptor( 150 characteristic_list[1], descriptor_list[0]) 151 self.per_ad.droid.gattServerCharacteristicAddDescriptor( 152 characteristic_list[2], descriptor_list[1]) 153 gatt_service = self.per_ad.droid.gattServerCreateService( 154 "00000000-0000-1000-8000-00805f9b34fb", 155 GattService.SERVICE_TYPE_PRIMARY.value) 156 gatt_service2 = self.per_ad.droid.gattServerCreateService( 157 "FFFFFFFF-0000-1000-8000-00805f9b34fb", 158 GattService.SERVICE_TYPE_PRIMARY.value) 159 gatt_service3 = self.per_ad.droid.gattServerCreateService( 160 "3846D7A0-69C8-11E4-BA00-0002A5D5C51B", 161 GattService.SERVICE_TYPE_PRIMARY.value) 162 for characteristic in characteristic_list: 163 self.per_ad.droid.gattServerAddCharacteristicToService( 164 gatt_service, characteristic) 165 self.per_ad.droid.gattServerAddService(gatt_server, gatt_service) 166 result = self._find_service_added_event( 167 gatt_server_callback, "00000000-0000-1000-8000-00805f9b34fb") 168 if not result: 169 return False 170 for characteristic in characteristic_list: 171 self.per_ad.droid.gattServerAddCharacteristicToService( 172 gatt_service2, characteristic) 173 self.per_ad.droid.gattServerAddService(gatt_server, gatt_service2) 174 result = self._find_service_added_event( 175 gatt_server_callback, "FFFFFFFF-0000-1000-8000-00805f9b34fb") 176 if not result: 177 return False 178 for characteristic in characteristic_list: 179 self.per_ad.droid.gattServerAddCharacteristicToService( 180 gatt_service3, characteristic) 181 self.per_ad.droid.gattServerAddService(gatt_server, gatt_service3) 182 result = self._find_service_added_event( 183 gatt_server_callback, "3846D7A0-69C8-11E4-BA00-0002A5D5C51B") 184 if not result: 185 return False, False 186 return gatt_server_callback, gatt_server 187 188 @BluetoothBaseTest.bt_test_wrap 189 def test_gatt_bredr_connect(self): 190 """Test GATT connection over BR/EDR. 191 192 Test establishing a gatt connection between a GATT server and GATT 193 client. 194 195 Steps: 196 1. Start a generic advertisement. 197 2. Start a generic scanner. 198 3. Find the advertisement and extract the mac address. 199 4. Stop the first scanner. 200 5. Create a GATT connection between the scanner and advertiser. 201 6. Disconnect the GATT connection. 202 203 Expected Result: 204 Verify that a connection was established and then disconnected 205 successfully. 206 207 Returns: 208 Pass if True 209 Fail if False 210 211 TAGS: BR/EDR, Filtering, GATT, Scanning 212 Priority: 0 213 """ 214 bluetooth_gatt, gatt_callback, adv_callback = ( 215 orchestrate_gatt_connection(self.cen_ad, self.per_ad, False, 216 self.per_droid_mac_address)) 217 return self._orchestrate_gatt_disconnection(bluetooth_gatt, 218 gatt_callback) 219 220 @BluetoothBaseTest.bt_test_wrap 221 def test_gatt_bredr_request_min_mtu(self): 222 """Test GATT connection over BR/EDR and exercise MTU sizes. 223 224 Test establishing a gatt connection between a GATT server and GATT 225 client. Request an MTU size that matches the correct minimum size. 226 227 Steps: 228 1. Start a generic advertisement. 229 2. Start a generic scanner. 230 3. Find the advertisement and extract the mac address. 231 4. Stop the first scanner. 232 5. Create a GATT connection between the scanner and advertiser. 233 6. From the scanner (client) request MTU size change to the 234 minimum value. 235 7. Find the MTU changed event on the client. 236 8. Disconnect the GATT connection. 237 238 Expected Result: 239 Verify that a connection was established and the MTU value found 240 matches the expected MTU value. 241 242 Returns: 243 Pass if True 244 Fail if False 245 246 TAGS: LE, Advertising, Filtering, Scanning, GATT, MTU 247 Priority: 0 248 """ 249 bluetooth_gatt, gatt_callback, adv_callback = ( 250 orchestrate_gatt_connection(self.cen_ad, self.per_ad, False, 251 self.per_droid_mac_address)) 252 self.cen_ad.droid.gattClientRequestMtu(bluetooth_gatt, 253 MtuSize.MIN.value) 254 mtu_event = self.cen_ad.ed.pop_event( 255 GattCbStrings.MTU_CHANGED.value.format( 256 bluetooth_gatt), self.default_timeout) 257 if mtu_event['data']['MTU'] != MtuSize.MIN.value: 258 return False 259 return self._orchestrate_gatt_disconnection(bluetooth_gatt, 260 gatt_callback) 261 262 @BluetoothBaseTest.bt_test_wrap 263 def test_gatt_bredr_request_max_mtu(self): 264 """Test GATT connection over BR/EDR and exercise MTU sizes. 265 266 Test establishing a gatt connection between a GATT server and GATT 267 client. Request an MTU size that matches the correct maximum size. 268 269 Steps: 270 1. Start a generic advertisement. 271 2. Start a generic scanner. 272 3. Find the advertisement and extract the mac address. 273 4. Stop the first scanner. 274 5. Create a GATT connection between the scanner and advertiser. 275 6. From the scanner (client) request MTU size change to the 276 maximum value. 277 7. Find the MTU changed event on the client. 278 8. Disconnect the GATT connection. 279 280 Expected Result: 281 Verify that a connection was established and the MTU value found 282 matches the expected MTU value. 283 284 Returns: 285 Pass if True 286 Fail if False 287 288 TAGS: LE, Advertising, Filtering, Scanning, GATT, MTU 289 Priority: 0 290 """ 291 bluetooth_gatt, gatt_callback, adv_callback = ( 292 orchestrate_gatt_connection(self.cen_ad, self.per_ad, False, 293 self.per_droid_mac_address)) 294 self.cen_ad.droid.gattClientRequestMtu(bluetooth_gatt, 295 MtuSize.MAX.value) 296 mtu_event = self.cen_ad.ed.pop_event( 297 GattCbStrings.MTU_CHANGED.value.format( 298 bluetooth_gatt), self.default_timeout) 299 if mtu_event['data']['MTU'] != MtuSize.MAX.value: 300 return False 301 return self._orchestrate_gatt_disconnection(bluetooth_gatt, 302 gatt_callback) 303 304 @BluetoothBaseTest.bt_test_wrap 305 def test_gatt_bredr_request_out_of_bounds_mtu(self): 306 """Test GATT connection over BR/EDR and exercise an out of bound MTU size. 307 308 Test establishing a gatt connection between a GATT server and GATT 309 client. Request an MTU size that is the MIN value minus 1. 310 311 Steps: 312 1. Start a generic advertisement. 313 2. Start a generic scanner. 314 3. Find the advertisement and extract the mac address. 315 4. Stop the first scanner. 316 5. Create a GATT connection between the scanner and advertiser. 317 6. From the scanner (client) request MTU size change to the 318 minimum value minus one. 319 7. Find the MTU changed event on the client. 320 8. Disconnect the GATT connection. 321 322 Expected Result: 323 Verify that an MTU changed event was not discovered and that 324 it didn't cause an exception when requesting an out of bounds 325 MTU. 326 327 Returns: 328 Pass if True 329 Fail if False 330 331 TAGS: LE, Advertising, Filtering, Scanning, GATT, MTU 332 Priority: 0 333 """ 334 bluetooth_gatt, gatt_callback, adv_callback = ( 335 orchestrate_gatt_connection(self.cen_ad, self.per_ad, False, 336 self.per_droid_mac_address)) 337 self.cen_ad.droid.gattClientRequestMtu(bluetooth_gatt, 338 MtuSize.MIN.value - 1) 339 try: 340 self.cen_ad.ed.pop_event( 341 GattCbStrings.MTU_CHANGED.value.format(bluetooth_gatt), 342 self.default_timeout) 343 self.log.error("Found {} event when it wasn't expected".format( 344 GattCbStrings.MTU_CHANGED.format(bluetooth_gatt))) 345 return False 346 except Exception: 347 self.log.debug("Successfully didn't find {} event".format( 348 GattCbStrings.MTU_CHANGED.value.format(bluetooth_gatt))) 349 return self._orchestrate_gatt_disconnection(bluetooth_gatt, 350 gatt_callback) 351 352 @BluetoothBaseTest.bt_test_wrap 353 def test_gatt_bredr_connect_trigger_on_read_rssi(self): 354 """Test GATT connection over BR/EDR read RSSI. 355 356 Test establishing a gatt connection between a GATT server and GATT 357 client then read the RSSI. 358 359 Steps: 360 1. Start a generic advertisement. 361 2. Start a generic scanner. 362 3. Find the advertisement and extract the mac address. 363 4. Stop the first scanner. 364 5. Create a GATT connection between the scanner and advertiser. 365 6. From the scanner, request to read the RSSI of the advertiser. 366 7. Disconnect the GATT connection. 367 368 Expected Result: 369 Verify that a connection was established and then disconnected 370 successfully. Verify that the RSSI was ready correctly. 371 372 Returns: 373 Pass if True 374 Fail if False 375 376 TAGS: BR/EDR, Scanning, GATT, RSSI 377 Priority: 1 378 """ 379 bluetooth_gatt, gatt_callback, adv_callback = ( 380 orchestrate_gatt_connection(self.cen_ad, self.per_ad, False, 381 self.per_droid_mac_address)) 382 if self.cen_ad.droid.gattClientReadRSSI(bluetooth_gatt): 383 self.cen_ad.ed.pop_event( 384 GattCbStrings.RD_REMOTE_RSSI.value.format( 385 gatt_callback), self.default_timeout) 386 return self._orchestrate_gatt_disconnection(bluetooth_gatt, 387 gatt_callback) 388 389 @BluetoothBaseTest.bt_test_wrap 390 def test_gatt_bredr_connect_trigger_on_services_discovered(self): 391 """Test GATT connection and discover services of peripheral. 392 393 Test establishing a gatt connection between a GATT server and GATT 394 client the discover all services from the connected device. 395 396 Steps: 397 1. Start a generic advertisement. 398 2. Start a generic scanner. 399 3. Find the advertisement and extract the mac address. 400 4. Stop the first scanner. 401 5. Create a GATT connection between the scanner and advertiser. 402 6. From the scanner (central device), discover services. 403 7. Disconnect the GATT connection. 404 405 Expected Result: 406 Verify that a connection was established and then disconnected 407 successfully. Verify that the service were discovered. 408 409 Returns: 410 Pass if True 411 Fail if False 412 413 TAGS: BR/EDR, Scanning, GATT, Services 414 Priority: 1 415 """ 416 bluetooth_gatt, gatt_callback, adv_callback = ( 417 orchestrate_gatt_connection(self.cen_ad, self.per_ad, False, 418 self.per_droid_mac_address)) 419 discovered_services_index = -1 420 if self.cen_ad.droid.gattClientDiscoverServices(bluetooth_gatt): 421 event = self.cen_ad.ed.pop_event( 422 GattCbStrings.GATT_SERV_DISC.value.format(gatt_callback), 423 self.default_timeout) 424 discovered_services_index = event['data']['ServicesIndex'] 425 return self._orchestrate_gatt_disconnection(bluetooth_gatt, 426 gatt_callback) 427 428 @BluetoothBaseTest.bt_test_wrap 429 def test_gatt_bredr_connect_trigger_on_services_discovered_iterate_attributes( 430 self): 431 """Test GATT connection and iterate peripherals attributes. 432 433 Test establishing a gatt connection between a GATT server and GATT 434 client and iterate over all the characteristics and descriptors of the 435 discovered services. 436 437 Steps: 438 1. Start a generic advertisement. 439 2. Start a generic scanner. 440 3. Find the advertisement and extract the mac address. 441 4. Stop the first scanner. 442 5. Create a GATT connection between the scanner and advertiser. 443 6. From the scanner (central device), discover services. 444 7. Iterate over all the characteristics and descriptors of the 445 discovered features. 446 8. Disconnect the GATT connection. 447 448 Expected Result: 449 Verify that a connection was established and then disconnected 450 successfully. Verify that the services, characteristics, and descriptors 451 were discovered. 452 453 Returns: 454 Pass if True 455 Fail if False 456 457 TAGS: BR/EDR, Scanning, GATT, Services 458 Characteristics, Descriptors 459 Priority: 1 460 """ 461 bluetooth_gatt, gatt_callback, adv_callback = ( 462 orchestrate_gatt_connection(self.cen_ad, self.per_ad, False, 463 self.per_droid_mac_address)) 464 discovered_services_index = -1 465 if self.cen_ad.droid.gattClientDiscoverServices(bluetooth_gatt): 466 event = self.cen_ad.ed.pop_event( 467 GattCbStrings.GATT_SERV_DISC.value.format(gatt_callback), 468 self.default_timeout) 469 discovered_services_index = event['data']['ServicesIndex'] 470 self._iterate_attributes(discovered_services_index) 471 return self._orchestrate_gatt_disconnection(bluetooth_gatt, 472 gatt_callback) 473 474 @BluetoothBaseTest.bt_test_wrap 475 def test_gatt_bredr_connect_with_service_uuid_variations(self): 476 """Test GATT connection with multiple service uuids. 477 478 Test establishing a gatt connection between a GATT server and GATT 479 client with multiple service uuid variations. 480 481 Steps: 482 1. Start a generic advertisement. 483 2. Start a generic scanner. 484 3. Find the advertisement and extract the mac address. 485 4. Stop the first scanner. 486 5. Create a GATT connection between the scanner and advertiser. 487 6. From the scanner (central device), discover services. 488 7. Verify that all the service uuid variations are found. 489 8. Disconnect the GATT connection. 490 491 Expected Result: 492 Verify that a connection was established and then disconnected 493 successfully. Verify that the service uuid variations are found. 494 495 Returns: 496 Pass if True 497 Fail if False 498 499 TAGS: BR/EDR, Scanning, GATT, Services 500 Priority: 2 501 """ 502 gatt_server_callback, gatt_server = self._setup_multiple_services() 503 if not gatt_server_callback or not gatt_server: 504 return False 505 bluetooth_gatt, gatt_callback, adv_callback = ( 506 orchestrate_gatt_connection(self.cen_ad, self.per_ad, False, 507 self.per_droid_mac_address)) 508 discovered_services_index = -1 509 if self.cen_ad.droid.gattClientDiscoverServices(bluetooth_gatt): 510 event = self.cen_ad.ed.pop_event( 511 GattCbStrings.GATT_SERV_DISC.value.format(gatt_callback), 512 self.default_timeout) 513 discovered_services_index = event['data']['ServicesIndex'] 514 self._iterate_attributes(discovered_services_index) 515 return self._orchestrate_gatt_disconnection(bluetooth_gatt, 516 gatt_callback) 517 518 @BluetoothBaseTest.bt_test_wrap 519 def test_gatt_bredr_connect_multiple_iterations(self): 520 """Test GATT connections multiple times. 521 522 Test establishing a gatt connection between a GATT server and GATT 523 client with multiple iterations. 524 525 Steps: 526 1. Start a generic advertisement. 527 2. Start a generic scanner. 528 3. Find the advertisement and extract the mac address. 529 4. Stop the first scanner. 530 5. Create a GATT connection between the scanner and advertiser. 531 6. Disconnect the GATT connection. 532 7. Repeat steps 5 and 6 twenty times. 533 534 Expected Result: 535 Verify that a connection was established and then disconnected 536 successfully twenty times. 537 538 Returns: 539 Pass if True 540 Fail if False 541 542 TAGS: BR/EDR, Scanning, GATT, Stress 543 Priority: 1 544 """ 545 autoconnect = False 546 mac_address = self.per_ad.droid.bluetoothGetLocalAddress() 547 for i in range(20): 548 bluetooth_gatt, gatt_callback, adv_callback = ( 549 orchestrate_gatt_connection(self.cen_ad, self.per_ad, False, 550 self.per_droid_mac_address)) 551 self.log.info("Disconnecting from peripheral device.") 552 test_result = self._orchestrate_gatt_disconnection(bluetooth_gatt, 553 gatt_callback) 554 if not test_result: 555 self.log.info("Failed to disconnect from peripheral device.") 556 return False 557 return True 558 559 @BluetoothBaseTest.bt_test_wrap 560 def test_bredr_write_descriptor_stress(self): 561 """Test GATT connection writing and reading descriptors. 562 563 Test establishing a gatt connection between a GATT server and GATT 564 client with multiple service uuid variations. 565 566 Steps: 567 1. Start a generic advertisement. 568 2. Start a generic scanner. 569 3. Find the advertisement and extract the mac address. 570 4. Stop the first scanner. 571 5. Create a GATT connection between the scanner and advertiser. 572 6. Discover services. 573 7. Write data to the descriptors of each characteristic 100 times. 574 8. Read the data sent to the descriptors. 575 9. Disconnect the GATT connection. 576 577 Expected Result: 578 Each descriptor in each characteristic is written and read 100 times. 579 580 Returns: 581 Pass if True 582 Fail if False 583 584 TAGS: BR/EDR, Scanning, GATT, Stress, Characteristics, Descriptors 585 Priority: 1 586 """ 587 gatt_server_callback, gatt_server = self._setup_multiple_services() 588 if not gatt_server_callback or not gatt_server: 589 return False 590 bluetooth_gatt, gatt_callback, adv_callback = ( 591 orchestrate_gatt_connection(self.cen_ad, self.per_ad, False, 592 self.per_droid_mac_address)) 593 if self.cen_ad.droid.gattClientDiscoverServices(bluetooth_gatt): 594 event = self.cen_ad.ed.pop_event( 595 GattCbStrings.GATT_SERV_DISC.value.format(gatt_callback), 596 self.default_timeout) 597 discovered_services_index = event['data']['ServicesIndex'] 598 else: 599 self.log.info("Failed to discover services.") 600 return False 601 services_count = self.cen_ad.droid.gattClientGetDiscoveredServicesCount( 602 discovered_services_index) 603 604 connected_device_list = self.per_ad.droid.gattServerGetConnectedDevices( 605 gatt_server) 606 if len(connected_device_list) == 0: 607 self.log.info("No devices connected from peripheral.") 608 return False 609 bt_device_id = 0 610 status = 1 611 offset = 1 612 test_value = [1,2,3,4,5,6,7] 613 test_value_return = [1,2,3] 614 for i in range(services_count): 615 characteristic_uuids = ( 616 self.cen_ad.droid.gattClientGetDiscoveredCharacteristicUuids( 617 discovered_services_index, i)) 618 for characteristic in characteristic_uuids: 619 descriptor_uuids = ( 620 self.cen_ad.droid.gattClientGetDiscoveredDescriptorUuids( 621 discovered_services_index, i, characteristic)) 622 for _ in range(100): 623 for descriptor in descriptor_uuids: 624 self.cen_ad.droid.gattClientDescriptorSetValue( 625 bluetooth_gatt, discovered_services_index, i, 626 characteristic, descriptor, test_value) 627 self.cen_ad.droid.gattClientWriteDescriptor( 628 bluetooth_gatt, discovered_services_index, i, 629 characteristic, descriptor) 630 event = self.per_ad.ed.pop_event( 631 GattCbStrings.DESC_WRITE_REQ.value.format( 632 gatt_callback), self.default_timeout) 633 self.log.info( 634 "onDescriptorWriteRequest event found: {}".format( 635 event)) 636 request_id = event['data']['requestId'] 637 found_value = event['data']['value'] 638 if found_value != test_value: 639 self.log.info("Values didn't match. Found: {}, " 640 "Expected: {}".format(found_value, 641 test_value)) 642 return False 643 self.per_ad.droid.gattServerSendResponse( 644 gatt_server, bt_device_id, request_id, status, 645 offset, test_value_return) 646 self.log.info( 647 "onDescriptorWrite event found: {}".format( 648 self.cen_ad.ed.pop_event( 649 GattCbStrings.DESC_WRITE.value.format( 650 bluetooth_gatt), 651 self.default_timeout))) 652 return True 653 654 @BluetoothBaseTest.bt_test_wrap 655 def test_gatt_bredr_connect_mitm_attack(self): 656 """Test GATT connection with permission write encrypted mitm. 657 658 Test establishing a gatt connection between a GATT server and GATT 659 client while the GATT server's characteristic includes the property 660 write value and the permission write encrypted mitm value. This will 661 prompt LE pairing and then the devices will create a bond. 662 663 Steps: 664 1. Create a GATT server and server callback on the peripheral device. 665 2. Create a unique service and characteristic uuid on the peripheral. 666 3. Create a characteristic on the peripheral with these properties: 667 GattCharacteristic.PROPERTY_WRITE.value, 668 GattCharacteristic.PERMISSION_WRITE_ENCRYPTED_MITM.value 669 4. Create a GATT service on the peripheral. 670 5. Add the characteristic to the GATT service. 671 6. Create a GATT connection between your central and peripheral device. 672 7. From the central device, discover the peripheral's services. 673 8. Iterate the services found until you find the unique characteristic 674 created in step 3. 675 9. Once found, write a random but valid value to the characteristic. 676 10. Start pairing helpers on both devices immediately after attempting 677 to write to the characteristic. 678 11. Within 10 seconds of writing the characteristic, there should be 679 a prompt to bond the device from the peripheral. The helpers will 680 handle the UI interaction automatically. (see 681 BluetoothConnectionFacade.java bluetoothStartPairingHelper). 682 12. Verify that the two devices are bonded. 683 684 Expected Result: 685 Verify that a connection was established and the devices are bonded. 686 687 Returns: 688 Pass if True 689 Fail if False 690 691 TAGS: LE, Advertising, Filtering, Scanning, GATT, Characteristic, MITM 692 Priority: 1 693 """ 694 gatt_server_callback = ( 695 self.per_ad.droid.gattServerCreateGattServerCallback()) 696 gatt_server = self.per_ad.droid.gattServerOpenGattServer( 697 gatt_server_callback) 698 service_uuid = "3846D7A0-69C8-11E4-BA00-0002A5D5C51B" 699 test_uuid = "aa7edd5a-4d1d-4f0e-883a-d145616a1630" 700 bonded = False 701 characteristic = self.per_ad.droid.gattServerCreateBluetoothGattCharacteristic( 702 test_uuid, GattCharacteristic.PROPERTY_WRITE.value, 703 GattCharacteristic.PERMISSION_WRITE_ENCRYPTED_MITM.value) 704 gatt_service = self.per_ad.droid.gattServerCreateService( 705 service_uuid, GattService.SERVICE_TYPE_PRIMARY.value) 706 self.per_ad.droid.gattServerAddCharacteristicToService(gatt_service, 707 characteristic) 708 self.per_ad.droid.gattServerAddService(gatt_server, gatt_service) 709 result = self._find_service_added_event(gatt_server_callback, 710 service_uuid) 711 if not result: 712 return False 713 bluetooth_gatt, gatt_callback, adv_callback = ( 714 orchestrate_gatt_connection(self.cen_ad, self.per_ad, False, 715 self.per_droid_mac_address)) 716 if bluetooth_gatt is False: 717 return False 718 if self.cen_ad.droid.gattClientDiscoverServices(bluetooth_gatt): 719 event = self.cen_ad.ed.pop_event( 720 GattCbStrings.GATT_SERV_DISC.value.format(gatt_callback), 721 self.default_timeout) 722 discovered_services_index = event['data']['ServicesIndex'] 723 else: 724 self.log.info("Failed to discover services.") 725 return False 726 test_value = [1,2,3,4,5,6,7] 727 services_count = self.cen_ad.droid.gattClientGetDiscoveredServicesCount( 728 discovered_services_index) 729 for i in range(services_count): 730 characteristic_uuids = ( 731 self.cen_ad.droid.gattClientGetDiscoveredCharacteristicUuids( 732 discovered_services_index, i)) 733 for characteristic_uuid in characteristic_uuids: 734 if characteristic_uuid == test_uuid: 735 self.cen_ad.droid.bluetoothStartPairingHelper() 736 self.per_ad.droid.bluetoothStartPairingHelper() 737 self.cen_ad.droid.gattClientCharacteristicSetValue( 738 bluetooth_gatt, discovered_services_index, i, 739 characteristic_uuid, test_value) 740 self.cen_ad.droid.gattClientWriteCharacteristic( 741 bluetooth_gatt, discovered_services_index, i, 742 characteristic_uuid) 743 start_time = time.time() + self.default_timeout 744 target_name = self.per_ad.droid.bluetoothGetLocalName() 745 while time.time() < start_time and bonded == False: 746 bonded_devices = self.cen_ad.droid.bluetoothGetBondedDevices( 747 ) 748 for device in bonded_devices: 749 if 'name' in device.keys() and device[ 750 'name'] == target_name: 751 bonded = True 752 break 753 return True 754