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 if (packet_type != HCI_EVENT_PACKET) return; 151 152 uint8_t public_oob = 0; 153 uint8_t auth_method = 0; 154 uint8_t auth_action = 0; 155 uint8_t auth_size = 0; 156 157 uint8_t auth_static_oob = 0; 158 uint16_t auth_output_oob_action; 159 uint16_t auth_input_oob_action; 160 161 switch(packet[0]){ 162 case HCI_EVENT_MESH_META: 163 switch(packet[2]){ 164 case MESH_SUBEVENT_PB_TRANSPORT_LINK_OPEN: 165 printf("Provisioner link opened"); 166 break; 167 case MESH_SUBEVENT_PB_PROV_CAPABILITIES: 168 printf("// Provisioner capabilities\n"); 169 public_oob = mesh_subevent_pb_prov_capabilities_get_public_key(packet); 170 if (public_oob){ 171 printf("PTS supports Public OOB, select Public OOB\n"); 172 } else { 173 printf("PTS does not supports Public OOB, select No Public OOB\n"); 174 } 175 auth_static_oob = mesh_subevent_pb_prov_capabilities_get_static_oob_type(packet); 176 auth_input_oob_action = mesh_subevent_pb_prov_capabilities_get_input_oob_action(packet); 177 auth_output_oob_action = mesh_subevent_pb_prov_capabilities_get_output_oob_action(packet); 178 if (auth_output_oob_action){ 179 auth_method = 0x02; // Output OOB 180 // find output action 181 int i; 182 for (i=0;i<5;i++){ 183 if (auth_output_oob_action & (1<<i)){ 184 auth_action = i; 185 auth_size = mesh_subevent_pb_prov_capabilities_get_output_oob_size(packet); 186 printf("// - Pick Output OOB Action with index %u, size %u\n", i, auth_size); 187 break; 188 } 189 } 190 } else if(auth_input_oob_action){ 191 auth_method = 0x03; // Input OOB 192 // find output action 193 int i; 194 for (i=0;i<5;i++){ 195 if (auth_input_oob_action & (1<<i)){ 196 auth_action = i; 197 auth_size = mesh_subevent_pb_prov_capabilities_get_input_oob_size(packet); 198 printf("// - Pick Input OOB Action with index %u, size %u\n", i, auth_size); 199 break; 200 } 201 } 202 } else if (auth_static_oob & 1){ 203 // set static oob - used for PTS 204 btstack_parse_hex(prov_static_oob_string, 16, prov_static_oob_data); 205 provisioning_provisioner_set_static_oob(pb_adv_cid, 16, prov_static_oob_data); 206 // pick Static OOB method 207 printf("// - Pick Static OOB\n"); 208 auth_method = 0x01; 209 } 210 provisioning_provisioner_select_authentication_method(1, 0, public_oob, auth_method, auth_action, auth_size); 211 break; 212 case MESH_SUBEVENT_PB_PROV_START_RECEIVE_PUBLIC_KEY_OOB: 213 printf("Simulate Read Public Key OOB\n"); 214 btstack_parse_hex(prov_public_key_string, 64, prov_public_key_data); 215 provisioning_provisioner_public_key_oob_received(pb_adv_cid, prov_public_key_data); 216 break; 217 case MESH_SUBEVENT_PB_PROV_OUTPUT_OOB_REQUEST: 218 printf("Enter passphrase: "); 219 fflush(stdout); 220 ui_chars_for_pin = 1; 221 ui_pin_offset = 0; 222 break; 223 case MESH_SUBEVENT_PB_PROV_START_EMIT_INPUT_OOB: 224 break; 225 case MESH_SUBEVENT_PB_PROV_COMPLETE: 226 printf("Provisioning complete\n"); 227 break; 228 default: 229 break; 230 } 231 break; 232 case GAP_EVENT_ADVERTISING_REPORT: 233 printf("received mesh message\n"); 234 break; 235 default: 236 break; 237 } 238 } 239 240 static uint8_t device_uuid[16]; 241 242 static void mesh_unprovisioned_beacon_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ 243 if (packet_type != MESH_BEACON_PACKET) return; 244 uint16_t oob; 245 memcpy(device_uuid, &packet[1], 16); 246 oob = big_endian_read_16(packet, 17); 247 printf("received unprovisioned device beacon, oob data %x, device uuid: ", oob); 248 printf_hexdump(device_uuid, 16); 249 pb_adv_create_link(device_uuid); 250 } 251 252 uint8_t pts_device_uuid[16]; 253 const char * pts_device_uuid_string = "001BDC0810210B0E0A0C000B0E0A0C00"; 254 255 static void stdin_process(char cmd){ 256 if (ui_chars_for_pin){ 257 printf("%c", cmd); 258 fflush(stdout); 259 if (cmd == '\n'){ 260 ui_pin[ui_pin_offset] = 0; 261 printf("\nSending Pin '%s'\n", ui_pin); 262 // provisioning_provisioner_input_oob_complete_alphanumeric(1, ui_pin, ui_pin_offset); 263 provisioning_provisioner_input_oob_complete_numeric(1, btstack_atoi((char*)ui_pin)); 264 ui_chars_for_pin = 0; 265 } else { 266 ui_pin[ui_pin_offset++] = cmd; 267 } 268 return; 269 } 270 switch (cmd){ 271 default: 272 printf("Command: '%c'\n", cmd); 273 break; 274 } 275 } 276 277 int btstack_main(void); 278 int btstack_main(void) 279 { 280 // register for HCI events 281 hci_event_callback_registration.callback = &packet_handler; 282 hci_add_event_handler(&hci_event_callback_registration); 283 284 // console 285 btstack_stdin_setup(stdin_process); 286 287 // crypto 288 btstack_crypto_init(); 289 290 // mesh 291 adv_bearer_init(); 292 adv_bearer_register_for_network_pdu(&mesh_message_handler); 293 294 beacon_init(); 295 beacon_register_for_unprovisioned_device_beacons(&mesh_unprovisioned_beacon_handler); 296 297 // Provisioning in device role 298 provisioning_provisioner_init(); 299 provisioning_provisioner_register_packet_handler(&mesh_message_handler); 300 301 // 302 btstack_parse_hex(pts_device_uuid_string, 16, pts_device_uuid); 303 btstack_print_hex(pts_device_uuid, 16, 0); 304 305 // turn on! 306 hci_power_control(HCI_POWER_ON); 307 308 return 0; 309 } 310 /* EXAMPLE_END */ 311