xref: /btstack/src/l2cap_signaling.c (revision b48a17ffb3704444b92b6681f29976dfd32c2f10)
195cbd947Smatthias.ringwald /*
295cbd947Smatthias.ringwald  *  l2cap_signaling.h
395cbd947Smatthias.ringwald  *
495cbd947Smatthias.ringwald  *  Created by Matthias Ringwald on 7/23/09.
595cbd947Smatthias.ringwald  */
695cbd947Smatthias.ringwald 
795cbd947Smatthias.ringwald #include "l2cap_signaling.h"
895cbd947Smatthias.ringwald 
9*b48a17ffSmatthias.ringwald #include <string.h>
10*b48a17ffSmatthias.ringwald 
1195cbd947Smatthias.ringwald static char *l2cap_signaling_commands_format[] = {
1295cbd947Smatthias.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
1395cbd947Smatthias.ringwald "22",   // 0x02 connection request: PSM, Source CID
1495cbd947Smatthias.ringwald "2222", // 0x03 connection response: Dest CID, Source CID, Result, Status
1595cbd947Smatthias.ringwald "22D",  // 0x04 config request: Dest CID, Flags, Configuration options
1695cbd947Smatthias.ringwald "222D", // 0x05 config response: Source CID, Flags, Result, Configuration options
1795cbd947Smatthias.ringwald "22",   // 0x06 disconection request: Dest CID, Source CID
1895cbd947Smatthias.ringwald "22",   // 0x07 disconection response: Dest CID, Source CID
1995cbd947Smatthias.ringwald "D",    // 0x08 echo request: Data
2095cbd947Smatthias.ringwald "D",    // 0x09 echo response: Data
2195cbd947Smatthias.ringwald "2",    // 0x0a information request: InfoType {1=Connectionless MTU, 2=Extended features supported}
2295cbd947Smatthias.ringwald "22D",  // 0x0b information response: InfoType, Result, Data
2395cbd947Smatthias.ringwald };
2495cbd947Smatthias.ringwald 
25da269baaSmatthias.ringwald uint8_t   sig_seq_nr  = 0xff;
26bb53b291Smatthias.ringwald uint16_t  source_cid  = 0x40;
2795cbd947Smatthias.ringwald 
28da269baaSmatthias.ringwald uint8_t l2cap_next_sig_id(void){
29da269baaSmatthias.ringwald     if (sig_seq_nr == 0xff) {
30da269baaSmatthias.ringwald         sig_seq_nr = 1;
31da269baaSmatthias.ringwald     } else {
32da269baaSmatthias.ringwald         sig_seq_nr++;
33da269baaSmatthias.ringwald     }
34da269baaSmatthias.ringwald     return sig_seq_nr;
35da269baaSmatthias.ringwald }
36da269baaSmatthias.ringwald 
37bb53b291Smatthias.ringwald uint16_t l2cap_next_source_cid(void){
38bb53b291Smatthias.ringwald     return source_cid++;
39da269baaSmatthias.ringwald }
40da269baaSmatthias.ringwald 
4195cbd947Smatthias.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){
4295cbd947Smatthias.ringwald 
4395cbd947Smatthias.ringwald     // 0 - Connection handle : PB=10 : BC=00
4495cbd947Smatthias.ringwald     bt_store_16(acl_buffer, 0, handle | (2 << 12) | (0 << 14));
4595cbd947Smatthias.ringwald     // 6 - L2CAP channel = 1
4695cbd947Smatthias.ringwald     bt_store_16(acl_buffer, 6, 1);
4795cbd947Smatthias.ringwald     // 8 - Code
4895cbd947Smatthias.ringwald     acl_buffer[8] = cmd;
4995cbd947Smatthias.ringwald     // 9 - id (!= 0 sequentially)
5095cbd947Smatthias.ringwald     acl_buffer[9] = identifier;
5195cbd947Smatthias.ringwald 
5295cbd947Smatthias.ringwald     // 12 - L2CAP signaling parameters
5395cbd947Smatthias.ringwald     uint16_t pos = 12;
5495cbd947Smatthias.ringwald     const char *format = l2cap_signaling_commands_format[cmd-1];
5595cbd947Smatthias.ringwald     uint16_t word;
5695cbd947Smatthias.ringwald     uint8_t * ptr;
5795cbd947Smatthias.ringwald     while (*format) {
5895cbd947Smatthias.ringwald         switch(*format) {
5995cbd947Smatthias.ringwald             case '1': //  8 bit value
6095cbd947Smatthias.ringwald             case '2': // 16 bit value
6195cbd947Smatthias.ringwald                 word = va_arg(argptr, int);
6295cbd947Smatthias.ringwald                 // minimal va_arg is int: 2 bytes on 8+16 bit CPUs
6395cbd947Smatthias.ringwald                 acl_buffer[pos++] = word & 0xff;
6495cbd947Smatthias.ringwald                 if (*format == '2') {
6595cbd947Smatthias.ringwald                     acl_buffer[pos++] = word >> 8;
6695cbd947Smatthias.ringwald                 }
6795cbd947Smatthias.ringwald                 break;
6895cbd947Smatthias.ringwald             case 'D': // variable data. passed: len, ptr
6995cbd947Smatthias.ringwald                 word = va_arg(argptr, int);
7095cbd947Smatthias.ringwald                 ptr  = va_arg(argptr, uint8_t *);
7195cbd947Smatthias.ringwald                 memcpy(&acl_buffer[pos], ptr, word);
7295cbd947Smatthias.ringwald                 pos += word;
7395cbd947Smatthias.ringwald                 break;
7495cbd947Smatthias.ringwald             default:
7595cbd947Smatthias.ringwald                 break;
7695cbd947Smatthias.ringwald         }
7795cbd947Smatthias.ringwald         format++;
7895cbd947Smatthias.ringwald     };
7995cbd947Smatthias.ringwald     va_end(argptr);
8095cbd947Smatthias.ringwald 
8195cbd947Smatthias.ringwald     // Fill in various length fields: it's the number of bytes following for ACL lenght and l2cap parameter length
8295cbd947Smatthias.ringwald     // - the l2cap payload length is counted after the following channel id (only payload)
8395cbd947Smatthias.ringwald 
8495cbd947Smatthias.ringwald     // 2 - ACL length
8595cbd947Smatthias.ringwald     bt_store_16(acl_buffer, 2,  pos - 4);
8695cbd947Smatthias.ringwald     // 4 - L2CAP packet length
8795cbd947Smatthias.ringwald     bt_store_16(acl_buffer, 4,  pos - 6 - 2);
8895cbd947Smatthias.ringwald     // 10 - L2CAP signaling parameter length
8995cbd947Smatthias.ringwald     bt_store_16(acl_buffer, 10, pos - 12);
9095cbd947Smatthias.ringwald 
9195cbd947Smatthias.ringwald     return pos;
9295cbd947Smatthias.ringwald }
93