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