xref: /btstack/src/classic/goep_client.c (revision 8f88fc00997369894ea339d04edf0a0e604a138e)
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 // #define ENABLE_GOEP_L2CAP
63 
64 #ifdef ENABLE_GOEP_L2CAP
65 #ifndef ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
66 #error "ENABLE_GOEP_L2CAP requires ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE. Please enable ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE or disable ENABLE_GOEP_L2CAP"
67 #endif
68 #endif
69 
70 typedef enum {
71     GOEP_INIT,
72     GOEP_W4_SDP,
73     GOEP_W4_CONNECTION,
74     GOEP_CONNECTED,
75 } goep_state_t;
76 
77 typedef struct {
78     uint16_t         cid;
79     goep_state_t     state;
80     bd_addr_t        bd_addr;
81     uint16_t         uuid;
82     hci_con_handle_t con_handle;
83     uint8_t          incoming;
84     uint8_t          rfcomm_port;
85     uint16_t         l2cap_psm;
86     uint16_t         bearer_cid;
87     uint16_t         bearer_mtu;
88 
89     // cached higher layer information PBAP + MAP
90     uint32_t         profile_supported_features;
91     uint8_t          map_mas_instance_id;
92     uint8_t          map_supported_message_types;
93 
94     uint8_t          obex_opcode;
95     uint32_t         obex_connection_id;
96     int              obex_connection_id_set;
97 
98     btstack_packet_handler_t client_handler;
99 } goep_client_t;
100 
101 static goep_client_t   goep_client_singleton;
102 static goep_client_t * goep_client = &goep_client_singleton;
103 
104 static uint8_t            goep_client_sdp_query_attribute_value[30];
105 static const unsigned int goep_client_sdp_query_attribute_value_buffer_size = sizeof(goep_client_sdp_query_attribute_value);
106 
107 static uint8_t goep_packet_buffer[150];
108 
109 #ifdef ENABLE_GOEP_L2CAP
110 static uint8_t ertm_buffer[1000];
111 static l2cap_ertm_config_t ertm_config = {
112     1,  // ertm mandatory
113     2,  // max transmit, some tests require > 1
114     2000,
115     12000,
116     512,    // l2cap ertm mtu
117     2,
118     2,
119     1,      // 16-bit FCS
120 };
121 #endif
122 
123 static inline void goep_client_emit_connected_event(goep_client_t * context, uint8_t status){
124     uint8_t event[15];
125     int pos = 0;
126     event[pos++] = HCI_EVENT_GOEP_META;
127     pos++;  // skip len
128     event[pos++] = GOEP_SUBEVENT_CONNECTION_OPENED;
129     little_endian_store_16(event,pos,context->cid);
130     pos+=2;
131     event[pos++] = status;
132     (void)memcpy(&event[pos], context->bd_addr, 6);
133     pos += 6;
134     little_endian_store_16(event,pos,context->con_handle);
135     pos += 2;
136     event[pos++] = context->incoming;
137     event[1] = pos - 2;
138     if (pos != sizeof(event)) log_error("goep_client_emit_connected_event size %u", pos);
139     context->client_handler(HCI_EVENT_PACKET, context->cid, &event[0], pos);
140 }
141 
142 static inline void goep_client_emit_connection_closed_event(goep_client_t * context){
143     uint8_t event[5];
144     int pos = 0;
145     event[pos++] = HCI_EVENT_GOEP_META;
146     pos++;  // skip len
147     event[pos++] = GOEP_SUBEVENT_CONNECTION_CLOSED;
148     little_endian_store_16(event,pos,context->cid);
149     pos+=2;
150     event[1] = pos - 2;
151     if (pos != sizeof(event)) log_error("goep_client_emit_connection_closed_event size %u", pos);
152     context->client_handler(HCI_EVENT_PACKET, context->cid, &event[0], pos);
153 }
154 
155 static inline void goep_client_emit_can_send_now_event(goep_client_t * context){
156     uint8_t event[5];
157     int pos = 0;
158     event[pos++] = HCI_EVENT_GOEP_META;
159     pos++;  // skip len
160     event[pos++] = GOEP_SUBEVENT_CAN_SEND_NOW;
161     little_endian_store_16(event,pos,context->cid);
162     pos+=2;
163     event[1] = pos - 2;
164     if (pos != sizeof(event)) log_error("goep_client_emit_can_send_now_event size %u", pos);
165     context->client_handler(HCI_EVENT_PACKET, context->cid, &event[0], pos);
166 }
167 
168 static void goep_client_handle_connection_opened(goep_client_t * context, uint8_t status, uint16_t mtu){
169     if (status) {
170         context->state = GOEP_INIT;
171         log_info("goep_client: open failed, status %u", status);
172     } else {
173         context->bearer_mtu = mtu;
174         context->state = GOEP_CONNECTED;
175         log_info("goep_client: connection opened. cid %u, max frame size %u", context->bearer_cid, context->bearer_mtu);
176     }
177     goep_client_emit_connected_event(context, status);
178 }
179 
180 static void goep_client_handle_connection_close(goep_client_t * context){
181     context->state = GOEP_INIT;
182     goep_client_emit_connection_closed_event(context);
183 }
184 
185 static void goep_client_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
186     UNUSED(channel);
187     UNUSED(size);
188     goep_client_t * context = goep_client;
189     switch (packet_type){
190         case HCI_EVENT_PACKET:
191             switch (hci_event_packet_get_type(packet)) {
192 #ifdef ENABLE_GOEP_L2CAP
193                 case L2CAP_EVENT_CHANNEL_OPENED:
194                     goep_client_handle_connection_opened(context, l2cap_event_channel_opened_get_status(packet),
195                         btstack_min(l2cap_event_channel_opened_get_remote_mtu(packet), l2cap_event_channel_opened_get_local_mtu(packet)));
196                     return;
197                 case L2CAP_EVENT_CAN_SEND_NOW:
198                     goep_client_emit_can_send_now_event(context);
199                     break;
200                 case L2CAP_EVENT_CHANNEL_CLOSED:
201                     goep_client_handle_connection_close(context);
202                     break;
203 #endif
204                 case RFCOMM_EVENT_CHANNEL_OPENED:
205                     goep_client_handle_connection_opened(context, rfcomm_event_channel_opened_get_status(packet), rfcomm_event_channel_opened_get_max_frame_size(packet));
206                     return;
207                 case RFCOMM_EVENT_CAN_SEND_NOW:
208                     goep_client_emit_can_send_now_event(context);
209                     break;
210                 case RFCOMM_EVENT_CHANNEL_CLOSED:
211                     goep_client_handle_connection_close(context);
212                     break;
213                 default:
214                     break;
215             }
216             break;
217         case L2CAP_DATA_PACKET:
218         case RFCOMM_DATA_PACKET:
219             context->client_handler(GOEP_DATA_PACKET, context->cid, packet, size);
220             break;
221         default:
222             break;
223     }
224 }
225 
226 static void goep_client_handle_sdp_query_event(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
227     goep_client_t * context = goep_client;
228 
229     UNUSED(packet_type);
230     UNUSED(channel);
231     UNUSED(size);
232 
233     des_iterator_t des_list_it;
234     des_iterator_t prot_it;
235     uint8_t status;
236 
237 
238     switch (hci_event_packet_get_type(packet)){
239         case SDP_EVENT_QUERY_ATTRIBUTE_VALUE:
240 
241             // check if relevant attribute
242             switch(sdp_event_query_attribute_byte_get_attribute_id(packet)){
243                 case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST:
244                 case BLUETOOTH_ATTRIBUTE_PBAP_SUPPORTED_FEATURES:
245 #ifdef ENABLE_GOEP_L2CAP
246                 case BLUETOOTH_ATTRIBUTE_GOEP_L2CAP_PSM:
247 #endif
248                     break;
249                 default:
250                     return;
251             }
252 
253             // warn if attribute too large to fit in our buffer
254             if (sdp_event_query_attribute_byte_get_attribute_length(packet) > goep_client_sdp_query_attribute_value_buffer_size) {
255                 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));
256                 break;
257             }
258 
259             // store single byte
260             goep_client_sdp_query_attribute_value[sdp_event_query_attribute_byte_get_data_offset(packet)] = sdp_event_query_attribute_byte_get_data(packet);
261 
262             // wait until value fully received
263             if ((uint16_t)(sdp_event_query_attribute_byte_get_data_offset(packet)+1) != sdp_event_query_attribute_byte_get_attribute_length(packet)) break;
264 
265             // process attributes
266             switch(sdp_event_query_attribute_byte_get_attribute_id(packet)) {
267                 case BLUETOOTH_ATTRIBUTE_PROTOCOL_DESCRIPTOR_LIST:
268                     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)) {
269                         uint8_t       *des_element;
270                         uint8_t       *element;
271                         uint32_t       uuid;
272 #ifdef ENABLE_GOEP_L2CAP
273                         uint16_t       l2cap_psm;
274 #endif
275 
276                         if (des_iterator_get_type(&des_list_it) != DE_DES) continue;
277 
278                         des_element = des_iterator_get_element(&des_list_it);
279                         des_iterator_init(&prot_it, des_element);
280 
281                         // first element is UUID
282                         element = des_iterator_get_element(&prot_it);
283                         if (de_get_element_type(element) != DE_UUID) continue;
284 
285                         uuid = de_get_uuid32(element);
286                         des_iterator_next(&prot_it);
287                         if (!des_iterator_has_more(&prot_it)) continue;
288 
289                         // second element is RFCOMM server channel or L2CAP PSM
290                         element = des_iterator_get_element(&prot_it);
291                         switch (uuid){
292 #ifdef ENABLE_GOEP_L2CAP
293                             case BLUETOOTH_PROTOCOL_L2CAP:
294                                 if (de_element_get_uint16(element, &l2cap_psm)){
295                                     context->l2cap_psm = l2cap_psm;
296                                 }
297                                 break;
298 #endif
299                             case BLUETOOTH_PROTOCOL_RFCOMM:
300                                 context->rfcomm_port = element[de_get_header_size(element)];
301                                 break;
302                             default:
303                                 break;
304                         }
305                     }
306                     break;
307 #ifdef ENABLE_GOEP_L2CAP
308                 case BLUETOOTH_ATTRIBUTE_GOEP_L2CAP_PSM:
309                     de_element_get_uint16(goep_client_sdp_query_attribute_value, &context->l2cap_psm);
310                     break;
311 #endif
312                 // BLUETOOTH_ATTRIBUTE_PBAP_SUPPORTED_FEATURES == BLUETOOTH_ATTRIBUTE_MAP_SUPPORTED_FEATURES == 0x0317
313                 case BLUETOOTH_ATTRIBUTE_PBAP_SUPPORTED_FEATURES:
314                     if (de_get_element_type(goep_client_sdp_query_attribute_value) != DE_UINT) break;
315                     if (de_get_size_type(goep_client_sdp_query_attribute_value) != DE_SIZE_32) break;
316                     context->profile_supported_features  = big_endian_read_32(goep_client_sdp_query_attribute_value, de_get_header_size(goep_client_sdp_query_attribute_value));
317                     log_info("PBAP/MAP supported_features 0x%x", (unsigned int) context->profile_supported_features);
318                     break;
319 
320                 case BLUETOOTH_ATTRIBUTE_MAS_INSTANCE_ID:
321                     if (de_get_element_type(goep_client_sdp_query_attribute_value) != DE_UINT) break;
322                     if (de_get_size_type(goep_client_sdp_query_attribute_value) != DE_SIZE_8) break;
323                     context->map_mas_instance_id = goep_client_sdp_query_attribute_value[de_get_header_size(goep_client_sdp_query_attribute_value)];
324                     log_info("MAS Instance ID 0x%x", context->map_mas_instance_id);
325                     break;
326 
327                 case BLUETOOTH_ATTRIBUTE_SUPPORTED_MESSAGE_TYPES:
328                     if (de_get_element_type(goep_client_sdp_query_attribute_value) != DE_UINT) break;
329                     if (de_get_size_type(goep_client_sdp_query_attribute_value) != DE_SIZE_8) break;
330                     context->map_supported_message_types = goep_client_sdp_query_attribute_value[de_get_header_size(goep_client_sdp_query_attribute_value)];
331                     log_info("Supported Message Types 0x%x", context->map_mas_instance_id);
332                     break;
333 
334                 default:
335                     break;
336             }
337             break;
338 
339         case SDP_EVENT_QUERY_COMPLETE:
340             status = sdp_event_query_complete_get_status(packet);
341             if (status != ERROR_CODE_SUCCESS){
342                 log_info("GOEP client, SDP query failed 0x%02x", status);
343                 context->state = GOEP_INIT;
344                 goep_client_emit_connected_event(goep_client, status);
345                 break;
346             }
347             if ((context->rfcomm_port == 0) && (context->l2cap_psm == 0)){
348                 log_info("No GOEP RFCOMM or L2CAP server found");
349                 context->state = GOEP_INIT;
350                 goep_client_emit_connected_event(goep_client, SDP_SERVICE_NOT_FOUND);
351                 break;
352             }
353 #ifdef ENABLE_GOEP_L2CAP
354             if (context->l2cap_psm){
355                 log_info("Remote GOEP L2CAP PSM: %u", context->l2cap_psm);
356                 l2cap_ertm_create_channel(&goep_client_packet_handler, context->bd_addr, context->l2cap_psm,
357                                           &ertm_config, ertm_buffer, sizeof(ertm_buffer), &context->bearer_cid);
358                 return;
359             }
360 #endif
361             log_info("Remote GOEP RFCOMM Server Channel: %u", context->rfcomm_port);
362             rfcomm_create_channel(&goep_client_packet_handler, context->bd_addr, context->rfcomm_port, &context->bearer_cid);
363             break;
364 
365         default:
366             break;
367     }
368 }
369 
370 static uint8_t * goep_client_get_outgoing_buffer(goep_client_t * context){
371     if (context->l2cap_psm){
372         return goep_packet_buffer;
373     } else {
374         return rfcomm_get_outgoing_buffer();
375     }
376 }
377 
378 static uint16_t goep_client_get_outgoing_buffer_len(goep_client_t * context){
379     if (context->l2cap_psm){
380         return sizeof(goep_packet_buffer);
381     } else {
382         return rfcomm_get_max_frame_size(context->bearer_cid);
383     }
384 }
385 
386 static void goep_client_packet_init(uint16_t goep_cid, uint8_t opcode){
387     UNUSED(goep_cid);
388     goep_client_t * context = goep_client;
389     if (context->l2cap_psm){
390     } else {
391         rfcomm_reserve_packet_buffer();
392     }
393     // store opcode for parsing of response
394     context->obex_opcode = opcode;
395 }
396 
397 void goep_client_init(void){
398     memset(goep_client, 0, sizeof(goep_client_t));
399     goep_client->state = GOEP_INIT;
400     goep_client->cid = 1;
401     goep_client->obex_connection_id = OBEX_CONNECTION_ID_INVALID;
402 }
403 
404 void goep_client_deinit(void){
405     memset(goep_client, 0, sizeof(goep_client_t));
406     memset(goep_client_sdp_query_attribute_value, 0, sizeof(goep_client_sdp_query_attribute_value));
407     memset(goep_packet_buffer, 0, sizeof(goep_packet_buffer));
408 }
409 
410 uint8_t goep_client_create_connection(btstack_packet_handler_t handler, bd_addr_t addr, uint16_t uuid, uint16_t * out_cid){
411     goep_client_t * context = goep_client;
412     if (context->state != GOEP_INIT) return BTSTACK_MEMORY_ALLOC_FAILED;
413     memset(context, 0, sizeof(goep_client_t));
414     context->client_handler = handler;
415     context->state = GOEP_W4_SDP;
416     context->uuid = uuid;
417     (void)memcpy(context->bd_addr, addr, 6);
418     context->profile_supported_features = PROFILE_FEATURES_NOT_PRESENT;
419     sdp_client_query_uuid16(&goep_client_handle_sdp_query_event, context->bd_addr, uuid);
420     *out_cid = context->cid;
421     return ERROR_CODE_SUCCESS;
422 }
423 
424 uint32_t goep_client_get_pbap_supported_features(uint16_t goep_cid){
425     UNUSED(goep_cid);
426     goep_client_t * context = goep_client;
427     return context->profile_supported_features;
428 }
429 
430 uint32_t goep_client_get_map_supported_features(uint16_t goep_cid){
431     UNUSED(goep_cid);
432     goep_client_t * context = goep_client;
433     return context->profile_supported_features;
434 }
435 
436 uint8_t goep_client_get_map_mas_instance_id(uint16_t goep_cid){
437     UNUSED(goep_cid);
438     goep_client_t * context = goep_client;
439     return context->map_mas_instance_id;
440 }
441 
442 uint8_t goep_client_get_map_suported_message_types(uint16_t goep_cid){
443     UNUSED(goep_cid);
444     goep_client_t * context = goep_client;
445     return context->map_supported_message_types;
446 }
447 
448 
449 bool goep_client_version_20_or_higher(uint16_t goep_cid){
450     UNUSED(goep_cid);
451     goep_client_t * context = goep_client;
452     return context->l2cap_psm != 0;
453 }
454 
455 void goep_client_request_can_send_now(uint16_t goep_cid){
456     UNUSED(goep_cid);
457     goep_client_t * context = goep_client;
458     if (context->l2cap_psm){
459         l2cap_request_can_send_now_event(context->bearer_cid);
460     } else {
461         rfcomm_request_can_send_now_event(context->bearer_cid);
462     }
463 }
464 
465 uint8_t goep_client_disconnect(uint16_t goep_cid){
466     UNUSED(goep_cid);
467     goep_client_t * context = goep_client;
468     if (context->l2cap_psm){
469         l2cap_disconnect(context->bearer_cid);
470     } else {
471         rfcomm_disconnect(context->bearer_cid);
472     }
473     return ERROR_CODE_SUCCESS;
474 }
475 
476 void goep_client_set_connection_id(uint16_t goep_cid, uint32_t connection_id){
477     UNUSED(goep_cid);
478     goep_client_t * context = goep_client;
479     context->obex_connection_id = connection_id;
480 }
481 
482 uint8_t goep_client_get_request_opcode(uint16_t goep_cid){
483     UNUSED(goep_cid);
484     goep_client_t * context = goep_client;
485     return context->obex_opcode;
486 }
487 
488 void goep_client_request_create_connect(uint16_t goep_cid, uint8_t obex_version_number, uint8_t flags, uint16_t maximum_obex_packet_length){
489     UNUSED(goep_cid);
490     goep_client_t * context = goep_client;
491     goep_client_packet_init(goep_cid, OBEX_OPCODE_CONNECT);
492 
493     // workaround: limit OBEX packet len to L2CAP/RFCOMM MTU to avoid handling of fragemented packets
494     maximum_obex_packet_length = btstack_min(maximum_obex_packet_length, context->bearer_mtu);
495 
496     uint8_t * buffer = goep_client_get_outgoing_buffer(context);
497     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context);
498     obex_message_builder_request_create_connect(buffer, buffer_len, obex_version_number, flags, maximum_obex_packet_length);
499 }
500 
501 void goep_client_request_create_get(uint16_t goep_cid){
502     UNUSED(goep_cid);
503     goep_client_t * context = goep_client;
504     goep_client_packet_init(goep_cid, OBEX_OPCODE_GET | OBEX_OPCODE_FINAL_BIT_MASK);
505 
506     uint8_t * buffer = goep_client_get_outgoing_buffer(context);
507     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context);
508     obex_message_builder_request_create_get(buffer, buffer_len, context->obex_connection_id);
509 }
510 
511 void goep_client_request_create_put(uint16_t goep_cid){
512     UNUSED(goep_cid);
513     goep_client_t * context = goep_client;
514     goep_client_packet_init(goep_cid, OBEX_OPCODE_PUT | OBEX_OPCODE_FINAL_BIT_MASK);
515 
516     uint8_t * buffer = goep_client_get_outgoing_buffer(context);
517     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context);
518     obex_message_builder_request_create_put(buffer, buffer_len, context->obex_connection_id);
519 }
520 
521 void goep_client_request_create_set_path(uint16_t goep_cid, uint8_t flags){
522     UNUSED(goep_cid);
523     goep_client_t * context = goep_client;
524     goep_client_packet_init(goep_cid, OBEX_OPCODE_SETPATH);
525 
526     uint8_t * buffer = goep_client_get_outgoing_buffer(context);
527     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context);
528     obex_message_builder_request_create_set_path(buffer, buffer_len, flags, context->obex_connection_id);
529 }
530 
531 void goep_client_request_create_abort(uint16_t goep_cid){
532     UNUSED(goep_cid);
533     goep_client_t * context = goep_client;
534     goep_client_packet_init(goep_cid, OBEX_OPCODE_ABORT);
535 
536     uint8_t * buffer = goep_client_get_outgoing_buffer(context);
537     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context);
538     obex_message_builder_request_create_abort(buffer, buffer_len, context->obex_connection_id);
539 }
540 
541 void goep_client_request_create_disconnect(uint16_t goep_cid){
542     UNUSED(goep_cid);
543     goep_client_t * context = goep_client;
544     goep_client_packet_init(goep_cid, OBEX_OPCODE_DISCONNECT);
545 
546     uint8_t * buffer = goep_client_get_outgoing_buffer(context);
547     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context);
548     obex_message_builder_request_create_disconnect(buffer, buffer_len, context->obex_connection_id);
549 }
550 
551 void goep_client_header_add_byte(uint16_t goep_cid, uint8_t header_type, uint8_t value){
552     UNUSED(goep_cid);
553     goep_client_t * context = goep_client;
554 
555     uint8_t * buffer = goep_client_get_outgoing_buffer(context);
556     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context);
557     obex_message_builder_header_add_byte(buffer, buffer_len, header_type, value);
558 }
559 
560 void goep_client_header_add_word(uint16_t goep_cid, uint8_t header_type, uint32_t value){
561     UNUSED(goep_cid);
562     goep_client_t * context = goep_client;
563 
564     uint8_t * buffer = goep_client_get_outgoing_buffer(context);
565     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context);
566     obex_message_builder_header_add_word(buffer, buffer_len, header_type, value);
567 }
568 
569 void goep_client_header_add_variable(uint16_t goep_cid, uint8_t header_type, const uint8_t * header_data, uint16_t header_data_length){
570     UNUSED(goep_cid);
571     goep_client_t * context = goep_client;
572 
573     uint8_t * buffer = goep_client_get_outgoing_buffer(context);
574     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context);
575     obex_message_builder_header_add_variable(buffer, buffer_len, header_type, header_data, header_data_length);
576 }
577 
578 void goep_client_header_add_srm_enable(uint16_t goep_cid){
579     UNUSED(goep_cid);
580     goep_client_t * context = goep_client;
581 
582     uint8_t * buffer = goep_client_get_outgoing_buffer(context);
583     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context);
584     obex_message_builder_header_add_srm_enable(buffer, buffer_len);
585 }
586 
587 void goep_client_header_add_target(uint16_t goep_cid, const uint8_t * target, uint16_t length){
588     UNUSED(goep_cid);
589     goep_client_t * context = goep_client;
590 
591     uint8_t * buffer = goep_client_get_outgoing_buffer(context);
592     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context);
593     obex_message_builder_header_add_target(buffer, buffer_len, target, length);
594 }
595 
596 void goep_client_header_add_application_parameters(uint16_t goep_cid, const uint8_t * data, uint16_t length){
597     UNUSED(goep_cid);
598     goep_client_t * context = goep_client;
599 
600     uint8_t * buffer = goep_client_get_outgoing_buffer(context);
601     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context);
602     obex_message_builder_header_add_application_parameters(buffer, buffer_len, data, length);
603 }
604 
605 void goep_client_header_add_challenge_response(uint16_t goep_cid, const uint8_t * data, uint16_t length){
606     UNUSED(goep_cid);
607     goep_client_t * context = goep_client;
608 
609     uint8_t * buffer = goep_client_get_outgoing_buffer(context);
610     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context);
611     obex_message_builder_header_add_challenge_response(buffer, buffer_len, data, length);
612 }
613 
614 void goep_client_body_add_static(uint16_t goep_cid, const uint8_t * data, uint32_t length){
615     UNUSED(goep_cid);
616     goep_client_t * context = goep_client;
617 
618     uint8_t * buffer = goep_client_get_outgoing_buffer(context);
619     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context);
620     obex_message_builder_body_add_static(buffer, buffer_len, data, length);
621 }
622 
623 uint16_t goep_client_body_get_outgoing_buffer_len(uint16_t goep_cid) {
624     UNUSED(goep_cid);
625     goep_client_t * context = goep_client;
626 
627     return goep_client_get_outgoing_buffer_len(context);
628 };
629 
630 void goep_client_body_fillup_static(uint16_t goep_cid, const uint8_t * data, uint32_t length, uint32_t * ret_length){
631     UNUSED(goep_cid);
632     goep_client_t * context = goep_client;
633 
634     uint8_t * buffer = goep_client_get_outgoing_buffer(context);
635     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context);
636     obex_message_builder_body_fillup_static(buffer, buffer_len, data, length, ret_length);
637 }
638 
639 void goep_client_header_add_name(uint16_t goep_cid, const char * name){
640     UNUSED(goep_cid);
641     goep_client_t * context = goep_client;
642 
643     uint8_t * buffer = goep_client_get_outgoing_buffer(context);
644     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context);
645     obex_message_builder_header_add_name(buffer, buffer_len, name);
646 }
647 
648 void goep_client_header_add_name_prefix(uint16_t goep_cid, const char * name, uint16_t name_len){
649     UNUSED(goep_cid);
650     goep_client_t * context = goep_client;
651 
652     uint8_t * buffer = goep_client_get_outgoing_buffer(context);
653     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context);
654     obex_message_builder_header_add_name_prefix(buffer, buffer_len, name, name_len);
655 }
656 
657 void goep_client_header_add_type(uint16_t goep_cid, const char * type){
658     UNUSED(goep_cid);
659     goep_client_t * context = goep_client;
660 
661     uint8_t * buffer = goep_client_get_outgoing_buffer(context);
662     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context);
663     obex_message_builder_header_add_type(buffer, buffer_len, type);
664 }
665 
666 void goep_client_header_add_length(uint16_t goep_cid, uint32_t length){
667     UNUSED(goep_cid);
668     goep_client_t * context = goep_client;
669 
670     uint8_t * buffer = goep_client_get_outgoing_buffer(context);
671     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context);
672     obex_message_builder_header_add_length(buffer, buffer_len, length);
673 }
674 
675 uint16_t goep_client_request_get_max_body_size(uint16_t goep_cid){
676     UNUSED(goep_cid);
677     goep_client_t * context = goep_client;
678 
679     uint8_t * buffer = goep_client_get_outgoing_buffer(context);
680     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context);
681     uint16_t pos = big_endian_read_16(buffer, 1);
682     return buffer_len - pos;
683 }
684 
685 int goep_client_execute(uint16_t goep_cid){
686     return goep_client_execute_with_final_bit (goep_cid, true);
687 }
688 
689 int goep_client_execute_with_final_bit(uint16_t goep_cid, bool final){
690     UNUSED(goep_cid);
691     goep_client_t * context = goep_client;
692     uint8_t * buffer = goep_client_get_outgoing_buffer(context);
693     uint16_t buffer_len = goep_client_get_outgoing_buffer_len(context);
694 
695     obex_message_builder_set_final_bit (buffer, buffer_len, final);
696 
697     uint16_t pos = big_endian_read_16(buffer, 1);
698     if (context->l2cap_psm){
699         return l2cap_send(context->bearer_cid, buffer, pos);
700     } else {
701         return rfcomm_send_prepared(context->bearer_cid, pos);
702     }
703 }
704 
705