Example #1
0
void l2cap_signaling_handler_channel(l2cap_channel_t *channel, uint8_t *command){

    uint8_t  code       = command[L2CAP_SIGNALING_COMMAND_CODE_OFFSET];
    uint8_t  identifier = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET];
    uint16_t result = 0;
    
    log_info("L2CAP signaling handler code %u, state %u\n", code, channel->state);
    
    // handle DISCONNECT REQUESTS seperately
    if (code == DISCONNECTION_REQUEST){
        switch (channel->state){
            case L2CAP_STATE_CONFIG:
            case L2CAP_STATE_OPEN:
            case L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST:
            case L2CAP_STATE_WAIT_DISCONNECT:
                l2cap_handle_disconnect_request(channel, identifier);
                break;

            default:
                // ignore in other states
                break;
        }
        return;
    }
    
    // @STATEMACHINE(l2cap)
    switch (channel->state) {
            
        case L2CAP_STATE_WAIT_CONNECT_RSP:
            switch (code){
                case CONNECTION_RESPONSE:
                    result = READ_BT_16 (command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET+4);
                    switch (result) {
                        case 0:
                            // successful connection
                            channel->remote_cid = READ_BT_16(command, L2CAP_SIGNALING_COMMAND_DATA_OFFSET);
                            channel->state = L2CAP_STATE_CONFIG;
                            channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ);
                            break;
                        case 1:
                            // connection pending. get some coffee
                            break;
                        default:
                            // channel closed
                            channel->state = L2CAP_STATE_CLOSED;

                            // map l2cap connection response result to BTstack status enumeration
                            l2cap_emit_channel_opened(channel, L2CAP_CONNECTION_RESPONSE_RESULT_SUCCESSFUL + result);
                            
                            // drop link key if security block
                            if (L2CAP_CONNECTION_RESPONSE_RESULT_SUCCESSFUL + result == L2CAP_CONNECTION_RESPONSE_RESULT_REFUSED_SECURITY){
                                hci_drop_link_key_for_bd_addr(&channel->address);
                            }
                            
                            // discard channel
                            linked_list_remove(&l2cap_channels, (linked_item_t *) channel);
                            btstack_memory_l2cap_channel_free(channel);
                            break;
                    }
                    break;
                    
                default:
                    //@TODO: implement other signaling packets
                    break;
            }
            break;

        case L2CAP_STATE_CONFIG:
            switch (code) {
                case CONFIGURE_REQUEST:
                    channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_REQ);
                    channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP);
                    l2cap_signaling_handle_configure_request(channel, command);
                    break;
                case CONFIGURE_RESPONSE:
                    channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP);
                    break;
                default:
                    break;
            }
            if (l2cap_channel_ready_for_open(channel)){
                // for open:
                channel->state = L2CAP_STATE_OPEN;
                l2cap_emit_channel_opened(channel, 0);
                l2cap_emit_credits(channel, 1);
            }
            break;
            
        case L2CAP_STATE_WAIT_DISCONNECT:
            switch (code) {
                case DISCONNECTION_RESPONSE:
                    l2cap_finialize_channel_close(channel);
                    break;
                default:
                    //@TODO: implement other signaling packets
                    break;
            }
            break;
            
        case L2CAP_STATE_CLOSED:
            // @TODO handle incoming requests
            break;
            
        case L2CAP_STATE_OPEN:
            //@TODO: implement other signaling packets, e.g. re-configure
            break;
        default:
            break;
    }
    // log_info("new state %u\n", channel->state);
}
Example #2
0
File: hci.c Project: ajsb85/ioio
static void event_handler(uint8_t *packet, int size){
    bd_addr_t addr;
    uint8_t link_type;
    hci_con_handle_t handle;
    hci_connection_t * conn;
    int i;
        
    switch (packet[0]) {
                        
        case HCI_EVENT_COMMAND_COMPLETE:
            // get num cmd packets
            // log_info("HCI_EVENT_COMMAND_COMPLETE cmds old %u - new %u\n", hci_stack.num_cmd_packets, packet[2]);
            hci_stack.num_cmd_packets = packet[2];
            
            if (COMMAND_COMPLETE_EVENT(packet, hci_read_buffer_size)){
                // from offset 5
                // status 
                // "The HC_ACL_Data_Packet_Length return parameter will be used to determine the size of the L2CAP segments contained in ACL Data Packets"
                hci_stack.acl_data_packet_length = READ_BT_16(packet, 6);
                // ignore: SCO data packet len (8)
                hci_stack.total_num_acl_packets  = packet[9];
                // ignore: total num SCO packets
                if (hci_stack.state == HCI_STATE_INITIALIZING){
                    // determine usable ACL payload size
                    if (HCI_ACL_PAYLOAD_SIZE < hci_stack.acl_data_packet_length){
                        hci_stack.acl_data_packet_length = HCI_ACL_PAYLOAD_SIZE;
                    }
                    // determine usable ACL packet types
                    hci_stack.packet_types = hci_acl_packet_types_for_buffer_size(hci_stack.acl_data_packet_length);
                    
                    log_error("hci_read_buffer_size: used size %u, count %u, packet types %04x\n",
                             hci_stack.acl_data_packet_length, hci_stack.total_num_acl_packets, hci_stack.packet_types); 
                }
            }
            if (COMMAND_COMPLETE_EVENT(packet, hci_write_scan_enable)){
                hci_emit_discoverable_enabled(hci_stack.discoverable);
            }
            break;
            
        case HCI_EVENT_COMMAND_STATUS:
            // get num cmd packets
            // log_info("HCI_EVENT_COMMAND_STATUS cmds - old %u - new %u\n", hci_stack.num_cmd_packets, packet[3]);
            hci_stack.num_cmd_packets = packet[3];
            break;
            
        case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS:
            for (i=0; i<packet[2];i++){
                handle = READ_BT_16(packet, 3 + 2*i);
                uint16_t num_packets = READ_BT_16(packet, 3 + packet[2]*2 + 2*i);
                conn = connection_for_handle(handle);
                if (!conn){
                    log_error("hci_number_completed_packet lists unused con handle %u\n", handle);
                    continue;
                }
                conn->num_acl_packets_sent -= num_packets;
                // log_info("hci_number_completed_packet %u processed for handle %u, outstanding %u\n", num_packets, handle, conn->num_acl_packets_sent);
            }
            break;
            
        case HCI_EVENT_CONNECTION_REQUEST:
            bt_flip_addr(addr, &packet[2]);
            // TODO: eval COD 8-10
            link_type = packet[11];
            log_info("Connection_incoming: %s, type %u\n", bd_addr_to_str(addr), link_type);
            if (link_type == 1) { // ACL
                conn = connection_for_address(addr);
                if (!conn) {
                    conn = create_connection_for_addr(addr);
                }
                if (!conn) {
                    // CONNECTION REJECTED DUE TO LIMITED RESOURCES (0X0D)
                    hci_stack.decline_reason = 0x0d;
                    BD_ADDR_COPY(hci_stack.decline_addr, addr);
                    break;
                }
                conn->state = RECEIVED_CONNECTION_REQUEST;
                hci_run();
            } else {
                // SYNCHRONOUS CONNECTION LIMIT TO A DEVICE EXCEEDED (0X0A)
                hci_stack.decline_reason = 0x0a;
                BD_ADDR_COPY(hci_stack.decline_addr, addr);
            }
            break;
            
        case HCI_EVENT_CONNECTION_COMPLETE:
            // Connection management
            bt_flip_addr(addr, &packet[5]);
            log_info("Connection_complete (status=%u) %s\n", packet[2], bd_addr_to_str(addr));
            conn = connection_for_address(addr);
            if (conn) {
                if (!packet[2]){
                    conn->state = OPEN;
                    conn->con_handle = READ_BT_16(packet, 3);

#ifdef HAVE_TICK
                    // restart timer
                    run_loop_set_timer(&conn->timeout, HCI_CONNECTION_TIMEOUT_MS);
                    run_loop_add_timer(&conn->timeout);
#endif
                    
                    log_info("New connection: handle %u, %s\n", conn->con_handle, bd_addr_to_str(conn->address));
                    
                    hci_emit_nr_connections_changed();
                } else {
                    // connection failed, remove entry
                    linked_list_remove(&hci_stack.connections, (linked_item_t *) conn);
                    btstack_memory_hci_connection_free( conn );
                    
                    // if authentication error, also delete link key
                    if (packet[2] == 0x05) {
                        hci_drop_link_key_for_bd_addr(&addr);
                    }
                }
            }
            break;

        case HCI_EVENT_LINK_KEY_REQUEST:
            log_info("HCI_EVENT_LINK_KEY_REQUEST\n");
            hci_add_connection_flags_for_flipped_bd_addr(&packet[2], RECV_LINK_KEY_REQUEST);
            if (!hci_stack.remote_device_db) break;
            hci_add_connection_flags_for_flipped_bd_addr(&packet[2], HANDLE_LINK_KEY_REQUEST);
            hci_run();
            // request already answered
            return;
            
        case HCI_EVENT_LINK_KEY_NOTIFICATION:
            hci_add_connection_flags_for_flipped_bd_addr(&packet[2], RECV_LINK_KEY_NOTIFICATION);
            if (!hci_stack.remote_device_db) break;
            bt_flip_addr(addr, &packet[2]);
            hci_stack.remote_device_db->put_link_key(&addr, (link_key_t *) &packet[8]);
            // still forward event to allow dismiss of pairing dialog
            break;
            
        case HCI_EVENT_PIN_CODE_REQUEST:
            hci_add_connection_flags_for_flipped_bd_addr(&packet[2], RECV_PIN_CODE_REQUEST);
            break;
            
#ifndef EMBEDDED
        case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE:
            if (!hci_stack.remote_device_db) break;
            if (packet[2]) break; // status not ok
            bt_flip_addr(addr, &packet[3]);
            // fix for invalid remote names - terminate on 0xff
            for (i=0; i<248;i++){
                if (packet[9+i] == 0xff){
                    packet[9+i] = 0;
                    break;
                }
            }
            memset(&device_name, 0, sizeof(device_name_t));
            strncpy((char*) device_name, (char*) &packet[9], 248);
            hci_stack.remote_device_db->put_name(&addr, &device_name);
            break;
            
        case HCI_EVENT_INQUIRY_RESULT:
        case HCI_EVENT_INQUIRY_RESULT_WITH_RSSI:
            if (!hci_stack.remote_device_db) break;
            // first send inq result packet
            hci_stack.packet_handler(HCI_EVENT_PACKET, packet, size);
            // then send cached remote names
            for (i=0; i<packet[2];i++){
                bt_flip_addr(addr, &packet[3+i*6]);
                if (hci_stack.remote_device_db->get_name(&addr, &device_name)){
                    hci_emit_remote_name_cached(&addr, &device_name);
                }
            }
            return;
#endif
            
        case HCI_EVENT_DISCONNECTION_COMPLETE:
            if (!packet[2]){
                handle = READ_BT_16(packet, 3);
                hci_connection_t * conn = connection_for_handle(handle);
                if (conn) {
                    hci_shutdown_connection(conn);
                }
            }
            break;
            
        case HCI_EVENT_HARDWARE_ERROR:
            if(hci_stack.control->hw_error){
                (*hci_stack.control->hw_error)();
            }
            break;

#ifdef HAVE_BLE
        case HCI_EVENT_LE_META:
            switch (packet[2]) {
                case HCI_SUBEVENT_LE_CONNECTION_COMPLETE:
                    // Connection management
                    bt_flip_addr(addr, &packet[8]);
                    log_info("LE Connection_complete (status=%u) %s\n", packet[3], bd_addr_to_str(addr));
                    // LE connections are auto-accepted, so just create a connection if there isn't one already
                    conn = connection_for_address(addr);
                    if (packet[3]){
                        if (conn){
                            // outgoing connection failed, remove entry
                            linked_list_remove(&hci_stack.connections, (linked_item_t *) conn);
                            btstack_memory_hci_connection_free( conn );
                        }
                        // if authentication error, also delete link key
                        if (packet[3] == 0x05) {
                            hci_drop_link_key_for_bd_addr(&addr);
                        }
                        break;
                    }
                    if (!conn){
                        conn = create_connection_for_addr(addr);
                    }
                    if (!conn){
                        // no memory
                        break;
                    }

                    conn->state = OPEN;
                    conn->con_handle = READ_BT_16(packet, 4);

                    // TODO: store - role, peer address type, conn_interval, conn_latency, supervision timeout, master clock
                    // restart timer
                    // run_loop_set_timer(&conn->timeout, HCI_CONNECTION_TIMEOUT_MS);
                    // run_loop_add_timer(&conn->timeout);

                    log_info("New connection: handle %u, %s\n", conn->con_handle, bd_addr_to_str(conn->address));

                    hci_emit_nr_connections_changed();
                    break;

        default:
            break;
    }
            break;
#endif

        default:
            break;
    }

    // handle BT initialization
    if (hci_stack.state == HCI_STATE_INITIALIZING){
        // handle H4 synchronization loss on restart
        // if (hci_stack.substate == 1 && packet[0] == HCI_EVENT_HARDWARE_ERROR){
        //    hci_stack.substate = 0;
        // }
        // handle normal init sequence
        if (hci_stack.substate % 2){
            // odd: waiting for event
            if (packet[0] == HCI_EVENT_COMMAND_COMPLETE){
                hci_stack.substate++;
            }
        }
    }
    
    // help with BT sleep
    if (hci_stack.state == HCI_STATE_FALLING_ASLEEP
        && hci_stack.substate == 1
        && COMMAND_COMPLETE_EVENT(packet, hci_write_scan_enable)){
        hci_stack.substate++;
    }
    
    hci_stack.packet_handler(HCI_EVENT_PACKET, packet, size);
	
    // execute main loop
    hci_run();
}
Example #3
0
int  stdin_process(struct data_source *ds){
    char buffer;
    read(ds->fd, &buffer, 1);

    // passkey input
    if (ui_digits_for_passkey){
        if (buffer < '0' || buffer > '9') return 0;
        printf("%c", buffer);
        fflush(stdout);
        ui_passkey = ui_passkey * 10 + buffer - '0';
        ui_digits_for_passkey--;
        if (ui_digits_for_passkey == 0){
            printf("\nSending Passkey '%06u'\n", ui_passkey);
            hci_send_cmd(&hci_user_passkey_request_reply, remote, ui_passkey);
        }
        return 0;
    }
    if (ui_chars_for_pin){
        printf("%c", buffer);
        fflush(stdout);
        if (buffer == '\n'){
            printf("\nSending Pin '%s'\n", ui_pin);
            hci_send_cmd(&hci_pin_code_request_reply, remote, ui_pin_offset, ui_pin);
        } else {
            ui_pin[ui_pin_offset++] = buffer;
        }
        return 0;
    }

    switch (buffer){
        case 'c':
            gap_connectable = 0;
            hci_connectable_control(0);
            show_usage();
            break;
        case 'C':
            gap_connectable = 1;
            hci_connectable_control(1);
            show_usage();
            break;
        case 'd':
            gap_discoverable = 0;
            hci_discoverable_control(0);
            show_usage();
            break;
        case 'D':
            gap_discoverable = 1;
            hci_discoverable_control(1);
            show_usage();
            break;
        case 'b':
            gap_bondable = 0;
            // gap_set_bondable_mode(0);
            update_auth_req();
            show_usage();
            break;
        case 'B':
            gap_bondable = 1;
            // gap_set_bondable_mode(1);
            update_auth_req();
            show_usage();
            break;
        case 'm':
            gap_mitm_protection = 0;
            update_auth_req();
            show_usage();
            break;
        case 'M':
            gap_mitm_protection = 1;
            update_auth_req();
            show_usage();
            break;

        case '<':
            gap_dedicated_bonding_mode = 0;
            update_auth_req();
            show_usage();
            break;
        case '>':
            gap_dedicated_bonding_mode = 1;
            update_auth_req();
            show_usage();
            break;

        case 'e':
            gap_io_capabilities = "IO_CAPABILITY_DISPLAY_ONLY";
            hci_ssp_set_io_capability(IO_CAPABILITY_DISPLAY_ONLY);
            show_usage();
            break;
        case 'f':
            gap_io_capabilities = "IO_CAPABILITY_DISPLAY_YES_NO";
            hci_ssp_set_io_capability(IO_CAPABILITY_DISPLAY_YES_NO);
            show_usage();
            break;
        case 'g':
            gap_io_capabilities = "IO_CAPABILITY_NO_INPUT_NO_OUTPUT";
            hci_ssp_set_io_capability(IO_CAPABILITY_NO_INPUT_NO_OUTPUT);
            show_usage();
            break;
        case 'h':
            gap_io_capabilities = "IO_CAPABILITY_KEYBOARD_ONLY";
            hci_ssp_set_io_capability(IO_CAPABILITY_KEYBOARD_ONLY);
            show_usage();
            break;

        case 'i':
            start_scan();
            break;

        case 'j':
            printf("Start dedicated bonding to %s using MITM %u\n", bd_addr_to_str(remote), gap_mitm_protection);
            gap_dedicated_bonding(remote, gap_mitm_protection);
            break;

        case 'z':
            printf("Start dedicated bonding to %s using legacy pairing\n", bd_addr_to_str(remote));
            gap_dedicated_bonding(remote, gap_mitm_protection);
            break;

        case 'y':
            printf("Disabling SSP for this session\n");
            hci_send_cmd(&hci_write_simple_pairing_mode, 0);
            break;

        case 'k':
            printf("Start SDP query for SPP service\n");
            sdp_query_rfcomm_channel_and_name_for_uuid(remote_rfcomm, 0x1101);
            break;

        case 't':
            printf("Terminate connection with handle 0x%04x\n", handle);
            hci_send_cmd(&hci_disconnect, handle, 0x13);  // remote closed connection
            break;

        case 'p':
            printf("Creating HCI Connection to %s\n", bd_addr_to_str(remote));
            hci_send_cmd(&hci_create_connection, remote, hci_usable_acl_packet_types(), 0, 0, 0, 1);
            break;
            // printf("Creating L2CAP Connection to %s, PSM SDP\n", bd_addr_to_str(remote));
            // l2cap_create_channel_internal(NULL, packet_handler, remote, PSM_SDP, 100);
            // break;
        // case 'u':
        //     printf("Creating L2CAP Connection to %s, PSM 3\n", bd_addr_to_str(remote));
        //     l2cap_create_channel_internal(NULL, packet_handler, remote, 3, 100);
        //     break;
        case 'q':
            printf("Send L2CAP Data\n");
            l2cap_send_internal(local_cid, (uint8_t *) "0123456789", 10);
       break;
        case 'r':
            printf("Send L2CAP ECHO Request\n");
            l2cap_send_echo_request(handle, (uint8_t *)  "Hello World!", 13);
            break;
        case 's':
            printf("L2CAP Channel Closed\n");
            l2cap_disconnect_internal(local_cid, 0);
            break;
        case 'x':
            printf("Outgoing L2CAP Channels to SDP will also require SSP\n");
            l2cap_require_security_level_2_for_outgoing_sdp();
            break;

        case 'l':
            printf("Creating RFCOMM Channel to %s #%u\n", bd_addr_to_str(remote_rfcomm), rfcomm_channel_nr);
             rfcomm_create_channel_internal(NULL, remote_rfcomm, rfcomm_channel_nr);
            break;
        case 'n':
            printf("Send RFCOMM Data\n");   // mtu < 60 
            rfcomm_send_internal(rfcomm_channel_id, (uint8_t *) "012345678901234567890123456789012345678901234567890123456789", mtu);
            break;
        case 'u':
            printf("Sending RLS indicating framing error\n");   // mtu < 60 
            rfcomm_send_local_line_status(rfcomm_channel_id, 9);
            break;
        case 'v':
            printf("Sending RPN CMD to select 115200 baud\n");   // mtu < 60 
            rfcomm_send_port_configuration(rfcomm_channel_id, RPN_BAUD_115200, RPN_DATA_BITS_8, RPN_STOP_BITS_1_0, RPN_PARITY_NONE, 0);
            break;
        case 'w':
            printf("Sending RPN REQ to query remote port settings\n");   // mtu < 60 
            rfcomm_query_port_configuration(rfcomm_channel_id);
            break;
        case 'o':
            printf("RFCOMM Channel Closed\n");
            rfcomm_disconnect_internal(rfcomm_channel_id);
            rfcomm_channel_id = 0;
            break;

        case '+':
            printf("Initiate SSP on current connection\n");
            gap_request_security_level(handle, LEVEL_2);
            break;

        case '*':
            printf("Sending SSP User Confirmation for %s\n", bd_addr_to_str(remote));
            hci_send_cmd(&hci_user_confirmation_request_reply, remote);
            break;

        case '=':
            printf("Deleting Link Key for %s\n", bd_addr_to_str(remote));
            hci_drop_link_key_for_bd_addr(remote);
            break;

        case 'U':
            printf("Sending UCD data on handle 0x%04x\n", handle);
            send_ucd_packet();
            break;

        case 'Q':
            printf("Closing HCI Connection to handle 0x%04x\n", handle);
            gap_disconnect(handle);
            break;

        default:
            show_usage();
            break;

    }
    return 0;
}