Beispiel #1
0
static void att_signed_write_handle_cmac_result(uint8_t hash[8]){
    
    if (att_server_state != ATT_SERVER_W4_SIGNED_WRITE_VALIDATION) return;

    if (memcmp(hash, &att_request_buffer[att_request_size-8], 8)){
        log_info("ATT Signed Write, invalid signature");
        att_server_state = ATT_SERVER_IDLE;
        return;
    }

    // update sequence number
    uint32_t counter_packet = READ_BT_32(att_request_buffer, att_request_size-12);
    le_device_db_remote_counter_set(att_ir_le_device_db_index, counter_packet+1);
    att_server_state = ATT_SERVER_REQUEST_RECEIVED_AND_VALIDATED;
    att_run();
}
Beispiel #2
0
static int btstack_command_handler(connection_t *connection, uint8_t *packet, uint16_t size){
    
    bd_addr_t addr;
    uint16_t cid;
    uint16_t psm;
    uint16_t service_channel;
    uint16_t mtu;
    uint8_t  reason;
    uint8_t  rfcomm_channel;
    uint8_t  rfcomm_credits;
    uint32_t service_record_handle;
    client_state_t *client;
    
    uint16_t serviceSearchPatternLen;
    uint16_t attributeIDListLen;

    // BTstack internal commands - 16 Bit OpCode, 8 Bit ParamLen, Params...
    switch (READ_CMD_OCF(packet)){
        case BTSTACK_GET_STATE:
            log_info("BTSTACK_GET_STATE");
            hci_emit_state();
            break;
        case BTSTACK_SET_POWER_MODE:
            log_info("BTSTACK_SET_POWER_MODE %u", packet[3]);
            // track client power requests
            client = client_for_connection(connection);
            if (!client) break;
            client->power_mode = packet[3];
            // handle merged state
            if (!clients_require_power_on()){
                start_power_off_timer();
            } else if (!power_management_sleep) {
                stop_power_off_timer();
                hci_power_control(HCI_POWER_ON);
            }
            break;
        case BTSTACK_GET_VERSION:
            log_info("BTSTACK_GET_VERSION");
            hci_emit_btstack_version();
            break;   
#ifdef USE_BLUETOOL
        case BTSTACK_SET_SYSTEM_BLUETOOTH_ENABLED:
            log_info("BTSTACK_SET_SYSTEM_BLUETOOTH_ENABLED %u", packet[3]);
            iphone_system_bt_set_enabled(packet[3]);
            hci_emit_system_bluetooth_enabled(iphone_system_bt_enabled());
            break;
            
        case BTSTACK_GET_SYSTEM_BLUETOOTH_ENABLED:
            log_info("BTSTACK_GET_SYSTEM_BLUETOOTH_ENABLED");
            hci_emit_system_bluetooth_enabled(iphone_system_bt_enabled());
            break;
#else
        case BTSTACK_SET_SYSTEM_BLUETOOTH_ENABLED:
        case BTSTACK_GET_SYSTEM_BLUETOOTH_ENABLED:
            hci_emit_system_bluetooth_enabled(0);
            break;
#endif
        case BTSTACK_SET_DISCOVERABLE:
            log_info("BTSTACK_SET_DISCOVERABLE discoverable %u)", packet[3]);
            // track client discoverable requests
            client = client_for_connection(connection);
            if (!client) break;
            client->discoverable = packet[3];
            // merge state
            hci_discoverable_control(clients_require_discoverable());
            break;
        case BTSTACK_SET_BLUETOOTH_ENABLED:
            log_info("BTSTACK_SET_BLUETOOTH_ENABLED: %u\n", packet[3]);
            if (packet[3]) {
                // global enable
                global_enable = 1;
                hci_power_control(HCI_POWER_ON);
            } else {
                global_enable = 0;
                clients_clear_power_request();
                hci_power_control(HCI_POWER_OFF);
            }
            break;
        case L2CAP_CREATE_CHANNEL_MTU:
            bt_flip_addr(addr, &packet[3]);
            psm = READ_BT_16(packet, 9);
            mtu = READ_BT_16(packet, 11);
            l2cap_create_channel_internal( connection, NULL, addr, psm, mtu);
            break;
        case L2CAP_CREATE_CHANNEL:
            bt_flip_addr(addr, &packet[3]);
            psm = READ_BT_16(packet, 9);
            l2cap_create_channel_internal( connection, NULL, addr, psm, 150);   // until r865
            break;
        case L2CAP_DISCONNECT:
            cid = READ_BT_16(packet, 3);
            reason = packet[5];
            l2cap_disconnect_internal(cid, reason);
            break;
        case L2CAP_REGISTER_SERVICE:
            psm = READ_BT_16(packet, 3);
            mtu = READ_BT_16(packet, 5);
            l2cap_register_service_internal(connection, NULL, psm, mtu);
            break;
        case L2CAP_UNREGISTER_SERVICE:
            psm = READ_BT_16(packet, 3);
            l2cap_unregister_service_internal(connection, psm);
            break;
        case L2CAP_ACCEPT_CONNECTION:
            cid    = READ_BT_16(packet, 3);
            l2cap_accept_connection_internal(cid);
            break;
        case L2CAP_DECLINE_CONNECTION:
            cid    = READ_BT_16(packet, 3);
            reason = packet[7];
            l2cap_decline_connection_internal(cid, reason);
            break;
        case RFCOMM_CREATE_CHANNEL:
            bt_flip_addr(addr, &packet[3]);
            rfcomm_channel = packet[9];
            rfcomm_create_channel_internal( connection, &addr, rfcomm_channel );
            break;
        case RFCOMM_CREATE_CHANNEL_WITH_CREDITS:
            bt_flip_addr(addr, &packet[3]);
            rfcomm_channel = packet[9];
            rfcomm_credits = packet[10];
            rfcomm_create_channel_with_initial_credits_internal( connection, &addr, rfcomm_channel, rfcomm_credits );
            break;
        case RFCOMM_DISCONNECT:
            cid = READ_BT_16(packet, 3);
            reason = packet[5];
            rfcomm_disconnect_internal(cid);
            break;
        case RFCOMM_REGISTER_SERVICE:
            rfcomm_channel = packet[3];
            mtu = READ_BT_16(packet, 4);
            rfcomm_register_service_internal(connection, rfcomm_channel, mtu);
            break;
        case RFCOMM_REGISTER_SERVICE_WITH_CREDITS:
            rfcomm_channel = packet[3];
            mtu = READ_BT_16(packet, 4);
            rfcomm_credits = packet[6];
            rfcomm_register_service_with_initial_credits_internal(connection, rfcomm_channel, mtu, rfcomm_credits);
            break;
        case RFCOMM_UNREGISTER_SERVICE:
            service_channel = READ_BT_16(packet, 3);
            rfcomm_unregister_service_internal(service_channel);
            break;
        case RFCOMM_ACCEPT_CONNECTION:
            cid    = READ_BT_16(packet, 3);
            rfcomm_accept_connection_internal(cid);
            break;
        case RFCOMM_DECLINE_CONNECTION:
            cid    = READ_BT_16(packet, 3);
            reason = packet[7];
            rfcomm_decline_connection_internal(cid);
            break;            
        case RFCOMM_GRANT_CREDITS:
            cid    = READ_BT_16(packet, 3);
            rfcomm_credits = packet[5];
            rfcomm_grant_credits(cid, rfcomm_credits);
            break;
        case RFCOMM_PERSISTENT_CHANNEL: {
            if (remote_device_db) {
                // enforce \0
                packet[3+248] = 0;
                rfcomm_channel = remote_device_db->persistent_rfcomm_channel((char*)&packet[3]);
            } else {
                // NOTE: hack for non-iOS platforms
                rfcomm_channel = rfcomm_channel_generator++;
            }
            log_info("RFCOMM_EVENT_PERSISTENT_CHANNEL %u", rfcomm_channel);
            uint8_t event[4];
            event[0] = RFCOMM_EVENT_PERSISTENT_CHANNEL;
            event[1] = sizeof(event) - 2;
            event[2] = 0;
            event[3] = rfcomm_channel;
            hci_dump_packet(HCI_EVENT_PACKET, 0, event, sizeof(event));
            socket_connection_send_packet(connection, HCI_EVENT_PACKET, 0, (uint8_t *) event, sizeof(event));
            break;
        }
            
        case SDP_REGISTER_SERVICE_RECORD:
            log_info("SDP_REGISTER_SERVICE_RECORD size %u\n", size);
            sdp_register_service_internal(connection, &packet[3]);
            break;
        case SDP_UNREGISTER_SERVICE_RECORD:
            service_record_handle = READ_BT_32(packet, 3);
            log_info("SDP_UNREGISTER_SERVICE_RECORD handle 0x%x ", service_record_handle);
            sdp_unregister_service_internal(connection, service_record_handle);
            break;
        case SDP_CLIENT_QUERY_RFCOMM_SERVICES: 
            bt_flip_addr(addr, &packet[3]);

            serviceSearchPatternLen = de_get_len(&packet[9]);
            memcpy(serviceSearchPattern, &packet[9], serviceSearchPatternLen);

            sdp_query_rfcomm_register_callback(handle_sdp_rfcomm_service_result, connection);
            sdp_query_rfcomm_channel_and_name_for_search_pattern(addr, serviceSearchPattern);

            break;
        case SDP_CLIENT_QUERY_SERVICES:
            bt_flip_addr(addr, &packet[3]);
            sdp_parser_init();
            sdp_parser_register_callback(handle_sdp_client_query_result);

            serviceSearchPatternLen = de_get_len(&packet[9]);
            memcpy(serviceSearchPattern, &packet[9], serviceSearchPatternLen);
            
            attributeIDListLen = de_get_len(&packet[9+serviceSearchPatternLen]); 
            memcpy(attributeIDList, &packet[9+serviceSearchPatternLen], attributeIDListLen);
            
            sdp_client_query(addr, (uint8_t*)&serviceSearchPattern[0], (uint8_t*)&attributeIDList[0]);

            // sdp_general_query_for_uuid(addr, 0x1002);
            break;
        default:
            log_error("Error: command %u not implemented\n:", READ_CMD_OCF(packet));
            break;
    }
    
    // verbose log info on command before dumped command unknown to PacketLogger or Wireshark
    hci_dump_packet( HCI_COMMAND_DATA_PACKET, 1, packet, size);

    return 0;
}
Beispiel #3
0
static void att_run(void){
    switch (att_server_state){
        case ATT_SERVER_IDLE:
        case ATT_SERVER_W4_SIGNED_WRITE_VALIDATION:
            return;
        case ATT_SERVER_REQUEST_RECEIVED:
            if (att_request_buffer[0] == ATT_SIGNED_WRITE_COMMAND){
                log_info("ATT Signed Write!");
                if (!sm_cmac_ready()) {
                    log_info("ATT Signed Write, sm_cmac engine not ready. Abort");
                    att_server_state = ATT_SERVER_IDLE;
                     return;
                }  
                if (att_request_size < (3 + 12)) {
                    log_info("ATT Signed Write, request to short. Abort.");
                    att_server_state = ATT_SERVER_IDLE;
                    return;
                }
                if (att_ir_lookup_active){
                    return;
                }
                if (att_ir_le_device_db_index < 0){
                    log_info("ATT Signed Write, CSRK not available");
                    att_server_state = ATT_SERVER_IDLE;
                    return;
                }

                // check counter
                uint32_t counter_packet = READ_BT_32(att_request_buffer, att_request_size-12);
                uint32_t counter_db     = le_device_db_remote_counter_get(att_ir_le_device_db_index);
                log_info("ATT Signed Write, DB counter %u, packet counter %u", counter_db, counter_packet);
                if (counter_packet < counter_db){
                    log_info("ATT Signed Write, db reports higher counter, abort");
                    att_server_state = ATT_SERVER_IDLE;
                    return;
                }

                // signature is { sequence counter, secure hash }
                sm_key_t csrk;
                le_device_db_csrk_get(att_ir_le_device_db_index, csrk);
                att_server_state = ATT_SERVER_W4_SIGNED_WRITE_VALIDATION;
                log_info("Orig Signature: ");
                hexdump( &att_request_buffer[att_request_size-8], 8);
                sm_cmac_start(csrk, att_request_size - 12, att_request_buffer, counter_packet, att_signed_write_handle_cmac_result);
                return;
            } 
            // NOTE: fall through for regular commands

        case ATT_SERVER_REQUEST_RECEIVED_AND_VALIDATED:
            if (!l2cap_can_send_fixed_channel_packet_now(att_connection.con_handle)) return;

            l2cap_reserve_packet_buffer();
            uint8_t * att_response_buffer = l2cap_get_outgoing_buffer();
            uint16_t  att_response_size   = att_handle_request(&att_connection, att_request_buffer, att_request_size, att_response_buffer);

            // intercept "insufficient authorization" for authenticated connections to allow for user authorization
            if ((att_response_size     >= 4)
            && (att_response_buffer[0] == ATT_ERROR_RESPONSE)
            && (att_response_buffer[4] == ATT_ERROR_INSUFFICIENT_AUTHORIZATION)
            && (att_connection.authenticated)){

            	switch (sm_authorization_state(att_client_addr_type, att_client_address)){
            		case AUTHORIZATION_UNKNOWN:
                        l2cap_release_packet_buffer();
		             	sm_request_authorization(att_client_addr_type, att_client_address);
	    		        return;
	    		    case AUTHORIZATION_PENDING:
                        l2cap_release_packet_buffer();
	    		    	return;
	    		    default:
	    		    	break;
            	}
            }

            att_server_state = ATT_SERVER_IDLE;
            if (att_response_size == 0) {
                l2cap_release_packet_buffer();
                return;
            }

            l2cap_send_prepared_connectionless(att_connection.con_handle, L2CAP_CID_ATTRIBUTE_PROTOCOL, att_response_size);

            // notify client about MTU exchange result
            if (att_response_buffer[0] == ATT_EXCHANGE_MTU_RESPONSE){
                att_emit_mtu_event(att_connection.con_handle, att_connection.mtu);
            }

            break;
    }
}
Beispiel #4
0
static void packet_handler (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
    bd_addr_t event_addr;
    uint8_t   rfcomm_channel_nr;
    uint16_t  mtu;
    int i;

	switch (packet_type) {
		case HCI_EVENT_PACKET:
			switch (packet[0]) {
					
				case BTSTACK_EVENT_STATE:
					// bt stack activated, get started - set local name
					if (packet[2] == HCI_STATE_WORKING) {
                        hci_send_cmd(&hci_write_local_name, "BTstack SPP Counter");
					}
					break;
				
				case HCI_EVENT_COMMAND_COMPLETE:
					if (COMMAND_COMPLETE_EVENT(packet, hci_read_bd_addr)){
                        bt_flip_addr(event_addr, &packet[6]);
                        printf("BD-ADDR: %s\n", bd_addr_to_str(event_addr));
                        break;
                    }
                    break;
					
				case HCI_EVENT_PIN_CODE_REQUEST:
					// inform about pin code request
                    printf("Pin code request - using '0000'\n");
                    bt_flip_addr(event_addr, &packet[2]);
					hci_send_cmd(&hci_pin_code_request_reply, &event_addr, 4, "0000");
					break;

                case HCI_EVENT_USER_CONFIRMATION_REQUEST:
                    // inform about user confirmation request
                    printf("SSP User Confirmation Request with numeric value '%06u'\n", READ_BT_32(packet, 8));
                    printf("SSP User Confirmation Auto accept\n");
                    break;

                
                case RFCOMM_EVENT_INCOMING_CONNECTION:
					// data: event (8), len(8), address(48), channel (8), rfcomm_cid (16)
					bt_flip_addr(event_addr, &packet[2]); 
					rfcomm_channel_nr = packet[8];
					rfcomm_channel_id = READ_BT_16(packet, 9);
					printf("RFCOMM channel %u requested for %s\n", rfcomm_channel_nr, bd_addr_to_str(event_addr));
                    rfcomm_accept_connection_internal(rfcomm_channel_id);
					break;
					
				case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE:
					// data: event(8), len(8), status (8), address (48), server channel(8), rfcomm_cid(16), max frame size(16)
					if (packet[2]) {
						printf("RFCOMM channel open failed, status %u\n", packet[2]);
					} else {
						rfcomm_channel_id = READ_BT_16(packet, 12);
						mtu = READ_BT_16(packet, 14);
						printf("RFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u\n", rfcomm_channel_id, mtu);
					}
					break;
                    
                case RFCOMM_EVENT_CHANNEL_CLOSED:
                    printf("RFCOMM channel closed\n");
                    rfcomm_channel_id = 0;
                    break;
                
                default:
                    break;
			}
            break;
        
        case RFCOMM_DATA_PACKET:
            printf("RCV: '");
            for (i=0;i<size;i++){
                putchar(packet[i]);
            }
            printf("'\n");
            break;

        default:
            break;
	}
}
Beispiel #5
0
/*************** PANU client routines *********************/
static void packet_handler (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
{
    uint8_t   event;
    bd_addr_t event_addr;
    bd_addr_t src_addr;
    bd_addr_t dst_addr;
    uint16_t  uuid_source;
    uint16_t  uuid_dest;
    uint16_t  mtu;    
    uint16_t  network_type;
    uint8_t   protocol_type;
    uint8_t   icmp_type;
    int       ihl;
    int       payload_offset;

    switch (packet_type) {
		case HCI_EVENT_PACKET:
            event = packet[0];
            switch (event) {            
                case BTSTACK_EVENT_STATE:
                    /* BT Stack activated, get started */ 
                    if (packet[2] == HCI_STATE_WORKING) {
                        printf("BNEP Test ready\n");
                        show_usage();
                    }
                    break;

                case HCI_EVENT_COMMAND_COMPLETE:
					if (COMMAND_COMPLETE_EVENT(packet, hci_read_bd_addr)){
                        bt_flip_addr(local_addr, &packet[6]);
                        printf("BD-ADDR: %s\n", bd_addr_to_str(local_addr));
                        break;
                    }
                    break;

                case HCI_EVENT_USER_CONFIRMATION_REQUEST:
                    // inform about user confirmation request
                    printf("SSP User Confirmation Request with numeric value '%06u'\n", READ_BT_32(packet, 8));
                    printf("SSP User Confirmation Auto accept\n");
                    break;
					
				case BNEP_EVENT_OPEN_CHANNEL_COMPLETE:
                    if (packet[2]) {
                        printf("BNEP channel open failed, status %02x\n", packet[2]);
                    } else {
                        // data: event(8), len(8), status (8), bnep source uuid (16), bnep destination uuid (16), remote_address (48)
                        uuid_source = READ_BT_16(packet, 3);
                        uuid_dest   = READ_BT_16(packet, 5);
                        mtu         = READ_BT_16(packet, 7);
                        bnep_cid    = channel;
                        //bt_flip_addr(event_addr, &packet[9]); 
                        memcpy(&event_addr, &packet[9], sizeof(bd_addr_t));
                        printf("BNEP connection open succeeded to %s source UUID 0x%04x dest UUID: 0x%04x, max frame size %u\n", bd_addr_to_str(event_addr), uuid_source, uuid_dest, mtu);
                    }
					break;
                    
                case BNEP_EVENT_CHANNEL_TIMEOUT:
                    printf("BNEP channel timeout! Channel will be closed\n");
                    break;
                    
                case BNEP_EVENT_CHANNEL_CLOSED:
                    printf("BNEP channel closed\n");
                    break;

                case BNEP_EVENT_READY_TO_SEND:
                    /* Check for parked network packets and send it out now */
                    if (network_buffer_len > 0) {
                        bnep_send(bnep_cid, network_buffer, network_buffer_len);
                        network_buffer_len = 0;
                    }
                    break;
                    
                default:
                    break;
            }
            break;
        case BNEP_DATA_PACKET:
            // show received packet on console

            // TODO: fix BNEP to return BD ADDR in little endian, to use these lines
            // bt_flip_addr(dst_addr, &packet[0]);
            // bt_flip_addr(src_addr, &packet[6]);
            // instead of these
            memcpy(dst_addr, &packet[0], 6);
            memcpy(src_addr, &packet[6], 6);
            // END TOOD

            network_type = READ_NET_16(packet, 12);
            printf("BNEP packet received\n");
            printf("Dst Addr: %s\n", bd_addr_to_str(dst_addr));
            printf("Src Addr: %s\n", bd_addr_to_str(src_addr));
            printf("Net Type: %04x\n", network_type);
            // ignore the next 60 bytes
            // hexdumpf(&packet[74], size - 74);
            switch (network_type){
                case NETWORK_TYPE_IPv4:
                    ihl = packet[14] & 0x0f;
                    payload_offset = 14 + (ihl << 2);
                    // protocol
                    protocol_type = packet[14 + 9]; // offset 9 into IPv4
                    switch (protocol_type){
                        case 0x01:  // ICMP
                            icmp_type = packet[payload_offset];
                            hexdumpf(&packet[payload_offset], size - payload_offset);
                            printf("ICMP packet of type %x\n", icmp_type);
                            switch (icmp_type){
                                case ICMP_V4_TYPE_PING_REQUEST:
                                    printf("IPv4 Ping Request received, sending pong\n");
                                    send_ping_response_ipv4();
                                    break;
                                break;
                            }
                        case 0x11:  // UDP
                            printf("UDP IPv4 packet\n");                        
                            hexdumpf(&packet[payload_offset], size - payload_offset);
                            break;
                        default:
                            printf("Unknown IPv4 protocol type %x", protocol_type);
                            break;
                    }
                    break;
                case NETWORK_TYPE_IPv6:
                    protocol_type = packet[6];
                    switch(protocol_type){
                        case 0x11: // UDP
                            printf("UDP IPv6 packet\n");
                            payload_offset = 40;    // fixed
                            hexdumpf(&packet[payload_offset], size - payload_offset);

                            // send response

                            break;
                        default:
                            printf("IPv6 packet of protocol 0x%02x\n", protocol_type);
                            hexdumpf(&packet[14], size - 14);
                            break;
                    }
                    break;
                default:
                    printf("Unknown network type %x", network_type);
                    break;
            }

            break;            
            
        default:
            break;
    }
}
Beispiel #6
0
static void handle_gatt_client_event(le_event_t * event) {

    uint8_t * packet = (uint8_t*) event;
    int connection_encrypted;

    // handle connect / disconncet events first
    switch (packet[0]) {
    case HCI_EVENT_LE_META:
        switch (packet[2]) {
        case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
            gc_handle = READ_BT_16(packet, 4);
            printf("Connection handle 0x%04x, request encryption\n", gc_handle);

            // we need to be paired to enable notifications
            tc_state = TC_W4_ENCRYPTED_CONNECTION;
            sm_send_security_request(gc_handle);
            break;
        default:
            break;
        }
        return;

    case HCI_EVENT_ENCRYPTION_CHANGE:
        if (gc_handle != READ_BT_16(packet, 3)) return;
        connection_encrypted = packet[5];
        log_info("Encryption state change: %u", connection_encrypted);
        if (!connection_encrypted) return;
        if (tc_state != TC_W4_ENCRYPTED_CONNECTION) return;

        // let's start
        printf("\nANCS Client - CONNECTED, discover ANCS service\n");
        tc_state = TC_W4_SERVICE_RESULT;
        gatt_client_discover_primary_services_by_uuid128(gc_id, gc_handle, ancs_service_uuid);
        return;

    case HCI_EVENT_DISCONNECTION_COMPLETE:
        notify_client(ANCS_CLIENT_DISCONNECTED);
        return;

    default:
        break;
    }

    le_characteristic_t characteristic;
    le_characteristic_value_event_t * value_event;
    switch(tc_state) {
    case TC_W4_SERVICE_RESULT:
        switch(event->type) {
        case GATT_SERVICE_QUERY_RESULT:
            ancs_service = ((le_service_event_t *) event)->service;
            ancs_service_found = 1;
            break;
        case GATT_QUERY_COMPLETE:
            if (!ancs_service_found) {
                printf("ANCS Service not found");
                tc_state = TC_IDLE;
                break;
            }
            tc_state = TC_W4_CHARACTERISTIC_RESULT;
            printf("ANCS Client - Discover characteristics for ANCS SERVICE \n");
            gatt_client_discover_characteristics_for_service(gc_id, gc_handle, &ancs_service);
            break;
        default:
            break;
        }
        break;

    case TC_W4_CHARACTERISTIC_RESULT:
        switch(event->type) {
        case GATT_CHARACTERISTIC_QUERY_RESULT:
            characteristic = ((le_characteristic_event_t *) event)->characteristic;
            if (memcmp(characteristic.uuid128, ancs_notification_source_uuid, 16) == 0) {
                printf("ANCS Notification Source Characterisic found\n");
                ancs_notification_source_characteristic = characteristic;
                ancs_characteristcs++;
                break;
            }
            if (memcmp(characteristic.uuid128, ancs_control_point_uuid, 16) == 0) {
                printf("ANCS Control Point found\n");
                ancs_control_point_characteristic = characteristic;
                ancs_characteristcs++;
                break;
            }
            if (memcmp(characteristic.uuid128, ancs_data_source_uuid, 16) == 0) {
                printf("ANCS Data Source Characterisic found\n");
                ancs_data_source_characteristic = characteristic;
                ancs_characteristcs++;
                break;
            }
            break;
        case GATT_QUERY_COMPLETE:
            printf("ANCS Characteristcs count %u\n", ancs_characteristcs);
            tc_state = TC_W4_NOTIFICATION_SOURCE_SUBSCRIBED;
            gatt_client_write_client_characteristic_configuration(gc_id, gc_handle, &ancs_notification_source_characteristic,
                    GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
            break;
        default:
            break;
        }
        break;
    case TC_W4_NOTIFICATION_SOURCE_SUBSCRIBED:
        switch(event->type) {
        case GATT_QUERY_COMPLETE:
            printf("ANCS Notification Source subscribed\n");
            tc_state = TC_W4_DATA_SOURCE_SUBSCRIBED;
            gatt_client_write_client_characteristic_configuration(gc_id, gc_handle, &ancs_data_source_characteristic,
                    GATT_CLIENT_CHARACTERISTICS_CONFIGURATION_NOTIFICATION);
            break;
        default:
            break;
        }
        break;
    case TC_W4_DATA_SOURCE_SUBSCRIBED:
        switch(event->type) {
        case GATT_QUERY_COMPLETE:
            printf("ANCS Data Source subscribed\n");
            tc_state = TC_SUBSCRIBED;
            notify_client(ANCS_CLIENT_CONNECTED);
            break;
        default:
            break;
        }
        break;
    case TC_SUBSCRIBED:
        if ( event->type != GATT_NOTIFICATION && event->type != GATT_INDICATION ) break;
        value_event = (le_characteristic_value_event_t *) event;
        if (value_event->value_handle == ancs_data_source_characteristic.value_handle) {
            int i;
            for (i=0; i<value_event->blob_length; i++) {
                ancs_chunk_parser_handle_byte(value_event->blob[i]);
            }
        } else if (value_event->value_handle == ancs_notification_source_characteristic.value_handle) {
            ancs_notification_uid = READ_BT_32(value_event->blob, 4);
            printf("Notification received: EventID %02x, EventFlags %02x, CategoryID %02x, CategoryCount %u, UID %04x\n",
                   value_event->blob[0], value_event->blob[1], value_event->blob[2], value_event->blob[3], (int) ancs_notification_uid);
            static uint8_t get_notification_attributes[] = {0, 0,0,0,0,  0,  1,32,0,  2,32,0, 3,32,0, 4, 5};
            bt_store_32(get_notification_attributes, 1, ancs_notification_uid);
            ancs_notification_uid = 0;
            ancs_chunk_parser_init();
            gatt_client_write_value_of_characteristic(gc_id, gc_handle, ancs_control_point_characteristic.value_handle,
                    sizeof(get_notification_attributes), get_notification_attributes);
        } else {
            printf("Unknown Source: ");
            printf_hexdump(value_event->blob , value_event->blob_length);
        }
        break;
    default:
        break;
    }
    // app_run();
}
Beispiel #7
0
void att_client_notify(uint16_t handle, uint8_t *data, uint16_t length)
{
  printf("==>state:%d len:%d   attrleftlen:%d\n", parse_state, length, attrleftlen);
    if (handle == attribute_handles[NOTIFICATION])
    {
        uint32_t uid =  READ_BT_32(data, 4);
        //uint32_t combine = READ_BT_32(data, 4);
        log_info("id: %d flags:%d catery:%d count: %d UID:%ld\n",
            data[0], data[1], data[2], data[3],
            uid
            );

        if (data[2] == CategoryIDIncomingCall)
        {
            // need convert the title to CLIP command

        }
        else
        {
            window_notify_ancs(data[0], uid, data[1], data[2]);
        }
    }
    else if (handle == attribute_handles[DATASOURCE])
    {
        log_info("data received\n");
        // start notification
        hexdump(data, length);
        uint16_t l;
        int index = 0;
        while(index < length)
        {
            switch(parse_state)
            {
                case STATE_NONE:
                    log_info("Command: %d\t", data[index]);
                    index++;
                    parse_state = STATE_UID;
                    break;
                case STATE_UID:
                    log_info("uid: %ld\t", READ_BT_32(data, index));
                    index += 4;
                    parse_state = STATE_ATTRIBUTEID;
                    break;
                case STATE_ATTRIBUTEID:
                    attributeid = data[index];
                    log_info("\nattributeid: %d\t", attributeid);
                    switch(attributeid)
                    {
                        case NotificationAttributeIDAppIdentifier:
                        bufptr = appidbuf;
                        len = 32;
                        break;
                        case NotificationAttributeIDTitle:
                        bufptr = titlebuf;
                        len = MAX_TITLE;
                        break;
                        case NotificationAttributeIDSubtitle:
                        bufptr = subtitlebuf;
                        len = MAX_TITLE;
                        break;
                        case NotificationAttributeIDMessage:
                        bufptr = msgbuf;
                        len = MAX_MESSAGE;
                        break;
                        case NotificationAttributeIDDate:
                        bufptr = datebuf;
                        len = 16;
                        break;
                    }
                    index++;
                    parse_state = STATE_ATTRIBUTELEN;
                    break;
                case STATE_ATTRIBUTELEN:
                    // //
                    // max length is less than 255.
                    if (length - index > 1)
                    {
                        attrleftlen = READ_BT_16(data, index);
                        log_info("len: %d\t", attrleftlen);
                        index+=2;
                        parse_state = STATE_ATTRIBUTE;
                        if (attrleftlen > len)
                            attrleftlen = len;
                        else
                            len = attrleftlen;
                    }
                    else
                    {
                        attrleftlen = data[index];
                        index++;
                        parse_state = STATE_ATTRIBUTELEN2;
                    }
                    break;
                case STATE_ATTRIBUTELEN2:
                    attrleftlen = attrleftlen + (uint16_t)data[index];
                    index++;
                    log_info("len: %d\t", attrleftlen);
                    parse_state = STATE_ATTRIBUTE;
                    if (attrleftlen > len)
                        attrleftlen = len;
                    else
                        len = attrleftlen;
                    break;
                case STATE_ATTRIBUTE:
                    if (length - index > attrleftlen)
                        l = attrleftlen;
                    else
                        l = length - index;
                    for(int i = 0; i < l; i++)
                    {
                        //putchar(data[index + i]);
                        bufptr[i + len - attrleftlen] = data[index + i];
                    }
                    index += l;
                    attrleftlen -= l;
                    if (attrleftlen == 0)
                    {
                        bufptr[len] = '\0';
                        if (attributeid == NotificationAttributeIDDate)
                            parse_state = STATE_DONE;
                        else
                            parse_state = STATE_ATTRIBUTEID;
                    }
                    break;
            }
        }
        // parse the data
        char icon = -1;
#define ICON_FACEBOOK 's'
#define ICON_TWITTER  't'
#define ICON_MSG      'u' 

        if (strcmp("com.apple.MobileSMS", appidbuf) == 0)
        {
            icon = ICON_MSG;
        }
        else if (strcmp("XX", appidbuf) == 0)
        {
            icon = ICON_TWITTER;
        }
        else if (strcmp("XX", appidbuf) == 0)
        {
            icon = ICON_FACEBOOK;
        }

        if (parse_state == STATE_DONE)
        {
            window_notify_content(titlebuf, subtitlebuf, msgbuf, datebuf, 0, icon);
            parse_state = STATE_NONE;
            printf("done!!!\n");
        }
    }
    else
    {
        log_info("handle: %d\n", handle);
    }
}
Beispiel #8
0
// enable LE, setup ADV data
static void packet_handler (void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
    bd_addr_t addr;
    uint8_t adv_data[] = { 02, 01, 05,   03, 02, 0xf0, 0xff }; 
    switch (packet_type) {
            
		case HCI_EVENT_PACKET:
			switch (packet[0]) {
				
                case BTSTACK_EVENT_STATE:
					// bt stack activated, get started - set local name
					if (packet[2] == HCI_STATE_WORKING) {
					   printf("Working!\n");
						hci_send_cmd(&hci_read_local_supported_features);
					}
					break;
                
                case DAEMON_EVENT_HCI_PACKET_SENT:
                    att_try_respond();
                    break;
                    
                case HCI_EVENT_LE_META:
                    switch (packet[2]) {
                        case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
                            // reset connection MTU
                            att_connection.mtu = 23;
                            break;
                        default:
                            break;
                    }
                    break;

                case BTSTACK_EVENT_NR_CONNECTIONS_CHANGED:
				    if (packet[2]) {
                        printf("Connected.\n");
                    } else {
				        printf("Not connected.\n");
                    }
                    break;
                    
                case HCI_EVENT_DISCONNECTION_COMPLETE:
                    att_response_handle =0;
                    att_response_size = 0;
                    
                    // restart advertising
                    hci_send_cmd(&hci_le_set_advertise_enable, 1);
                    break;
                    
				case HCI_EVENT_COMMAND_COMPLETE:
					if (COMMAND_COMPLETE_EVENT(packet, hci_read_bd_addr)){
    					bt_flip_addr(addr, &packet[6]);
					    printf("BD ADDR: %s\n", bd_addr_to_str(addr));
						break;
					}
					if (COMMAND_COMPLETE_EVENT(packet, hci_read_local_supported_features)){
					     printf("Local supported features: %04X%04X\n", READ_BT_32(packet, 10), READ_BT_32(packet, 6));
                        hci_send_cmd(&hci_set_event_mask, 0xffffffff, 0x20001fff);
						break;
					}
					if (COMMAND_COMPLETE_EVENT(packet, hci_set_event_mask)){
                        hci_send_cmd(&hci_write_le_host_supported, 1, 1);
						break;
					}
					if (COMMAND_COMPLETE_EVENT(packet, hci_write_le_host_supported)){
				        hci_send_cmd(&hci_le_set_event_mask, 0xffffffff, 0xffffffff);
                    	break;
					}
					if (COMMAND_COMPLETE_EVENT(packet, hci_le_set_event_mask)){
				        hci_send_cmd(&hci_le_read_buffer_size);
                    	break;
					}
				    if (COMMAND_COMPLETE_EVENT(packet, hci_le_read_buffer_size)){
					    printf("LE buffer size: %u, count %u\n", READ_BT_16(packet,6), packet[8]);
					   hci_send_cmd(&hci_le_read_supported_states);
					   break;
					}
				    if (COMMAND_COMPLETE_EVENT(packet, hci_le_read_supported_states)){
					   hci_send_cmd(&hci_le_set_advertising_parameters,  0x0400, 0x0800, 0, 0, 0, &addr, 0x07, 0);
					   break;
					}
				    if (COMMAND_COMPLETE_EVENT(packet, hci_le_set_advertising_parameters)){
					   hci_send_cmd(&hci_le_set_advertising_data, sizeof(adv_data), adv_data);
					   break;
					}
				    if (COMMAND_COMPLETE_EVENT(packet, hci_le_set_advertising_data)){
					   hci_send_cmd(&hci_le_set_scan_response_data, 10, adv_data);
					   break;
					}
				    if (COMMAND_COMPLETE_EVENT(packet, hci_le_set_scan_response_data)){
					   hci_send_cmd(&hci_le_set_advertise_enable, 1);
					   break;
					}
				    if (COMMAND_COMPLETE_EVENT(packet, hci_le_set_advertise_enable)){
                        hci_discoverable_control(1);
                        break;
					}
                    
			}
	}
}
/* LISTING_START(GAPLEAdvDataParsing): Parsing advertising data */
static void dump_advertisement_data(uint8_t * adv_data, uint8_t adv_size){
    ad_context_t context;
    bd_addr_t address;
    uint8_t uuid_128[16];
    for (ad_iterator_init(&context, adv_size, adv_data) ; ad_iterator_has_more(&context) ; ad_iterator_next(&context)){
        uint8_t data_type = ad_iterator_get_data_type(&context);
        uint8_t size      = ad_iterator_get_data_len(&context);
        uint8_t * data    = ad_iterator_get_data(&context);
        
        if (data_type > 0 && data_type < 0x1B){
            printf("    %s: ", ad_types[data_type]);
        } 
        int i;
        // Assigned Numbers GAP
    
        switch (data_type){
            case 0x01: // Flags
                // show only first octet, ignore rest
                for (i=0; i<8;i++){
                    if (data[0] & (1<<i)){
                        printf("%s; ", flags[i]);
                    }

                }
                break;
            case 0x02: // Incomplete List of 16-bit Service Class UUIDs
            case 0x03: // Complete List of 16-bit Service Class UUIDs
            case 0x14: // List of 16-bit Service Solicitation UUIDs
                for (i=0; i<size;i+=2){
                    printf("%02X ", READ_BT_16(data, i));
                }
                break;
            case 0x04: // Incomplete List of 32-bit Service Class UUIDs
            case 0x05: // Complete List of 32-bit Service Class UUIDs
                for (i=0; i<size;i+=4){
                    printf("%04X ", READ_BT_32(data, i));
                }
                break;
            case 0x06: // Incomplete List of 128-bit Service Class UUIDs
            case 0x07: // Complete List of 128-bit Service Class UUIDs
            case 0x15: // List of 128-bit Service Solicitation UUIDs
                swap128(data, uuid_128);
                printUUID128(uuid_128);
                break;
            case 0x08: // Shortened Local Name
            case 0x09: // Complete Local Name
                for (i=0; i<size;i++){
                    printf("%c", (char)(data[i]));
                }
                break;
            case 0x0A: // Tx Power Level 
                printf("%d dBm", *(int8_t*)data);
                break;
            case 0x12: // Slave Connection Interval Range 
                printf("Connection Interval Min = %u ms, Max = %u ms", READ_BT_16(data, 0) * 5/4, READ_BT_16(data, 2) * 5/4);
                break;
            case 0x16: // Service Data 
                printf_hexdump(data, size);
                break;
            case 0x17: // Public Target Address
            case 0x18: // Random Target Address
                bt_flip_addr(address, data);
                print_bd_addr(address);
                break;
            case 0x19: // Appearance 
                // https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml
                printf("%02X", READ_BT_16(data, 0) );
                break;
            case 0x1A: // Advertising Interval 
                printf("%u ms", READ_BT_16(data, 0) * 5/8 );
                break;
            case 0x3D: // 3D Information Data 
                printf_hexdump(data, size);
                break;
            case 0xFF: // Manufacturer Specific Data 
                break;
            case 0x0D: // Class of Device (3B)
            case 0x0E: // Simple Pairing Hash C (16B)
            case 0x0F: // Simple Pairing Randomizer R (16B) 
            case 0x10: // Device ID 
            case 0x11: // Security Manager TK Value (16B)
            default:
                printf("Unknown Advertising Data Type"); 
                break;
        }        
        printf("\n");
    }
    printf("\n");
}
Beispiel #10
0
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){

    uint16_t psm;
    uint32_t passkey;

    if (packet_type == UCD_DATA_PACKET){
        printf("UCD Data for PSM %04x received, size %u\n", READ_BT_16(packet, 0), size - 2);
    }

    if (packet_type != HCI_EVENT_PACKET) return;

    switch (packet[0]) {
        case HCI_EVENT_INQUIRY_RESULT:
        case HCI_EVENT_INQUIRY_RESULT_WITH_RSSI:
        case HCI_EVENT_INQUIRY_COMPLETE:
        case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE:
            inquiry_packet_handler(packet_type, packet, size);
            break;

        case BTSTACK_EVENT_STATE:
            // bt stack activated, get started 
            if (packet[2] == HCI_STATE_WORKING){
                printf("BTstack Bluetooth Classic Test Ready\n");
                hci_send_cmd(&hci_write_inquiry_mode, 0x01); // with RSSI
                show_usage();
            }
            break;
        case GAP_DEDICATED_BONDING_COMPLETED:
            printf("GAP Dedicated Bonding Complete, status %u\n", packet[2]);
            break;

        case HCI_EVENT_CONNECTION_COMPLETE:
            if (!packet[2]){
                handle = READ_BT_16(packet, 3);
                bt_flip_addr(remote, &packet[5]);
                printf("HCI_EVENT_CONNECTION_COMPLETE: handle 0x%04x\n", handle);
            }
            break;

        case HCI_EVENT_USER_PASSKEY_REQUEST:
            bt_flip_addr(remote, &packet[2]);
            printf("GAP User Passkey Request for %s\nPasskey:", bd_addr_to_str(remote));
            fflush(stdout);
            ui_digits_for_passkey = 6;
            break;

        case HCI_EVENT_USER_CONFIRMATION_REQUEST:
            bt_flip_addr(remote, &packet[2]);
            passkey = READ_BT_32(packet, 8);
            printf("GAP User Confirmation Request for %s, number '%06u'\n", bd_addr_to_str(remote),passkey);
            break;

        case HCI_EVENT_PIN_CODE_REQUEST:
            bt_flip_addr(remote, &packet[2]);
            printf("GAP Legacy PIN Request for %s (press ENTER to send)\nPasskey:", bd_addr_to_str(remote));
            fflush(stdout);
            ui_chars_for_pin = 1;
            break;

        case L2CAP_EVENT_CHANNEL_OPENED:
            // inform about new l2cap connection
            bt_flip_addr(remote, &packet[3]);
            psm = READ_BT_16(packet, 11); 
            local_cid = READ_BT_16(packet, 13); 
            handle = READ_BT_16(packet, 9);
            if (packet[2] == 0) {
                printf("L2CAP Channel successfully opened: %s, handle 0x%02x, psm 0x%02x, local cid 0x%02x, remote cid 0x%02x\n",
                       bd_addr_to_str(remote), handle, psm, local_cid,  READ_BT_16(packet, 15));
            } else {
                printf("L2CAP connection to device %s failed. status code %u\n", bd_addr_to_str(remote), packet[2]);
            }
            break;

        case L2CAP_EVENT_INCOMING_CONNECTION: {
            // data: event (8), len(8), address(48), handle (16), psm (16), local_cid(16), remote_cid (16) 
            psm = READ_BT_16(packet, 10);
            // uint16_t l2cap_cid  = READ_BT_16(packet, 12);
            printf("L2CAP incoming connection request on PSM %u\n", psm); 
            // l2cap_accept_connection_internal(l2cap_cid);
            break;
        }

        case RFCOMM_EVENT_INCOMING_CONNECTION:
            // data: event (8), len(8), address(48), channel (8), rfcomm_cid (16)
            bt_flip_addr(remote, &packet[2]); 
            rfcomm_channel_nr = packet[8];
            rfcomm_channel_id = READ_BT_16(packet, 9);
            printf("RFCOMM channel %u requested for %s\n\r", rfcomm_channel_nr, bd_addr_to_str(remote));
            rfcomm_accept_connection_internal(rfcomm_channel_id);
            break;
            
        case RFCOMM_EVENT_OPEN_CHANNEL_COMPLETE:
            // data: event(8), len(8), status (8), address (48), server channel(8), rfcomm_cid(16), max frame size(16)
            if (packet[2]) {
                printf("RFCOMM channel open failed, status %u\n\r", packet[2]);
            } else {
                rfcomm_channel_id = READ_BT_16(packet, 12);
                mtu = READ_BT_16(packet, 14);
                if (mtu > 60){
                    printf("BTstack libusb hack: using reduced MTU for sending instead of %u\n", mtu);
                    mtu = 60;
                }
                printf("\n\rRFCOMM channel open succeeded. New RFCOMM Channel ID %u, max frame size %u\n\r", rfcomm_channel_id, mtu);
            }
            break;
            
        case RFCOMM_EVENT_CHANNEL_CLOSED:
            rfcomm_channel_id = 0;
            break;

        default:
            break;
    }
}