void l2cap_close_connection(void *connection){ linked_item_t *it; // close open channels - note to myself: no channel is freed, so no new for fancy iterator tricks l2cap_channel_t * channel; for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){ channel = (l2cap_channel_t *) it; if (channel->connection == connection) { channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST; } } // unregister services it = (linked_item_t *) &l2cap_services; while (it->next) { l2cap_service_t * service = (l2cap_service_t *) it->next; if (service->connection == connection){ it->next = it->next->next; btstack_memory_l2cap_service_free(service); } else { it = it->next; } } // process l2cap_run(); }
void l2cap_disconnect_internal(uint16_t local_cid, uint8_t reason){ // find channel for local_cid l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid); if (channel) { channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_REQUEST; } // process l2cap_run(); }
void l2cap_decline_connection_internal(uint16_t local_cid, uint8_t reason){ l2cap_channel_t * channel = l2cap_get_channel_for_local_cid( local_cid); if (!channel) { log_error( "l2cap_decline_connection_internal called but local_cid 0x%x not found", local_cid); return; } channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_DECLINE; channel->reason = reason; l2cap_run(); }
static void l2cap_register_signaling_response(hci_con_handle_t handle, uint8_t code, uint8_t sig_id, uint16_t data){ if (signaling_responses_pending < NR_PENDING_SIGNALING_RESPONSES) { signaling_responses[signaling_responses_pending].handle = handle; signaling_responses[signaling_responses_pending].code = code; signaling_responses[signaling_responses_pending].sig_id = sig_id; signaling_responses[signaling_responses_pending].data = data; signaling_responses_pending++; l2cap_run(); } }
static void l2cap_register_signaling_response(hci_con_handle_t handle, uint8_t code, uint8_t sig_id, uint16_t data){ // Vol 3, Part A, 4.3: "The DCID and SCID fields shall be ignored when the result field indi- cates the connection was refused." if (signaling_responses_pending < NR_PENDING_SIGNALING_RESPONSES) { signaling_responses[signaling_responses_pending].handle = handle; signaling_responses[signaling_responses_pending].code = code; signaling_responses[signaling_responses_pending].sig_id = sig_id; signaling_responses[signaling_responses_pending].data = data; signaling_responses_pending++; l2cap_run(); } }
void l2cap_accept_connection_internal(uint16_t local_cid){ l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(local_cid); if (!channel) { log_error("l2cap_accept_connection_internal called but local_cid 0x%x not found", local_cid); return; } channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_RESPONSE_ACCEPT; // process l2cap_run(); }
static void l2cap_handle_connection_success_for_addr(bd_addr_t address, hci_con_handle_t 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 ( ! BD_ADDR_CMP( channel->address, address) ){ if (channel->state == L2CAP_STATE_WAIT_CONNECTION_COMPLETE || channel->state == L2CAP_STATE_WILL_SEND_CREATE_CONNECTION) { // success, start l2cap handshake channel->state = L2CAP_STATE_WILL_SEND_CONNECTION_REQUEST; channel->handle = handle; channel->local_cid = l2cap_next_local_cid(); } } } // process l2cap_run(); }
void l2cap_acl_handler( uint8_t *packet, uint16_t size ){ // Get Channel ID uint16_t channel_id = READ_L2CAP_CHANNEL_ID(packet); hci_con_handle_t handle = READ_ACL_CONNECTION_HANDLE(packet); switch (channel_id) { case L2CAP_CID_SIGNALING: { uint16_t command_offset = 8; while (command_offset < size) { // handle signaling commands l2cap_signaling_handler_dispatch(handle, &packet[command_offset]); // increment command_offset command_offset += L2CAP_SIGNALING_COMMAND_DATA_OFFSET + READ_BT_16(packet, command_offset + L2CAP_SIGNALING_COMMAND_LENGTH_OFFSET); } break; } case L2CAP_CID_ATTRIBUTE_PROTOCOL: if (attribute_protocol_packet_handler) { (*attribute_protocol_packet_handler)(ATT_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER); } break; case L2CAP_CID_SECURITY_MANAGER_PROTOCOL: if (security_protocol_packet_handler) { (*security_protocol_packet_handler)(SM_DATA_PACKET, handle, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER); } break; default: { // Find channel for this channel_id and connection handle l2cap_channel_t * channel = l2cap_get_channel_for_local_cid(channel_id); if (channel) { l2cap_dispatch(channel, L2CAP_DATA_PACKET, &packet[COMPLETE_L2CAP_HEADER], size-COMPLETE_L2CAP_HEADER); } break; } } l2cap_run(); }
// open outgoing L2CAP channel void l2cap_create_channel_internal(void * connection, btstack_packet_handler_t packet_handler, bd_addr_t address, uint16_t psm, uint16_t mtu){ // alloc structure l2cap_channel_t * chan = (l2cap_channel_t*) btstack_memory_l2cap_channel_get(); if (!chan) { // emit error event l2cap_channel_t dummy_channel; BD_ADDR_COPY(dummy_channel.address, address); dummy_channel.psm = psm; l2cap_emit_channel_opened(&dummy_channel, BTSTACK_MEMORY_ALLOC_FAILED); return; } // limit local mtu to max acl packet length if (mtu > l2cap_max_mtu()) { mtu = l2cap_max_mtu(); } // fill in BD_ADDR_COPY(chan->address, address); chan->psm = psm; chan->handle = 0; chan->connection = connection; chan->packet_handler = packet_handler; chan->remote_mtu = L2CAP_MINIMAL_MTU; chan->local_mtu = mtu; chan->packets_granted = 0; // set initial state chan->state = L2CAP_STATE_WILL_SEND_CREATE_CONNECTION; chan->state_var = L2CAP_CHANNEL_STATE_VAR_NONE; chan->remote_sig_id = L2CAP_SIG_ID_INVALID; chan->local_sig_id = L2CAP_SIG_ID_INVALID; // add to connections list linked_list_add(&l2cap_channels, (linked_item_t *) chan); l2cap_run(); }
static void l2cap_handle_disconnect_request(l2cap_channel_t *channel, uint16_t identifier){ channel->remote_sig_id = identifier; channel->state = L2CAP_STATE_WILL_SEND_DISCONNECT_RESPONSE; l2cap_run(); }
void l2cap_event_handler( uint8_t *packet, uint16_t size ){ bd_addr_t address; hci_con_handle_t handle; l2cap_channel_t * channel; linked_item_t *it; int hci_con_used; switch(packet[0]){ // handle connection complete events case HCI_EVENT_CONNECTION_COMPLETE: bt_flip_addr(address, &packet[5]); if (packet[2] == 0){ handle = READ_BT_16(packet, 3); l2cap_handle_connection_success_for_addr(address, handle); } else { l2cap_handle_connection_failed_for_addr(address, packet[2]); } break; // handle successful create connection cancel command case HCI_EVENT_COMMAND_COMPLETE: if ( COMMAND_COMPLETE_EVENT(packet, hci_create_connection_cancel) ) { if (packet[5] == 0){ bt_flip_addr(address, &packet[6]); // CONNECTION TERMINATED BY LOCAL HOST (0X16) l2cap_handle_connection_failed_for_addr(address, 0x16); } } l2cap_run(); // try sending signaling packets first break; case HCI_EVENT_COMMAND_STATUS: l2cap_run(); // try sending signaling packets first break; // handle disconnection complete events case HCI_EVENT_DISCONNECTION_COMPLETE: // send l2cap disconnect events for all channels on this handle handle = READ_BT_16(packet, 3); it = (linked_item_t *) &l2cap_channels; while (it->next){ l2cap_channel_t * channel = (l2cap_channel_t *) it->next; if ( channel->handle == handle ){ // update prev item before free'ing next element - don't call l2cap_finalize_channel_close it->next = it->next->next; l2cap_emit_channel_closed(channel); btstack_memory_l2cap_channel_free(channel); } else { it = it->next; } } break; case HCI_EVENT_NUMBER_OF_COMPLETED_PACKETS: l2cap_run(); // try sending signaling packets first l2cap_hand_out_credits(); break; // HCI Connection Timeouts case L2CAP_EVENT_TIMEOUT_CHECK: handle = READ_BT_16(packet, 2); if (hci_authentication_active_for_handle(handle)) break; hci_con_used = 0; for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){ channel = (l2cap_channel_t *) it; if (channel->handle == handle) { hci_con_used = 1; } } if (hci_con_used) break; if (!hci_can_send_packet_now(HCI_COMMAND_DATA_PACKET)) break; hci_send_cmd(&hci_disconnect, handle, 0x13); // remote closed connection break; case DAEMON_EVENT_HCI_PACKET_SENT: for (it = (linked_item_t *) l2cap_channels; it ; it = it->next){ channel = (l2cap_channel_t *) it; if (channel->packet_handler) { (* (channel->packet_handler))(HCI_EVENT_PACKET, channel->local_cid, packet, size); } } if (attribute_protocol_packet_handler) { (*attribute_protocol_packet_handler)(HCI_EVENT_PACKET, 0, packet, size); } if (security_protocol_packet_handler) { (*security_protocol_packet_handler)(HCI_EVENT_PACKET, 0, packet, size); } break; default: break; } // pass on (*packet_handler)(NULL, HCI_EVENT_PACKET, 0, packet, size); }