xref: /btstack/src/l2cap.c (revision 43625864d262f22c09d4ea5b6eb3c8becbe91100)
1*43625864Smatthias.ringwald /*
2*43625864Smatthias.ringwald  *  l2cap.c
3*43625864Smatthias.ringwald  *
4*43625864Smatthias.ringwald  *  Logical Link Control and Adaption Protocl (L2CAP)
5*43625864Smatthias.ringwald  *
6*43625864Smatthias.ringwald  *  Created by Matthias Ringwald on 5/16/09.
7*43625864Smatthias.ringwald  */
8*43625864Smatthias.ringwald 
9*43625864Smatthias.ringwald #include "l2cap.h"
10*43625864Smatthias.ringwald 
11*43625864Smatthias.ringwald #include <stdarg.h>
12*43625864Smatthias.ringwald #include <string.h>
13*43625864Smatthias.ringwald 
14*43625864Smatthias.ringwald #include <stdio.h>
15*43625864Smatthias.ringwald 
16*43625864Smatthias.ringwald static char *l2cap_signaling_commands_format[] = {
17*43625864Smatthias.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
18*43625864Smatthias.ringwald     "22",   // 0x02 connection request: PSM, Source CID
19*43625864Smatthias.ringwald     "2222", // 0x03 connection response: Dest CID, Source CID, Result, Status
20*43625864Smatthias.ringwald     "22D",  // 0x04 config request: Dest CID, Flags, Configuration options
21*43625864Smatthias.ringwald     "222D", // 0x05 config response: Source CID, Flags, Result, Configuration options
22*43625864Smatthias.ringwald     "22",   // 0x06 disconection request: Dest CID, Source CID
23*43625864Smatthias.ringwald     "22",   // 0x07 disconection response: Dest CID, Source CID
24*43625864Smatthias.ringwald     "D",    // 0x08 echo request: Data
25*43625864Smatthias.ringwald     "D",    // 0x09 echo response: Data
26*43625864Smatthias.ringwald     "2",    // 0x0a information request: InfoType {1=Connectionless MTU, 2=Extended features supported}
27*43625864Smatthias.ringwald     "22D",  // 0x0b information response: InfoType, Result, Data
28*43625864Smatthias.ringwald };
29*43625864Smatthias.ringwald 
30*43625864Smatthias.ringwald static uint8_t * sig_buffer;
31*43625864Smatthias.ringwald 
32*43625864Smatthias.ringwald uint8_t   sig_seq_nr;
33*43625864Smatthias.ringwald uint16_t  local_cid;
34*43625864Smatthias.ringwald 
35*43625864Smatthias.ringwald int l2cap_send_signaling_packet(hci_con_handle_t handle, L2CAP_SIGNALING_COMMANDS cmd, uint8_t identifier, ...){
36*43625864Smatthias.ringwald 
37*43625864Smatthias.ringwald     // 0 - Connection handle : PB=10 : BC=00
38*43625864Smatthias.ringwald      bt_store_16(sig_buffer, 0, handle | (2 << 12) | (0 << 14));
39*43625864Smatthias.ringwald     // 6 - L2CAP channel = 1
40*43625864Smatthias.ringwald     bt_store_16(sig_buffer, 6, 1);
41*43625864Smatthias.ringwald     // 8 - Code
42*43625864Smatthias.ringwald     sig_buffer[8] = cmd;
43*43625864Smatthias.ringwald     // 9 - id (!= 0 sequentially)
44*43625864Smatthias.ringwald     sig_buffer[9] = identifier;
45*43625864Smatthias.ringwald 
46*43625864Smatthias.ringwald     // 12 - L2CAP signaling parameters
47*43625864Smatthias.ringwald     uint16_t pos = 12;
48*43625864Smatthias.ringwald     va_list argptr;
49*43625864Smatthias.ringwald     va_start(argptr, identifier);
50*43625864Smatthias.ringwald     const char *format = l2cap_signaling_commands_format[cmd-1];
51*43625864Smatthias.ringwald     uint16_t word;
52*43625864Smatthias.ringwald     uint8_t * ptr;
53*43625864Smatthias.ringwald     while (*format) {
54*43625864Smatthias.ringwald         switch(*format) {
55*43625864Smatthias.ringwald             case '1': //  8 bit value
56*43625864Smatthias.ringwald             case '2': // 16 bit value
57*43625864Smatthias.ringwald                 word = va_arg(argptr, int);
58*43625864Smatthias.ringwald                 // minimal va_arg is int: 2 bytes on 8+16 bit CPUs
59*43625864Smatthias.ringwald                 sig_buffer[pos++] = word & 0xff;
60*43625864Smatthias.ringwald                 if (*format == '2') {
61*43625864Smatthias.ringwald                     sig_buffer[pos++] = word >> 8;
62*43625864Smatthias.ringwald                 }
63*43625864Smatthias.ringwald                 break;
64*43625864Smatthias.ringwald             case 'D': // variable data. passed: len, ptr
65*43625864Smatthias.ringwald                 word = va_arg(argptr, int);
66*43625864Smatthias.ringwald                 ptr  = va_arg(argptr, uint8_t *);
67*43625864Smatthias.ringwald                 memcpy(&sig_buffer[pos], ptr, word);
68*43625864Smatthias.ringwald                 pos += word;
69*43625864Smatthias.ringwald                 break;
70*43625864Smatthias.ringwald             default:
71*43625864Smatthias.ringwald                 break;
72*43625864Smatthias.ringwald         }
73*43625864Smatthias.ringwald         format++;
74*43625864Smatthias.ringwald     };
75*43625864Smatthias.ringwald     va_end(argptr);
76*43625864Smatthias.ringwald 
77*43625864Smatthias.ringwald     // Fill in various length fields: it's the number of bytes following for ACL lenght and l2cap parameter length
78*43625864Smatthias.ringwald     // - the l2cap payload length is counted after the following channel id (only payload)
79*43625864Smatthias.ringwald 
80*43625864Smatthias.ringwald     // 2 - ACL length
81*43625864Smatthias.ringwald     bt_store_16(sig_buffer, 2,  pos - 4);
82*43625864Smatthias.ringwald     // 4 - L2CAP packet length
83*43625864Smatthias.ringwald     bt_store_16(sig_buffer, 4,  pos - 6 - 2);
84*43625864Smatthias.ringwald     // 10 - L2CAP signaling parameter length
85*43625864Smatthias.ringwald     bt_store_16(sig_buffer, 10, pos - 12);
86*43625864Smatthias.ringwald 
87*43625864Smatthias.ringwald     return hci_send_acl_packet(sig_buffer, pos);
88*43625864Smatthias.ringwald }
89*43625864Smatthias.ringwald 
90*43625864Smatthias.ringwald void l2cap_init(){
91*43625864Smatthias.ringwald     sig_buffer = malloc( 48 );
92*43625864Smatthias.ringwald     sig_seq_nr = 1;
93*43625864Smatthias.ringwald     local_cid = 0x40;
94*43625864Smatthias.ringwald }