implemented minimal outgoing-only L2CAP state machine, BT HID connection in test.c working

This commit is contained in:
matthias.ringwald 2009-07-29 21:06:04 +00:00
parent 0b6464c774
commit 87ea0ea477
11 changed files with 183 additions and 231 deletions

View File

@ -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

35
aclocal.m4 vendored
View File

@ -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])
# -------------------------------------------

View File

@ -10,199 +10,59 @@
#include <strings.h>
#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();

View File

@ -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 = "<group>"; };
9C1F0E990FDAE023008F472F /* run_loop.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; name = run_loop.h; path = src/run_loop.h; sourceTree = "<group>"; };
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 = "<group>"; };
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 = "<absolute>"; };
9C46FC340FA906F700ABEF05 /* hci.c */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.c; name = hci.c; path = src/hci.c; sourceTree = "<group>"; };
9C46FC350FA906F700ABEF05 /* hci.h */ = {isa = PBXFileReference; fileEncoding = 5; lastKnownFileType = sourcecode.c.h; name = hci.h; path = src/hci.h; sourceTree = "<group>"; };
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 = "<group>"; };
@ -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 = "<group>";
@ -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;
};

View File

@ -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;
}

View File

@ -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, ...);

View File

@ -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;
}

View File

@ -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)
/**

View File

@ -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 <stdio.h>
#include <strings.h>
#include <unistd.h> /* UNIX standard function definitions */
@ -338,3 +340,5 @@ hci_transport_t * hci_transport_usb_instance() {
}
return hci_transport_usb;
}
#endif

View File

@ -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;

View File

@ -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)
#define BD_ADDR_COPY(dest,src) memcpy(dest,src,BD_ADDR_LEN)