sm_pairing_central.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  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
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the copyright holders nor the names of
  14. * contributors may be used to endorse or promote products derived
  15. * from this software without specific prior written permission.
  16. * 4. Any redistribution, use, or modification is done solely for
  17. * personal benefit and not for any commercial purpose or for
  18. * monetary gain.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
  21. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  23. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
  24. * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  25. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  26. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  27. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  28. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  29. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  30. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. *
  33. * Please inquire about commercial licensing options at
  34. * contact@bluekitchen-gmbh.com
  35. *
  36. */
  37. #define BTSTACK_FILE__ "sm_pairing_central.c"
  38. // *****************************************************************************
  39. /* EXAMPLE_START(sm_pairing_central): LE Peripheral - Test pairing combinations
  40. *
  41. * @text Depending on the Authentication requiremens and IO Capabilities,
  42. * the pairing process uses different short and long term key generation method.
  43. * This example helps explore the different options incl. LE Secure Connections.
  44. * It scans for advertisements and connects to the first device that lists a
  45. * random service.
  46. */
  47. // *****************************************************************************
  48. #include <stdint.h>
  49. #include <inttypes.h>
  50. #include <stdio.h>
  51. #include <stdlib.h>
  52. #include <string.h>
  53. #include "btstack.h"
  54. // sm_pairing_central.gatt contains the declaration of the provided GATT Services + Characteristics
  55. // sm_pairing_central.h contains the binary representation of sm_pairing_central.gatt
  56. // it is generated by the build system by calling: $BTSTACK_ROOT/tool/compile_gatt.py sm_pairing_central.gatt sm_pairing_central.h
  57. // it needs to be regenerated when the GATT Database declared in sm_pairing_central.gatt file is modified
  58. #include "sm_pairing_central.h"
  59. // We're looking for a remote device that lists this service in the advertisement
  60. // LightBlue assigns 0x1111 as the UUID for a Blank service.
  61. #define REMOTE_SERVICE 0x1111
  62. // Fixed passkey - used with sm_pairing_peripheral. Passkey is random in general
  63. #define FIXED_PASSKEY 123456
  64. static btstack_packet_callback_registration_t hci_event_callback_registration;
  65. static btstack_packet_callback_registration_t sm_event_callback_registration;
  66. /* @section GAP LE setup for receiving advertisements
  67. *
  68. * @text GAP LE advertisements are received as custom HCI events of the
  69. * GAP_EVENT_ADVERTISING_REPORT type. To receive them, you'll need to register
  70. * the HCI packet handler, as shown in Listing GAPLEAdvSetup.
  71. */
  72. /* LISTING_START(GAPLEAdvSetup): Setting up GAP LE client for receiving advertisements */
  73. static void hci_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
  74. static void sm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size);
  75. static void sm_pairing_central_setup(void){
  76. l2cap_init();
  77. // setup le device db
  78. le_device_db_init();
  79. // setup SM: Display only
  80. sm_init();
  81. // setup ATT server
  82. att_server_init(profile_data, NULL, NULL);
  83. /**
  84. * Choose ONE of the following configurations
  85. * Bonding is disabled to allow for repeated testing. It can be enabled by or'ing
  86. * SM_AUTHREQ_BONDING to the authentication requirements like this:
  87. * sm_set_authentication_requirements( X | SM_AUTHREQ_BONDING)
  88. */
  89. // register handler
  90. hci_event_callback_registration.callback = &hci_packet_handler;
  91. hci_add_event_handler(&hci_event_callback_registration);
  92. sm_event_callback_registration.callback = &sm_packet_handler;
  93. sm_add_event_handler(&sm_event_callback_registration);
  94. // LE Legacy Pairing, Just Works
  95. // sm_set_io_capabilities(IO_CAPABILITY_DISPLAY_YES_NO);
  96. // sm_set_authentication_requirements(0);
  97. // LE Legacy Pairing, Passkey entry initiator enter, responder (us) displays
  98. // sm_set_io_capabilities(IO_CAPABILITY_DISPLAY_ONLY);
  99. // sm_set_authentication_requirements(SM_AUTHREQ_MITM_PROTECTION);
  100. // sm_use_fixed_passkey_in_display_role(FIXED_PASSKEY);
  101. #ifdef ENABLE_LE_SECURE_CONNECTIONS
  102. // enable LE Secure Connections Only mode - disables Legacy pairing
  103. // sm_set_secure_connections_only_mode(true);
  104. // LE Secure Connections, Just Works
  105. // sm_set_io_capabilities(IO_CAPABILITY_DISPLAY_YES_NO);
  106. // sm_set_authentication_requirements(SM_AUTHREQ_SECURE_CONNECTION);
  107. // LE Secure Connections, Numeric Comparison
  108. sm_set_io_capabilities(IO_CAPABILITY_DISPLAY_YES_NO);
  109. sm_set_authentication_requirements(SM_AUTHREQ_SECURE_CONNECTION|SM_AUTHREQ_MITM_PROTECTION);
  110. // LE Secure Pairing, Passkey entry initiator (us) enters, responder displays
  111. // sm_set_io_capabilities(IO_CAPABILITY_KEYBOARD_ONLY);
  112. // sm_set_authentication_requirements(SM_AUTHREQ_SECURE_CONNECTION|SM_AUTHREQ_MITM_PROTECTION);
  113. // sm_use_fixed_passkey_in_display_role(FIXED_PASSKEY);
  114. // LE Secure Pairing, Passkey entry initiator (us) displays, responder enters
  115. // sm_set_io_capabilities(IO_CAPABILITY_DISPLAY_ONLY);
  116. // sm_set_authentication_requirements(SM_AUTHREQ_SECURE_CONNECTION|SM_AUTHREQ_MITM_PROTECTION);
  117. #endif
  118. }
  119. /* LISTING_END */
  120. /* @section HCI packet handler
  121. *
  122. * @text The HCI packet handler has to start the scanning,
  123. * and to handle received advertisements. Advertisements are received
  124. * as HCI event packets of the GAP_EVENT_ADVERTISING_REPORT type,
  125. * see Listing HCIPacketHandler.
  126. */
  127. /* LISTING_START(HCIPacketHandler): Scanning and receiving advertisements */
  128. static void hci_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
  129. UNUSED(channel);
  130. UNUSED(size);
  131. if (packet_type != HCI_EVENT_PACKET) return;
  132. hci_con_handle_t con_handle;
  133. switch (hci_event_packet_get_type(packet)) {
  134. case BTSTACK_EVENT_STATE:
  135. // BTstack activated, get started
  136. if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING){
  137. printf("Start scaning!\n");
  138. gap_set_scan_parameters(1,0x0030, 0x0030);
  139. gap_start_scan();
  140. }
  141. break;
  142. case GAP_EVENT_ADVERTISING_REPORT:{
  143. bd_addr_t address;
  144. gap_event_advertising_report_get_address(packet, address);
  145. uint8_t address_type = gap_event_advertising_report_get_address_type(packet);
  146. uint8_t length = gap_event_advertising_report_get_data_length(packet);
  147. const uint8_t * data = gap_event_advertising_report_get_data(packet);
  148. // printf("Advertisement event: addr-type %u, addr %s, data[%u] ",
  149. // address_type, bd_addr_to_str(address), length);
  150. // printf_hexdump(data, length);
  151. if (!ad_data_contains_uuid16(length, (uint8_t *) data, REMOTE_SERVICE)) break;
  152. printf("Found remote with UUID %04x, connecting...\n", REMOTE_SERVICE);
  153. gap_stop_scan();
  154. gap_connect(address,address_type);
  155. break;
  156. }
  157. case HCI_EVENT_LE_META:
  158. // wait for connection complete
  159. if (hci_event_le_meta_get_subevent_code(packet) != HCI_SUBEVENT_LE_CONNECTION_COMPLETE) break;
  160. con_handle = hci_subevent_le_connection_complete_get_connection_handle(packet);
  161. printf("Connection complete\n");
  162. // start pairing
  163. sm_request_pairing(con_handle);
  164. break;
  165. case HCI_EVENT_ENCRYPTION_CHANGE:
  166. con_handle = hci_event_encryption_change_get_connection_handle(packet);
  167. printf("Connection encrypted: %u\n", hci_event_encryption_change_get_encryption_enabled(packet));
  168. break;
  169. default:
  170. break;
  171. }
  172. }
  173. /* @section HCI packet handler
  174. *
  175. * @text The SM packet handler receives Security Manager Events required for pairing.
  176. * It also receives events generated during Identity Resolving
  177. * see Listing SMPacketHandler.
  178. */
  179. /* LISTING_START(SMPacketHandler): Scanning and receiving advertisements */
  180. static void sm_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
  181. UNUSED(channel);
  182. UNUSED(size);
  183. if (packet_type != HCI_EVENT_PACKET) return;
  184. switch (hci_event_packet_get_type(packet)) {
  185. case SM_EVENT_JUST_WORKS_REQUEST:
  186. printf("Just works requested\n");
  187. sm_just_works_confirm(sm_event_just_works_request_get_handle(packet));
  188. break;
  189. case SM_EVENT_NUMERIC_COMPARISON_REQUEST:
  190. printf("Confirming numeric comparison: %"PRIu32"\n", sm_event_numeric_comparison_request_get_passkey(packet));
  191. sm_numeric_comparison_confirm(sm_event_passkey_display_number_get_handle(packet));
  192. break;
  193. case SM_EVENT_PASSKEY_DISPLAY_NUMBER:
  194. printf("Display Passkey: %"PRIu32"\n", sm_event_passkey_display_number_get_passkey(packet));
  195. break;
  196. case SM_EVENT_PASSKEY_INPUT_NUMBER:
  197. printf("Passkey Input requested\n");
  198. printf("Sending fixed passkey %"PRIu32"\n", FIXED_PASSKEY);
  199. sm_passkey_input(sm_event_passkey_input_number_get_handle(packet), FIXED_PASSKEY);
  200. break;
  201. case SM_EVENT_PAIRING_COMPLETE:
  202. switch (sm_event_pairing_complete_get_status(packet)){
  203. case ERROR_CODE_SUCCESS:
  204. printf("Pairing complete, success\n");
  205. break;
  206. case ERROR_CODE_CONNECTION_TIMEOUT:
  207. printf("Pairing failed, timeout\n");
  208. break;
  209. case ERROR_CODE_REMOTE_USER_TERMINATED_CONNECTION:
  210. printf("Pairing failed, disconnected\n");
  211. break;
  212. case ERROR_CODE_AUTHENTICATION_FAILURE:
  213. printf("Pairing failed, reason = %u\n", sm_event_pairing_complete_get_reason(packet));
  214. break;
  215. default:
  216. break;
  217. }
  218. break;
  219. default:
  220. break;
  221. }
  222. }
  223. /* LISTING_END */
  224. int btstack_main(void);
  225. int btstack_main(void)
  226. {
  227. sm_pairing_central_setup();
  228. // turn on!
  229. hci_power_control(HCI_POWER_ON);
  230. return 0;
  231. }
  232. /* EXAMPLE_END */