diff --git a/example/libusb/panu_demo.c b/example/libusb/panu_demo.c index e473bb395..9a79b33fa 100644 --- a/example/libusb/panu_demo.c +++ b/example/libusb/panu_demo.c @@ -363,6 +363,10 @@ static void packet_handler (void * connection, uint8_t packet_type, uint16_t cha } break; + case BNEP_EVENT_CHANNEL_TIMEOUT: + printf("BNEP channel timeout! Channel will be closed\n"); + break; + case BNEP_EVENT_CHANNEL_CLOSED: printf("BNEP channel closed\n"); run_loop_remove_data_source(&tap_dev_ds); diff --git a/include/btstack/hci_cmds.h b/include/btstack/hci_cmds.h index d08019a24..93fb16631 100644 --- a/include/btstack/hci_cmds.h +++ b/include/btstack/hci_cmds.h @@ -407,8 +407,11 @@ extern "C" { // data: event(8), len(8), bnep source uuid (16), bnep destination uuid (16), remote_address (48) #define BNEP_EVENT_CHANNEL_CLOSED 0xC3 +// data: event(8), len(8), bnep source uuid (16), bnep destination uuid (16), remote_address (48), channel state (8) +#define BNEP_EVENT_CHANNEL_TIMEOUT 0xC4 + // data: event(8), len(8) -#define BNEP_EVENT_READY_TO_SEND 0xC4 +#define BNEP_EVENT_READY_TO_SEND 0xC5 // data: event(8), address_type(8), address (48), [number(32)] #define SM_JUST_WORKS_REQUEST 0xD0 diff --git a/src/bnep.c b/src/bnep.c index bdf6f7cf1..aa95bfc0e 100644 --- a/src/bnep.c +++ b/src/bnep.c @@ -56,7 +56,7 @@ #include "l2cap.h" -#define BNEP_CONNECTION_TIMEOUT_MS 30000 +#define BNEP_CONNECTION_TIMEOUT_MS 10000 static linked_list_t bnep_services = NULL; static linked_list_t bnep_channels = NULL; @@ -68,6 +68,7 @@ static void (*app_packet_handler)(void * connection, uint8_t packet_type, static bnep_channel_t * bnep_channel_for_l2cap_cid(uint16_t l2cap_cid); +static void bnep_channel_finalize(bnep_channel_t *channel); static void bnep_run(void); /* Emit service registered event */ @@ -112,6 +113,20 @@ static void bnep_emit_incoming_connection(bnep_channel_t *channel) (*app_packet_handler)(channel->connection, HCI_EVENT_PACKET, channel->l2cap_cid, (uint8_t *) event, sizeof(event)); } +static void bnep_emit_channel_timeout(bnep_channel_t *channel) +{ + log_info("BNEP_EVENT_CHANNEL_TIMEOUT bd_addr: %s", bd_addr_to_str(channel->remote_addr)); + uint8_t event[2 + sizeof(bd_addr_t) + 2 * sizeof(uint16_t) + sizeof(uint8_t)]; + event[0] = BNEP_EVENT_CHANNEL_TIMEOUT; + event[1] = sizeof(event) - 2; + bt_store_16(event, 2, channel->uuid_source); + bt_store_16(event, 4, channel->uuid_dest); + BD_ADDR_COPY(&event[6], channel->remote_addr); + event[12] = channel->state; + hci_dump_packet( HCI_EVENT_PACKET, 0, event, sizeof(event)); + (*app_packet_handler)(channel->connection, HCI_EVENT_PACKET, channel->l2cap_cid, (uint8_t *) event, sizeof(event)); +} + static void bnep_emit_channel_closed(bnep_channel_t *channel) { log_info("BNEP_EVENT_CHANNEL_CLOSED bd_addr: %s", bd_addr_to_str(channel->remote_addr)); @@ -423,6 +438,39 @@ int bnep_send(uint16_t bnep_cid, uint8_t *packet, uint16_t len) return err; } +/* BNEP timeout timer helper function */ +static void bnep_channel_timer_handler(timer_source_t *timer) +{ + bnep_channel_t *channel = (bnep_channel_t *)linked_item_get_user((linked_item_t *) timer); + log_info( "bnep_channel_timeout_handler callback: shutting down connection!"); + bnep_emit_channel_timeout(channel); + bnep_channel_finalize(channel); +} + + +static void bnep_channel_stop_timer(bnep_channel_t *channel) +{ + if (channel->timer_active) { + run_loop_remove_timer(&channel->timer); + channel->timer_active = 0; + } +} + +static void bnep_channel_start_timer(bnep_channel_t *channel, int timeout) +{ + /* Stop any eventually running timeout timer */ + bnep_channel_stop_timer(channel); + + /* Start bnep channel timeout check timer */ + run_loop_set_timer(&channel->timer, timeout); + channel->timer.process = bnep_channel_timer_handler; + linked_item_set_user((linked_item_t*) &channel->timer, channel); + run_loop_add_timer(&channel->timer); + channel->timer_active = 1; +} + +/* BNEP statemachine functions */ + inline static void bnep_channel_state_add(bnep_channel_t *channel, BNEP_CHANNEL_STATE_VAR event){ channel->state_var = (BNEP_CHANNEL_STATE_VAR) (channel->state_var | event); } @@ -516,8 +564,11 @@ static void bnep_channel_finalize(bnep_channel_t *channel) if (channel->state == BNEP_CHANNEL_STATE_CONNECTED) { bnep_emit_channel_closed(channel); } - + l2cap_cid = channel->l2cap_cid; + + /* Stop any eventually running timer */ + bnep_channel_stop_timer(channel); /* Free ressources and then close the l2cap channel */ bnep_channel_free(channel); @@ -615,6 +666,8 @@ static int bnep_handle_connection_response(bnep_channel_t *channel, uint8_t *pac if (response_code == BNEP_RESP_SETUP_SUCCESS) { log_info("BNEP_CONNCTION_RESPONSE: Channel established to %s", bd_addr_to_str(channel->remote_addr)); channel->state = BNEP_CHANNEL_STATE_CONNECTED; + /* Stop timeout timer! */ + bnep_channel_stop_timer(channel); bnep_emit_open_channel_complete(channel, 0); } else { log_error("BNEP_CONNCTION_RESPONSE: Connection to %s failed. Err: %d", bd_addr_to_str(channel->remote_addr), response_code); @@ -946,6 +999,9 @@ static int bnep_hci_event_handler(uint8_t *packet, uint16_t size) /* Set channel into accept state */ channel->state = BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_REQUEST; + + /* Start connection timeout timer */ + bnep_channel_start_timer(channel, BNEP_CONNECTION_TIMEOUT_MS); log_info("L2CAP_EVENT_INCOMING_CONNECTION (l2cap_cid 0x%02x) for PSM_BNEP => accept", l2cap_cid); l2cap_accept_connection_internal(l2cap_cid); @@ -1199,6 +1255,8 @@ static void bnep_channel_state_machine(bnep_channel_t* channel, bnep_channel_eve (channel->state == BNEP_CHANNEL_STATE_WAIT_FOR_CONNECTION_REQUEST)) { /* Set channel state to STATE_CONNECTED */ channel->state = BNEP_CHANNEL_STATE_CONNECTED; + /* Stop timeout timer! */ + bnep_channel_stop_timer(channel); } bnep_channel_state_remove(channel, BNEP_CHANNEL_STATE_VAR_SND_CONNECTION_RESPONSE); @@ -1274,6 +1332,8 @@ int bnep_connect(void * connection, bd_addr_t *addr, uint16_t l2cap_psm, uint16_ channel->uuid_source = BNEP_UUID_PANU; channel->uuid_dest = uuid_dest; + bnep_channel_start_timer(channel, BNEP_CONNECTION_TIMEOUT_MS); + l2cap_create_channel_internal(connection, bnep_packet_handler, *addr, l2cap_psm, l2cap_max_mtu()); return 0; diff --git a/src/bnep.h b/src/bnep.h index 559a77eb5..b114fbb1b 100644 --- a/src/bnep.h +++ b/src/bnep.h @@ -167,6 +167,9 @@ typedef struct { bnep_multi_filter multicast_filter[MAX_BNEP_MULTICAST_FILTER]; // multicast address filter, define fixed size for now uint16_t multicast_filter_count; + + timer_source_t timer; // Timeout timer + int timer_active; // Is a timer running? // l2cap packet handler btstack_packet_handler_t packet_handler;