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