xref: /btstack/src/l2cap.c (revision 0af41d30f6690ed0fe5ceee50b029eb8980a5b38)
143625864Smatthias.ringwald /*
243625864Smatthias.ringwald  *  l2cap.c
343625864Smatthias.ringwald  *
443625864Smatthias.ringwald  *  Logical Link Control and Adaption Protocl (L2CAP)
543625864Smatthias.ringwald  *
643625864Smatthias.ringwald  *  Created by Matthias Ringwald on 5/16/09.
743625864Smatthias.ringwald  */
843625864Smatthias.ringwald 
943625864Smatthias.ringwald #include "l2cap.h"
1043625864Smatthias.ringwald 
1143625864Smatthias.ringwald #include <stdarg.h>
1243625864Smatthias.ringwald #include <string.h>
1343625864Smatthias.ringwald 
1443625864Smatthias.ringwald #include <stdio.h>
1543625864Smatthias.ringwald 
1643625864Smatthias.ringwald static char *l2cap_signaling_commands_format[] = {
1743625864Smatthias.ringwald     "D",    // 0x01 command reject: reason {cmd not understood (0), sig MTU exceeded (2:max sig MTU), invalid CID (4:req CID)}, data len, data
1843625864Smatthias.ringwald     "22",   // 0x02 connection request: PSM, Source CID
1943625864Smatthias.ringwald     "2222", // 0x03 connection response: Dest CID, Source CID, Result, Status
2043625864Smatthias.ringwald     "22D",  // 0x04 config request: Dest CID, Flags, Configuration options
2143625864Smatthias.ringwald     "222D", // 0x05 config response: Source CID, Flags, Result, Configuration options
2243625864Smatthias.ringwald     "22",   // 0x06 disconection request: Dest CID, Source CID
2343625864Smatthias.ringwald     "22",   // 0x07 disconection response: Dest CID, Source CID
2443625864Smatthias.ringwald     "D",    // 0x08 echo request: Data
2543625864Smatthias.ringwald     "D",    // 0x09 echo response: Data
2643625864Smatthias.ringwald     "2",    // 0x0a information request: InfoType {1=Connectionless MTU, 2=Extended features supported}
2743625864Smatthias.ringwald     "22D",  // 0x0b information response: InfoType, Result, Data
2843625864Smatthias.ringwald };
2943625864Smatthias.ringwald 
3043625864Smatthias.ringwald static uint8_t * sig_buffer;
3143625864Smatthias.ringwald 
32*0af41d30Smatthias.ringwald uint8_t   sig_seq_nr = 1;
33*0af41d30Smatthias.ringwald uint16_t  local_cid  = 0x40;
3443625864Smatthias.ringwald 
35*0af41d30Smatthias.ringwald uint16_t l2cap_create_signaling_internal(uint8_t * acl_buffer,hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, va_list argptr){
3643625864Smatthias.ringwald 
3743625864Smatthias.ringwald     // 0 - Connection handle : PB=10 : BC=00
38*0af41d30Smatthias.ringwald      bt_store_16(acl_buffer, 0, handle | (2 << 12) | (0 << 14));
3943625864Smatthias.ringwald     // 6 - L2CAP channel = 1
40*0af41d30Smatthias.ringwald     bt_store_16(acl_buffer, 6, 1);
4143625864Smatthias.ringwald     // 8 - Code
42*0af41d30Smatthias.ringwald     acl_buffer[8] = cmd;
4343625864Smatthias.ringwald     // 9 - id (!= 0 sequentially)
44*0af41d30Smatthias.ringwald     acl_buffer[9] = identifier;
4543625864Smatthias.ringwald 
4643625864Smatthias.ringwald     // 12 - L2CAP signaling parameters
4743625864Smatthias.ringwald     uint16_t pos = 12;
4843625864Smatthias.ringwald     const char *format = l2cap_signaling_commands_format[cmd-1];
4943625864Smatthias.ringwald     uint16_t word;
5043625864Smatthias.ringwald     uint8_t * ptr;
5143625864Smatthias.ringwald     while (*format) {
5243625864Smatthias.ringwald         switch(*format) {
5343625864Smatthias.ringwald             case '1': //  8 bit value
5443625864Smatthias.ringwald             case '2': // 16 bit value
5543625864Smatthias.ringwald                 word = va_arg(argptr, int);
5643625864Smatthias.ringwald                 // minimal va_arg is int: 2 bytes on 8+16 bit CPUs
57*0af41d30Smatthias.ringwald                 acl_buffer[pos++] = word & 0xff;
5843625864Smatthias.ringwald                 if (*format == '2') {
59*0af41d30Smatthias.ringwald                     acl_buffer[pos++] = word >> 8;
6043625864Smatthias.ringwald                 }
6143625864Smatthias.ringwald                 break;
6243625864Smatthias.ringwald             case 'D': // variable data. passed: len, ptr
6343625864Smatthias.ringwald                 word = va_arg(argptr, int);
6443625864Smatthias.ringwald                 ptr  = va_arg(argptr, uint8_t *);
65*0af41d30Smatthias.ringwald                 memcpy(&acl_buffer[pos], ptr, word);
6643625864Smatthias.ringwald                 pos += word;
6743625864Smatthias.ringwald                 break;
6843625864Smatthias.ringwald             default:
6943625864Smatthias.ringwald                 break;
7043625864Smatthias.ringwald         }
7143625864Smatthias.ringwald         format++;
7243625864Smatthias.ringwald     };
7343625864Smatthias.ringwald     va_end(argptr);
7443625864Smatthias.ringwald 
7543625864Smatthias.ringwald     // Fill in various length fields: it's the number of bytes following for ACL lenght and l2cap parameter length
7643625864Smatthias.ringwald     // - the l2cap payload length is counted after the following channel id (only payload)
7743625864Smatthias.ringwald 
7843625864Smatthias.ringwald     // 2 - ACL length
79*0af41d30Smatthias.ringwald     bt_store_16(acl_buffer, 2,  pos - 4);
8043625864Smatthias.ringwald     // 4 - L2CAP packet length
81*0af41d30Smatthias.ringwald     bt_store_16(acl_buffer, 4,  pos - 6 - 2);
8243625864Smatthias.ringwald     // 10 - L2CAP signaling parameter length
83*0af41d30Smatthias.ringwald     bt_store_16(acl_buffer, 10, pos - 12);
8443625864Smatthias.ringwald 
85*0af41d30Smatthias.ringwald     return pos;
86*0af41d30Smatthias.ringwald }
87*0af41d30Smatthias.ringwald int l2cap_send_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, ...){
88*0af41d30Smatthias.ringwald     va_list argptr;
89*0af41d30Smatthias.ringwald     va_start(argptr, identifier);
90*0af41d30Smatthias.ringwald     uint16_t len = l2cap_create_signaling_internal(sig_buffer, handle, cmd, identifier, argptr);
91*0af41d30Smatthias.ringwald     return hci_send_acl_packet(sig_buffer, len);
92*0af41d30Smatthias.ringwald }
93*0af41d30Smatthias.ringwald 
94*0af41d30Smatthias.ringwald uint16_t l2cap_create_signaling_packet(uint8_t *acl_buffer, hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, ...){
95*0af41d30Smatthias.ringwald     va_list argptr;
96*0af41d30Smatthias.ringwald     va_start(argptr, identifier);
97*0af41d30Smatthias.ringwald     uint16_t len = l2cap_create_signaling_internal(acl_buffer, handle, cmd, identifier, argptr);
98*0af41d30Smatthias.ringwald     va_end(argptr);
99*0af41d30Smatthias.ringwald     return len;
10043625864Smatthias.ringwald }
10143625864Smatthias.ringwald 
10243625864Smatthias.ringwald void l2cap_init(){
10343625864Smatthias.ringwald     sig_buffer = malloc( 48 );
10443625864Smatthias.ringwald }