2017-03-19 22:32:10 +01:00
/*
* Copyright ( C ) 2014 BlueKitchen GmbH
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
*
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. Neither the name of the copyright holders nor the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission .
* 4. Any redistribution , use , or modification is done solely for
* personal benefit and not for any commercial purpose or for
* monetary gain .
*
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
* ` ` AS IS ' ' AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
* LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL MATTHIAS
* RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT ,
* INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING ,
* BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS
* OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY ,
* OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE .
*
* Please inquire about commercial licensing options at
* contact @ bluekitchen - gmbh . com
*
*/
2017-03-24 23:39:20 +01:00
# define __BTSTACK_FILE__ "goep_client.c"
2017-03-19 22:32:10 +01:00
# include "btstack_config.h"
# include <stdint.h>
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include "btstack_debug.h"
# include "hci_dump.h"
# include "bluetooth_sdp.h"
# include "btstack_event.h"
# include "classic/goep_client.h"
# include "classic/obex.h"
# include "classic/obex_iterator.h"
# include "classic/rfcomm.h"
2018-08-30 14:45:38 +02:00
# include "classic/sdp_client.h"
# include "classic/sdp_util.h"
2018-08-30 11:20:06 +02:00
# include "l2cap.h"
2017-03-19 22:32:10 +01:00
//------------------------------------------------------------------------------------------------------------
// goep_client.c
//
2018-10-03 17:16:00 +02:00
# define ENABLE_GOEP_L2CAP
2018-10-01 17:23:15 +02:00
2017-03-19 22:32:10 +01:00
typedef enum {
GOEP_INIT ,
GOEP_W4_SDP ,
GOEP_W4_CONNECTION ,
GOEP_CONNECTED ,
} goep_state_t ;
typedef struct {
uint16_t cid ;
goep_state_t state ;
bd_addr_t bd_addr ;
hci_con_handle_t con_handle ;
uint8_t incoming ;
2018-08-30 14:45:38 +02:00
uint8_t rfcomm_port ;
uint16_t l2cap_psm ;
2017-03-19 22:32:10 +01:00
uint16_t bearer_cid ;
uint16_t bearer_mtu ;
2018-08-30 14:45:38 +02:00
uint32_t pbap_supported_features ;
2017-03-19 22:32:10 +01:00
uint8_t obex_opcode ;
uint32_t obex_connection_id ;
int obex_connection_id_set ;
btstack_packet_handler_t client_handler ;
} goep_client_t ;
static goep_client_t _goep_client ;
static goep_client_t * goep_client = & _goep_client ;
2018-08-30 14:45:38 +02:00
static uint8_t attribute_value [ 30 ] ;
static const unsigned int attribute_value_buffer_size = sizeof ( attribute_value ) ;
2018-08-31 20:20:19 +02:00
static uint8_t goep_packet_buffer [ 100 ] ;
2018-09-04 16:14:50 +02:00
# ifdef ENABLE_GOEP_L2CAP
2018-10-03 17:16:00 +02:00
static uint8_t ertm_buffer [ 2000 ] ;
2018-08-31 16:51:44 +02:00
static l2cap_ertm_config_t ertm_config = {
1 , // ertm mandatory
2 , // max transmit, some tests require > 1
2000 ,
12000 ,
2018-10-03 17:16:00 +02:00
250 , // l2cap ertm mtu
2 ,
2 ,
2018-08-31 16:51:44 +02:00
} ;
2018-09-04 16:14:50 +02:00
# endif
2018-08-31 16:51:44 +02:00
2017-03-19 22:32:10 +01:00
static inline void goep_client_emit_connected_event ( goep_client_t * context , uint8_t status ) {
2018-08-31 16:51:44 +02:00
uint8_t event [ 15 ] ;
2017-03-19 22:32:10 +01:00
int pos = 0 ;
event [ pos + + ] = HCI_EVENT_GOEP_META ;
pos + + ; // skip len
event [ pos + + ] = GOEP_SUBEVENT_CONNECTION_OPENED ;
little_endian_store_16 ( event , pos , context - > cid ) ;
pos + = 2 ;
event [ pos + + ] = status ;
memcpy ( & event [ pos ] , context - > bd_addr , 6 ) ;
pos + = 6 ;
little_endian_store_16 ( event , pos , context - > con_handle ) ;
pos + = 2 ;
event [ pos + + ] = context - > incoming ;
event [ 1 ] = pos - 2 ;
if ( pos ! = sizeof ( event ) ) log_error ( " goep_client_emit_connected_event size %u " , pos ) ;
context - > client_handler ( HCI_EVENT_PACKET , context - > cid , & event [ 0 ] , pos ) ;
}
static inline void goep_client_emit_connection_closed_event ( goep_client_t * context ) {
uint8_t event [ 5 ] ;
int pos = 0 ;
event [ pos + + ] = HCI_EVENT_GOEP_META ;
pos + + ; // skip len
event [ pos + + ] = GOEP_SUBEVENT_CONNECTION_CLOSED ;
little_endian_store_16 ( event , pos , context - > cid ) ;
pos + = 2 ;
event [ 1 ] = pos - 2 ;
if ( pos ! = sizeof ( event ) ) log_error ( " goep_client_emit_connection_closed_event size %u " , pos ) ;
context - > client_handler ( HCI_EVENT_PACKET , context - > cid , & event [ 0 ] , pos ) ;
}
static inline void goep_client_emit_can_send_now_event ( goep_client_t * context ) {
uint8_t event [ 5 ] ;
int pos = 0 ;
event [ pos + + ] = HCI_EVENT_GOEP_META ;
pos + + ; // skip len
event [ pos + + ] = GOEP_SUBEVENT_CAN_SEND_NOW ;
little_endian_store_16 ( event , pos , context - > cid ) ;
pos + = 2 ;
event [ 1 ] = pos - 2 ;
if ( pos ! = sizeof ( event ) ) log_error ( " goep_client_emit_can_send_now_event size %u " , pos ) ;
context - > client_handler ( HCI_EVENT_PACKET , context - > cid , & event [ 0 ] , pos ) ;
}
2018-08-30 10:59:28 +02:00
static void goep_client_handle_connection_opened ( goep_client_t * context , uint8_t status , uint16_t mtu ) {
if ( status ) {
context - > state = GOEP_INIT ;
log_info ( " goep_client: open failed, status %u " , status ) ;
} else {
context - > bearer_mtu = mtu ;
context - > state = GOEP_CONNECTED ;
log_info ( " goep_client: connection opened. cid %u, max frame size %u " , context - > bearer_cid , context - > bearer_mtu ) ;
}
goep_client_emit_connected_event ( context , status ) ;
}
static void goep_client_handle_connection_close ( goep_client_t * context ) {
context - > state = GOEP_INIT ;
goep_client_emit_connection_closed_event ( context ) ;
}
2018-08-30 14:45:38 +02:00
static void goep_client_packet_handler ( uint8_t packet_type , uint16_t channel , uint8_t * packet , uint16_t size ) {
2017-03-19 22:32:10 +01:00
UNUSED ( channel ) ;
UNUSED ( size ) ;
2018-08-30 11:14:36 +02:00
goep_client_t * context = goep_client ;
2017-03-19 22:32:10 +01:00
switch ( packet_type ) {
case HCI_EVENT_PACKET :
switch ( hci_event_packet_get_type ( packet ) ) {
2018-09-04 16:14:50 +02:00
# ifdef ENABLE_GOEP_L2CAP
2018-08-30 14:45:38 +02:00
case L2CAP_EVENT_CHANNEL_OPENED :
goep_client_handle_connection_opened ( context , l2cap_event_channel_opened_get_status ( packet ) ,
btstack_min ( l2cap_event_channel_opened_get_remote_mtu ( packet ) , l2cap_event_channel_opened_get_local_mtu ( packet ) ) ) ;
return ;
case L2CAP_EVENT_CAN_SEND_NOW :
goep_client_emit_can_send_now_event ( context ) ;
break ;
case L2CAP_EVENT_CHANNEL_CLOSED :
goep_client_handle_connection_close ( context ) ;
break ;
2018-09-04 16:14:50 +02:00
# endif
2017-03-19 22:32:10 +01:00
case RFCOMM_EVENT_CHANNEL_OPENED :
2018-08-30 11:14:36 +02:00
goep_client_handle_connection_opened ( context , rfcomm_event_channel_opened_get_status ( packet ) , rfcomm_event_channel_opened_get_max_frame_size ( packet ) ) ;
2017-03-19 22:32:10 +01:00
return ;
case RFCOMM_EVENT_CAN_SEND_NOW :
2018-08-30 11:14:36 +02:00
goep_client_emit_can_send_now_event ( context ) ;
2017-03-19 22:32:10 +01:00
break ;
2018-08-17 17:13:44 +02:00
case RFCOMM_EVENT_CHANNEL_CLOSED :
2018-08-30 11:14:36 +02:00
goep_client_handle_connection_close ( context ) ;
2017-03-19 22:32:10 +01:00
break ;
default :
break ;
}
break ;
2018-08-30 14:45:38 +02:00
case L2CAP_DATA_PACKET :
2017-03-19 22:32:10 +01:00
case RFCOMM_DATA_PACKET :
2018-08-30 11:14:36 +02:00
context - > client_handler ( GOEP_DATA_PACKET , context - > cid , packet , size ) ;
2017-03-19 22:32:10 +01:00
break ;
default :
break ;
}
}
2018-08-30 14:45:38 +02:00
static void goep_client_handle_sdp_query_event ( uint8_t packet_type , uint16_t channel , uint8_t * packet , uint16_t size ) {
goep_client_t * context = goep_client ;
2017-03-19 22:32:10 +01:00
UNUSED ( packet_type ) ;
UNUSED ( channel ) ;
UNUSED ( size ) ;
2018-08-30 14:45:38 +02:00
des_iterator_t des_list_it ;
des_iterator_t prot_it ;
uint8_t status ;
switch ( hci_event_packet_get_type ( packet ) ) {
case SDP_EVENT_QUERY_ATTRIBUTE_VALUE :
// check if relevant attribute
switch ( sdp_event_query_attribute_byte_get_attribute_id ( packet ) ) {
case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST :
case BLUETOOTH_ATTRIBUTE_PBAP_SUPPORTED_FEATURES :
2018-09-04 16:14:50 +02:00
# ifdef ENABLE_GOEP_L2CAP
2018-08-30 14:45:38 +02:00
case BLUETOOTH_ATTRIBUTE_GOEP_L2CAP_PSM :
2018-09-04 16:14:50 +02:00
# endif
2018-08-30 14:45:38 +02:00
break ;
default :
return ;
}
// warn if attribute too large to fit in our buffer
if ( sdp_event_query_attribute_byte_get_attribute_length ( packet ) > attribute_value_buffer_size ) {
log_error ( " SDP attribute value size exceeded for attribute %x: available %d, required %d " , sdp_event_query_attribute_byte_get_attribute_id ( packet ) , attribute_value_buffer_size , sdp_event_query_attribute_byte_get_attribute_length ( packet ) ) ;
break ;
}
// store single byte
attribute_value [ sdp_event_query_attribute_byte_get_data_offset ( packet ) ] = sdp_event_query_attribute_byte_get_data ( packet ) ;
// wait until value fully received
if ( ( uint16_t ) ( sdp_event_query_attribute_byte_get_data_offset ( packet ) + 1 ) ! = sdp_event_query_attribute_byte_get_attribute_length ( packet ) ) break ;
// process attributes
switch ( sdp_event_query_attribute_byte_get_attribute_id ( packet ) ) {
case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST :
for ( des_iterator_init ( & des_list_it , attribute_value ) ; des_iterator_has_more ( & des_list_it ) ; des_iterator_next ( & des_list_it ) ) {
uint8_t * des_element ;
uint8_t * element ;
uint32_t uuid ;
2018-09-28 15:10:14 +02:00
# ifdef ENABLE_GOEP_L2CAP
uint16_t l2cap_psm ;
# endif
2018-08-30 14:45:38 +02:00
if ( des_iterator_get_type ( & des_list_it ) ! = DE_DES ) continue ;
des_element = des_iterator_get_element ( & des_list_it ) ;
des_iterator_init ( & prot_it , des_element ) ;
2018-10-01 17:23:15 +02:00
// first element is UUID
element = des_iterator_get_element ( & prot_it ) ;
2018-08-30 14:45:38 +02:00
if ( de_get_element_type ( element ) ! = DE_UUID ) continue ;
uuid = de_get_uuid32 ( element ) ;
2018-10-01 17:23:15 +02:00
des_iterator_next ( & prot_it ) ;
if ( ! des_iterator_has_more ( & prot_it ) ) continue ;
// second element is RFCOMM server channel or L2CAP PSM
element = des_iterator_get_element ( & prot_it ) ;
2018-08-30 14:45:38 +02:00
switch ( uuid ) {
2018-09-28 15:10:14 +02:00
# ifdef ENABLE_GOEP_L2CAP
case BLUETOOTH_PROTOCOL_L2CAP :
if ( de_element_get_uint16 ( element , & l2cap_psm ) ) {
context - > l2cap_psm = l2cap_psm ;
}
break ;
# endif
2018-08-30 14:45:38 +02:00
case BLUETOOTH_PROTOCOL_RFCOMM :
context - > rfcomm_port = element [ de_get_header_size ( element ) ] ;
break ;
default :
break ;
}
}
break ;
2018-09-04 16:14:50 +02:00
# ifdef ENABLE_GOEP_L2CAP
2018-08-30 14:45:38 +02:00
case BLUETOOTH_ATTRIBUTE_GOEP_L2CAP_PSM :
de_element_get_uint16 ( attribute_value , & context - > l2cap_psm ) ;
break ;
2018-09-04 16:14:50 +02:00
# endif
2018-08-30 14:45:38 +02:00
case BLUETOOTH_ATTRIBUTE_PBAP_SUPPORTED_FEATURES :
if ( de_get_element_type ( attribute_value ) ! = DE_UINT ) break ;
if ( de_get_size_type ( attribute_value ) ! = DE_SIZE_32 ) break ;
context - > pbap_supported_features = big_endian_read_32 ( attribute_value , de_get_header_size ( attribute_value ) ) ;
log_info ( " pbap_supported_features 0x%x " , context - > pbap_supported_features ) ;
break ;
default :
break ;
}
2017-03-19 22:32:10 +01:00
break ;
2018-08-30 14:45:38 +02:00
2017-03-19 22:32:10 +01:00
case SDP_EVENT_QUERY_COMPLETE :
2018-08-30 14:45:38 +02:00
status = sdp_event_query_complete_get_status ( packet ) ;
if ( status ! = ERROR_CODE_SUCCESS ) {
log_info ( " GOEP client, SDP query failed 0x%02x " , status ) ;
2018-08-30 11:14:36 +02:00
context - > state = GOEP_INIT ;
2018-08-30 14:45:38 +02:00
goep_client_emit_connected_event ( goep_client , status ) ;
2017-08-22 11:11:10 +02:00
break ;
2018-08-30 14:45:38 +02:00
}
if ( context - > rfcomm_port = = 0 & & context - > l2cap_psm = = 0 ) {
log_info ( " No GOEP RFCOMM or L2CAP server found " ) ;
2018-08-30 11:14:36 +02:00
context - > state = GOEP_INIT ;
2017-03-19 22:32:10 +01:00
goep_client_emit_connected_event ( goep_client , ERROR_CODE_UNSUPPORTED_FEATURE_OR_PARAMETER_VALUE ) ;
break ;
}
2018-09-04 16:14:50 +02:00
# ifdef ENABLE_GOEP_L2CAP
2018-08-30 14:45:38 +02:00
if ( context - > l2cap_psm ) {
log_info ( " Remote GOEP L2CAP PSM: %u " , context - > l2cap_psm ) ;
2018-08-31 16:51:44 +02:00
l2cap_create_ertm_channel ( & goep_client_packet_handler , context - > bd_addr , context - > l2cap_psm ,
& ertm_config , ertm_buffer , sizeof ( ertm_buffer ) , & context - > bearer_cid ) ;
2018-09-04 16:14:50 +02:00
return ;
2018-08-30 14:45:38 +02:00
}
2018-09-04 16:14:50 +02:00
# endif
log_info ( " Remote GOEP RFCOMM Server Channel: %u " , context - > rfcomm_port ) ;
rfcomm_create_channel ( & goep_client_packet_handler , context - > bd_addr , context - > rfcomm_port , & context - > bearer_cid ) ;
2017-03-19 22:32:10 +01:00
}
}
2018-08-30 11:14:36 +02:00
static uint8_t * goep_client_get_outgoing_buffer ( goep_client_t * context ) {
2018-08-30 14:45:38 +02:00
if ( context - > l2cap_psm ) {
2018-08-31 20:20:19 +02:00
return goep_packet_buffer ;
2018-08-30 11:14:36 +02:00
} else {
return rfcomm_get_outgoing_buffer ( ) ;
}
}
2017-03-19 22:32:10 +01:00
static void goep_client_packet_append ( const uint8_t * data , uint16_t len ) {
2018-08-30 11:14:36 +02:00
goep_client_t * context = goep_client ;
uint8_t * buffer = goep_client_get_outgoing_buffer ( context ) ;
2017-03-19 22:32:10 +01:00
uint16_t pos = big_endian_read_16 ( buffer , 1 ) ;
memcpy ( & buffer [ pos ] , data , len ) ;
pos + = len ;
big_endian_store_16 ( buffer , 1 , pos ) ;
}
static void goep_client_packet_init ( uint16_t goep_cid , uint8_t opcode ) {
UNUSED ( goep_cid ) ;
2018-08-30 11:14:36 +02:00
goep_client_t * context = goep_client ;
2018-08-30 14:45:38 +02:00
if ( context - > l2cap_psm ) {
2018-08-30 11:14:36 +02:00
} else {
rfcomm_reserve_packet_buffer ( ) ;
}
uint8_t * buffer = goep_client_get_outgoing_buffer ( context ) ;
2017-03-19 22:32:10 +01:00
buffer [ 0 ] = opcode ;
big_endian_store_16 ( buffer , 1 , 3 ) ;
// store opcode for parsing of response
2018-08-30 11:14:36 +02:00
context - > obex_opcode = opcode ;
2017-03-19 22:32:10 +01:00
}
2018-10-01 21:03:14 +02:00
static void goep_client_add_variable_header ( uint16_t goep_cid , uint8_t header_type , uint16_t header_data_length , const uint8_t * header_data ) {
UNUSED ( goep_cid ) ;
uint8_t header [ 3 ] ;
header [ 0 ] = header_type ;
big_endian_store_16 ( header , 1 , sizeof ( header ) + header_data_length ) ;
goep_client_packet_append ( & header [ 0 ] , sizeof ( header ) ) ;
goep_client_packet_append ( header_data , header_data_length ) ;
}
2018-10-03 17:16:00 +02:00
# if 1
2018-10-01 21:03:14 +02:00
static void goep_client_add_byte_header ( uint16_t goep_cid , uint8_t header_type , uint8_t value ) {
UNUSED ( goep_cid ) ;
uint8_t header [ 2 ] ;
header [ 0 ] = header_type ;
header [ 1 ] = value ;
goep_client_packet_append ( & header [ 0 ] , sizeof ( header ) ) ;
}
2018-10-02 14:22:44 +02:00
# endif
2018-10-01 21:03:14 +02:00
static void goep_client_add_word_header ( uint16_t goep_cid , uint8_t header_type , uint32_t value ) {
UNUSED ( goep_cid ) ;
uint8_t header [ 5 ] ;
header [ 0 ] = header_type ;
big_endian_store_32 ( header , 1 , value ) ;
goep_client_packet_append ( & header [ 0 ] , sizeof ( header ) ) ;
}
2017-03-19 22:32:10 +01:00
static void goep_client_packet_add_connection_id ( uint16_t goep_cid ) {
UNUSED ( goep_cid ) ;
2018-08-30 11:14:36 +02:00
goep_client_t * context = goep_client ;
2017-03-19 22:32:10 +01:00
// add connection_id header if set, must be first header if used
2018-08-30 11:14:36 +02:00
if ( context - > obex_connection_id ! = OBEX_CONNECTION_ID_INVALID ) {
2018-10-01 21:03:14 +02:00
goep_client_add_word_header ( goep_cid , OBEX_HEADER_CONNECTION_ID , context - > obex_connection_id ) ;
2017-03-19 22:32:10 +01:00
}
}
void goep_client_init ( void ) {
memset ( goep_client , 0 , sizeof ( goep_client_t ) ) ;
goep_client - > state = GOEP_INIT ;
goep_client - > cid = 1 ;
goep_client - > obex_connection_id = OBEX_CONNECTION_ID_INVALID ;
}
uint8_t goep_client_create_connection ( btstack_packet_handler_t handler , bd_addr_t addr , uint16_t uuid , uint16_t * out_cid ) {
2018-08-30 11:14:36 +02:00
goep_client_t * context = goep_client ;
if ( context - > state ! = GOEP_INIT ) return BTSTACK_MEMORY_ALLOC_FAILED ;
context - > client_handler = handler ;
context - > state = GOEP_W4_SDP ;
2018-08-30 14:45:38 +02:00
context - > l2cap_psm = 0 ;
context - > rfcomm_port = 0 ;
2018-09-28 11:43:22 +02:00
context - > pbap_supported_features = PBAP_FEATURES_NOT_PRESENT ;
2018-08-30 11:14:36 +02:00
memcpy ( context - > bd_addr , addr , 6 ) ;
2018-08-30 14:45:38 +02:00
sdp_client_query_uuid16 ( & goep_client_handle_sdp_query_event , context - > bd_addr , uuid ) ;
2018-08-30 11:14:36 +02:00
* out_cid = context - > cid ;
2017-03-19 22:32:10 +01:00
return 0 ;
}
2018-09-20 17:44:10 +02:00
uint32_t goep_client_get_pbap_supported_features ( uint16_t goep_cid ) {
UNUSED ( goep_cid ) ;
goep_client_t * context = goep_client ;
return context - > pbap_supported_features ;
}
2017-03-19 22:32:10 +01:00
uint8_t goep_client_disconnect ( uint16_t goep_cid ) {
UNUSED ( goep_cid ) ;
2018-08-30 11:14:36 +02:00
goep_client_t * context = goep_client ;
rfcomm_disconnect ( context - > bearer_cid ) ;
2017-03-19 22:32:10 +01:00
return 0 ;
}
void goep_client_set_connection_id ( uint16_t goep_cid , uint32_t connection_id ) {
UNUSED ( goep_cid ) ;
2018-08-30 11:14:36 +02:00
goep_client_t * context = goep_client ;
context - > obex_connection_id = connection_id ;
2017-03-19 22:32:10 +01:00
}
uint8_t goep_client_get_request_opcode ( uint16_t goep_cid ) {
UNUSED ( goep_cid ) ;
2018-08-30 11:14:36 +02:00
goep_client_t * context = goep_client ;
return context - > obex_opcode ;
2017-03-19 22:32:10 +01:00
}
void goep_client_request_can_send_now ( uint16_t goep_cid ) {
UNUSED ( goep_cid ) ;
2018-08-30 11:14:36 +02:00
goep_client_t * context = goep_client ;
2018-08-30 14:45:38 +02:00
if ( context - > l2cap_psm ) {
2018-08-30 11:20:06 +02:00
l2cap_request_can_send_now_event ( context - > bearer_cid ) ;
2018-08-30 11:14:36 +02:00
} else {
rfcomm_request_can_send_now_event ( context - > bearer_cid ) ;
}
2017-03-19 22:32:10 +01:00
}
void goep_client_create_connect_request ( uint16_t goep_cid , uint8_t obex_version_number , uint8_t flags , uint16_t maximum_obex_packet_length ) {
UNUSED ( goep_cid ) ;
2018-08-30 11:14:36 +02:00
goep_client_t * context = goep_client ;
2017-03-19 22:32:10 +01:00
goep_client_packet_init ( goep_cid , OBEX_OPCODE_CONNECT ) ;
uint8_t fields [ 4 ] ;
fields [ 0 ] = obex_version_number ;
fields [ 1 ] = flags ;
2018-08-30 14:45:38 +02:00
// workaround: limit OBEX packet len to L2CAP/RFCOMM MTU to avoid handling of fragemented packets
2018-08-30 11:14:36 +02:00
maximum_obex_packet_length = btstack_min ( maximum_obex_packet_length , context - > bearer_mtu ) ;
2017-03-19 22:32:10 +01:00
big_endian_store_16 ( fields , 2 , maximum_obex_packet_length ) ;
goep_client_packet_append ( & fields [ 0 ] , sizeof ( fields ) ) ;
}
2018-09-05 14:26:29 +02:00
void goep_client_create_disconnect_request ( uint16_t goep_cid ) {
UNUSED ( goep_cid ) ;
goep_client_packet_init ( goep_cid , OBEX_OPCODE_DISCONNECT ) ;
goep_client_packet_add_connection_id ( goep_cid ) ;
}
2017-03-19 22:32:10 +01:00
void goep_client_create_get_request ( uint16_t goep_cid ) {
goep_client_packet_init ( goep_cid , OBEX_OPCODE_GET | OBEX_OPCODE_FINAL_BIT_MASK ) ;
goep_client_packet_add_connection_id ( goep_cid ) ;
2018-10-03 17:16:00 +02:00
goep_client_add_byte_header ( goep_cid , OBEX_HEADER_SINGLE_RESPONSE_MODE , 0x01 ) ;
2017-03-19 22:32:10 +01:00
}
void goep_client_create_set_path_request ( uint16_t goep_cid , uint8_t flags ) {
UNUSED ( goep_cid ) ;
goep_client_packet_init ( goep_cid , OBEX_OPCODE_SETPATH ) ;
uint8_t fields [ 2 ] ;
fields [ 0 ] = flags ;
fields [ 1 ] = 0 ; // reserved
goep_client_packet_append ( & fields [ 0 ] , sizeof ( fields ) ) ;
goep_client_packet_add_connection_id ( goep_cid ) ;
}
2018-08-20 17:47:18 +02:00
void goep_client_add_header_target ( uint16_t goep_cid , uint16_t length , const uint8_t * target ) {
2018-10-01 21:03:14 +02:00
goep_client_add_variable_header ( goep_cid , OBEX_HEADER_TARGET , length , target ) ;
2018-08-20 17:47:18 +02:00
}
void goep_client_add_header_application_parameters ( uint16_t goep_cid , uint16_t length , const uint8_t * data ) {
2018-10-01 21:03:14 +02:00
goep_client_add_variable_header ( goep_cid , OBEX_HEADER_APPLICATION_PARAMETERS , length , data ) ;
2017-03-19 22:32:10 +01:00
}
2018-09-17 17:08:17 +02:00
void goep_client_add_header_challenge_response ( uint16_t goep_cid , uint16_t length , const uint8_t * data ) {
2018-10-01 21:03:14 +02:00
goep_client_add_variable_header ( goep_cid , OBEX_HEADER_AUTHENTICATION_RESPONSE , length , data ) ;
2018-09-17 17:08:17 +02:00
}
2017-03-19 22:32:10 +01:00
void goep_client_add_header_name ( uint16_t goep_cid , const char * name ) {
UNUSED ( goep_cid ) ;
2018-08-30 11:14:36 +02:00
goep_client_t * context = goep_client ;
2017-03-19 22:32:10 +01:00
int len_incl_zero = strlen ( name ) + 1 ;
2018-08-30 11:14:36 +02:00
uint8_t * buffer = goep_client_get_outgoing_buffer ( context ) ;
2017-03-19 22:32:10 +01:00
uint16_t pos = big_endian_read_16 ( buffer , 1 ) ;
buffer [ pos + + ] = OBEX_HEADER_NAME ;
big_endian_store_16 ( buffer , pos , 1 + 2 + len_incl_zero * 2 ) ;
pos + = 2 ;
int i ;
// @note name[len] == 0
for ( i = 0 ; i < len_incl_zero ; i + + ) {
buffer [ pos + + ] = 0 ;
buffer [ pos + + ] = * name + + ;
}
big_endian_store_16 ( buffer , 1 , pos ) ;
}
void goep_client_add_header_type ( uint16_t goep_cid , const char * type ) {
UNUSED ( goep_cid ) ;
uint8_t header [ 3 ] ;
header [ 0 ] = OBEX_HEADER_TYPE ;
int len_incl_zero = strlen ( type ) + 1 ;
big_endian_store_16 ( header , 1 , 1 + 2 + len_incl_zero ) ;
goep_client_packet_append ( & header [ 0 ] , sizeof ( header ) ) ;
goep_client_packet_append ( ( const uint8_t * ) type , len_incl_zero ) ;
}
int goep_client_execute ( uint16_t goep_cid ) {
UNUSED ( goep_cid ) ;
2018-08-30 11:14:36 +02:00
goep_client_t * context = goep_client ;
uint8_t * buffer = goep_client_get_outgoing_buffer ( context ) ;
2017-03-19 22:32:10 +01:00
uint16_t pos = big_endian_read_16 ( buffer , 1 ) ;
2018-08-30 14:45:38 +02:00
if ( context - > l2cap_psm ) {
2018-08-31 20:20:19 +02:00
// return l2cap_send_prepared(context->bearer_cid, pos);
return l2cap_send ( context - > bearer_cid , buffer , pos ) ;
2018-08-30 11:14:36 +02:00
} else {
return rfcomm_send_prepared ( context - > bearer_cid , pos ) ;
}
2017-03-19 22:32:10 +01:00
}