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 * [email protected] 35 * 36 */ 37 38 #define BTSTACK_FILE__ "provisioner.c" 39 40 #include <stdint.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include "mesh/adv_bearer.h" 45 #include "mesh/pb_adv.h" 46 #include "mesh/beacon.h" 47 #include "provisioning.h" 48 #include "provisioning_provisioner.h" 49 #include "btstack.h" 50 #include "btstack_tlv.h" 51 52 static btstack_packet_callback_registration_t hci_event_callback_registration; 53 54 static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); 55 56 static mesh_provisioning_data_t provisioning_data; 57 58 // pin entry 59 static int ui_chars_for_pin; 60 static uint8_t ui_pin[17]; 61 static int ui_pin_offset; 62 63 static const btstack_tlv_t * btstack_tlv_singleton_impl; 64 static void * btstack_tlv_singleton_context; 65 66 static uint16_t pb_adv_cid; 67 68 // PTS defaults 69 static uint8_t prov_static_oob_data[16]; 70 static const char * prov_static_oob_string = "00000000000000000102030405060708"; 71 72 static uint8_t prov_public_key_data[64]; 73 static const char * prov_public_key_string = "F465E43FF23D3F1B9DC7DFC04DA8758184DBC966204796ECCF0D6CF5E16500CC0201D048BCBBD899EEEFC424164E33C201C2B010CA6B4D43A8A155CAD8ECB279"; 74 75 static int scan_hex_byte(const char * byte_string){ 76 int upper_nibble = nibble_for_char(*byte_string++); 77 if (upper_nibble < 0) return -1; 78 int lower_nibble = nibble_for_char(*byte_string); 79 if (lower_nibble < 0) return -1; 80 return (upper_nibble << 4) | lower_nibble; 81 } 82 83 static int btstack_parse_hex(const char * string, uint16_t len, uint8_t * buffer){ 84 int i; 85 for (i = 0; i < len; i++) { 86 int single_byte = scan_hex_byte(string); 87 if (single_byte < 0) return 0; 88 string += 2; 89 buffer[i] = (uint8_t)single_byte; 90 // don't check seperator after last byte 91 if (i == len - 1) { 92 return 1; 93 } 94 // optional seperator 95 char separator = *string; 96 if (separator == ':' && separator == '-' && separator == ' ') { 97 string++; 98 } 99 } 100 return 1; 101 } 102 103 static void btstack_print_hex(const uint8_t * data, uint16_t len, char separator){ 104 int i; 105 for (i=0;i<len;i++){ 106 printf("%02x", data[i]); 107 if (separator){ 108 printf("%c", separator); 109 } 110 } 111 printf("\n"); 112 } 113 114 static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 115 UNUSED(channel); 116 UNUSED(size); 117 bd_addr_t addr; 118 int i; 119 int prov_len; 120 121 switch (packet_type) { 122 case HCI_EVENT_PACKET: 123 switch (hci_event_packet_get_type(packet)) { 124 case BTSTACK_EVENT_STATE: 125 if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING) break; 126 // dump bd_addr in pts format 127 gap_local_bd_addr(addr); 128 printf("Local addr: %s - ", bd_addr_to_str(addr)); 129 for (i=0;i<6;i++) { 130 printf("%02x", addr[i]); 131 } 132 printf("\n"); 133 // get tlv 134 btstack_tlv_get_instance(&btstack_tlv_singleton_impl, &btstack_tlv_singleton_context); 135 // load provisioning data 136 prov_len = btstack_tlv_singleton_impl->get_tag(btstack_tlv_singleton_context, 'PROV', (uint8_t *) &provisioning_data, sizeof(mesh_provisioning_data_t)); 137 printf("Provisioning data available: %u\n", prov_len ? 1 : 0); 138 // setup scanning 139 gap_set_scan_parameters(0, 0x300, 0x300); 140 gap_start_scan(); 141 break; 142 default: 143 break; 144 } 145 break; 146 } 147 } 148 149 static void mesh_message_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 150 UNUSED(channel); 151 UNUSED(size); 152 153 if (packet_type != HCI_EVENT_PACKET) return; 154 155 uint8_t public_oob = 0; 156 uint8_t auth_method = 0; 157 uint8_t auth_action = 0; 158 uint8_t auth_size = 0; 159 160 uint8_t auth_static_oob = 0; 161 uint16_t auth_output_oob_action; 162 uint16_t auth_input_oob_action; 163 164 switch(packet[0]){ 165 case HCI_EVENT_MESH_META: 166 switch(packet[2]){ 167 case MESH_SUBEVENT_PB_TRANSPORT_LINK_OPEN: 168 printf("Provisioner link opened"); 169 break; 170 case MESH_SUBEVENT_PB_PROV_CAPABILITIES: 171 printf("// Provisioner capabilities\n"); 172 public_oob = mesh_subevent_pb_prov_capabilities_get_public_key(packet); 173 if (public_oob){ 174 printf("PTS supports Public OOB, select Public OOB\n"); 175 } else { 176 printf("PTS does not supports Public OOB, select No Public OOB\n"); 177 } 178 auth_static_oob = mesh_subevent_pb_prov_capabilities_get_static_oob_type(packet); 179 auth_input_oob_action = mesh_subevent_pb_prov_capabilities_get_input_oob_action(packet); 180 auth_output_oob_action = mesh_subevent_pb_prov_capabilities_get_output_oob_action(packet); 181 if (auth_output_oob_action){ 182 auth_method = 0x02; // Output OOB 183 // find output action 184 int i; 185 for (i=0;i<5;i++){ 186 if (auth_output_oob_action & (1<<i)){ 187 auth_action = i; 188 auth_size = mesh_subevent_pb_prov_capabilities_get_output_oob_size(packet); 189 printf("// - Pick Output OOB Action with index %u, size %u\n", i, auth_size); 190 break; 191 } 192 } 193 } else if(auth_input_oob_action){ 194 auth_method = 0x03; // Input OOB 195 // find output action 196 int i; 197 for (i=0;i<5;i++){ 198 if (auth_input_oob_action & (1<<i)){ 199 auth_action = i; 200 auth_size = mesh_subevent_pb_prov_capabilities_get_input_oob_size(packet); 201 printf("// - Pick Input OOB Action with index %u, size %u\n", i, auth_size); 202 break; 203 } 204 } 205 } else if (auth_static_oob & 1){ 206 // set static oob - used for PTS 207 btstack_parse_hex(prov_static_oob_string, 16, prov_static_oob_data); 208 provisioning_provisioner_set_static_oob(pb_adv_cid, 16, prov_static_oob_data); 209 // pick Static OOB method 210 printf("// - Pick Static OOB\n"); 211 auth_method = 0x01; 212 } 213 provisioning_provisioner_select_authentication_method(1, 0, public_oob, auth_method, auth_action, auth_size); 214 break; 215 case MESH_SUBEVENT_PB_PROV_START_RECEIVE_PUBLIC_KEY_OOB: 216 printf("Simulate Read Public Key OOB\n"); 217 btstack_parse_hex(prov_public_key_string, 64, prov_public_key_data); 218 provisioning_provisioner_public_key_oob_received(pb_adv_cid, prov_public_key_data); 219 break; 220 case MESH_SUBEVENT_PB_PROV_OUTPUT_OOB_REQUEST: 221 printf("Enter passphrase: "); 222 fflush(stdout); 223 ui_chars_for_pin = 1; 224 ui_pin_offset = 0; 225 break; 226 case MESH_SUBEVENT_PB_PROV_START_EMIT_INPUT_OOB: 227 break; 228 case MESH_SUBEVENT_PB_PROV_COMPLETE: 229 printf("Provisioning complete\n"); 230 break; 231 default: 232 break; 233 } 234 break; 235 case GAP_EVENT_ADVERTISING_REPORT: 236 printf("received mesh message\n"); 237 break; 238 default: 239 break; 240 } 241 } 242 243 static uint8_t device_uuid[16]; 244 245 static void mesh_unprovisioned_beacon_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 246 UNUSED(channel); 247 UNUSED(size); 248 249 if (packet_type != MESH_BEACON_PACKET) return; 250 251 uint16_t oob; 252 memcpy(device_uuid, &packet[1], 16); 253 oob = big_endian_read_16(packet, 17); 254 printf("received unprovisioned device beacon, oob data %x, device uuid: ", oob); 255 printf_hexdump(device_uuid, 16); 256 pb_adv_create_link(device_uuid); 257 } 258 259 uint8_t pts_device_uuid[16]; 260 const char * pts_device_uuid_string = "001BDC0810210B0E0A0C000B0E0A0C00"; 261 262 static void stdin_process(char cmd){ 263 if (ui_chars_for_pin){ 264 printf("%c", cmd); 265 fflush(stdout); 266 if (cmd == '\n'){ 267 ui_pin[ui_pin_offset] = 0; 268 printf("\nSending Pin '%s'\n", ui_pin); 269 // provisioning_provisioner_input_oob_complete_alphanumeric(1, ui_pin, ui_pin_offset); 270 provisioning_provisioner_input_oob_complete_numeric(1, btstack_atoi((char*)ui_pin)); 271 ui_chars_for_pin = 0; 272 } else { 273 ui_pin[ui_pin_offset++] = cmd; 274 } 275 return; 276 } 277 switch (cmd){ 278 default: 279 printf("Command: '%c'\n", cmd); 280 break; 281 } 282 } 283 284 int btstack_main(void); 285 int btstack_main(void) 286 { 287 // register for HCI events 288 hci_event_callback_registration.callback = &packet_handler; 289 hci_add_event_handler(&hci_event_callback_registration); 290 291 // console 292 btstack_stdin_setup(stdin_process); 293 294 // crypto 295 btstack_crypto_init(); 296 297 // mesh 298 adv_bearer_init(); 299 adv_bearer_register_for_network_pdu(&mesh_message_handler); 300 301 beacon_init(); 302 beacon_register_for_unprovisioned_device_beacons(&mesh_unprovisioned_beacon_handler); 303 304 // Provisioning in device role 305 provisioning_provisioner_init(); 306 provisioning_provisioner_register_packet_handler(&mesh_message_handler); 307 308 // 309 btstack_parse_hex(pts_device_uuid_string, 16, pts_device_uuid); 310 btstack_print_hex(pts_device_uuid, 16, 0); 311 312 // turn on! 313 hci_power_control(HCI_POWER_ON); 314 315 return 0; 316 } 317 /* EXAMPLE_END */ 318