Ejemplo n.º 1
0
static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type){
    char buffer;
    read(ds->fd, &buffer, 1);
    switch (buffer){
        case 'c':
            printf("Creating L2CAP Connection to %s, PSM SDP\n", bd_addr_to_str(remote));
            l2cap_create_channel(packet_handler, remote, PSM_SDP, 100, NULL);
            break;
        case 's':
            printf("Send L2CAP Data\n");
            l2cap_send(local_cid, (uint8_t *) "0123456789", 10);
            break;
        case 'e':
            printf("Send L2CAP ECHO Request\n");
            l2cap_send_echo_request(handle, (uint8_t *)  "Hello World!", 13);
            break;
        case 'd':
            printf("L2CAP Channel Closed\n");
            l2cap_disconnect(local_cid, 0);
            break;
        case '\n':
        case '\r':
            break;
        default:
            show_usage();
            break;

    }
}
Ejemplo n.º 2
0
static void stdin_process(char buffer){
    switch (buffer){
        case 'c':
            printf("Creating L2CAP Connection to %s, PSM SDP\n", bd_addr_to_str(remote));
            if (l2cap_ertm){
                l2cap_create_ertm_channel(packet_handler, remote, BLUETOOTH_PROTOCOL_SDP, &ertm_config, ertm_buffer, sizeof(ertm_buffer), &local_cid);
            } else {
                l2cap_create_channel(packet_handler, remote, BLUETOOTH_PROTOCOL_SDP, 100, &local_cid);
            }
            break;
        case 'b':
            printf("Set channel busy\n");
            l2cap_ertm_set_busy(local_cid);
            break;
        case 'B':
            printf("Set channel ready\n");
            l2cap_ertm_set_ready(local_cid);
            break;
        case 's':
            printf("Send some L2CAP Data\n");
            l2cap_send(local_cid, (uint8_t *) "0123456789", 10);
            break;
        case 'S':
            printf("Send more L2CAP Data\n");
            l2cap_send(local_cid, (uint8_t *) "0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789", 100);
            break;
        case 'd':
            printf("L2CAP Channel Closed\n");
            l2cap_disconnect(local_cid, 0);
            break;
        case 'e':
            printf("L2CAP Enhanced Retransmission Mode (ERTM) optional\n");
            l2cap_ertm = 1;
            ertm_config.ertm_mandatory = 0;
            break;
        case 'E':
            printf("L2CAP Enhanced Retransmission Mode (ERTM) mandatory\n");
            l2cap_ertm = 1;
            ertm_config.ertm_mandatory = 1;
            break;
        case 'p':
            printf("Send L2CAP ECHO Request\n");
            l2cap_send_echo_request(handle, (uint8_t *)  "Hello World!", 13);
            break;
        case 't':
            printf("Disconnect ACL handle\n");
            gap_disconnect(handle);
            break;
        case '\n':
        case '\r':
            break;
        default:
            show_usage();
            break;

    }
}
Ejemplo n.º 3
0
uint8_t sdp_client_query(btstack_packet_handler_t callback, bd_addr_t remote, const uint8_t * des_service_search_pattern, const uint8_t * des_attribute_id_list){
    if (!sdp_client_ready()) return SDP_QUERY_BUSY;

    sdp_parser_init(callback);
    service_search_pattern = des_service_search_pattern;
    attribute_id_list = des_attribute_id_list;
    continuationStateLen = 0;
    PDU_ID = SDP_ServiceSearchAttributeResponse;

    sdp_client_state = W4_CONNECT;
    return l2cap_create_channel(sdp_client_packet_handler, remote, BLUETOOTH_PROTOCOL_SDP, l2cap_max_mtu(), NULL);
}
Ejemplo n.º 4
0
void avdtp_initiator_stream_config_subsm(avdtp_connection_t * connection, uint8_t *packet, uint16_t size, int offset, avdtp_context_t * context){
    // int status = 0;
    avdtp_stream_endpoint_t * stream_endpoint = NULL;
    
    uint8_t remote_sep_index;
    avdtp_sep_t sep;
    if (connection->initiator_connection_state == AVDTP_SIGNALING_CONNECTION_INITIATOR_W4_ANSWER) {
        connection->initiator_connection_state = AVDTP_SIGNALING_CONNECTION_INITIATOR_IDLE;
    } else {
        stream_endpoint = avdtp_stream_endpoint_associated_with_acp_seid(connection->remote_seid, context);
        if (!stream_endpoint){
            stream_endpoint = avdtp_stream_endpoint_with_seid(connection->local_seid, context);
        }
        if (!stream_endpoint) return;
        sep.seid = connection->remote_seid;
        
        if (stream_endpoint->initiator_config_state != AVDTP_INITIATOR_W4_ANSWER) return;
        stream_endpoint->initiator_config_state = AVDTP_INITIATOR_STREAM_CONFIG_IDLE;
    }
    
    switch (connection->signaling_packet.message_type){
        case AVDTP_RESPONSE_ACCEPT_MSG:
            switch (connection->signaling_packet.signal_identifier){
                case AVDTP_SI_DISCOVER:{
                    if (connection->signaling_packet.transaction_label != connection->initiator_transaction_label){
                        log_info("    unexpected transaction label, got %d, expected %d", connection->signaling_packet.transaction_label, connection->initiator_transaction_label);
                        // status = BAD_HEADER_FORMAT;
                        break;
                    }
                    
                    if (size == 3){
                        log_info("    ERROR code %02x", packet[offset]);
                        break;
                    }
                    
                int i;
                    for (i = offset; i < size; i += 2){
                        sep.seid = packet[i] >> 2;
                        offset++;
                        if (sep.seid < 0x01 || sep.seid > 0x3E){
                            log_info("    invalid sep id");
                            // status = BAD_ACP_SEID;
                            break;
                        }
                        sep.in_use = (packet[i] >> 1) & 0x01;
                        sep.media_type = (avdtp_media_type_t)(packet[i+1] >> 4);
                        sep.type = (avdtp_sep_type_t)((packet[i+1] >> 3) & 0x01);

                        if (avdtp_find_remote_sep(connection, sep.seid) == 0xFF){
                            connection->remote_seps[connection->remote_seps_num++] = sep;
                        }
                        avdtp_signaling_emit_sep(context->avdtp_callback, connection->avdtp_cid, sep);
                    }
                    break;
                }
                
                case AVDTP_SI_GET_CAPABILITIES:
                case AVDTP_SI_GET_ALL_CAPABILITIES:
                    sep.registered_service_categories = avdtp_unpack_service_capabilities(connection, &sep.capabilities, packet+offset, size-offset);
                    if (get_bit16(sep.registered_service_categories, AVDTP_MEDIA_CODEC)){
                        switch (sep.capabilities.media_codec.media_codec_type){
                            case AVDTP_CODEC_SBC: 
                                avdtp_signaling_emit_media_codec_sbc_capability(context->avdtp_callback, connection->avdtp_cid, connection->local_seid, connection->remote_seid, sep.capabilities.media_codec);
                                break;
                            default:
                                avdtp_signaling_emit_media_codec_other_capability(context->avdtp_callback, connection->avdtp_cid, connection->local_seid, connection->remote_seid, sep.capabilities.media_codec);
                                break;
                        }
                    }
                    break;
                
                case AVDTP_SI_GET_CONFIGURATION:
                    sep.configured_service_categories = avdtp_unpack_service_capabilities(connection, &sep.configuration, packet+offset, size-offset);
                    if (get_bit16(sep.configured_service_categories, AVDTP_MEDIA_CODEC)){
                        switch (sep.configuration.media_codec.media_codec_type){
                            case AVDTP_CODEC_SBC: 
                                avdtp_signaling_emit_media_codec_sbc_configuration(context->avdtp_callback, connection->avdtp_cid, connection->local_seid, connection->remote_seid, sep.configuration.media_codec);
                                break;
                            default:
                                avdtp_signaling_emit_media_codec_other_configuration(context->avdtp_callback, connection->avdtp_cid, connection->local_seid,  connection->remote_seid, sep.configuration.media_codec);
                                break;
                        }
                    }
                    break;
                
                case AVDTP_SI_RECONFIGURE:
                    if (!stream_endpoint){
                        log_error("AVDTP_SI_RECONFIGURE: stream endpoint is null");
                        break;
                    }
                    sep.configured_service_categories = avdtp_unpack_service_capabilities(connection, &sep.configuration, connection->signaling_packet.command+4, connection->signaling_packet.size-4);
                    // TODO check if configuration is supported
                    
                    remote_sep_index = avdtp_find_remote_sep(connection, sep.seid);
                    if (remote_sep_index != 0xFF){
                        stream_endpoint->remote_sep_index = remote_sep_index;
                        connection->remote_seps[stream_endpoint->remote_sep_index] = sep;
                        stream_endpoint->state = AVDTP_STREAM_ENDPOINT_CONFIGURED;
                        log_info("INT: update seid %d, to %p", connection->remote_seps[stream_endpoint->remote_sep_index].seid, stream_endpoint);
                    } 
                    break;

                case AVDTP_SI_SET_CONFIGURATION:{
                    if (!stream_endpoint){
                        log_error("AVDTP_SI_SET_CONFIGURATION: stream endpoint is null");
                        break;
                    }
                    sep.configured_service_categories = stream_endpoint->remote_capabilities_bitmap;
                    sep.configuration = stream_endpoint->remote_capabilities;
                    sep.in_use = 1;
                    // TODO check if configuration is supported
                    
                    // find or add sep
                    remote_sep_index = avdtp_find_remote_sep(connection, sep.seid);
                    if (remote_sep_index != 0xFF){
                        stream_endpoint->remote_sep_index = remote_sep_index;
                    } else {
                        stream_endpoint->remote_sep_index = connection->remote_seps_num;
                        connection->remote_seps_num++;
                    }
                    connection->remote_seps[stream_endpoint->remote_sep_index] = sep;
                    log_info("INT: configured remote seid %d, to %p", connection->remote_seps[stream_endpoint->remote_sep_index].seid, stream_endpoint);
                    stream_endpoint->state = AVDTP_STREAM_ENDPOINT_CONFIGURED;
                    break;
                }
                
                case AVDTP_SI_OPEN:
                    if (!stream_endpoint){
                        log_error("AVDTP_SI_OPEN: stream endpoint is null");
                        break;
                    }
                    if (stream_endpoint->state != AVDTP_STREAM_ENDPOINT_W2_REQUEST_OPEN_STREAM) {
                        log_error("AVDTP_SI_OPEN in wrong stream endpoint state");
                        return;
                    }
                    stream_endpoint->state = AVDTP_STREAM_ENDPOINT_W4_L2CAP_FOR_MEDIA_CONNECTED;
                    connection->local_seid = stream_endpoint->sep.seid;
                    l2cap_create_channel(context->packet_handler, connection->remote_addr, BLUETOOTH_PROTOCOL_AVDTP, 0xffff, NULL);
                    return;
                case AVDTP_SI_START:
                    if (!stream_endpoint){
                        log_error("AVDTP_SI_START: stream endpoint is null");
                        break;
                    }
                    if (stream_endpoint->state != AVDTP_STREAM_ENDPOINT_OPENED) {
                        log_error("AVDTP_SI_START in wrong stream endpoint state");
                        return;
                    }
                    stream_endpoint->state = AVDTP_STREAM_ENDPOINT_STREAMING;
                    break;
                case AVDTP_SI_SUSPEND:
                    if (!stream_endpoint){
                        log_error("AVDTP_SI_SUSPEND: stream endpoint is null");
                        break;
                    }
                    if (stream_endpoint->state != AVDTP_STREAM_ENDPOINT_STREAMING) {
                        log_error("AVDTP_SI_SUSPEND in wrong stream endpoint state");
                        return;
                    }
                    stream_endpoint->state = AVDTP_STREAM_ENDPOINT_OPENED;
                    break;
                case AVDTP_SI_CLOSE:
                    if (!stream_endpoint){
                        log_error("AVDTP_SI_CLOSE: stream endpoint is null");
                        break;
                    }
                    stream_endpoint->state = AVDTP_STREAM_ENDPOINT_CLOSING;
                    break;
                case AVDTP_SI_ABORT:
                    if (!stream_endpoint){
                        log_error("AVDTP_SI_ABORT: stream endpoint is null");
                        break;
                    }
                    stream_endpoint->state = AVDTP_STREAM_ENDPOINT_ABORTING;
                    break;
                default:
                    log_info("    AVDTP_RESPONSE_ACCEPT_MSG, signal %d not implemented", connection->signaling_packet.signal_identifier);
                    break;
            }
            avdtp_signaling_emit_accept(context->avdtp_callback, connection->avdtp_cid, 0, connection->signaling_packet.signal_identifier);
            connection->initiator_transaction_label++;
            break;
        case AVDTP_RESPONSE_REJECT_MSG:
            log_info("    AVDTP_RESPONSE_REJECT_MSG signal %d", connection->signaling_packet.signal_identifier);
            avdtp_signaling_emit_reject(context->avdtp_callback, connection->avdtp_cid, connection->local_seid, connection->signaling_packet.signal_identifier);
            return;
        case AVDTP_GENERAL_REJECT_MSG:
            log_info("    AVDTP_GENERAL_REJECT_MSG signal %d", connection->signaling_packet.signal_identifier);
            avdtp_signaling_emit_general_reject(context->avdtp_callback, connection->avdtp_cid, connection->local_seid, connection->signaling_packet.signal_identifier);
            return;
        default:
            break;
    }
}
Ejemplo n.º 5
0
/* LISTING_START(packetHandler): Packet Handler */
static void packet_handler (uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
{
    /* LISTING_PAUSE */
    uint8_t   event;
    bd_addr_t event_addr;
    uint8_t   status;
    uint16_t  l2cap_cid;

    /* LISTING_RESUME */
    switch (packet_type) {
		case HCI_EVENT_PACKET:
            event = hci_event_packet_get_type(packet);
            switch (event) {            
                /* @text When BTSTACK_EVENT_STATE with state HCI_STATE_WORKING
                 * is received and the example is started in client mode, the remote SDP HID query is started.
                 */
                case BTSTACK_EVENT_STATE:
                    if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING){
                        printf("Start SDP HID query for remote HID Device.\n");
                        sdp_client_query_uuid16(&handle_sdp_client_query_result, remote_addr, BLUETOOTH_SERVICE_CLASS_HUMAN_INTERFACE_DEVICE_SERVICE);
                    }
                    break;

                /* LISTING_PAUSE */
                case HCI_EVENT_PIN_CODE_REQUEST:
					// inform about pin code request
                    printf("Pin code request - using '0000'\n");
                    hci_event_pin_code_request_get_bd_addr(packet, event_addr);
                    gap_pin_code_response(event_addr, "0000");
					break;

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

                /* LISTING_RESUME */

                case L2CAP_EVENT_CHANNEL_OPENED: 
                    status = packet[2];
                    if (status){
                        printf("L2CAP Connection failed: 0x%02x\n", status);
                        break;
                    }
                    l2cap_cid  = little_endian_read_16(packet, 13);
                    if (!l2cap_cid) break;
                    if (l2cap_cid == l2cap_hid_control_cid){
                        status = l2cap_create_channel(packet_handler, remote_addr, hid_interrupt_psm, 48, &l2cap_hid_interrupt_cid);
                        if (status){
                            printf("Connecting to HID Control failed: 0x%02x\n", status);
                            break;
                        }
                    }                        
                    if (l2cap_cid == l2cap_hid_interrupt_cid){
                        printf("HID Connection established\n");
                    }
                    break;
                default:
                    break;
            }
            break;
        case L2CAP_DATA_PACKET:
            // for now, just dump incoming data
            if (channel == l2cap_hid_interrupt_cid){
                hid_host_handle_interrupt_report(packet,  size);
            } else if (channel == l2cap_hid_control_cid){
                printf("HID Control: ");
                printf_hexdump(packet, size);
            } else {
                break;
            }
        default:
            break;
    }
}
Ejemplo n.º 6
0
static void handle_sdp_client_query_result(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {

    UNUSED(packet_type);
    UNUSED(channel);
    UNUSED(size);

    des_iterator_t attribute_list_it;
    des_iterator_t additional_des_it;
    des_iterator_t prot_it;
    uint8_t       *des_element;
    uint8_t       *element;
    uint32_t       uuid;
    uint8_t        status;

    switch (hci_event_packet_get_type(packet)){
        case SDP_EVENT_QUERY_ATTRIBUTE_VALUE:
            if (sdp_event_query_attribute_byte_get_attribute_length(packet) <= attribute_value_buffer_size) {
                attribute_value[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet);
                if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) == sdp_event_query_attribute_byte_get_attribute_length(packet)) {
                    switch(sdp_event_query_attribute_byte_get_attribute_id(packet)) {
                        case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST:
                            for (des_iterator_init(&attribute_list_it, attribute_value); des_iterator_has_more(&attribute_list_it); des_iterator_next(&attribute_list_it)) {                                    
                                if (des_iterator_get_type(&attribute_list_it) != DE_DES) continue;
                                des_element = des_iterator_get_element(&attribute_list_it);
                                des_iterator_init(&prot_it, des_element);
                                element = des_iterator_get_element(&prot_it);
                                if (de_get_element_type(element) != DE_UUID) continue;
                                uuid = de_get_uuid32(element);
                                switch (uuid){
                                    case BLUETOOTH_PROTOCOL_L2CAP:
                                        if (!des_iterator_has_more(&prot_it)) continue;
                                        des_iterator_next(&prot_it);
                                        de_element_get_uint16(des_iterator_get_element(&prot_it), &hid_control_psm);
                                        printf("HID Control PSM: 0x%04x\n", (int) hid_control_psm);
                                        break;
                                    default:
                                        break;
                                }
                            }
                            break;
                        case BLUETOOTH_ATTRIBUTE_ADDITIONAL_PROTOCOL_DESCRIPTOR_LISTS:
                            for (des_iterator_init(&attribute_list_it, attribute_value); des_iterator_has_more(&attribute_list_it); des_iterator_next(&attribute_list_it)) {                                    
                                if (des_iterator_get_type(&attribute_list_it) != DE_DES) continue;
                                des_element = des_iterator_get_element(&attribute_list_it);
                                for (des_iterator_init(&additional_des_it, des_element); des_iterator_has_more(&additional_des_it); des_iterator_next(&additional_des_it)) {                                    
                                    if (des_iterator_get_type(&additional_des_it) != DE_DES) continue;
                                    des_element = des_iterator_get_element(&additional_des_it);
                                    des_iterator_init(&prot_it, des_element);
                                    element = des_iterator_get_element(&prot_it);
                                    if (de_get_element_type(element) != DE_UUID) continue;
                                    uuid = de_get_uuid32(element);
                                    switch (uuid){
                                        case BLUETOOTH_PROTOCOL_L2CAP:
                                            if (!des_iterator_has_more(&prot_it)) continue;
                                            des_iterator_next(&prot_it);
                                            de_element_get_uint16(des_iterator_get_element(&prot_it), &hid_interrupt_psm);
                                            printf("HID Interrupt PSM: 0x%04x\n", (int) hid_interrupt_psm);
                                            break;
                                        default:
                                            break;
                                    }
                                }
                            }
                            break;
                        case BLUETOOTH_ATTRIBUTE_HID_DESCRIPTOR_LIST:
                            for (des_iterator_init(&attribute_list_it, attribute_value); des_iterator_has_more(&attribute_list_it); des_iterator_next(&attribute_list_it)) {
                                if (des_iterator_get_type(&attribute_list_it) != DE_DES) continue;
                                des_element = des_iterator_get_element(&attribute_list_it);
                                for (des_iterator_init(&additional_des_it, des_element); des_iterator_has_more(&additional_des_it); des_iterator_next(&additional_des_it)) {                                    
                                    if (des_iterator_get_type(&additional_des_it) != DE_STRING) continue;
                                    element = des_iterator_get_element(&additional_des_it);
                                    const uint8_t * descriptor = de_get_string(element);
                                    hid_descriptor_len = de_get_data_size(element);
                                    memcpy(hid_descriptor, descriptor, hid_descriptor_len);
                                    printf("HID Descriptor:\n");
                                    printf_hexdump(hid_descriptor, hid_descriptor_len);
                                }
                            }                        
                            break;
                        default:
                            break;
                    }
                }
            } else {
                fprintf(stderr, "SDP attribute value buffer size exceeded: available %d, required %d\n", attribute_value_buffer_size, sdp_event_query_attribute_byte_get_attribute_length(packet));
            }
            break;
            
        case SDP_EVENT_QUERY_COMPLETE:
            if (!hid_control_psm) {
                printf("HID Control PSM missing\n");
                break;
            }
            if (!hid_interrupt_psm) {
                printf("HID Interrupt PSM missing\n");
                break;
            }
            printf("Setup HID\n");
            status = l2cap_create_channel(packet_handler, remote_addr, hid_control_psm, 48, &l2cap_hid_control_cid);
            if (status){
                printf("Connecting to HID Control failed: 0x%02x\n", status);
            }
            break;
    }
}