improved l2cap error handling, better config options validation

This commit is contained in:
matthias.ringwald 2012-10-30 19:55:24 +00:00
parent 5b4f6e5776
commit 63a7246a86
2 changed files with 61 additions and 14 deletions

View File

@ -376,7 +376,7 @@ void l2cap_run(void){
hci_con_handle_t handle = signaling_responses[0].handle;
uint8_t sig_id = signaling_responses[0].sig_id;
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){
case CONNECTION_REQUEST:
@ -395,6 +395,9 @@ void l2cap_run(void){
l2cap_send_signaling_packet(handle, INFORMATION_RESPONSE, sig_id, infoType, 1, 0, NULL);
}
break;
case COMMAND_REJECT:
l2cap_send_signaling_packet(handle, COMMAND_REJECT, sig_id, result);
break;
default:
// should not happen
break;
@ -453,9 +456,25 @@ void l2cap_run(void){
case L2CAP_STATE_CONFIG:
if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP){
uint16_t flags = 0;
channelStateVarClearFlag(channel, L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP);
channelStateVarSetFlag(channel, L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP);
l2cap_send_signaling_packet(channel->handle, CONFIGURE_RESPONSE, channel->remote_sig_id, channel->remote_cid, 0, 0, 0, NULL);
if (channel->state_var & L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP_CONT) {
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){
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];
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
uint16_t end_pos = 4 + READ_BT_16(command, L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET);
uint16_t pos = 8;
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++];
// 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);
// 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;
}
@ -876,9 +909,12 @@ void l2cap_signaling_handler_channel(l2cap_channel_t *channel, uint8_t *command)
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);
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;
case CONFIGURE_RESPONSE:
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
if (code < 1 || code == ECHO_RESPONSE || code > INFORMATION_REQUEST){
l2cap_register_signaling_response(handle, COMMAND_REJECT, sig_id, L2CAP_REJ_CMD_UNKNOWN);
return;
}

View File

@ -75,6 +75,12 @@ extern "C" {
#define L2CAP_CID_ATTRIBUTE_PROTOCOL 0x0004
#define L2CAP_CID_SIGNALING_LE 0x0005
#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_register_packet_handler(void (*handler)(void * connection, uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size));
@ -125,13 +131,17 @@ typedef enum {
} L2CAP_STATE;
typedef enum {
L2CAP_CHANNEL_STATE_VAR_NONE = 0,
L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_REQ = 1 << 0,
L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP = 1 << 1,
L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ = 1 << 2,
L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP = 1 << 3,
L2CAP_CHANNEL_STATE_VAR_SENT_CONF_REQ = 1 << 4,
L2CAP_CHANNEL_STATE_VAR_SENT_CONF_RSP = 1 << 5,
L2CAP_CHANNEL_STATE_VAR_NONE = 0,
L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_REQ = 1 << 0,
L2CAP_CHANNEL_STATE_VAR_RCVD_CONF_RSP = 1 << 1,
L2CAP_CHANNEL_STATE_VAR_SEND_CONF_REQ = 1 << 2,
L2CAP_CHANNEL_STATE_VAR_SEND_CONF_RSP = 1 << 3,
L2CAP_CHANNEL_STATE_VAR_SENT_CONF_REQ = 1 << 4,
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;
// info regarding an actual coneection
@ -192,7 +202,7 @@ typedef struct l2cap_signaling_response {
hci_con_handle_t handle;
uint8_t sig_id;
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;