xref: /btstack/src/classic/goep_client.c (revision 29274966a2f18a918e5c1513d9ac17b6b7cbf396)
1 /*
2  * Copyright (C) 2014 BlueKitchen GmbH
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holders nor the names of
14  *    contributors may be used to endorse or promote products derived
15  *    from this software without specific prior written permission.
16  * 4. Any redistribution, use, or modification is done solely for
17  *    personal benefit and not for any commercial purpose or for
18  *    monetary gain.
19  *
20  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
24  * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * Please inquire about commercial licensing options at
34  * [email protected]
35  *
36  */
37 
38 #define BTSTACK_FILE__ "goep_client.c"
39 
40 #include "btstack_config.h"
41 
42 #include <stdint.h>
43 #include <string.h>
44 
45 #include "btstack_debug.h"
46 #include "hci_dump.h"
47 #include "bluetooth_sdp.h"
48 #include "btstack_event.h"
49 #include "classic/goep_client.h"
50 #include "classic/obex_message_builder.h"
51 #include "classic/obex.h"
52 #include "classic/obex_iterator.h"
53 #include "classic/rfcomm.h"
54 #include "classic/sdp_client.h"
55 #include "classic/sdp_util.h"
56 #include "l2cap.h"
57 
58 //------------------------------------------------------------------------------------------------------------
59 // goep_client.c
60 //
61 
62 #ifdef ENABLE_GOEP_L2CAP
63 #ifndef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
64 #error "ENABLE_GOEP_L2CAP requires ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE. Please enable ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE or disable ENABLE_GOEP_L2CAP"
65 #endif
66 #endif
67 
68 static uint16_t goep_client_cid;
69 static btstack_linked_list_t goep_clients;
70 
71 static goep_client_t *    goep_client_sdp_active;
72 static uint8_t            goep_client_sdp_query_attribute_value[30];
73 static const unsigned int goep_client_sdp_query_attribute_value_buffer_size = sizeof(goep_client_sdp_query_attribute_value);
74 static uint8_t goep_packet_buffer[500];
75 
goep_client_emit_connected_event(goep_client_t * goep_client,uint8_t status)76 static inline void goep_client_emit_connected_event(goep_client_t * goep_client, uint8_t status){
77     uint8_t event[15];
78     int pos = 0;
79     event[pos++] = HCI_EVENT_GOEP_META;
80     pos++;  // skip len
81     event[pos++] = GOEP_SUBEVENT_CONNECTION_OPENED;
82     little_endian_store_16(event, pos, goep_client->cid);
83     pos+=2;
84     event[pos++] = status;
85     (void)memcpy(&event[pos], goep_client->bd_addr, 6);
86     pos += 6;
87     little_endian_store_16(event, pos, goep_client->con_handle);
88     pos += 2;
89     event[pos++] = goep_client->incoming;
90     event[1] = pos - 2;
91     if (pos != sizeof(event)) log_error("goep_client_emit_connected_event size %u", pos);
92     goep_client->client_handler(HCI_EVENT_PACKET, goep_client->cid, &event[0], pos);
93 }
94 
goep_client_emit_connection_closed_event(goep_client_t * goep_client)95 static inline void goep_client_emit_connection_closed_event(goep_client_t * goep_client){
96     uint8_t event[5];
97     int pos = 0;
98     event[pos++] = HCI_EVENT_GOEP_META;
99     pos++;  // skip len
100     event[pos++] = GOEP_SUBEVENT_CONNECTION_CLOSED;
101     little_endian_store_16(event, pos, goep_client->cid);
102     pos+=2;
103     event[1] = pos - 2;
104     if (pos != sizeof(event)) log_error("goep_client_emit_connection_closed_event size %u", pos);
105     goep_client->client_handler(HCI_EVENT_PACKET, goep_client->cid, &event[0], pos);
106 }
107 
goep_client_emit_can_send_now_event(goep_client_t * goep_client)108 static inline void goep_client_emit_can_send_now_event(goep_client_t * goep_client){
109     uint8_t event[5];
110     int pos = 0;
111     event[pos++] = HCI_EVENT_GOEP_META;
112     pos++;  // skip len
113     event[pos++] = GOEP_SUBEVENT_CAN_SEND_NOW;
114     little_endian_store_16(event, pos, goep_client->cid);
115     pos+=2;
116     event[1] = pos - 2;
117     if (pos != sizeof(event)) log_error("goep_client_emit_can_send_now_event size %u", pos);
118     goep_client->client_handler(HCI_EVENT_PACKET, goep_client->cid, &event[0], pos);
119 }
120 
goep_client_handle_connection_opened(goep_client_t * goep_client,uint8_t status,uint16_t mtu)121 static void goep_client_handle_connection_opened(goep_client_t * goep_client, uint8_t status, uint16_t mtu){
122     if (status) {
123         goep_client->state = GOEP_CLIENT_INIT;
124         btstack_linked_list_remove(&goep_clients, (btstack_linked_item_t *) goep_client);
125         log_info("goep_client: open failed, status %u", status);
126     } else {
127         goep_client->bearer_mtu = mtu;
128         goep_client->state = GOEP_CLIENT_CONNECTED;
129         log_info("goep_client: connection opened. cid %u, max frame size %u", goep_client->bearer_cid, goep_client->bearer_mtu);
130     }
131     goep_client_emit_connected_event(goep_client, status);
132 }
133 
goep_client_handle_connection_close(goep_client_t * goep_client)134 static void goep_client_handle_connection_close(goep_client_t * goep_client){
135     goep_client->state = GOEP_CLIENT_INIT;
136     btstack_linked_list_remove(&goep_clients, (btstack_linked_item_t *) goep_client);
137     goep_client_emit_connection_closed_event(goep_client);
138 }
139 
goep_client_for_cid(uint16_t cid)140 static goep_client_t * goep_client_for_cid(uint16_t cid){
141     btstack_linked_list_iterator_t it;
142     btstack_linked_list_iterator_init(&it, &goep_clients);
143     while (btstack_linked_list_iterator_has_next(&it)){
144         goep_client_t * goep_client = (goep_client_t *) btstack_linked_list_iterator_next(&it);
145         if (goep_client->cid == cid){
146             return goep_client;
147         }
148     }
149     return NULL;
150 }
151 
goep_client_for_bearer_cid(uint16_t bearer_cid)152 static goep_client_t * goep_client_for_bearer_cid(uint16_t bearer_cid){
153     btstack_linked_list_iterator_t it;
154     btstack_linked_list_iterator_init(&it, &goep_clients);
155     while (btstack_linked_list_iterator_has_next(&it)){
156         goep_client_t * goep_client = (goep_client_t *) btstack_linked_list_iterator_next(&it);
157         if (goep_client->bearer_cid == bearer_cid){
158             return goep_client;
159         }
160     }
161     return NULL;
162 }
163 
goep_client_packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)164 static void goep_client_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
165     UNUSED(channel);
166     UNUSED(size);
167     goep_client_t * goep_client;
168     switch (packet_type){
169         case HCI_EVENT_PACKET:
170             switch (hci_event_packet_get_type(packet)) {
171 #ifdef ENABLE_GOEP_L2CAP
172                 case L2CAP_EVENT_CHANNEL_OPENED:
173                     goep_client = goep_client_for_bearer_cid(l2cap_event_channel_opened_get_local_cid(packet));
174                     btstack_assert(goep_client != NULL);
175                     goep_client_handle_connection_opened(goep_client, l2cap_event_channel_opened_get_status(packet),
176                                                          btstack_min(l2cap_event_channel_opened_get_remote_mtu(packet), l2cap_event_channel_opened_get_local_mtu(packet)));
177                     break;
178                 case L2CAP_EVENT_CAN_SEND_NOW:
179                     goep_client = goep_client_for_bearer_cid(l2cap_event_can_send_now_get_local_cid(packet));
180                     btstack_assert(goep_client != NULL);
181                     goep_client_emit_can_send_now_event(goep_client);
182                     break;
183                 case L2CAP_EVENT_CHANNEL_CLOSED:
184                     goep_client = goep_client_for_bearer_cid(l2cap_event_channel_closed_get_local_cid(packet));
185                     btstack_assert(goep_client != NULL);
186                     goep_client_handle_connection_close(goep_client);
187                     break;
188 #endif
189                 case RFCOMM_EVENT_CHANNEL_OPENED:
190                     goep_client = goep_client_for_bearer_cid(rfcomm_event_channel_opened_get_rfcomm_cid(packet));
191                     btstack_assert(goep_client != NULL);
192                     goep_client_handle_connection_opened(goep_client, rfcomm_event_channel_opened_get_status(packet), rfcomm_event_channel_opened_get_max_frame_size(packet));
193                     return;
194                 case RFCOMM_EVENT_CAN_SEND_NOW:
195                     goep_client = goep_client_for_bearer_cid(rfcomm_event_can_send_now_get_rfcomm_cid(packet));
196                     btstack_assert(goep_client != NULL);
197                     goep_client_emit_can_send_now_event(goep_client);
198                     break;
199                 case RFCOMM_EVENT_CHANNEL_CLOSED:
200                     goep_client = goep_client_for_bearer_cid(rfcomm_event_channel_closed_get_rfcomm_cid(packet));
201                     btstack_assert(goep_client != NULL);
202                     goep_client_handle_connection_close(goep_client);
203                     break;
204                 default:
205                     break;
206             }
207             break;
208         case L2CAP_DATA_PACKET:
209         case RFCOMM_DATA_PACKET:
210             goep_client = goep_client_for_bearer_cid(channel);
211             btstack_assert(goep_client != NULL);
212             goep_client->client_handler(GOEP_DATA_PACKET, goep_client->cid, packet, size);
213             break;
214         default:
215             break;
216     }
217 }
218 
goep_client_handle_sdp_query_end_of_record(goep_client_t * goep_client)219 static void goep_client_handle_sdp_query_end_of_record(goep_client_t * goep_client){
220     if (goep_client->uuid == BLUETOOTH_SERVICE_CLASS_MESSAGE_ACCESS_SERVER){
221         // use matching SDP record with highest MAP version as there might be additional records for backwards compatibility
222         if (goep_client->mas_info.instance_id == goep_client->map_mas_instance_id){
223             if (goep_client->mas_info.version > goep_client->map_version){
224                 // Requested MAS Instance found, accept info
225                 goep_client->rfcomm_port = goep_client->mas_info.rfcomm_port;
226                 goep_client->profile_supported_features = goep_client->mas_info.supported_features;
227                 goep_client->map_supported_message_types = goep_client->mas_info.supported_message_types;
228 #ifdef ENABLE_GOEP_L2CAP
229                 goep_client->l2cap_psm = goep_client->mas_info.l2cap_psm;
230                 goep_client->map_version = goep_client->mas_info.version;
231                 log_info("MAS Instance #%u found, version %u.%u: rfcomm #%u, l2cap 0x%04x ", goep_client->map_mas_instance_id,
232                          goep_client->map_version, goep_client->map_version, goep_client->rfcomm_port, goep_client->l2cap_psm);
233 #else
234                 log_info("MAS Instance #%u found, rfcomm #%u", goep_client->map_mas_instance_id,
235                      goep_client->rfcomm_port);
236 #endif
237             }
238         }
239     }
240 }
goep_client_start_connect(goep_client_t * goep_client)241 static uint8_t goep_client_start_connect(goep_client_t * goep_client){
242 #ifdef ENABLE_GOEP_L2CAP
243     if (goep_client->l2cap_psm && (goep_client->ertm_buffer != NULL)){
244         log_info("Remote GOEP L2CAP PSM: 0x%x", goep_client->l2cap_psm);
245         return l2cap_ertm_create_channel(&goep_client_packet_handler, goep_client->bd_addr, goep_client->l2cap_psm,
246         &goep_client->ertm_config, goep_client->ertm_buffer,
247         goep_client->ertm_buffer_size, &goep_client->bearer_cid);
248     }
249 #endif
250     log_info("Remote GOEP RFCOMM Server Channel: %u", goep_client->rfcomm_port);
251     return rfcomm_create_channel(&goep_client_packet_handler, goep_client->bd_addr, goep_client->rfcomm_port, &goep_client->bearer_cid);
252 }
253 
goep_client_handle_sdp_query_event(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)254 static void goep_client_handle_sdp_query_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
255     goep_client_t * goep_client = goep_client_sdp_active;
256     btstack_assert(goep_client != NULL);
257 
258     UNUSED(packet_type);
259     UNUSED(channel);
260     UNUSED(size);
261 
262     des_iterator_t des_list_it;
263     des_iterator_t prot_it;
264     uint8_t status;
265     uint16_t record_index;
266     bool goep_server_found;
267 
268     switch (hci_event_packet_get_type(packet)){
269         case SDP_EVENT_QUERY_ATTRIBUTE_VALUE:
270 
271             // detect new record
272             record_index = sdp_event_query_attribute_byte_get_record_id(packet);
273             if (record_index != goep_client->record_index){
274                 goep_client->record_index = record_index;
275                 goep_client_handle_sdp_query_end_of_record(goep_client);
276                 memset(&goep_client->mas_info, 0, sizeof(goep_client->mas_info));
277             }
278 
279             // check if relevant attribute
280             switch(sdp_event_query_attribute_byte_get_attribute_id(packet)){
281                 case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST:
282                 case BLUETOOTH_ATTRIBUTE_PBAP_SUPPORTED_FEATURES:
283                 case BLUETOOTH_ATTRIBUTE_MAS_INSTANCE_ID:
284                 case BLUETOOTH_ATTRIBUTE_SUPPORTED_MESSAGE_TYPES:
285                 case BLUETOOTH_ATTRIBUTE_BLUETOOTH_PROFILE_DESCRIPTOR_LIST:
286 #ifdef ENABLE_GOEP_L2CAP
287                 case BLUETOOTH_ATTRIBUTE_GOEP_L2CAP_PSM:
288 #endif
289                     break;
290                 default:
291                     return;
292             }
293 
294             // warn if attribute too large to fit in our buffer
295             if (sdp_event_query_attribute_byte_get_attribute_length(packet) > goep_client_sdp_query_attribute_value_buffer_size) {
296                 log_error("SDP attribute value size exceeded for attribute %x: available %d, required %d", sdp_event_query_attribute_byte_get_attribute_id(packet), goep_client_sdp_query_attribute_value_buffer_size, sdp_event_query_attribute_byte_get_attribute_length(packet));
297                 break;
298             }
299 
300             // store single byte
301             goep_client_sdp_query_attribute_value[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet);
302 
303             // wait until value fully received
304             if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) != sdp_event_query_attribute_byte_get_attribute_length(packet)) break;
305 
306             // process attributes
307             switch(sdp_event_query_attribute_byte_get_attribute_id(packet)) {
308                 case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST:
309                     for (des_iterator_init(&des_list_it, goep_client_sdp_query_attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) {
310                         uint8_t       *des_element;
311                         uint8_t       *element;
312                         uint32_t       uuid;
313 
314                         if (des_iterator_get_type(&des_list_it) != DE_DES) continue;
315 
316                         des_element = des_iterator_get_element(&des_list_it);
317                         des_iterator_init(&prot_it, des_element);
318 
319                         // first element is UUID
320                         element = des_iterator_get_element(&prot_it);
321                         if (de_get_element_type(element) != DE_UUID) continue;
322 
323                         uuid = de_get_uuid32(element);
324                         des_iterator_next(&prot_it);
325                         if (!des_iterator_has_more(&prot_it)) continue;
326 
327                         // second element is RFCOMM server channel or L2CAP PSM
328                         element = des_iterator_get_element(&prot_it);
329                         if (uuid == BLUETOOTH_PROTOCOL_RFCOMM){
330                             if (goep_client->uuid == BLUETOOTH_SERVICE_CLASS_MESSAGE_ACCESS_SERVER) {
331                                 goep_client->mas_info.rfcomm_port = element[de_get_header_size(element)];
332                             } else {
333                                 goep_client->rfcomm_port = element[de_get_header_size(element)];
334                             }
335                         }
336                     }
337                     break;
338 
339                 case BLUETOOTH_ATTRIBUTE_BLUETOOTH_PROFILE_DESCRIPTOR_LIST:
340                     for (des_iterator_init(&des_list_it, goep_client_sdp_query_attribute_value); des_iterator_has_more(&des_list_it); des_iterator_next(&des_list_it)) {
341                         uint8_t       *des_element;
342                         uint8_t       *element;
343                         uint32_t       uuid;
344 
345                         if (des_iterator_get_type(&des_list_it) != DE_DES) continue;
346 
347                         des_element = des_iterator_get_element(&des_list_it);
348                         des_iterator_init(&prot_it, des_element);
349                         element = des_iterator_get_element(&prot_it);
350 
351                         if (de_get_element_type(element) != DE_UUID) continue;
352 
353                         uuid = de_get_uuid32(element);
354                         des_iterator_next(&prot_it);
355                         switch (uuid){
356                             case BLUETOOTH_SERVICE_CLASS_MESSAGE_ACCESS_PROFILE:
357                                 if (!des_iterator_has_more(&prot_it)) continue;
358                                 de_element_get_uint16(des_iterator_get_element(&prot_it), &goep_client->mas_info.version);
359                                 break;
360                             default:
361                                 break;
362                         }
363                     }
364                     break;
365 
366 #ifdef ENABLE_GOEP_L2CAP
367                 case BLUETOOTH_ATTRIBUTE_GOEP_L2CAP_PSM:
368                     if (goep_client->uuid == BLUETOOTH_SERVICE_CLASS_MESSAGE_ACCESS_SERVER){
369                         de_element_get_uint16(goep_client_sdp_query_attribute_value, &goep_client->mas_info.l2cap_psm);
370                     } else {
371                         de_element_get_uint16(goep_client_sdp_query_attribute_value, &goep_client->l2cap_psm);
372                     }
373                     break;
374 #endif
375 
376                 // BLUETOOTH_ATTRIBUTE_PBAP_SUPPORTED_FEATURES == BLUETOOTH_ATTRIBUTE_MAP_SUPPORTED_FEATURES == 0x0317
377                 case BLUETOOTH_ATTRIBUTE_PBAP_SUPPORTED_FEATURES:
378                     if (de_get_element_type(goep_client_sdp_query_attribute_value) != DE_UINT) break;
379                     if (de_get_size_type(goep_client_sdp_query_attribute_value) != DE_SIZE_32) break;
380                     if (goep_client->uuid == BLUETOOTH_SERVICE_CLASS_MESSAGE_ACCESS_SERVER) {
381                         goep_client->mas_info.supported_features  = big_endian_read_32(goep_client_sdp_query_attribute_value, de_get_header_size(goep_client_sdp_query_attribute_value));
382                     } else {
383                         goep_client->profile_supported_features  = big_endian_read_32(goep_client_sdp_query_attribute_value, de_get_header_size(goep_client_sdp_query_attribute_value));
384                     }
385                     break;
386 
387                 case BLUETOOTH_ATTRIBUTE_MAS_INSTANCE_ID:
388                     if (de_get_element_type(goep_client_sdp_query_attribute_value) != DE_UINT) break;
389                     if (de_get_size_type(goep_client_sdp_query_attribute_value) != DE_SIZE_8) break;
390                     goep_client->mas_info.instance_id = goep_client_sdp_query_attribute_value[de_get_header_size(goep_client_sdp_query_attribute_value)];
391                     break;
392 
393                 case BLUETOOTH_ATTRIBUTE_SUPPORTED_MESSAGE_TYPES:
394                     if (de_get_element_type(goep_client_sdp_query_attribute_value) != DE_UINT) break;
395                     if (de_get_size_type(goep_client_sdp_query_attribute_value) != DE_SIZE_8) break;
396                     goep_client->mas_info.supported_message_types = goep_client_sdp_query_attribute_value[de_get_header_size(goep_client_sdp_query_attribute_value)];
397                     break;
398 
399                 default:
400                     break;
401             }
402             break;
403 
404         case SDP_EVENT_QUERY_COMPLETE:
405             goep_client_sdp_active = NULL;
406             goep_client_handle_sdp_query_end_of_record(goep_client);
407             status = sdp_event_query_complete_get_status(packet);
408             if (status != ERROR_CODE_SUCCESS){
409                 log_info("GOEP client, SDP query failed 0x%02x", status);
410                 goep_client_handle_connection_opened(goep_client, status, 0);
411                 break;
412             }
413             goep_server_found = false;
414             if (goep_client->rfcomm_port != 0){
415                 goep_server_found = true;
416             }
417 #ifdef ENABLE_GOEP_L2CAP
418             if (goep_client->l2cap_psm != 0){
419                 goep_server_found = true;
420             }
421 #endif
422             if (goep_server_found == false){
423                 log_info("No GOEP RFCOMM or L2CAP server found");
424                 goep_client_handle_connection_opened(goep_client, SDP_SERVICE_NOT_FOUND, 0);
425                 break;
426             }
427             (void) goep_client_start_connect(goep_client);
428             break;
429 
430         default:
431             break;
432     }
433 }
434 
goep_client_get_outgoing_buffer(goep_client_t * goep_client)435 static uint8_t * goep_client_get_outgoing_buffer(goep_client_t * goep_client){
436     if (goep_client->l2cap_psm){
437         return goep_packet_buffer;
438     } else {
439         return rfcomm_get_outgoing_buffer();
440     }
441 }
442 
goep_client_get_outgoing_buffer_len(goep_client_t * goep_client)443 static uint16_t goep_client_get_outgoing_buffer_len(goep_client_t * goep_client){
444     if (goep_client->l2cap_psm){
445         return btstack_min((uint32_t)sizeof(goep_packet_buffer), goep_client->bearer_mtu);
446     } else {
447         return rfcomm_get_max_frame_size(goep_client->bearer_cid);
448     }
449 }
450 
goep_client_packet_init(goep_client_t * goep_client,uint8_t opcode)451 static void goep_client_packet_init(goep_client_t *goep_client, uint8_t opcode) {
452     if (goep_client->l2cap_psm != 0){
453     } else {
454         rfcomm_reserve_packet_buffer();
455     }
456     // store opcode for parsing of response
457     goep_client->obex_opcode = opcode;
458 }
459 
goep_client_init(void)460 void goep_client_init(void){
461 }
462 
goep_client_deinit(void)463 void goep_client_deinit(void){
464     goep_clients = NULL;
465     goep_client_cid = 0;
466     memset(goep_client_sdp_query_attribute_value, 0, sizeof(goep_client_sdp_query_attribute_value));
467     memset(goep_packet_buffer, 0, sizeof(goep_packet_buffer));
468 }
469 
geop_client_sdp_query_start(void * context)470 static void geop_client_sdp_query_start(void * context){
471     uint16_t goep_cid = (uint16_t)(uintptr_t) context;
472     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
473     if (context != NULL){
474         goep_client_sdp_active = goep_client;
475         sdp_client_query_uuid16(&goep_client_handle_sdp_query_event, goep_client->bd_addr,
476                                 goep_client->uuid);
477     }
478 }
479 
480 uint8_t
goep_client_connect(goep_client_t * goep_client,l2cap_ertm_config_t * l2cap_ertm_config,uint8_t * l2cap_ertm_buffer,uint16_t l2cap_ertm_buffer_size,btstack_packet_handler_t handler,bd_addr_t addr,uint16_t uuid,uint8_t instance_id,uint16_t * out_cid)481 goep_client_connect(goep_client_t *goep_client, l2cap_ertm_config_t *l2cap_ertm_config, uint8_t *l2cap_ertm_buffer,
482                     uint16_t l2cap_ertm_buffer_size, btstack_packet_handler_t handler, bd_addr_t addr, uint16_t uuid,
483                     uint8_t instance_id, uint16_t *out_cid) {
484     btstack_assert(goep_client != NULL);
485 
486     // get new goep cid, skip 0x0000
487     goep_client_cid++;
488     if (goep_client_cid == 0) {
489         goep_client_cid = 1;
490     }
491 
492     // add to list
493     memset(goep_client, 0, sizeof(goep_client_t));
494     goep_client->state = GOEP_CLIENT_W4_SDP;
495     goep_client->cid = goep_client_cid;
496     goep_client->client_handler = handler;
497     goep_client->uuid = uuid;
498     goep_client->map_mas_instance_id = instance_id;
499     goep_client->profile_supported_features = PROFILE_FEATURES_NOT_PRESENT;
500     (void)memcpy(goep_client->bd_addr, addr, 6);
501     goep_client->sdp_query_request.callback = geop_client_sdp_query_start;
502     goep_client->sdp_query_request.context = (void *)(uintptr_t) goep_client->cid;
503     goep_client->obex_connection_id = OBEX_CONNECTION_ID_INVALID;
504 #ifdef ENABLE_GOEP_L2CAP
505     if (l2cap_ertm_config != NULL){
506         memcpy(&goep_client->ertm_config, l2cap_ertm_config, sizeof(l2cap_ertm_config_t));
507     }
508     goep_client->ertm_buffer_size = l2cap_ertm_buffer_size;
509     goep_client->ertm_buffer = l2cap_ertm_buffer;
510 #else
511     UNUSED(l2cap_ertm_buffer);
512     UNUSED(l2cap_ertm_config);
513     UNUSED(l2cap_ertm_buffer_size);
514 #endif
515     btstack_linked_list_add(&goep_clients, (btstack_linked_item_t *) goep_client);
516 
517     // request sdp query
518     sdp_client_register_query_callback(&goep_client->sdp_query_request);
519 
520     *out_cid = goep_client->cid;
521     return ERROR_CODE_SUCCESS;
522 }
523 
524 #ifdef ENABLE_GOEP_L2CAP
goep_client_connect_l2cap(goep_client_t * goep_client,l2cap_ertm_config_t * l2cap_ertm_config,uint8_t * l2cap_ertm_buffer,uint16_t l2cap_ertm_buffer_size,btstack_packet_handler_t handler,bd_addr_t addr,uint16_t l2cap_psm,uint16_t * out_cid)525 uint8_t goep_client_connect_l2cap(goep_client_t *goep_client, l2cap_ertm_config_t *l2cap_ertm_config, uint8_t *l2cap_ertm_buffer,
526                           uint16_t l2cap_ertm_buffer_size, btstack_packet_handler_t handler, bd_addr_t addr, uint16_t l2cap_psm,
527                           uint16_t *out_cid){
528     btstack_assert(goep_client != NULL);
529     btstack_assert(l2cap_ertm_config != NULL);
530     btstack_assert(l2cap_ertm_buffer != NULL);
531 
532     // get new goep cid, skip 0x0000
533     goep_client_cid++;
534     if (goep_client_cid == 0) {
535         goep_client_cid = 1;
536     }
537 
538     // add to list
539     memset(goep_client, 0, sizeof(goep_client_t));
540     goep_client->state = GOEP_CLIENT_W4_SDP;
541     goep_client->cid = goep_client_cid;
542     goep_client->client_handler = handler;
543     goep_client->profile_supported_features = PROFILE_FEATURES_NOT_PRESENT;
544     (void)memcpy(goep_client->bd_addr, addr, 6);
545     goep_client->obex_connection_id = OBEX_CONNECTION_ID_INVALID;
546     memcpy(&goep_client->ertm_config, l2cap_ertm_config, sizeof(l2cap_ertm_config_t));
547     goep_client->ertm_buffer_size = l2cap_ertm_buffer_size;
548     goep_client->ertm_buffer = l2cap_ertm_buffer;
549     btstack_linked_list_add_tail(&goep_clients, (btstack_linked_item_t *) goep_client);
550 
551     goep_client->l2cap_psm = l2cap_psm;
552 
553     *out_cid = goep_client->cid;
554 
555     return goep_client_start_connect(goep_client);
556 }
557 #endif
558 
goep_client_get_pbap_supported_features(uint16_t goep_cid)559 uint32_t goep_client_get_pbap_supported_features(uint16_t goep_cid){
560     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
561     if (goep_client == NULL){
562         return PBAP_FEATURES_NOT_PRESENT;
563     }
564     return goep_client->profile_supported_features;
565 }
566 
goep_client_get_map_supported_features(uint16_t goep_cid)567 uint32_t goep_client_get_map_supported_features(uint16_t goep_cid){
568     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
569     if (goep_client == NULL){
570         return PROFILE_FEATURES_NOT_PRESENT;
571     }
572     return goep_client->profile_supported_features;
573 }
574 
goep_client_get_map_mas_instance_id(uint16_t goep_cid)575 uint8_t goep_client_get_map_mas_instance_id(uint16_t goep_cid){
576     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
577     if (goep_client == NULL){
578         return 0;
579     }
580     return goep_client->map_mas_instance_id;
581 }
582 
goep_client_get_map_supported_message_types(uint16_t goep_cid)583 uint8_t goep_client_get_map_supported_message_types(uint16_t goep_cid){
584     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
585     if (goep_client == NULL){
586         return 0;
587     }
588     return goep_client->map_supported_message_types;
589 }
590 
591 
goep_client_version_20_or_higher(uint16_t goep_cid)592 bool goep_client_version_20_or_higher(uint16_t goep_cid){
593     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
594     if (goep_client == NULL){
595         return false;
596     }
597     return goep_client->l2cap_psm != 0;
598 }
599 
goep_client_request_can_send_now(uint16_t goep_cid)600 void goep_client_request_can_send_now(uint16_t goep_cid){
601     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
602     if (goep_client == NULL){
603         return;
604     }
605     if (goep_client->l2cap_psm){
606         l2cap_request_can_send_now_event(goep_client->bearer_cid);
607     } else {
608         rfcomm_request_can_send_now_event(goep_client->bearer_cid);
609     }
610 }
611 
goep_client_disconnect(uint16_t goep_cid)612 uint8_t goep_client_disconnect(uint16_t goep_cid){
613     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
614     if (goep_client == NULL){
615         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
616     }
617     if (goep_client->l2cap_psm){
618         l2cap_disconnect(goep_client->bearer_cid);
619     } else {
620         rfcomm_disconnect(goep_client->bearer_cid);
621     }
622     return ERROR_CODE_SUCCESS;
623 }
624 
goep_client_set_connection_id(uint16_t goep_cid,uint32_t connection_id)625 void goep_client_set_connection_id(uint16_t goep_cid, uint32_t connection_id){
626     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
627     if (goep_client == NULL){
628         return;
629     }
630     goep_client->obex_connection_id = connection_id;
631 }
632 
goep_client_get_request_opcode(uint16_t goep_cid)633 uint8_t goep_client_get_request_opcode(uint16_t goep_cid){
634     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
635     if (goep_client == NULL){
636         return 0;
637     }
638     return goep_client->obex_opcode;
639 }
640 
goep_client_request_create_connect(uint16_t goep_cid,uint8_t obex_version_number,uint8_t flags,uint16_t maximum_obex_packet_length)641 void goep_client_request_create_connect(uint16_t goep_cid, uint8_t obex_version_number, uint8_t flags, uint16_t maximum_obex_packet_length){
642     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
643     if (goep_client == NULL){
644         return;
645     }
646     goep_client_packet_init(goep_client, OBEX_OPCODE_CONNECT);
647     // workaround: limit OBEX packet len to L2CAP/RFCOMM MTU to avoid handling of fragemented packets
648     maximum_obex_packet_length = btstack_min(maximum_obex_packet_length, goep_client->bearer_mtu);
649 
650     uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client);
651     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client);
652     obex_message_builder_request_create_connect(buffer, buffer_len, obex_version_number, flags, maximum_obex_packet_length);
653 }
654 
goep_client_request_create_get(uint16_t goep_cid)655 void goep_client_request_create_get(uint16_t goep_cid){
656     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
657     if (goep_client == NULL){
658         return;
659     }
660     goep_client_packet_init(goep_client, OBEX_OPCODE_GET | OBEX_OPCODE_FINAL_BIT_MASK);
661     uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client);
662     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client);
663     obex_message_builder_request_create_get(buffer, buffer_len, goep_client->obex_connection_id);
664 }
665 
goep_client_request_create_put(uint16_t goep_cid)666 void goep_client_request_create_put(uint16_t goep_cid){
667     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
668     if (goep_client == NULL){
669         return;
670     }
671     goep_client_packet_init(goep_client, OBEX_OPCODE_PUT | OBEX_OPCODE_FINAL_BIT_MASK);
672     uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client);
673     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client);
674     obex_message_builder_request_create_put(buffer, buffer_len, goep_client->obex_connection_id);
675 }
676 
goep_client_request_create_set_path(uint16_t goep_cid,uint8_t flags)677 void goep_client_request_create_set_path(uint16_t goep_cid, uint8_t flags){
678     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
679     if (goep_client == NULL){
680         return;
681     }
682     goep_client_packet_init(goep_client, OBEX_OPCODE_SETPATH);
683     uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client);
684     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client);
685     obex_message_builder_request_create_set_path(buffer, buffer_len, flags, goep_client->obex_connection_id);
686 }
687 
goep_client_request_create_abort(uint16_t goep_cid)688 void goep_client_request_create_abort(uint16_t goep_cid){
689     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
690     if (goep_client == NULL){
691         return;
692     }
693     goep_client_packet_init(goep_client, OBEX_OPCODE_ABORT);
694 
695     uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client);
696     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client);
697     obex_message_builder_request_create_abort(buffer, buffer_len, goep_client->obex_connection_id);
698 }
699 
goep_client_request_create_disconnect(uint16_t goep_cid)700 void goep_client_request_create_disconnect(uint16_t goep_cid){
701     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
702     if (goep_client == NULL){
703         return;
704     }
705     goep_client_packet_init(goep_client, OBEX_OPCODE_DISCONNECT);
706     uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client);
707     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client);
708     obex_message_builder_request_create_disconnect(buffer, buffer_len, goep_client->obex_connection_id);
709 }
710 
goep_client_header_add_byte(uint16_t goep_cid,uint8_t header_type,uint8_t value)711 void goep_client_header_add_byte(uint16_t goep_cid, uint8_t header_type, uint8_t value){
712     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
713     if (goep_client == NULL){
714         return;
715     }
716     uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client);
717     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client);
718     obex_message_builder_header_add_byte(buffer, buffer_len, header_type, value);
719 }
720 
goep_client_header_add_word(uint16_t goep_cid,uint8_t header_type,uint32_t value)721 void goep_client_header_add_word(uint16_t goep_cid, uint8_t header_type, uint32_t value){
722     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
723     if (goep_client == NULL){
724         return;
725     }
726     uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client);
727     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client);
728     obex_message_builder_header_add_word(buffer, buffer_len, header_type, value);
729 }
730 
goep_client_header_add_variable(uint16_t goep_cid,uint8_t header_type,const uint8_t * header_data,uint16_t header_data_length)731 void goep_client_header_add_variable(uint16_t goep_cid, uint8_t header_type, const uint8_t * header_data, uint16_t header_data_length){
732     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
733     if (goep_client == NULL){
734         return;
735     }
736     uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client);
737     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client);
738     obex_message_builder_header_add_variable(buffer, buffer_len, header_type, header_data, header_data_length);
739 }
740 
goep_client_header_add_srm_enable(uint16_t goep_cid)741 void goep_client_header_add_srm_enable(uint16_t goep_cid){
742     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
743     if (goep_client == NULL){
744         return;
745     }
746     uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client);
747     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client);
748     obex_message_builder_header_add_srm_enable(buffer, buffer_len);
749 }
750 
goep_client_header_add_srmp_waiting(uint16_t goep_cid)751 void goep_client_header_add_srmp_waiting(uint16_t goep_cid){
752     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
753     if (goep_client == NULL){
754         return;
755     }
756     uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client);
757     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client);
758     obex_message_builder_header_add_srmp_wait(buffer, buffer_len);
759 }
760 
goep_client_header_add_target(uint16_t goep_cid,const uint8_t * target,uint16_t length)761 void goep_client_header_add_target(uint16_t goep_cid, const uint8_t * target, uint16_t length){
762     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
763     if (goep_client == NULL){
764         return;
765     }
766     uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client);
767     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client);
768     obex_message_builder_header_add_target(buffer, buffer_len, target, length);
769 }
770 
goep_client_header_add_application_parameters(uint16_t goep_cid,const uint8_t * data,uint16_t length)771 void goep_client_header_add_application_parameters(uint16_t goep_cid, const uint8_t * data, uint16_t length){
772     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
773     if (goep_client == NULL){
774         return;
775     }
776     uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client);
777     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client);
778     obex_message_builder_header_add_application_parameters(buffer, buffer_len, data, length);
779 }
780 
goep_client_header_add_challenge_response(uint16_t goep_cid,const uint8_t * data,uint16_t length)781 void goep_client_header_add_challenge_response(uint16_t goep_cid, const uint8_t * data, uint16_t length){
782     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
783     if (goep_client == NULL){
784         return;
785     }
786     uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client);
787     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client);
788     obex_message_builder_header_add_challenge_response(buffer, buffer_len, data, length);
789 }
790 
goep_client_body_add_static(uint16_t goep_cid,const uint8_t * data,uint32_t length)791 void goep_client_body_add_static(uint16_t goep_cid, const uint8_t * data, uint32_t length){
792     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
793     if (goep_client == NULL){
794         return;
795     }
796     uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client);
797     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client);
798     obex_message_builder_body_add_static(buffer, buffer_len, data, length);
799 }
800 
goep_client_body_get_outgoing_buffer_len(uint16_t goep_cid)801 uint16_t goep_client_body_get_outgoing_buffer_len(uint16_t goep_cid) {
802     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
803     if (goep_client == NULL){
804         return 0;
805     }
806     return goep_client_get_outgoing_buffer_len(goep_client);
807 }
808 
goep_client_body_fillup_static(uint16_t goep_cid,const uint8_t * data,uint32_t length,uint32_t * ret_length)809 void goep_client_body_fillup_static(uint16_t goep_cid, const uint8_t * data, uint32_t length, uint32_t * ret_length){
810     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
811     if (goep_client == NULL){
812         return;
813     }
814     uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client);
815     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client);
816     obex_message_builder_body_fillup_static(buffer, buffer_len, data, length, ret_length);
817 }
818 
goep_client_header_add_name(uint16_t goep_cid,const char * name)819 void goep_client_header_add_name(uint16_t goep_cid, const char * name){
820     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
821     if (goep_client == NULL){
822         return;
823     }
824     uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client);
825     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client);
826     obex_message_builder_header_add_name(buffer, buffer_len, name);
827 }
828 
goep_client_header_add_name_prefix(uint16_t goep_cid,const char * name,uint16_t name_len)829 void goep_client_header_add_name_prefix(uint16_t goep_cid, const char * name, uint16_t name_len){
830     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
831     if (goep_client == NULL){
832         return;
833     }
834     uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client);
835     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client);
836     obex_message_builder_header_add_name_prefix(buffer, buffer_len, name, name_len);
837 }
838 
goep_client_header_add_unicode_prefix(uint16_t goep_cid,uint8_t header_id,const char * name,uint16_t name_len)839 void goep_client_header_add_unicode_prefix(uint16_t goep_cid, uint8_t header_id, const char * name, uint16_t name_len){
840     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
841     if (goep_client == NULL){
842         return;
843     }
844     uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client);
845     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client);
846     obex_message_builder_header_add_unicode_prefix(buffer, buffer_len, header_id, name, name_len);
847 }
848 
goep_client_header_add_type(uint16_t goep_cid,const char * type)849 void goep_client_header_add_type(uint16_t goep_cid, const char * type){
850     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
851     if (goep_client == NULL){
852         return;
853     }
854     uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client);
855     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client);
856     obex_message_builder_header_add_type(buffer, buffer_len, type);
857 }
858 
goep_client_header_add_length(uint16_t goep_cid,uint32_t length)859 void goep_client_header_add_length(uint16_t goep_cid, uint32_t length){
860     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
861     if (goep_client == NULL){
862         return;
863     }
864     uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client);
865     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client);
866     obex_message_builder_header_add_length(buffer, buffer_len, length);
867 }
868 
goep_client_request_get_max_body_size(uint16_t goep_cid)869 uint16_t goep_client_request_get_max_body_size(uint16_t goep_cid){
870     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
871     if (goep_client == NULL){
872         return 0;
873     }
874     uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client);
875     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client);
876     uint16_t pos = big_endian_read_16(buffer, 1);
877     return buffer_len - pos;
878 }
879 
goep_client_execute(uint16_t goep_cid)880 int goep_client_execute(uint16_t goep_cid){
881     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
882     if (goep_client == NULL){
883         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
884     }
885     return goep_client_execute_with_final_bit (goep_cid, true);
886 }
887 
goep_client_execute_with_final_bit(uint16_t goep_cid,bool final)888 int goep_client_execute_with_final_bit(uint16_t goep_cid, bool final){
889     goep_client_t * goep_client = goep_client_for_cid(goep_cid);
890     if (goep_client == NULL){
891         return ERROR_CODE_UNKNOWN_CONNECTION_IDENTIFIER;
892     }
893     uint8_t * buffer = goep_client_get_outgoing_buffer(goep_client);
894     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(goep_client);
895 
896     obex_message_builder_set_final_bit (buffer, buffer_len, final);
897 
898     uint16_t pos = big_endian_read_16(buffer, 1);
899     if (goep_client->l2cap_psm){
900         return l2cap_send(goep_client->bearer_cid, buffer, pos);
901     } else {
902         return rfcomm_send_prepared(goep_client->bearer_cid, pos);
903     }
904 }
905 
906