mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-04-18 14:42:33 +00:00
improved l2cap error handling, better config options validation
This commit is contained in:
parent
5b4f6e5776
commit
63a7246a86
49
src/l2cap.c
49
src/l2cap.c
@ -376,7 +376,7 @@ void l2cap_run(void){
|
|||||||
hci_con_handle_t handle = signaling_responses[0].handle;
|
hci_con_handle_t handle = signaling_responses[0].handle;
|
||||||
uint8_t sig_id = signaling_responses[0].sig_id;
|
uint8_t sig_id = signaling_responses[0].sig_id;
|
||||||
uint16_t infoType = signaling_responses[0].data; // INFORMATION_REQUEST
|
uint16_t infoType = signaling_responses[0].data; // INFORMATION_REQUEST
|
||||||
uint16_t result = signaling_responses[0].data; // CONNECTION_REQUEST
|
uint16_t result = signaling_responses[0].data; // CONNECTION_REQUEST, COMMAND_REJECT
|
||||||
|
|
||||||
switch (signaling_responses[0].code){
|
switch (signaling_responses[0].code){
|
||||||
case CONNECTION_REQUEST:
|
case CONNECTION_REQUEST:
|
||||||
@ -395,6 +395,9 @@ void l2cap_run(void){
|
|||||||
l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, infoType, 1, 0, NULL);
|
l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, infoType, 1, 0, NULL);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case COMMAND_REJECT:
|
||||||
|
l2cap_send_signaling_packet(handle, COMMAND_REJECT, sig_id, result);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
// should not happen
|
// should not happen
|
||||||
break;
|
break;
|
||||||
@ -453,9 +456,25 @@ void l2cap_run(void){
|
|||||||
|
|
||||||
case L2CAP_STATE_CONFIG:
|
case L2CAP_STATE_CONFIG:
|
||||||
if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP){
|
if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP){
|
||||||
|
uint16_t flags = 0;
|
||||||
channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP);
|
channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP);
|
||||||
channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP);
|
if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_CONT) {
|
||||||
l2cap_send_signaling_packet(channel->handle, CONFIGURE_RESPONSE, channel->remote_sig_id, channel->remote_cid, 0, 0, 0, NULL);
|
flags = 1;
|
||||||
|
} else {
|
||||||
|
channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP);
|
||||||
|
}
|
||||||
|
if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_INVALID){
|
||||||
|
l2cap_send_signaling_packet(channel->handle, CONFIGURE_RESPONSE, channel->remote_sig_id, channel->remote_cid, flags, L2CAP_CONF_RESULT_UNKNOWN_OPTIONS, 0, NULL);
|
||||||
|
} else if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU){
|
||||||
|
config_options[0] = 1; // MTU
|
||||||
|
config_options[1] = 2; // len param
|
||||||
|
bt_store_16( (uint8_t*)&config_options, 2, channel->remote_mtu);
|
||||||
|
l2cap_send_signaling_packet(channel->handle, CONFIGURE_RESPONSE, channel->remote_sig_id, channel->remote_cid, flags, 0, 4, &config_options);
|
||||||
|
channelStateVarClearFlag(channel,L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU);
|
||||||
|
} else {
|
||||||
|
l2cap_send_signaling_packet(channel->handle, CONFIGURE_RESPONSE, channel->remote_sig_id, channel->remote_cid, flags, 0, 0, NULL);
|
||||||
|
}
|
||||||
|
channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_CONT);
|
||||||
}
|
}
|
||||||
else if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ){
|
else if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ){
|
||||||
channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ);
|
channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ);
|
||||||
@ -783,16 +802,30 @@ void l2cap_signaling_handle_configure_request(l2cap_channel_t *channel, uint8_t
|
|||||||
|
|
||||||
channel->remote_sig_id = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET];
|
channel->remote_sig_id = command[L2CAP_SIGNALING_COMMAND_SIGID_OFFSET];
|
||||||
|
|
||||||
|
uint16_t flags = READ_BT_16(command, 6);
|
||||||
|
if (flags & 1) {
|
||||||
|
channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_CONT);
|
||||||
|
}
|
||||||
|
|
||||||
// accept the other's configuration options
|
// accept the other's configuration options
|
||||||
uint16_t end_pos = 4 + READ_BT_16(command, L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET);
|
uint16_t end_pos = 4 + READ_BT_16(command, L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET);
|
||||||
uint16_t pos = 8;
|
uint16_t pos = 8;
|
||||||
while (pos < end_pos){
|
while (pos < end_pos){
|
||||||
uint8_t type = command[pos++];
|
uint8_t option_hint = command[pos] >> 7;
|
||||||
|
uint8_t option_type = command[pos] & 0x7f;
|
||||||
|
log_info("l2cap cid %u, hint %u, type %u", channel->local_cid, option_hint, option_type);
|
||||||
|
pos++;
|
||||||
uint8_t length = command[pos++];
|
uint8_t length = command[pos++];
|
||||||
// MTU { type(8): 1, len(8):2, MTU(16) }
|
// MTU { type(8): 1, len(8):2, MTU(16) }
|
||||||
if ((type & 0x7f) == 1 && length == 2){
|
if (option_type == 1 && length == 2){
|
||||||
channel->remote_mtu = READ_BT_16(command, pos);
|
channel->remote_mtu = READ_BT_16(command, pos);
|
||||||
// log_info("l2cap cid 0x%02x, remote mtu %u\n", channel->local_cid, channel->remote_mtu);
|
// log_info("l2cap cid 0x%02x, remote mtu %u\n", channel->local_cid, channel->remote_mtu);
|
||||||
|
channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU);
|
||||||
|
}
|
||||||
|
// check for unknown options
|
||||||
|
if (option_hint == 0 && (option_type == 0 || option_type >= 0x07)){
|
||||||
|
log_info("l2cap cid %u, unknown options");
|
||||||
|
channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_INVALID);
|
||||||
}
|
}
|
||||||
pos += length;
|
pos += length;
|
||||||
}
|
}
|
||||||
@ -876,9 +909,12 @@ void l2cap_signaling_handler_channel(l2cap_channel_t *channel, uint8_t *command)
|
|||||||
case L2CAP_STATE_CONFIG:
|
case L2CAP_STATE_CONFIG:
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case CONFIGURE_REQUEST:
|
case CONFIGURE_REQUEST:
|
||||||
channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_REQ);
|
|
||||||
channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP);
|
channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP);
|
||||||
l2cap_signaling_handle_configure_request(channel, command);
|
l2cap_signaling_handle_configure_request(channel, command);
|
||||||
|
if (!(channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_CONT)){
|
||||||
|
// only done if continuation not set
|
||||||
|
channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_REQ);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CONFIGURE_RESPONSE:
|
case CONFIGURE_RESPONSE:
|
||||||
channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP);
|
channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP);
|
||||||
@ -927,6 +963,7 @@ void l2cap_signaling_handler_dispatch( hci_con_handle_t handle, uint8_t * comman
|
|||||||
|
|
||||||
// not for a particular channel, and not CONNECTION_REQUEST, ECHO_[REQUEST|RESPONSE], INFORMATION_REQUEST
|
// not for a particular channel, and not CONNECTION_REQUEST, ECHO_[REQUEST|RESPONSE], INFORMATION_REQUEST
|
||||||
if (code < 1 || code == ECHO_RESPONSE || code > INFORMATION_REQUEST){
|
if (code < 1 || code == ECHO_RESPONSE || code > INFORMATION_REQUEST){
|
||||||
|
l2cap_register_signaling_response(handle, COMMAND_REJECT, sig_id, L2CAP_REJ_CMD_UNKNOWN);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
26
src/l2cap.h
26
src/l2cap.h
@ -76,6 +76,12 @@ extern "C" {
|
|||||||
#define L2CAP_CID_SIGNALING_LE 0x0005
|
#define L2CAP_CID_SIGNALING_LE 0x0005
|
||||||
#define L2CAP_CID_SECURITY_MANAGER_PROTOCOL 0x0006
|
#define L2CAP_CID_SECURITY_MANAGER_PROTOCOL 0x0006
|
||||||
|
|
||||||
|
// L2CAP Configuration Result Codes
|
||||||
|
#define L2CAP_CONF_RESULT_UNKNOWN_OPTIONS 0x0003
|
||||||
|
|
||||||
|
// L2CAP Reject Result Codes
|
||||||
|
#define L2CAP_REJ_CMD_UNKNOWN 0x0000
|
||||||
|
|
||||||
void l2cap_init(void);
|
void l2cap_init(void);
|
||||||
void l2cap_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size));
|
void l2cap_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size));
|
||||||
void l2cap_create_channel_internal(void * connection, btstack_packet_handler_t packet_handler, bd_addr_t address, uint16_t psm, uint16_t mtu);
|
void l2cap_create_channel_internal(void * connection, btstack_packet_handler_t packet_handler, bd_addr_t address, uint16_t psm, uint16_t mtu);
|
||||||
@ -125,13 +131,17 @@ typedef enum {
|
|||||||
} L2CAP_STATE;
|
} L2CAP_STATE;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
L2CAP_CHANNEL_STATE_VAR_NONE = 0,
|
L2CAP_CHANNEL_STATE_VAR_NONE = 0,
|
||||||
L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_REQ = 1 << 0,
|
L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_REQ = 1 << 0,
|
||||||
L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP = 1 << 1,
|
L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP = 1 << 1,
|
||||||
L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ = 1 << 2,
|
L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ = 1 << 2,
|
||||||
L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP = 1 << 3,
|
L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP = 1 << 3,
|
||||||
L2CAP_CHANNEL_STATE_VAR_SENT_CONF_REQ = 1 << 4,
|
L2CAP_CHANNEL_STATE_VAR_SENT_CONF_REQ = 1 << 4,
|
||||||
L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP = 1 << 5,
|
L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP = 1 << 5,
|
||||||
|
L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_MTU = 1 << 6, // in CONF RSP, add MTU field
|
||||||
|
L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_CONT = 1 << 7, // in CONF RSP, set CONTINUE flag
|
||||||
|
L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_INVALID = 1 << 8, // in CONF RSP, send UNKNOWN OPTIONS
|
||||||
|
L2CAP_CHANNEL_STATE_VAR_SEND_CMD_REJ_UNKNOWN = 1 << 9, // send CMD_REJ with reason unknown
|
||||||
} L2CAP_CHANNEL_STATE_VAR;
|
} L2CAP_CHANNEL_STATE_VAR;
|
||||||
|
|
||||||
// info regarding an actual coneection
|
// info regarding an actual coneection
|
||||||
@ -192,7 +202,7 @@ typedef struct l2cap_signaling_response {
|
|||||||
hci_con_handle_t handle;
|
hci_con_handle_t handle;
|
||||||
uint8_t sig_id;
|
uint8_t sig_id;
|
||||||
uint8_t code;
|
uint8_t code;
|
||||||
uint16_t data; // infoType for INFORMATION REQUEST, result for CONNECTION request
|
uint16_t data; // infoType for INFORMATION REQUEST, result for CONNECTION request and command unknown
|
||||||
} l2cap_signaling_response_t;
|
} l2cap_signaling_response_t;
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user