mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-25 16:43:28 +00:00
start with l2cap implementation
This commit is contained in:
parent
016f6766b7
commit
da269baadb
@ -19,6 +19,7 @@
|
|||||||
hci_con_handle_t con_handle_out = 0;
|
hci_con_handle_t con_handle_out = 0;
|
||||||
hci_con_handle_t con_handle_in = 0;
|
hci_con_handle_t con_handle_in = 0;
|
||||||
uint16_t dest_cid;
|
uint16_t dest_cid;
|
||||||
|
uint16_t local_cid;
|
||||||
|
|
||||||
#define BT_HID
|
#define BT_HID
|
||||||
// #define POWER_CYCLE_TEST
|
// #define POWER_CYCLE_TEST
|
||||||
@ -115,7 +116,8 @@ if (packet[0] == HCI_EVENT_CONNECTION_COMPLETE){
|
|||||||
#ifndef MITM
|
#ifndef MITM
|
||||||
// request l2cap connection
|
// request l2cap connection
|
||||||
printf("> CONNECTION REQUEST\n");
|
printf("> CONNECTION REQUEST\n");
|
||||||
bt_send_l2cap_signaling_packet(con_handle_out, CONNECTION_REQUEST, sig_seq_nr++, 0x13, local_cid);
|
local_cid = l2cap_next_local_cid();
|
||||||
|
bt_send_l2cap_signaling_packet(con_handle_out, CONNECTION_REQUEST, l2cap_next_sig_id(), 0x13, local_cid);
|
||||||
#else
|
#else
|
||||||
printf("Connected to target device, please start!\n");
|
printf("Connected to target device, please start!\n");
|
||||||
#endif
|
#endif
|
||||||
@ -174,8 +176,8 @@ void acl_handler(uint8_t *packet, int size){
|
|||||||
uint16_t status = READ_BT_16(packet, 18);
|
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);
|
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){
|
if (result == 0){
|
||||||
printf("> CONFIGURE_REQUEST: id %u\n", sig_seq_nr);
|
// printf("> CONFIGURE_REQUEST: id %u\n", sig_seq_nr);
|
||||||
bt_send_l2cap_signaling_packet(con_handle_out, CONFIGURE_REQUEST, sig_seq_nr++, dest_cid, 0, 4, &config_options);
|
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){
|
else if (packet[8] == CONFIGURE_RESPONSE){
|
||||||
|
@ -23,6 +23,8 @@ uint8_t l2cap_sig_buffer[48];
|
|||||||
|
|
||||||
static connection_t *btstack_connection = NULL;
|
static connection_t *btstack_connection = NULL;
|
||||||
|
|
||||||
|
static linked_list_t l2cap_channels = NULL;
|
||||||
|
|
||||||
/** prototypes */
|
/** prototypes */
|
||||||
static void dummy_handler(uint8_t *packet, int size);
|
static void dummy_handler(uint8_t *packet, int size);
|
||||||
int btstack_packet_handler(connection_t *connection, uint8_t packet_type, uint8_t *data, uint16_t size);
|
int btstack_packet_handler(connection_t *connection, uint8_t packet_type, uint8_t *data, uint16_t size);
|
||||||
@ -31,12 +33,14 @@ int btstack_packet_handler(connection_t *connection, uint8_t packet_type, uint8_
|
|||||||
static void (*event_packet_handler)(uint8_t *packet, int size) = dummy_handler;
|
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 (*acl_packet_handler) (uint8_t *packet, int size) = dummy_handler;
|
||||||
|
|
||||||
|
|
||||||
// init BTstack library
|
// init BTstack library
|
||||||
int bt_open(){
|
int bt_open(){
|
||||||
|
|
||||||
|
// BTdaemon
|
||||||
socket_connection_register_packet_callback(btstack_packet_handler);
|
socket_connection_register_packet_callback(btstack_packet_handler);
|
||||||
btstack_connection = socket_connection_open_tcp();
|
btstack_connection = socket_connection_open_tcp();
|
||||||
if (!btstack_connection) return -1;
|
if (!btstack_connection) return -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -45,12 +49,52 @@ int bt_close(){
|
|||||||
return socket_connection_close_tcp(btstack_connection);
|
return socket_connection_close_tcp(btstack_connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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]);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// handle disconnection complete events
|
||||||
|
// TODO ...
|
||||||
|
}
|
||||||
|
void l2cap_data_handler( uint8_t *packet, uint16_t size ){
|
||||||
|
// Get Channel ID
|
||||||
|
|
||||||
|
// Signaling Packet?
|
||||||
|
|
||||||
|
// Get Signaling Identifier
|
||||||
|
|
||||||
|
// Find channel for this sig_id
|
||||||
|
|
||||||
|
// Handle CONNECTION_RESPONSE
|
||||||
|
|
||||||
|
// Handle CONFIGURE_RESPONSE
|
||||||
|
|
||||||
|
// Handle CONFIGURE_REQUEST
|
||||||
|
}
|
||||||
|
|
||||||
int btstack_packet_handler(connection_t *connection, uint8_t packet_type, uint8_t *data, uint16_t size){
|
int btstack_packet_handler(connection_t *connection, uint8_t packet_type, uint8_t *data, uint16_t size){
|
||||||
switch (packet_type){
|
switch (packet_type){
|
||||||
case HCI_EVENT_PACKET:
|
case HCI_EVENT_PACKET:
|
||||||
|
l2cap_event_handler(data, size);
|
||||||
(*event_packet_handler)(data, size);
|
(*event_packet_handler)(data, size);
|
||||||
break;
|
break;
|
||||||
case HCI_ACL_DATA_PACKET:
|
case HCI_ACL_DATA_PACKET:
|
||||||
|
l2cap_data_handler(data, size);
|
||||||
(*acl_packet_handler)(data, size);
|
(*acl_packet_handler)(data, size);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -96,3 +140,35 @@ void bt_register_acl_packet_handler (void (*handler)(uint8_t *packet, int size)
|
|||||||
acl_packet_handler = handler;
|
acl_packet_handler = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// open outgoing L2CAP channel
|
||||||
|
l2cap_channel_t * l2cap_create_channel(bd_addr_t address, uint16_t psm, void (*event_cb)(uint8_t *packet, uint16_t size),
|
||||||
|
void (*data_cb)(uint8_t *packet, uint16_t size)){
|
||||||
|
// alloc structure
|
||||||
|
l2cap_channel_t * chan = malloc(sizeof(l2cap_channel_t));
|
||||||
|
if (!chan) return NULL;
|
||||||
|
|
||||||
|
// fill in
|
||||||
|
BD_ADDR_COPY(chan->address, address);
|
||||||
|
chan->psm = psm;
|
||||||
|
chan->handle = 0;
|
||||||
|
chan->event_callback = event_cb;
|
||||||
|
chan->data_callback = data_cb;
|
||||||
|
|
||||||
|
// set initial state
|
||||||
|
chan->state = L2CAP_STATE_CLOSED;
|
||||||
|
chan->sig_id = L2CAP_SIG_ID_INVALID;
|
||||||
|
|
||||||
|
// add to connections list
|
||||||
|
linked_list_add(&l2cap_channels, (linked_item_t *) chan);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
return chan;
|
||||||
|
}
|
||||||
|
|
||||||
|
void l2cap_disconnect(l2cap_channel_t *channel, uint8_t reason){
|
||||||
|
// TODO implement
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -8,9 +8,12 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "hci.h"
|
#include "hci.h"
|
||||||
#include "l2cap.h"
|
#include "l2cap.h"
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
// init BTstack library
|
// init BTstack library
|
||||||
int bt_open();
|
int bt_open();
|
||||||
|
|
||||||
@ -23,10 +26,14 @@ int bt_send_cmd(hci_cmd_t *cmd, ...);
|
|||||||
// send hci acl packet
|
// send hci acl packet
|
||||||
int bt_send_acl_packet(uint8_t *packet, int size);
|
int bt_send_acl_packet(uint8_t *packet, int size);
|
||||||
|
|
||||||
// TODO: temp
|
|
||||||
int bt_send_l2cap_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, ...);
|
|
||||||
|
|
||||||
// register packet and event handler
|
// 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, int size));
|
||||||
void bt_register_acl_packet_handler (void (*handler)(uint8_t *packet, int size));
|
void bt_register_acl_packet_handler (void (*handler)(uint8_t *packet, int size));
|
||||||
|
|
||||||
|
// TODO: temp
|
||||||
|
int bt_send_l2cap_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, ...);
|
||||||
|
|
||||||
|
// outgoing connections
|
||||||
|
l2cap_channel_t * l2cap_create_channel(bd_addr_t bd_addr, uint16_t psm, void (*event_cb)(uint8_t *packet, uint16_t size),
|
||||||
|
void (*data_cb)(uint8_t *packet, uint16_t size));
|
||||||
|
void l2cap_disconnect(l2cap_channel_t *channel, uint8_t reason);
|
||||||
|
27
src/l2cap.h
27
src/l2cap.h
@ -10,9 +10,34 @@
|
|||||||
|
|
||||||
#include "hci.h"
|
#include "hci.h"
|
||||||
#include "l2cap_signaling.h"
|
#include "l2cap_signaling.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
#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_OPEN,
|
||||||
|
L2CAP_STATE_W4_L2CA_DISCON_RSP, // from application
|
||||||
|
L2CAP_STATE_W4_L2CAP_DISCON_RSP, // from peer
|
||||||
|
} L2CAP_STATE;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
L2CAP_STATE state;
|
||||||
|
uint8_t sig_id;
|
||||||
|
uint16_t local_cid;
|
||||||
|
bd_addr_t address;
|
||||||
|
uint16_t psm;
|
||||||
|
hci_con_handle_t handle;
|
||||||
|
void (*event_callback)(uint8_t *packet, uint16_t size);
|
||||||
|
void (*data_callback)(uint8_t *packet, uint16_t size);
|
||||||
|
// uint16_t mtu_incoming;
|
||||||
|
// uint16_t mtu_outgoing;
|
||||||
|
// uint16_t flush_timeout_incoming;
|
||||||
|
// uint16_t flush_timeout_outgoing;
|
||||||
} l2cap_channel_t;
|
} l2cap_channel_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -22,9 +22,22 @@ static char *l2cap_signaling_commands_format[] = {
|
|||||||
"22D", // 0x0b information response: InfoType, Result, Data
|
"22D", // 0x0b information response: InfoType, Result, Data
|
||||||
};
|
};
|
||||||
|
|
||||||
uint8_t sig_seq_nr = 1;
|
uint8_t sig_seq_nr = 0xff;
|
||||||
uint16_t local_cid = 0x40;
|
uint16_t local_cid = 0x40;
|
||||||
|
|
||||||
|
uint8_t l2cap_next_sig_id(void){
|
||||||
|
if (sig_seq_nr == 0xff) {
|
||||||
|
sig_seq_nr = 1;
|
||||||
|
} else {
|
||||||
|
sig_seq_nr++;
|
||||||
|
}
|
||||||
|
return sig_seq_nr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t l2cap_next_local_cid(void){
|
||||||
|
return local_cid++;
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t l2cap_create_signaling_internal(uint8_t * acl_buffer,hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, va_list argptr){
|
uint16_t l2cap_create_signaling_internal(uint8_t * acl_buffer,hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, va_list argptr){
|
||||||
|
|
||||||
// 0 - Connection handle : PB=10 : BC=00
|
// 0 - Connection handle : PB=10 : BC=00
|
||||||
|
@ -24,8 +24,8 @@ typedef enum {
|
|||||||
INFORMATIONAL_RESPONSE
|
INFORMATIONAL_RESPONSE
|
||||||
} L2CAP_SIGNALING_COMMANDS;
|
} L2CAP_SIGNALING_COMMANDS;
|
||||||
|
|
||||||
extern uint16_t local_cid;
|
|
||||||
extern uint8_t sig_seq_nr;
|
|
||||||
|
|
||||||
uint16_t l2cap_create_signaling_packet(uint8_t *acl_buffer, hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, ...);
|
uint16_t l2cap_create_signaling_packet(uint8_t *acl_buffer, hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, ...);
|
||||||
uint16_t l2cap_create_signaling_internal(uint8_t * acl_buffer,hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, va_list argptr);
|
uint16_t l2cap_create_signaling_internal(uint8_t * acl_buffer,hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, va_list argptr);
|
||||||
|
uint8_t l2cap_next_sig_id();
|
||||||
|
uint16_t l2cap_next_local_cid();
|
||||||
|
|
||||||
|
@ -45,3 +45,4 @@ void print_bd_addr( bd_addr_t addr){
|
|||||||
}
|
}
|
||||||
printf("%02X", ((uint8_t *)addr)[i]);
|
printf("%02X", ((uint8_t *)addr)[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,4 +40,4 @@ void hexdump(void *data, int size);
|
|||||||
void print_bd_addr( bd_addr_t addr);
|
void print_bd_addr( bd_addr_t addr);
|
||||||
|
|
||||||
#define BD_ADDR_CMP(a,b) memcmp(a,b, BD_ADDR_LEN)
|
#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)
|
Loading…
x
Reference in New Issue
Block a user