diff --git a/TODO.txt b/TODO.txt index 2c54ca240..5229a30a8 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,20 +1,20 @@ /* new todo file for BTstack */ +UNTIL 13. August 2009 : Google Open Source Jam +- implement L2CAP state machine +- decide on naming conventions for various layers +- provide demos: + - BT Scanner: module info, inquiry, remote name + - Terminal app with L2CAP support - Python or Java PC demo + - evtl. SDP browser + - evtl. RFCOMM to BT GPS + NEXT: -- implement client BT API in btstack.h: prefix all functions by bt_$PROTOCOL_* - - client/server part using unix domain sockets (portable and fast) -- generalize run_loop_add/remove into linked_list_add/remove +- client/server part using unix domain sockets (portable and fast) +- implement RFCOMM +- implement - use linked_list for: - - run loop - event handler - data handler -- keep track of HCI state (links, inquiries, acl flow control) in linked list -- implement L2CAP state machine - implement PAN - -IMPROVE -- make data_source_t opaque: data_source_set_fd, data_source_set_cb -- implement TimerSource - implement some kind of noitfy mechanism between multiple units -- support better handling of multiple parallel socket connections? - - callback to announce new connection, allow to store local context pointer diff --git a/aclocal.m4 b/aclocal.m4 index 6cccc51f2..1306e82d9 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1,4 +1,4 @@ -# generated automatically by aclocal 1.10.2 -*- Autoconf -*- +# generated automatically by aclocal 1.10.1 -*- Autoconf -*- # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, # 2005, 2006, 2007, 2008 Free Software Foundation, Inc. @@ -13,7 +13,7 @@ m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl -m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.63],, +m4_if(AC_AUTOCONF_VERSION, [2.63],, [m4_warning([this file was generated for autoconf 2.63. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. @@ -175,7 +175,7 @@ else fi[]dnl ])# PKG_CHECK_MODULES -# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# Copyright (C) 2002, 2003, 2005, 2006, 2007 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, @@ -190,7 +190,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.10' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. -m4_if([$1], [1.10.2], [], +m4_if([$1], [1.10.1], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) @@ -204,12 +204,12 @@ m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. -# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +# This function is AC_REQUIREd by AC_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], -[AM_AUTOMAKE_VERSION([1.10.2])dnl +[AM_AUTOMAKE_VERSION([1.10.1])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl -_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) +_AM_AUTOCONF_VERSION(AC_AUTOCONF_VERSION)]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- @@ -459,28 +459,19 @@ _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl # Generate code to set up dependency tracking. -*- Autoconf -*- -# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 # Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. -#serial 4 +#serial 3 # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], -[# Autoconf 2.62 quotes --file arguments for eval, but not when files -# are listed without --file. Let's play safe and only enable the eval -# if we detect the quoting. -case $CONFIG_FILES in -*\'*) eval set x "$CONFIG_FILES" ;; -*) set x $CONFIG_FILES ;; -esac -shift -for mf -do +[for mf in $CONFIG_FILES; do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. @@ -812,13 +803,13 @@ esac # Helper functions for option handling. -*- Autoconf -*- -# Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc. +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. -# serial 4 +# serial 3 # _AM_MANGLE_OPTION(NAME) # ----------------------- @@ -835,7 +826,7 @@ AC_DEFUN([_AM_SET_OPTION], # ---------------------------------- # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], -[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) +[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- diff --git a/example/test.c b/example/test.c index 832880c39..59aeb5ac3 100644 --- a/example/test.c +++ b/example/test.c @@ -10,199 +10,59 @@ #include #include "../src/btstack.h" -#include "../src/linked_list.h" #include "../src/run_loop.h" -#include "../src/socket_connection.h" #include "../src/hci.h" #include "../src/l2cap.h" hci_con_handle_t con_handle_out = 0; -hci_con_handle_t con_handle_in = 0; uint16_t dest_cid; uint16_t local_cid; -#define BT_HID -// #define POWER_CYCLE_TEST -// #define MITM +void acl_handler(uint8_t *packet, uint16_t size){ + // just dump data + hexdump( packet, size ); +} - -void event_handler(uint8_t *packet, int size){ +void event_handler(uint8_t *packet, uint16_t size){ // printf("Event type: %x, opcode: %x, other %x\n", packet[0], packet[3] | packet[4] << 8); -#if defined(BT_HID) || defined(MITM) bd_addr_t addr = {0x00, 0x03, 0xc9, 0x3d, 0x77, 0x43 }; // Think Outside Keyboard // bt stack activated, get started if (packet[0] == HCI_EVENT_BTSTACK_WORKING || (packet[0] == HCI_EVENT_BTSTACK_STATE && packet[2] == HCI_STATE_WORKING)) { - bt_send_cmd(&hci_write_class_of_device, 0x7A020C); // used on iPhone - } - - if ( COMMAND_COMPLETE_EVENT(packet, hci_write_class_of_device) ) { - bt_send_cmd(&hci_write_local_name, "BT in the Middle"); + bt_send_cmd(&hci_write_local_name, "BTstack-Test"); } + // set local name if ( COMMAND_COMPLETE_EVENT(packet, hci_write_local_name) ) { -#if 1 bt_send_cmd(&hci_write_authentication_enable, 1); } + + // use pairing if ( COMMAND_COMPLETE_EVENT(packet, hci_write_authentication_enable) ) { -#endif -#if 0 bt_send_cmd(&hci_write_inquiry_mode, 2); } + + // inform about pin code request + if (packet[0] == HCI_EVENT_PIN_CODE_REQUEST){ + printf("Please enter PIN 1234 on remote device\n"); + } + + // connect to device at addr if ( COMMAND_COMPLETE_EVENT(packet, hci_write_inquiry_mode) ) { -#endif -#if 0 - bt_send_cmd(&hci_set_event_mask, 0xffffffff, 0x1fffffff); - } - - uint8_t eir[] = { - 0x0d, 0x09, 0x4d, 0x69, 0x6c, 0x61, 0x73, 0x20, 0x69, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x0f, 0x02, - 0x00, 0x12, 0x1f, 0x11, 0x07, 0x11, 0x2f, 0x11, 0x0a, 0x11, 0x16, 0x11, 0x15, 0x11, 0x27, 0xff, - 0x00, 0x4c, 0x02, 0x24, 0x02, 0x86, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - }; - if ( COMMAND_COMPLETE_EVENT(packet, hci_set_event_mask) ) { -#endif -#if 0 - bt_send_cmd(&hci_write_extended_inquiry_response, 0, eir); - } - if ( COMMAND_COMPLETE_EVENT(packet, hci_write_extended_inquiry_response) ) { -#endif -#if 0 - bt_send_cmd(&hci_write_simple_pairing_mode, 1); - } - if ( COMMAND_COMPLETE_EVENT(packet, hci_write_simple_pairing_mode) ) { -#endif -#if 0 - bt_send_cmd(&hci_inquiry, HCI_INQUIRY_LAP, 15, 0); - } - if (packet[0] == HCI_EVENT_INQUIRY_COMPLETE) -#endif -#if 1 - bt_send_cmd(&hci_create_connection, &addr, 0x18, 0, 0, 0, 0); -#endif -} -if (packet[0] == HCI_EVENT_CONNECTION_REQUEST){ - bt_flip_addr(addr, &packet[2]); - bt_send_cmd(&hci_accept_connection_request, &addr, 1); + l2cap_create_channel(addr, 0x13, event_handler, acl_handler); + } + + if (packet[0] == HCI_EVENT_L2CAP_CHANNEL_OPENED){ + printf("Channel successfully opened, handle 0x%02x, local cid 0x%02x\n", READ_BT_16(packet, 2), READ_BT_16(packet, 4));; + } } -if (packet[0] == HCI_EVENT_PIN_CODE_REQUEST){ - printf("Please enter PIN 1234 on remote device\n"); -} - -// connection established -> start L2CAP conection -if (packet[0] == HCI_EVENT_CONNECTION_COMPLETE){ - if (packet[2] == 0){ - // get new connection handle - if (! con_handle_out) { - con_handle_out = READ_BT_16(packet, 3); - } else { - con_handle_in = READ_BT_16(packet, 3); - } -#ifndef MITM - // request l2cap connection - printf("> CONNECTION REQUEST\n"); - local_cid = l2cap_next_local_cid(); - bt_send_l2cap_signaling_packet(con_handle_out, CONNECTION_REQUEST, l2cap_next_sig_id(), 0x13, local_cid); -#else - printf("Connected to target device, please start!\n"); -#endif - - } -} -#endif - -#ifdef POWER_CYCLE_TEST -if (packet[0] == HCI_EVENT_BTSTACK_WORKING) { - bt_send_cmd(&hci_inquiry, HCI_INQUIRY_LAP, 10, 0); -} -if (packet[0] == HCI_EVENT_INQUIRY_COMPLETE){ - // power cycle - hci_power_control( HCI_POWER_OFF ); - // - printf ("Power off!\n"); - sleep(10); - printf ("Restart!\n"); - hci_power_control( HCI_POWER_ON ); -} -#endif -} - -void acl_handler(uint8_t *packet, int size){ - -#ifdef MITM - // forward packet on "other" connection - hci_con_handle_t incoming_hdl = READ_BT_16(packet, 0) & 0xfff; - hci_con_handle_t outgoing_hdl = 0; -#if 0 - if (incoming_hdl == con_handle_in){ - outgoing_hdl = con_handle_out; - } else if (incoming_hdl == con_handle_out){ - outgoing_hdl = con_handle_in; - } else { - printf("Incoming acl packet on handle %u\n!", incoming_hdl); - } -#else - outgoing_hdl = incoming_hdl; -#endif - if (outgoing_hdl){ - bt_store_16( packet, 0, (READ_BT_16(packet, 0) & 0xf000) | outgoing_hdl); - bt_send_acl_packet(packet, size); - } - -#else - uint16_t source_cid; - uint16_t result; - uint8_t config_options[] = { 1, 2, 150, 0}; // mtu = 48 - // connection response - if (packet[8] == CONNECTION_RESPONSE){ - dest_cid = READ_BT_16(packet, 12); - source_cid = READ_BT_16(packet, 14); - result = READ_BT_16(packet, 16); - uint16_t status = READ_BT_16(packet, 18); - printf("< CONNECTION_RESPONSE: id %u, dest cid %u, src cid %u, result %u, status %u\n", packet[9], dest_cid, source_cid, result, status); - if (result == 0){ - // printf("> CONFIGURE_REQUEST: id %u\n", sig_seq_nr); - bt_send_l2cap_signaling_packet(con_handle_out, CONFIGURE_REQUEST, l2cap_next_sig_id(), dest_cid, 0, 4, &config_options); - } - } - else if (packet[8] == CONFIGURE_RESPONSE){ - source_cid = READ_BT_16(packet, 12); - uint16_t flags = READ_BT_16(packet, 14); - result = READ_BT_16(packet, 16); - printf("< CONFIGURE_RESPONSE: id %u, src cid %u, flags %u, result %u!!!\n", packet[9], source_cid, flags, result); - hexdump(&packet[18], size-18); - } - else if (packet[8] == CONFIGURE_REQUEST){ - printf("< CONFIGURE_REQUEST: id %u\n", packet[9]); - hexdump(&packet[16], size-16); - printf("> CONFIGURE_RESPONSE: id %u\n", packet[9]); - bt_send_l2cap_signaling_packet(con_handle_out, CONFIGURE_RESPONSE, packet[9], local_cid, 0, 0, size - 16, &packet[16]); - } - else { - printf("Unknown ACL ^^^ \n"); - } -#endif -} int main (int argc, const char * argv[]){ bt_open(); bt_register_event_packet_handler(event_handler); - bt_register_acl_packet_handler (acl_handler); bt_send_cmd(&hci_set_power_mode, HCI_POWER_ON ); run_loop_execute(); bt_close(); diff --git a/project.xcodeproj/project.pbxproj b/project.xcodeproj/project.pbxproj index 987d42d95..1c0250a39 100644 --- a/project.xcodeproj/project.pbxproj +++ b/project.xcodeproj/project.pbxproj @@ -14,9 +14,9 @@ 9C00F86510191097008DAB17 /* utils.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C00F86210191097008DAB17 /* utils.c */; }; 9C00F87310191130008DAB17 /* l2cap_signaling.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C00F87210191130008DAB17 /* l2cap_signaling.c */; }; 9C00F87410191130008DAB17 /* l2cap_signaling.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C00F87210191130008DAB17 /* l2cap_signaling.c */; }; + 9C05FC971020D3F300255261 /* socket_connection.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C00F7301017ACC3008DAB17 /* socket_connection.c */; }; 9C1F0E9A0FDAE023008F472F /* run_loop.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C1F0E980FDAE023008F472F /* run_loop.c */; }; 9C2071F310014D3200A07EA4 /* hci_transport_usb.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C2071F210014D3200A07EA4 /* hci_transport_usb.c */; }; - 9C20720F10025E0500A07EA4 /* libusb-1.0.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 9C20720E10025E0500A07EA4 /* libusb-1.0.dylib */; }; 9C46FC390FA906F700ABEF05 /* hci.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C46FC340FA906F700ABEF05 /* hci.c */; }; 9C46FC3A0FA906F700ABEF05 /* hci_transport_h4.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C46FC360FA906F700ABEF05 /* hci_transport_h4.c */; }; 9C7B5AC0100BD3340065D87E /* linked_list.c in Sources */ = {isa = PBXBuildFile; fileRef = 9C7B5ABF100BD3340065D87E /* linked_list.c */; }; @@ -60,7 +60,6 @@ 9C1F0E980FDAE023008F472F /* run_loop.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; name = run_loop.c; path = src/run_loop.c; sourceTree = ""; }; 9C1F0E990FDAE023008F472F /* run_loop.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; name = run_loop.h; path = src/run_loop.h; sourceTree = ""; }; 9C2071F210014D3200A07EA4 /* hci_transport_usb.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; name = hci_transport_usb.c; path = src/hci_transport_usb.c; sourceTree = ""; }; - 9C20720E10025E0500A07EA4 /* libusb-1.0.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = "libusb-1.0.dylib"; path = "/usr/local/lib/libusb-1.0.dylib"; sourceTree = ""; }; 9C46FC340FA906F700ABEF05 /* hci.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; name = hci.c; path = src/hci.c; sourceTree = ""; }; 9C46FC350FA906F700ABEF05 /* hci.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; name = hci.h; path = src/hci.h; sourceTree = ""; }; 9C46FC360FA906F700ABEF05 /* hci_transport_h4.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; name = hci_transport_h4.c; path = src/hci_transport_h4.c; sourceTree = ""; }; @@ -90,7 +89,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9C20720F10025E0500A07EA4 /* libusb-1.0.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -113,7 +111,6 @@ 1AB674ADFE9D54B511CA2CBB /* Products */, 9CC152C61009052100223347 /* config.h */, 9CA3C0900FB8B3C4005F48DE /* TODO.txt */, - 9C20720E10025E0500A07EA4 /* libusb-1.0.dylib */, ); name = project; sourceTree = ""; @@ -271,6 +268,7 @@ 9C00F7D81019082F008DAB17 /* hci_cmds.c in Sources */, 9C00F86410191097008DAB17 /* utils.c in Sources */, 9C00F87310191130008DAB17 /* l2cap_signaling.c in Sources */, + 9C05FC971020D3F300255261 /* socket_connection.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/src/btstack.c b/src/btstack.c index f3c25cd1a..ac620def5 100644 --- a/src/btstack.c +++ b/src/btstack.c @@ -26,12 +26,12 @@ static connection_t *btstack_connection = NULL; static linked_list_t l2cap_channels = NULL; /** prototypes */ -static void dummy_handler(uint8_t *packet, int size); +static void dummy_handler(uint8_t *packet, uint16_t size); int btstack_packet_handler(connection_t *connection, uint8_t packet_type, uint8_t *data, uint16_t size); /* callback to L2CAP layer */ -static void (*event_packet_handler)(uint8_t *packet, int size) = dummy_handler; -static void (*acl_packet_handler) (uint8_t *packet, int size) = dummy_handler; +static void (*event_packet_handler)(uint8_t *packet, uint16_t size) = dummy_handler; +static void (*acl_packet_handler) (uint8_t *packet, uint16_t size) = dummy_handler; // init BTstack library int bt_open(){ @@ -52,18 +52,21 @@ int bt_close(){ void l2cap_event_handler( uint8_t *packet, uint16_t size ){ // handle connection complete events if (packet[0] == HCI_EVENT_CONNECTION_COMPLETE && packet[2] == 0){ - linked_item_t *it; bd_addr_t address; bt_flip_addr(address, &packet[5]); + + linked_item_t *it; for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){ l2cap_channel_t * chan = (l2cap_channel_t *) it; if ( ! BD_ADDR_CMP( chan->address, address) ){ if (chan->state == L2CAP_STATE_CLOSED) { - chan->state = L2CAP_STATE_CONNECTED; chan->handle = READ_BT_16(packet, 3); chan->sig_id = l2cap_next_sig_id(); chan->local_cid = l2cap_next_local_cid(); + bt_send_l2cap_signaling_packet( chan->handle, CONNECTION_REQUEST, chan->sig_id, chan->psm, chan->local_cid); + + chan->state = L2CAP_STATE_WAIT_CONNECT_RSP; } } } @@ -71,20 +74,94 @@ void l2cap_event_handler( uint8_t *packet, uint16_t size ){ // handle disconnection complete events // TODO ... } -void l2cap_data_handler( uint8_t *packet, uint16_t size ){ - // Get Channel ID +void l2cap_signaling_handler(l2cap_channel_t *channel, uint8_t *packet, uint16_t size){ + + static uint8_t config_options[] = { 1, 2, 150, 0}; // mtu = 48 + + uint8_t code = READ_L2CAP_SIGNALING_CODE( packet ); + uint8_t identifier = READ_L2CAP_SIGNALING_IDENTIFIER( packet ); + + switch (channel->state) { + + case L2CAP_STATE_WAIT_CONNECT_RSP: + switch (code){ + case CONNECTION_RESPONSE: + if ( READ_BT_16 (packet, L2CAP_SIGNALING_DATA_OFFSET+3) == 0){ + // successfull connection + channel->dest_cid = READ_BT_16(packet, L2CAP_SIGNALING_DATA_OFFSET + 0); + channel->sig_id = l2cap_next_sig_id(); + bt_send_l2cap_signaling_packet(channel->handle, CONFIGURE_REQUEST, channel->sig_id, channel->dest_cid, 0, 4, &config_options); + channel->state = L2CAP_STATE_WAIT_CONFIG_REQ_RSP; + } else { + // TODO implement failed + } + break; + // TODO implement other signaling packets + } + break; + + case L2CAP_STATE_WAIT_CONFIG_REQ_RSP: + switch (code) { + case CONFIGURE_RESPONSE: + channel->state = L2CAP_STATE_WAIT_CONFIG_REQ; + break; + } + break; + + case L2CAP_STATE_WAIT_CONFIG_REQ: + switch (code) { + case CONFIGURE_REQUEST: + + // accept the other's configuration options + bt_send_l2cap_signaling_packet(channel->handle, CONFIGURE_RESPONSE, identifier, channel->dest_cid, 0, 0, size - 16, &packet[16]); + + channel->state = L2CAP_STATE_OPEN; + + // notify client + uint8_t event[6]; + event[0] = HCI_EVENT_L2CAP_CHANNEL_OPENED; + event[1] = 4; + bt_store_16(event, 2, channel->handle); + bt_store_16(event, 4, channel->local_cid); + (*channel->event_callback)(event, sizeof(event)); + break; + } + break; + } +} + +void l2cap_data_handler( uint8_t *packet, uint16_t size ){ + + // Get Channel ID + uint16_t channel_id = READ_L2CAP_CHANNEL_ID(packet); + + // Get Connection + hci_con_handle_t handle = READ_ACL_CONNECTION_HANDLE(packet); + // Signaling Packet? + if (channel_id == 1) { + // Get Signaling Identifier + uint8_t sig_id = READ_L2CAP_SIGNALING_IDENTIFIER(packet); + + // Find channel for this sig_id and connection handle + linked_item_t *it; + for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){ + l2cap_channel_t * chan = (l2cap_channel_t *) it; + if ( chan->sig_id == sig_id && chan->handle == handle) { + l2cap_signaling_handler( chan, packet, size); + } + } + } - // Get Signaling Identifier - - // Find channel for this sig_id - - // Handle CONNECTION_RESPONSE - - // Handle CONFIGURE_RESPONSE - - // Handle CONFIGURE_REQUEST + // Find channel for this channel_id and connection handle + linked_item_t *it; + for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){ + l2cap_channel_t * channel = (l2cap_channel_t *) it; + if ( channel->local_cid == channel_id && channel->handle == handle) { + (*channel->data_callback)(packet, size); + } + } } int btstack_packet_handler(connection_t *connection, uint8_t packet_type, uint8_t *data, uint16_t size){ @@ -128,15 +205,15 @@ int bt_send_l2cap_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_COMM return bt_send_acl_packet(l2cap_sig_buffer, len); } -static void dummy_handler(uint8_t *packet, int size){ +static void dummy_handler(uint8_t *packet, uint16_t size){ } // register packet and event handler -void bt_register_event_packet_handler(void (*handler)(uint8_t *packet, int size)){ +void bt_register_event_packet_handler(void (*handler)(uint8_t *packet, uint16_t size)){ event_packet_handler = handler; } -void bt_register_acl_packet_handler (void (*handler)(uint8_t *packet, int size)){ +void bt_register_acl_packet_handler (void (*handler)(uint8_t *packet, uint16_t size)){ acl_packet_handler = handler; } @@ -163,7 +240,7 @@ l2cap_channel_t * l2cap_create_channel(bd_addr_t address, uint16_t psm, void (*e // send connection request // BD_ADDR, Packet_Type, Page_Scan_Repetition_Mode, Reserved, Clock_Offset, Allow_Role_Switch - bt_send_cmd(&hci_create_connection, &address, 0x18, 0, 0, 0, 0); + bt_send_cmd(&hci_create_connection, address, 0x18, 0, 0, 0, 0); return chan; } diff --git a/src/btstack.h b/src/btstack.h index 3c1153aa2..ba72e446f 100644 --- a/src/btstack.h +++ b/src/btstack.h @@ -27,8 +27,8 @@ int bt_send_cmd(hci_cmd_t *cmd, ...); int bt_send_acl_packet(uint8_t *packet, int size); // register packet and event handler -void bt_register_event_packet_handler(void (*handler)(uint8_t *packet, int size)); -void bt_register_acl_packet_handler (void (*handler)(uint8_t *packet, int size)); +void bt_register_event_packet_handler(void (*handler)(uint8_t *packet, uint16_t size)); +void bt_register_acl_packet_handler (void (*handler)(uint8_t *packet, uint16_t size)); // TODO: temp int bt_send_l2cap_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, ...); diff --git a/src/daemon.c b/src/daemon.c index b0f8eef24..32112c10e 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -48,7 +48,7 @@ static int daemon_packet_handler(connection_t *connection, uint8_t packet_type, // printf("ACL from client: "); break; } - hexdump(data, length); + // hexdump(data, length); // printf("\n"); return 0; } diff --git a/src/hci_cmds.h b/src/hci_cmds.h index c4a881430..ccc0b02ee 100644 --- a/src/hci_cmds.h +++ b/src/hci_cmds.h @@ -74,6 +74,9 @@ #define HCI_EVENT_BTSTACK_WORKING 0x80 #define HCI_EVENT_BTSTACK_STATE 0x81 +// data: event (8), len(8), handle(16), channel(16) +#define HCI_EVENT_L2CAP_CHANNEL_OPENED 0x82 + #define COMMAND_COMPLETE_EVENT(event,cmd) ( event[0] == HCI_EVENT_COMMAND_COMPLETE && READ_BT_16(event,3) == cmd.opcode) /** diff --git a/src/hci_transport_usb.c b/src/hci_transport_usb.c index a469de0a2..9c6bd293d 100644 --- a/src/hci_transport_usb.c +++ b/src/hci_transport_usb.c @@ -17,6 +17,8 @@ // ACL Data 0 0 0x82 Bulk (IN) 32/64 // ACL Data 0 0 0x02 Bulk (OUT) 32/64 +#ifdef HAVE_TRANSPORT_USB + #include #include #include /* UNIX standard function definitions */ @@ -338,3 +340,5 @@ hci_transport_t * hci_transport_usb_instance() { } return hci_transport_usb; } + +#endif \ No newline at end of file diff --git a/src/l2cap.h b/src/l2cap.h index 8d84a219a..ce7df6fb5 100644 --- a/src/l2cap.h +++ b/src/l2cap.h @@ -15,20 +15,23 @@ #define L2CAP_SIG_ID_INVALID 0 typedef enum { - L2CAP_STATE_CLOSED, // no baseband - L2CAP_STATE_CONNECTED, // baseband connection - L2CAP_STATE_W4_L2CA_CONNECTION_RSP, // from application - L2CAP_STATE_W4_L2CAP_CONNECTION_RSP, // from peer - L2CAP_STATE_CONFIG, + L2CAP_STATE_CLOSED, // no baseband + L2CAP_STATE_WAIT_CONNECT, // from application + L2CAP_STATE_WAIT_CONNECT_RSP, // from peer + L2CAP_STATE_WAIT_CONFIG_REQ_RSP, + L2CAP_STATE_WAIT_CONFIG_REQ, L2CAP_STATE_OPEN, - L2CAP_STATE_W4_L2CA_DISCON_RSP, // from application - L2CAP_STATE_W4_L2CAP_DISCON_RSP, // from peer + L2CAP_STATE_WAIT_DISCONNECT, // from application } L2CAP_STATE; typedef struct { + // linked list - assert: first field + linked_item_t item; + L2CAP_STATE state; uint8_t sig_id; uint16_t local_cid; + uint16_t dest_cid; bd_addr_t address; uint16_t psm; hci_con_handle_t handle; diff --git a/src/utils.h b/src/utils.h index 81df2a703..243ce2dca 100644 --- a/src/utils.h +++ b/src/utils.h @@ -32,6 +32,22 @@ typedef uint8_t link_key_t[LINK_KEY_LEN]; #define READ_BT_24( buffer, pos) ( ((uint32_t) buffer[pos]) | (((uint32_t)buffer[pos+1]) << 8) | (((uint32_t)buffer[pos+2]) << 16)) #define READ_BT_32( buffer, pos) ( ((uint32_t) buffer[pos]) | (((uint32_t)buffer[pos+1]) << 8) | (((uint32_t)buffer[pos+2]) << 16) | (((uint32_t) buffer[pos+3])) << 24) +// ACL Packet +#define READ_ACL_CONNECTION_HANDLE( buffer ) ( READ_BT_16(buffer,0) & 0x0fff) +#define READ_ACL_FLAGS( buffer ) ( buffer[1] >> 4 ) +#define READ_ACL_LENGTH( buffer ) (READ_BT_16(buffer, 2) + +// L2CAP Packet +#define READ_L2CAP_LENGTH(buffer) ( READ_BT_16(buffer, 4)) +#define READ_L2CAP_CHANNEL_ID(buffer) ( READ_BT_16(buffer, 6)) + +// L2CAP Signaling Packet +#define READ_L2CAP_SIGNALING_CODE( buffer ) (buffer[ 8]) +#define READ_L2CAP_SIGNALING_IDENTIFIER( buffer ) (buffer[ 9]) +#define READ_L2CAP_SIGNALING_LENGTH( buffer ) (buffer[10]) + +#define L2CAP_SIGNALING_DATA_OFFSET 12 + void bt_store_16(uint8_t *buffer, uint16_t pos, uint16_t value); void bt_store_32(uint8_t *buffer, uint16_t pos, uint32_t value); void bt_flip_addr(bd_addr_t dest, bd_addr_t src); @@ -40,4 +56,4 @@ void hexdump(void *data, int size); void print_bd_addr( bd_addr_t addr); #define BD_ADDR_CMP(a,b) memcmp(a,b, BD_ADDR_LEN) -#define BD_ADDR_COPY(dest,src) memcpy(dest,src,BD_ADDR_LEN) \ No newline at end of file +#define BD_ADDR_COPY(dest,src) memcpy(dest,src,BD_ADDR_LEN)