Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.
Path: blob/next/external/cache/sources/hcitools/monitor/l2cap.c
Views: 3959
/*1*2* BlueZ - Bluetooth protocol stack for Linux3*4* Copyright (C) 2011-2012 Intel Corporation5* Copyright (C) 2004-2010 Marcel Holtmann <[email protected]>6*7*8* This program is free software; you can redistribute it and/or modify9* it under the terms of the GNU General Public License as published by10* the Free Software Foundation; either version 2 of the License, or11* (at your option) any later version.12*13* This program is distributed in the hope that it will be useful,14* but WITHOUT ANY WARRANTY; without even the implied warranty of15* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the16* GNU General Public License for more details.17*18* You should have received a copy of the GNU General Public License19* along with this program; if not, write to the Free Software20* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA21*22*/2324#ifdef HAVE_CONFIG_H25#include <config.h>26#endif2728#include <stdio.h>29#include <stdlib.h>30#include <inttypes.h>3132#include <bluetooth/bluetooth.h>3334#include "bt.h"35#include "packet.h"36#include "display.h"37#include "l2cap.h"38#include "uuid.h"39#include "sdp.h"4041#define MAX_CHAN 644243struct chan_data {44uint16_t index;45uint16_t handle;46uint16_t scid;47uint16_t dcid;48uint16_t psm;49uint8_t ctrlid;50uint8_t mode;51};5253static struct chan_data chan_list[MAX_CHAN];5455static void assign_scid(const struct l2cap_frame *frame,56uint16_t scid, uint16_t psm, uint8_t ctrlid)57{58int i, n = -1;5960for (i = 0; i < MAX_CHAN; i++) {61if (n < 0 && chan_list[i].handle == 0x0000)62n = i;6364if (chan_list[i].index != frame->index)65continue;6667if (chan_list[i].handle != frame->handle)68continue;6970if (frame->in) {71if (chan_list[i].dcid == scid) {72n = i;73break;74}75} else {76if (chan_list[i].scid == scid) {77n = i;78break;79}80}81}8283if (n < 0)84return;8586memset(&chan_list[n], 0, sizeof(chan_list[n]));87chan_list[n].index = frame->index;88chan_list[n].handle = frame->handle;8990if (frame->in)91chan_list[n].dcid = scid;92else93chan_list[n].scid = scid;9495chan_list[n].psm = psm;96chan_list[n].ctrlid = ctrlid;97chan_list[n].mode = 0;98}99100static void release_scid(const struct l2cap_frame *frame, uint16_t scid)101{102int i;103104for (i = 0; i < MAX_CHAN; i++) {105if (chan_list[i].index != frame->index)106continue;107108if (chan_list[i].handle != frame->handle)109continue;110111if (frame->in) {112if (chan_list[i].scid == scid) {113chan_list[i].handle = 0;114break;115}116} else {117if (chan_list[i].dcid == scid) {118chan_list[i].handle = 0;119break;120}121}122}123}124125static void assign_dcid(const struct l2cap_frame *frame,126uint16_t dcid, uint16_t scid)127{128int i;129130for (i = 0; i < MAX_CHAN; i++) {131if (chan_list[i].index != frame->index)132continue;133134if (chan_list[i].handle != frame->handle)135continue;136137if (frame->in) {138if (chan_list[i].scid == scid) {139chan_list[i].dcid = dcid;140break;141}142} else {143if (chan_list[i].dcid == scid) {144chan_list[i].scid = dcid;145break;146}147}148}149}150151static void assign_mode(const struct l2cap_frame *frame,152uint8_t mode, uint16_t dcid)153{154int i;155156for (i = 0; i < MAX_CHAN; i++) {157if (chan_list[i].index != frame->index)158continue;159160if (chan_list[i].handle != frame->handle)161continue;162163if (frame->in) {164if (chan_list[i].scid == dcid) {165chan_list[i].mode = mode;166break;167}168} else {169if (chan_list[i].dcid == dcid) {170chan_list[i].mode = mode;171break;172}173}174}175}176177static uint16_t get_psm(const struct l2cap_frame *frame)178{179int i;180181for (i = 0; i < MAX_CHAN; i++) {182if (chan_list[i].index != frame->index &&183chan_list[i].ctrlid == 0)184continue;185186if (chan_list[i].handle != frame->handle &&187chan_list[i].ctrlid != frame->index)188continue;189190if (frame->in) {191if (chan_list[i].scid == frame->cid)192return chan_list[i].psm;193} else {194if (chan_list[i].dcid == frame->cid)195return chan_list[i].psm;196}197}198199return 0;200}201202static uint8_t get_mode(const struct l2cap_frame *frame)203{204int i;205206for (i = 0; i < MAX_CHAN; i++) {207if (chan_list[i].index != frame->index &&208chan_list[i].ctrlid == 0)209continue;210211if (chan_list[i].handle != frame->handle &&212chan_list[i].ctrlid != frame->index)213continue;214215if (frame->in) {216if (chan_list[i].scid == frame->cid)217return chan_list[i].mode;218} else {219if (chan_list[i].dcid == frame->cid)220return chan_list[i].mode;221}222}223224return 0;225}226227static uint16_t get_chan(const struct l2cap_frame *frame)228{229int i;230231for (i = 0; i < MAX_CHAN; i++) {232if (chan_list[i].index != frame->index &&233chan_list[i].ctrlid == 0)234continue;235236if (chan_list[i].handle != frame->handle &&237chan_list[i].ctrlid != frame->index)238continue;239240if (frame->in) {241if (chan_list[i].scid == frame->cid)242return i;243} else {244if (chan_list[i].dcid == frame->cid)245return i;246}247}248249return 0;250}251252#define MAX_INDEX 16253254struct index_data {255void *frag_buf;256uint16_t frag_pos;257uint16_t frag_len;258uint16_t frag_cid;259};260261static struct index_data index_list[MAX_INDEX];262263static void clear_fragment_buffer(uint16_t index)264{265free(index_list[index].frag_buf);266index_list[index].frag_buf = NULL;267index_list[index].frag_pos = 0;268index_list[index].frag_len = 0;269}270271static void print_psm(uint16_t psm)272{273print_field("PSM: %d (0x%4.4x)", btohs(psm), btohs(psm));274}275276static void print_cid(const char *type, uint16_t cid)277{278print_field("%s CID: %d", type, btohs(cid));279}280281static void print_reject_reason(uint16_t reason)282{283const char *str;284285switch (btohs(reason)) {286case 0x0000:287str = "Command not understood";288break;289case 0x0001:290str = "Signaling MTU exceeded";291break;292case 0x0002:293str = "Invalid CID in request";294break;295default:296str = "Reserved";297break;298}299300print_field("Reason: %s (0x%4.4x)", str, btohs(reason));301}302303static void print_conn_result(uint16_t result)304{305const char *str;306307switch (btohs(result)) {308case 0x0000:309str = "Connection successful";310break;311case 0x0001:312str = "Connection pending";313break;314case 0x0002:315str = "Connection refused - PSM not supported";316break;317case 0x0003:318str = "Connection refused - security block";319break;320case 0x0004:321str = "Connection refused - no resources available";322break;323default:324str = "Reserved";325break;326}327328print_field("Result: %s (0x%4.4x)", str, btohs(result));329}330331static void print_conn_status(uint16_t status)332{333const char *str;334335switch (btohs(status)) {336case 0x0000:337str = "No further information available";338break;339case 0x0001:340str = "Authentication pending";341break;342case 0x0002:343str = "Authorization pending";344break;345default:346str = "Reserved";347break;348}349350print_field("Status: %s (0x%4.4x)", str, btohs(status));351}352353static void print_config_flags(uint16_t flags)354{355const char *str;356357if (btohs(flags) & 0x0001)358str = " (continuation)";359else360str = "";361362print_field("Flags: 0x%4.4x%s", btohs(flags), str);363}364365static void print_config_result(uint16_t result)366{367const char *str;368369switch (btohs(result)) {370case 0x0000:371str = "Success";372break;373case 0x0001:374str = "Failure - unacceptable parameters";375break;376case 0x0002:377str = "Failure - rejected";378break;379case 0x0003:380str = "Failure - unknown options";381break;382case 0x0004:383str = "Pending";384break;385case 0x0005:386str = "Failure - flow spec rejected";387break;388default:389str = "Reserved";390break;391}392393print_field("Result: %s (0x%4.4x)", str, btohs(result));394}395396static struct {397uint8_t type;398uint8_t len;399const char *str;400} options_table[] = {401{ 0x01, 2, "Maximum Transmission Unit" },402{ 0x02, 2, "Flush Timeout" },403{ 0x03, 22, "Quality of Service" },404{ 0x04, 9, "Retransmission and Flow Control" },405{ 0x05, 1, "Frame Check Sequence" },406{ 0x06, 16, "Extended Flow Specification" },407{ 0x07, 2, "Extended Window Size" },408{ }409};410411static void print_config_options(const struct l2cap_frame *frame,412uint8_t offset, uint16_t dcid, bool response)413{414const uint8_t *data = frame->data + offset;415uint16_t size = frame->size - offset;416uint16_t consumed = 0;417418while (consumed < size - 2) {419const char *str = "Unknown";420uint8_t type = data[consumed];421uint8_t len = data[consumed + 1];422uint8_t expect_len = 0;423int i;424425for (i = 0; options_table[i].str; i++) {426if (options_table[i].type == type) {427str = options_table[i].str;428expect_len = options_table[i].len;429break;430}431}432433print_field("Option: %s (0x%2.2x)", str, type);434435if (expect_len == 0) {436consumed += 2;437break;438}439440if (len != expect_len) {441print_text(COLOR_ERROR, "wrong option size (%d != %d)",442len, expect_len);443consumed += 2;444break;445}446447switch (type) {448case 0x01:449print_field(" MTU: %d",450bt_get_le16(data + consumed + 2));451break;452case 0x02:453print_field(" Flush timeout: %d",454bt_get_le16(data + consumed + 2));455break;456case 0x03:457switch (data[consumed + 3]) {458case 0x00:459str = "No Traffic";460break;461case 0x01:462str = "Best Effort";463break;464case 0x02:465str = "Guaranteed";466break;467default:468str = "Reserved";469break;470}471print_field(" Flags: 0x%2.2x", data[consumed + 2]);472print_field(" Service type: %s (0x%2.2x)",473str, data[consumed + 3]);474print_field(" Token rate: 0x%8.8x",475bt_get_le32(data + consumed + 4));476print_field(" Token bucket size: 0x%8.8x",477bt_get_le32(data + consumed + 8));478print_field(" Peak bandwidth: 0x%8.8x",479bt_get_le32(data + consumed + 12));480print_field(" Latency: 0x%8.8x",481bt_get_le32(data + consumed + 16));482print_field(" Delay variation: 0x%8.8x",483bt_get_le32(data + consumed + 20));484break;485case 0x04:486if (response)487assign_mode(frame, data[consumed + 2], dcid);488489switch (data[consumed + 2]) {490case 0x00:491str = "Basic";492break;493case 0x01:494str = "Retransmission";495break;496case 0x02:497str = "Flow control";498break;499case 0x03:500str = "Enhanced retransmission";501break;502case 0x04:503str = "Streaming";504break;505default:506str = "Reserved";507break;508}509print_field(" Mode: %s (0x%2.2x)",510str, data[consumed + 2]);511print_field(" TX window size: %d", data[consumed + 3]);512print_field(" Max transmit: %d", data[consumed + 4]);513print_field(" Retransmission timeout: %d",514bt_get_le16(data + consumed + 5));515print_field(" Monitor timeout: %d",516bt_get_le16(data + consumed + 7));517print_field(" Maximum PDU size: %d",518bt_get_le16(data + consumed + 9));519break;520case 0x05:521switch (data[consumed + 2]) {522case 0x00:523str = "No FCS";524break;525case 0x01:526str = "16-bit FCS";527break;528default:529str = "Reserved";530break;531}532print_field(" FCS: %s (0x%2.2d)",533str, data[consumed + 2]);534break;535case 0x06:536switch (data[consumed + 3]) {537case 0x00:538str = "No traffic";539break;540case 0x01:541str = "Best effort";542break;543case 0x02:544str = "Guaranteed";545break;546default:547str = "Reserved";548break;549}550print_field(" Identifier: 0x%2.2x",551data[consumed + 2]);552print_field(" Service type: %s (0x%2.2x)",553str, data[consumed + 3]);554print_field(" Maximum SDU size: 0x%4.4x",555bt_get_le16(data + consumed + 4));556print_field(" SDU inter-arrival time: 0x%8.8x",557bt_get_le32(data + consumed + 6));558print_field(" Access latency: 0x%8.8x",559bt_get_le32(data + consumed + 10));560print_field(" Flush timeout: 0x%8.8x",561bt_get_le32(data + consumed + 14));562break;563case 0x07:564print_field(" Max window size: %d",565bt_get_le16(data + consumed + 2));566break;567default:568packet_hexdump(data + consumed + 2, len);569break;570}571572consumed += len + 2;573}574575if (consumed < size)576packet_hexdump(data + consumed, size - consumed);577}578579static void print_info_type(uint16_t type)580{581const char *str;582583switch (btohs(type)) {584case 0x0001:585str = "Connectionless MTU";586break;587case 0x0002:588str = "Extended features supported";589break;590case 0x0003:591str = "Fixed channels supported";592break;593default:594str = "Reserved";595break;596}597598print_field("Type: %s (0x%4.4x)", str, btohs(type));599}600601static void print_info_result(uint16_t result)602{603const char *str;604605switch (btohs(result)) {606case 0x0000:607str = "Success";608break;609case 0x0001:610str = "Not supported";611break;612default:613str = "Reserved";614break;615}616617print_field("Result: %s (0x%4.4x)", str, btohs(result));618}619620static struct {621uint8_t bit;622const char *str;623} features_table[] = {624{ 0, "Flow control mode" },625{ 1, "Retransmission mode" },626{ 2, "Bi-directional QoS" },627{ 3, "Enhanced Retransmission Mode" },628{ 4, "Streaming Mode" },629{ 5, "FCS Option" },630{ 6, "Extended Flow Specification for BR/EDR" },631{ 7, "Fixed Channels" },632{ 8, "Extended Window Size" },633{ 9, "Unicast Connectionless Data Reception" },634{ 31, "Reserved for feature mask extension" },635{ }636};637638static void print_features(uint32_t features)639{640uint32_t mask = features;641int i;642643print_field("Features: 0x%8.8x", features);644645for (i = 0; features_table[i].str; i++) {646if (features & (1 << features_table[i].bit)) {647print_field(" %s", features_table[i].str);648mask &= ~(1 << features_table[i].bit);649}650}651652if (mask)653print_field(" Unknown features (0x%8.8x)", mask);654}655656static struct {657uint16_t cid;658const char *str;659} channels_table[] = {660{ 0x0000, "Null identifier" },661{ 0x0001, "L2CAP Signaling (BR/EDR)" },662{ 0x0002, "Connectionless reception" },663{ 0x0003, "AMP Manager Protocol" },664{ 0x0004, "Attribute Protocol" },665{ 0x0005, "L2CAP Signaling (LE)" },666{ 0x0006, "Security Manager" },667{ 0x003f, "AMP Test Manager" },668{ }669};670671static void print_channels(uint64_t channels)672{673uint64_t mask = channels;674int i;675676print_field("Channels: 0x%16.16" PRIx64, channels);677678for (i = 0; channels_table[i].str; i++) {679if (channels & (1 << channels_table[i].cid)) {680print_field(" %s", channels_table[i].str);681mask &= ~(1 << channels_table[i].cid);682}683}684685if (mask)686print_field(" Unknown channels (0x%8.8" PRIx64 ")", mask);687}688689static void print_move_result(uint16_t result)690{691const char *str;692693switch (btohs(result)) {694case 0x0000:695str = "Move success";696break;697case 0x0001:698str = "Move pending";699break;700case 0x0002:701str = "Move refused - Controller ID not supported";702break;703case 0x0003:704str = "Move refused - new Controller ID is same";705break;706case 0x0004:707str = "Move refused - Configuration not supported";708break;709case 0x0005:710str = "Move refused - Move Channel collision";711break;712case 0x0006:713str = "Move refused - Channel not allowed to be moved";714break;715default:716str = "Reserved";717break;718}719720print_field("Result: %s (0x%4.4x)", str, btohs(result));721}722723static void print_move_cfm_result(uint16_t result)724{725const char *str;726727switch (btohs(result)) {728case 0x0000:729str = "Move success - both sides succeed";730break;731case 0x0001:732str = "Move failure - one or both sides refuse";733break;734default:735str = "Reserved";736break;737}738739print_field("Result: %s (0x%4.4x)", str, btohs(result));740}741742static void print_conn_param_result(uint16_t result)743{744const char *str;745746switch (btohs(result)) {747case 0x0000:748str = "Connection Parameters accepted";749break;750case 0x0001:751str = "Connection Parameters rejected";752break;753default:754str = "Reserved";755break;756}757758print_field("Result: %s (0x%4.4x)", str, btohs(result));759}760761static void sig_cmd_reject(const struct l2cap_frame *frame)762{763const struct bt_l2cap_pdu_cmd_reject *pdu = frame->data;764const void *data = frame->data;765uint16_t size = frame->size;766uint16_t scid, dcid;767768print_reject_reason(pdu->reason);769770data += sizeof(*pdu);771size -= sizeof(*pdu);772773switch (btohs(pdu->reason)) {774case 0x0000:775if (size != 0) {776print_text(COLOR_ERROR, "invalid data size");777packet_hexdump(data, size);778break;779}780break;781case 0x0001:782if (size != 2) {783print_text(COLOR_ERROR, "invalid data size");784packet_hexdump(data, size);785break;786}787print_field("MTU: %d", bt_get_le16(data));788break;789case 0x0002:790if (size != 4) {791print_text(COLOR_ERROR, "invalid data size");792packet_hexdump(data, size);793break;794}795dcid = bt_get_le16(data);796scid = bt_get_le16(data + 2);797print_cid("Destination", htobs(dcid));798print_cid("Source", htobs(scid));799break;800default:801packet_hexdump(data, size);802break;803}804}805806static void sig_conn_req(const struct l2cap_frame *frame)807{808const struct bt_l2cap_pdu_conn_req *pdu = frame->data;809810print_psm(pdu->psm);811print_cid("Source", pdu->scid);812813assign_scid(frame, btohs(pdu->scid), btohs(pdu->psm), 0);814}815816static void sig_conn_rsp(const struct l2cap_frame *frame)817{818const struct bt_l2cap_pdu_conn_rsp *pdu = frame->data;819820print_cid("Destination", pdu->dcid);821print_cid("Source", pdu->scid);822print_conn_result(pdu->result);823print_conn_status(pdu->status);824825assign_dcid(frame, btohs(pdu->dcid), btohs(pdu->scid));826}827828static void sig_config_req(const struct l2cap_frame *frame)829{830const struct bt_l2cap_pdu_config_req *pdu = frame->data;831832print_cid("Destination", pdu->dcid);833print_config_flags(pdu->flags);834print_config_options(frame, 4, btohs(pdu->dcid), false);835}836837static void sig_config_rsp(const struct l2cap_frame *frame)838{839const struct bt_l2cap_pdu_config_rsp *pdu = frame->data;840841print_cid("Source", pdu->scid);842print_config_flags(pdu->flags);843print_config_result(pdu->result);844print_config_options(frame, 6, btohs(pdu->scid), true);845}846847static void sig_disconn_req(const struct l2cap_frame *frame)848{849const struct bt_l2cap_pdu_disconn_req *pdu = frame->data;850851print_cid("Destination", pdu->dcid);852print_cid("Source", pdu->scid);853}854855static void sig_disconn_rsp(const struct l2cap_frame *frame)856{857const struct bt_l2cap_pdu_disconn_rsp *pdu = frame->data;858859print_cid("Destination", pdu->dcid);860print_cid("Source", pdu->scid);861862release_scid(frame, btohs(pdu->scid));863}864865static void sig_echo_req(const struct l2cap_frame *frame)866{867packet_hexdump(frame->data, frame->size);868}869870static void sig_echo_rsp(const struct l2cap_frame *frame)871{872packet_hexdump(frame->data, frame->size);873}874875static void sig_info_req(const struct l2cap_frame *frame)876{877const struct bt_l2cap_pdu_info_req *pdu = frame->data;878879print_info_type(pdu->type);880}881882static void sig_info_rsp(const struct l2cap_frame *frame)883{884const struct bt_l2cap_pdu_info_rsp *pdu = frame->data;885const void *data = frame->data;886uint16_t size = frame->size;887888print_info_type(pdu->type);889print_info_result(pdu->result);890891data += sizeof(*pdu);892size -= sizeof(*pdu);893894if (btohs(pdu->result) != 0x0000) {895if (size > 0) {896print_text(COLOR_ERROR, "invalid data size");897packet_hexdump(data, size);898}899return;900}901902switch (btohs(pdu->type)) {903case 0x0001:904if (size != 2) {905print_text(COLOR_ERROR, "invalid data size");906packet_hexdump(data, size);907break;908}909print_field("MTU: %d", bt_get_le16(data));910break;911case 0x0002:912if (size != 4) {913print_text(COLOR_ERROR, "invalid data size");914packet_hexdump(data, size);915break;916}917print_features(bt_get_le32(data));918break;919case 0x0003:920if (size != 8) {921print_text(COLOR_ERROR, "invalid data size");922packet_hexdump(data, size);923break;924}925print_channels(bt_get_le64(data));926break;927default:928packet_hexdump(data, size);929break;930}931}932933static void sig_create_chan_req(const struct l2cap_frame *frame)934{935const struct bt_l2cap_pdu_create_chan_req *pdu = frame->data;936937print_psm(pdu->psm);938print_cid("Source", pdu->scid);939print_field("Controller ID: %d", pdu->ctrlid);940941assign_scid(frame, btohs(pdu->scid), btohs(pdu->psm), pdu->ctrlid);942}943944static void sig_create_chan_rsp(const struct l2cap_frame *frame)945{946const struct bt_l2cap_pdu_create_chan_rsp *pdu = frame->data;947948print_cid("Destination", pdu->dcid);949print_cid("Source", pdu->scid);950print_conn_result(pdu->result);951print_conn_status(pdu->status);952953assign_dcid(frame, btohs(pdu->dcid), btohs(pdu->scid));954}955956static void sig_move_chan_req(const struct l2cap_frame *frame)957{958const struct bt_l2cap_pdu_move_chan_req *pdu = frame->data;959960print_cid("Initiator", pdu->icid);961print_field("Controller ID: %d", pdu->ctrlid);962}963964static void sig_move_chan_rsp(const struct l2cap_frame *frame)965{966const struct bt_l2cap_pdu_move_chan_rsp *pdu = frame->data;967968print_cid("Initiator", pdu->icid);969print_move_result(pdu->result);970}971972static void sig_move_chan_cfm(const struct l2cap_frame *frame)973{974const struct bt_l2cap_pdu_move_chan_cfm *pdu = frame->data;975976print_cid("Initiator", pdu->icid);977print_move_cfm_result(pdu->result);978}979980static void sig_move_chan_cfm_rsp(const struct l2cap_frame *frame)981{982const struct bt_l2cap_pdu_move_chan_cfm_rsp *pdu = frame->data;983984print_cid("Initiator", pdu->icid);985}986987static void sig_conn_param_req(const struct l2cap_frame *frame)988{989const struct bt_l2cap_pdu_conn_param_req *pdu = frame->data;990991print_field("Min interval: %d", btohs(pdu->min_interval));992print_field("Max interval: %d", btohs(pdu->max_interval));993print_field("Slave latency: %d", btohs(pdu->latency));994print_field("Timeout multiplier: %d", btohs(pdu->timeout));995}996997static void sig_conn_param_rsp(const struct l2cap_frame *frame)998{999const struct bt_l2cap_pdu_conn_param_rsp *pdu = frame->data;10001001print_conn_param_result(pdu->result);1002}10031004struct sig_opcode_data {1005uint8_t opcode;1006const char *str;1007void (*func) (const struct l2cap_frame *frame);1008uint16_t size;1009bool fixed;1010};10111012static const struct sig_opcode_data bredr_sig_opcode_table[] = {1013{ 0x01, "Command Reject",1014sig_cmd_reject, 2, false },1015{ 0x02, "Connection Request",1016sig_conn_req, 4, true },1017{ 0x03, "Connection Response",1018sig_conn_rsp, 8, true },1019{ 0x04, "Configure Request",1020sig_config_req, 4, false },1021{ 0x05, "Configure Response",1022sig_config_rsp, 6, false },1023{ 0x06, "Disconnection Request",1024sig_disconn_req, 4, true },1025{ 0x07, "Disconnection Response",1026sig_disconn_rsp, 4, true },1027{ 0x08, "Echo Request",1028sig_echo_req, 0, false },1029{ 0x09, "Echo Response",1030sig_echo_rsp, 0, false },1031{ 0x0a, "Information Request",1032sig_info_req, 2, true },1033{ 0x0b, "Information Response",1034sig_info_rsp, 4, false },1035{ 0x0c, "Create Channel Request",1036sig_create_chan_req, 5, true },1037{ 0x0d, "Create Channel Response",1038sig_create_chan_rsp, 8, true },1039{ 0x0e, "Move Channel Request",1040sig_move_chan_req, 3, true },1041{ 0x0f, "Move Channel Response",1042sig_move_chan_rsp, 4, true },1043{ 0x10, "Move Channel Confirmation",1044sig_move_chan_cfm, 4, true },1045{ 0x11, "Move Channel Confirmation Response",1046sig_move_chan_cfm_rsp, 2, true },1047{ },1048};10491050static const struct sig_opcode_data le_sig_opcode_table[] = {1051{ 0x01, "Command Reject",1052sig_cmd_reject, 2, false },1053{ 0x12, "Connection Parameter Update Request",1054sig_conn_param_req, 8, true },1055{ 0x13, "Connection Parameter Update Response",1056sig_conn_param_rsp, 2, true },1057{ },1058};10591060static void bredr_sig_packet(uint16_t index, bool in, uint16_t handle,1061uint16_t cid, const void *data, uint16_t size)1062{1063struct l2cap_frame frame;10641065while (size > 0) {1066const struct bt_l2cap_hdr_sig *hdr = data;1067const struct sig_opcode_data *opcode_data = NULL;1068const char *opcode_color, *opcode_str;1069uint16_t len;1070int i;10711072if (size < 4) {1073print_text(COLOR_ERROR, "malformed signal packet");1074packet_hexdump(data, size);1075return;1076}10771078len = btohs(hdr->len);10791080data += 4;1081size -= 4;10821083if (size < len) {1084print_text(COLOR_ERROR, "invalid signal packet size");1085packet_hexdump(data, size);1086return;1087}10881089for (i = 0; bredr_sig_opcode_table[i].str; i++) {1090if (bredr_sig_opcode_table[i].opcode == hdr->code) {1091opcode_data = &bredr_sig_opcode_table[i];1092break;1093}1094}10951096if (opcode_data) {1097if (opcode_data->func) {1098if (in)1099opcode_color = COLOR_MAGENTA;1100else1101opcode_color = COLOR_BLUE;1102} else1103opcode_color = COLOR_WHITE_BG;1104opcode_str = opcode_data->str;1105} else {1106opcode_color = COLOR_WHITE_BG;1107opcode_str = "Unknown";1108}11091110print_indent(6, opcode_color, "L2CAP: ", opcode_str,1111COLOR_OFF,1112" (0x%2.2x) ident %d len %d",1113hdr->code, hdr->ident, len);11141115if (!opcode_data || !opcode_data->func) {1116packet_hexdump(data, len);1117data += len;1118size -= len;1119return;1120}11211122if (opcode_data->fixed) {1123if (len != opcode_data->size) {1124print_text(COLOR_ERROR, "invalid size");1125packet_hexdump(data, len);1126data += len;1127size -= len;1128continue;1129}1130} else {1131if (len < opcode_data->size) {1132print_text(COLOR_ERROR, "too short packet");1133packet_hexdump(data, size);1134data += len;1135size -= len;1136continue;1137}1138}11391140l2cap_frame_init(&frame, index, in, handle, cid, data, len);1141opcode_data->func(&frame);11421143data += len;1144size -= len;1145}11461147packet_hexdump(data, size);1148}11491150static void le_sig_packet(uint16_t index, bool in, uint16_t handle,1151uint16_t cid, const void *data, uint16_t size)1152{1153struct l2cap_frame frame;1154const struct bt_l2cap_hdr_sig *hdr = data;1155const struct sig_opcode_data *opcode_data = NULL;1156const char *opcode_color, *opcode_str;1157uint16_t len;1158int i;11591160if (size < 4) {1161print_text(COLOR_ERROR, "malformed signal packet");1162packet_hexdump(data, size);1163return;1164}11651166len = btohs(hdr->len);11671168data += 4;1169size -= 4;11701171if (size != len) {1172print_text(COLOR_ERROR, "invalid signal packet size");1173packet_hexdump(data, size);1174return;1175}11761177for (i = 0; le_sig_opcode_table[i].str; i++) {1178if (le_sig_opcode_table[i].opcode == hdr->code) {1179opcode_data = &le_sig_opcode_table[i];1180break;1181}1182}11831184if (opcode_data) {1185if (opcode_data->func) {1186if (in)1187opcode_color = COLOR_MAGENTA;1188else1189opcode_color = COLOR_BLUE;1190} else1191opcode_color = COLOR_WHITE_BG;1192opcode_str = opcode_data->str;1193} else {1194opcode_color = COLOR_WHITE_BG;1195opcode_str = "Unknown";1196}11971198print_indent(6, opcode_color, "LE L2CAP: ", opcode_str, COLOR_OFF,1199" (0x%2.2x) ident %d len %d",1200hdr->code, hdr->ident, len);12011202if (!opcode_data || !opcode_data->func) {1203packet_hexdump(data, len);1204return;1205}12061207if (opcode_data->fixed) {1208if (len != opcode_data->size) {1209print_text(COLOR_ERROR, "invalid size");1210packet_hexdump(data, len);1211return;1212}1213} else {1214if (len < opcode_data->size) {1215print_text(COLOR_ERROR, "too short packet");1216packet_hexdump(data, size);1217return;1218}1219}12201221l2cap_frame_init(&frame, index, in, handle, cid, data, len);1222opcode_data->func(&frame);1223}12241225static void connless_packet(uint16_t index, bool in, uint16_t handle,1226uint16_t cid, const void *data, uint16_t size)1227{1228struct l2cap_frame frame;1229const struct bt_l2cap_hdr_connless *hdr = data;1230uint16_t psm;12311232if (size < 2) {1233print_text(COLOR_ERROR, "malformed connectionless packet");1234packet_hexdump(data, size);1235return;1236}12371238psm = btohs(hdr->psm);12391240data += 2;1241size -= 2;12421243print_indent(6, COLOR_CYAN, "L2CAP: Connectionless", "", COLOR_OFF,1244" len %d [PSM %d]", size, psm);12451246switch (psm) {1247default:1248packet_hexdump(data, size);1249break;1250}12511252l2cap_frame_init(&frame, index, in, handle, cid, data, size);1253}12541255static void print_controller_list(const uint8_t *data, uint16_t size)1256{1257while (size > 2) {1258const char *str;12591260print_field("Controller ID: %d", data[0]);12611262switch (data[1]) {1263case 0x00:1264str = "Primary BR/EDR Controller";1265break;1266case 0x01:1267str = "802.11 AMP Controller";1268break;1269default:1270str = "Reserved";1271break;1272}12731274print_field(" Type: %s (0x%2.2x)", str, data[1]);12751276switch (data[2]) {1277case 0x00:1278str = "Present";1279break;1280case 0x01:1281str = "Bluetooth only";1282break;1283case 0x02:1284str = "No capacity";1285break;1286case 0x03:1287str = "Low capacity";1288break;1289case 0x04:1290str = "Medium capacity";1291break;1292case 0x05:1293str = "High capacity";1294break;1295case 0x06:1296str = "Full capacity";1297break;1298default:1299str = "Reserved";1300break;1301}13021303print_field(" Status: %s (0x%2.2x)", str, data[2]);13041305data += 3;1306size -= 3;1307}13081309packet_hexdump(data, size);1310}13111312static void amp_cmd_reject(const struct l2cap_frame *frame)1313{1314const struct bt_l2cap_amp_cmd_reject *pdu = frame->data;13151316print_field("Reason: 0x%4.4x", btohs(pdu->reason));1317}13181319static void amp_discover_req(const struct l2cap_frame *frame)1320{1321const struct bt_l2cap_amp_discover_req *pdu = frame->data;13221323print_field("MTU/MPS size: %d", btohs(pdu->size));1324print_field("Extended feature mask: 0x%4.4x", btohs(pdu->features));1325}13261327static void amp_discover_rsp(const struct l2cap_frame *frame)1328{1329const struct bt_l2cap_amp_discover_rsp *pdu = frame->data;13301331print_field("MTU/MPS size: %d", btohs(pdu->size));1332print_field("Extended feature mask: 0x%4.4x", btohs(pdu->features));13331334print_controller_list(frame->data + 4, frame->size - 4);1335}13361337static void amp_change_notify(const struct l2cap_frame *frame)1338{1339print_controller_list(frame->data, frame->size);1340}13411342static void amp_change_response(const struct l2cap_frame *frame)1343{1344}13451346static void amp_get_info_req(const struct l2cap_frame *frame)1347{1348const struct bt_l2cap_amp_get_info_req *pdu = frame->data;13491350print_field("Controller ID: %d", pdu->ctrlid);1351}13521353static void amp_get_info_rsp(const struct l2cap_frame *frame)1354{1355const struct bt_l2cap_amp_get_info_rsp *pdu = frame->data;1356const char *str;13571358print_field("Controller ID: %d", pdu->ctrlid);13591360switch (pdu->status) {1361case 0x00:1362str = "Success";1363break;1364case 0x01:1365str = "Invalid Controller ID";1366break;1367default:1368str = "Reserved";1369break;1370}13711372print_field("Status: %s (0x%2.2x)", str, pdu->status);13731374print_field("Total bandwidth: %d kbps", btohl(pdu->total_bw));1375print_field("Max guaranteed bandwidth: %d kbps", btohl(pdu->max_bw));1376print_field("Min latency: %d", btohl(pdu->min_latency));13771378print_field("PAL capabilities: 0x%4.4x", btohs(pdu->pal_cap));1379print_field("Max ASSOC length: %d", btohs(pdu->max_assoc_len));1380}13811382static void amp_get_assoc_req(const struct l2cap_frame *frame)1383{1384const struct bt_l2cap_amp_get_assoc_req *pdu = frame->data;13851386print_field("Controller ID: %d", pdu->ctrlid);1387}13881389static void amp_get_assoc_rsp(const struct l2cap_frame *frame)1390{1391const struct bt_l2cap_amp_get_assoc_rsp *pdu = frame->data;1392const char *str;13931394print_field("Controller ID: %d", pdu->ctrlid);13951396switch (pdu->status) {1397case 0x00:1398str = "Success";1399break;1400case 0x01:1401str = "Invalid Controller ID";1402break;1403default:1404str = "Reserved";1405break;1406}14071408print_field("Status: %s (0x%2.2x)", str, pdu->status);14091410packet_hexdump(frame->data + 2, frame->size - 2);1411}14121413static void amp_create_phy_link_req(const struct l2cap_frame *frame)1414{1415const struct bt_l2cap_amp_create_phy_link_req *pdu = frame->data;14161417print_field("Local controller ID: %d", pdu->local_ctrlid);1418print_field("Remote controller ID: %d", pdu->remote_ctrlid);14191420packet_hexdump(frame->data + 2, frame->size - 2);1421}14221423static void amp_create_phy_link_rsp(const struct l2cap_frame *frame)1424{1425const struct bt_l2cap_amp_create_phy_link_rsp *pdu = frame->data;1426const char *str;14271428print_field("Local controller ID: %d", pdu->local_ctrlid);1429print_field("Remote controller ID: %d", pdu->remote_ctrlid);14301431switch (pdu->status) {1432case 0x00:1433str = "Success";1434break;1435case 0x01:1436str = "Invalid Controller ID";1437break;1438case 0x02:1439str = "Failed - Unable to start link creation";1440break;1441case 0x03:1442str = "Failed - Collision occurred";1443break;1444case 0x04:1445str = "Failed - Disconnected link packet received";1446break;1447case 0x05:1448str = "Failed - Link already exists";1449break;1450case 0x06:1451str = "Failed - Security violation";1452break;1453default:1454str = "Reserved";1455break;1456}14571458print_field("Status: %s (0x%2.2x)", str, pdu->status);1459}14601461static void amp_disconn_phy_link_req(const struct l2cap_frame *frame)1462{1463const struct bt_l2cap_amp_disconn_phy_link_req *pdu = frame->data;14641465print_field("Local controller ID: %d", pdu->local_ctrlid);1466print_field("Remote controller ID: %d", pdu->remote_ctrlid);1467}14681469static void amp_disconn_phy_link_rsp(const struct l2cap_frame *frame)1470{1471const struct bt_l2cap_amp_disconn_phy_link_rsp *pdu = frame->data;1472const char *str;14731474print_field("Local controller ID: %d", pdu->local_ctrlid);1475print_field("Remote controller ID: %d", pdu->remote_ctrlid);14761477switch (pdu->status) {1478case 0x00:1479str = "Success";1480break;1481case 0x01:1482str = "Invalid Controller ID";1483break;1484case 0x02:1485str = "Failed - No link exists";1486break;1487default:1488str = "Reserved";1489break;1490}14911492print_field("Status: %s (0x%2.2x)", str, pdu->status);1493}14941495struct amp_opcode_data {1496uint8_t opcode;1497const char *str;1498void (*func) (const struct l2cap_frame *frame);1499uint16_t size;1500bool fixed;1501};15021503static const struct amp_opcode_data amp_opcode_table[] = {1504{ 0x01, "Command Reject",1505amp_cmd_reject, 2, false },1506{ 0x02, "Discover Request",1507amp_discover_req, 4, true },1508{ 0x03, "Discover Response",1509amp_discover_rsp, 7, false },1510{ 0x04, "Change Notify",1511amp_change_notify, 3, false },1512{ 0x05, "Change Response",1513amp_change_response, 0, true },1514{ 0x06, "Get Info Request",1515amp_get_info_req, 1, true },1516{ 0x07, "Get Info Response",1517amp_get_info_rsp, 18, true },1518{ 0x08, "Get Assoc Request",1519amp_get_assoc_req, 1, true },1520{ 0x09, "Get Assoc Response",1521amp_get_assoc_rsp, 2, false },1522{ 0x0a, "Create Physical Link Request",1523amp_create_phy_link_req, 2, false },1524{ 0x0b, "Create Physical Link Response",1525amp_create_phy_link_rsp, 3, true },1526{ 0x0c, "Disconnect Physical Link Request",1527amp_disconn_phy_link_req, 2, true },1528{ 0x0d, "Disconnect Physical Link Response",1529amp_disconn_phy_link_rsp, 3, true },1530{ },1531};15321533static void amp_packet(uint16_t index, bool in, uint16_t handle,1534uint16_t cid, const void *data, uint16_t size)1535{1536struct l2cap_frame frame;1537uint16_t control, fcs, len;1538uint8_t opcode, ident;1539const struct amp_opcode_data *opcode_data = NULL;1540const char *opcode_color, *opcode_str;1541int i;15421543if (size < 4) {1544print_text(COLOR_ERROR, "malformed info frame packet");1545packet_hexdump(data, size);1546return;1547}15481549control = bt_get_le16(data);1550fcs = bt_get_le16(data + size - 2);15511552print_indent(6, COLOR_CYAN, "Channel:", "", COLOR_OFF,1553" %d dlen %d control 0x%4.4x fcs 0x%4.4x",15543, size, control, fcs);15551556if (control & 0x01)1557return;15581559if (size < 8) {1560print_text(COLOR_ERROR, "malformed manager packet");1561packet_hexdump(data, size);1562return;1563}15641565opcode = *((const uint8_t *) (data + 2));1566ident = *((const uint8_t *) (data + 3));1567len = bt_get_le16(data + 4);15681569if (len != size - 8) {1570print_text(COLOR_ERROR, "invalid manager packet size");1571packet_hexdump(data + 2, size - 4);1572return;1573}15741575for (i = 0; amp_opcode_table[i].str; i++) {1576if (amp_opcode_table[i].opcode == opcode) {1577opcode_data = &_opcode_table[i];1578break;1579}1580}15811582if (opcode_data) {1583if (opcode_data->func) {1584if (in)1585opcode_color = COLOR_MAGENTA;1586else1587opcode_color = COLOR_BLUE;1588} else1589opcode_color = COLOR_WHITE_BG;1590opcode_str = opcode_data->str;1591} else {1592opcode_color = COLOR_WHITE_BG;1593opcode_str = "Unknown";1594}15951596print_indent(6, opcode_color, "AMP: ", opcode_str, COLOR_OFF,1597" (0x%2.2x) ident %d len %d", opcode, ident, len);15981599if (!opcode_data || !opcode_data->func) {1600packet_hexdump(data + 6, size - 8);1601return;1602}16031604if (opcode_data->fixed) {1605if (len != opcode_data->size) {1606print_text(COLOR_ERROR, "invalid size");1607packet_hexdump(data + 6, size - 8);1608return;1609}1610} else {1611if (len < opcode_data->size) {1612print_text(COLOR_ERROR, "too short packet");1613packet_hexdump(data + 6, size - 8);1614return;1615}1616}16171618l2cap_frame_init(&frame, index, in, handle, cid, data + 6, len);1619opcode_data->func(&frame);1620}16211622static void print_hex_field(const char *label, const uint8_t *data,1623uint8_t len)1624{1625char str[len * 2 + 1];1626uint8_t i;16271628str[0] = '\0';16291630for (i = 0; i < len; i++)1631sprintf(str + (i * 2), "%2.2x", data[i]);16321633print_field("%s: %s", label, str);1634}16351636static void print_uuid(const char *label, const void *data, uint16_t size)1637{1638const char *str;16391640switch (size) {1641case 2:1642str = uuid16_to_str(bt_get_le16(data));1643print_field("%s: %s (0x%4.4x)", label, str, bt_get_le16(data));1644break;1645case 4:1646str = uuid32_to_str(bt_get_le32(data));1647print_field("%s: %s (0x%8.8x)", label, str, bt_get_le32(data));1648break;1649case 16:1650str = uuid128_to_str(data);1651print_field("%s: %s (%8.8x-%4.4x-%4.4x-%4.4x-%8.8x%4.4x)",1652label, str,1653bt_get_le32(data + 12), bt_get_le16(data + 10),1654bt_get_le16(data + 8), bt_get_le16(data + 6),1655bt_get_le32(data + 2), bt_get_le16(data + 0));1656break;1657default:1658packet_hexdump(data, size);1659break;1660}1661}16621663static void print_handle_range(const char *label, const void *data)1664{1665print_field("%s: 0x%4.4x-0x%4.4x", label,1666bt_get_le16(data), bt_get_le16(data + 2));1667}16681669static void print_data_list(const char *label, uint8_t length,1670const void *data, uint16_t size)1671{1672uint8_t count;16731674if (length == 0)1675return;16761677count = size / length;16781679print_field("%s: %u entr%s", label, count, count == 1 ? "y" : "ies");16801681while (size >= length) {1682print_field("Handle: 0x%4.4x", bt_get_le16(data));1683print_hex_field("Value", data + 2, length - 2);16841685data += length;1686size -= length;1687}16881689packet_hexdump(data, size);1690}16911692static void print_attribute_info(uint16_t type, const void *data, uint16_t len)1693{1694const char *str = uuid16_to_str(type);16951696print_field("%s: %s (0x%4.4x)", "Attribute type", str, type);16971698switch (type) {1699case 0x2800: /* Primary Service */1700case 0x2801: /* Secondary Service */1701print_uuid(" UUID", data, len);1702break;1703case 0x2802: /* Include */1704if (len < 4) {1705print_hex_field(" Value", data, len);1706break;1707}1708print_handle_range(" Handle range", data);1709print_uuid(" UUID", data + 4, len - 4);1710break;1711case 0x2803: /* Characteristic */1712if (len < 3) {1713print_hex_field(" Value", data, len);1714break;1715}1716print_field(" Properties: 0x%2.2x", *((uint8_t *) data));1717print_field(" Handle: 0x%2.2x", bt_get_le16(data + 1));1718print_uuid(" UUID", data + 3, len - 3);1719break;1720default:1721print_hex_field("Value", data, len);1722break;1723}1724}17251726static const char *att_opcode_to_str(uint8_t opcode);17271728static void att_error_response(const struct l2cap_frame *frame)1729{1730const struct bt_l2cap_att_error_response *pdu = frame->data;1731const char *str;17321733switch (pdu->error) {1734case 0x01:1735str = "Invalid Handle";1736break;1737case 0x02:1738str = "Read Not Permitted";1739break;1740case 0x03:1741str = "Write Not Permitted";1742break;1743case 0x04:1744str = "Invalid PDU";1745break;1746case 0x05:1747str = "Insufficient Authentication";1748break;1749case 0x06:1750str = "Request Not Supported";1751break;1752case 0x07:1753str = "Invalid Offset";1754break;1755case 0x08:1756str = "Insufficient Authorization";1757break;1758case 0x09:1759str = "Prepare Queue Full";1760break;1761case 0x0a:1762str = "Attribute Not Found";1763break;1764case 0x0b:1765str = "Attribute Not Long";1766break;1767case 0x0c:1768str = "Insufficient Encryption Key Size";1769break;1770case 0x0d:1771str = "Invalid Attribute Value Length";1772break;1773case 0x0e:1774str = "Unlikely Error";1775break;1776case 0x0f:1777str = "Insufficient Encryption";1778break;1779case 0x10:1780str = "Unsupported Group Type";1781break;1782case 0x11:1783str = "Insufficient Resources";1784break;1785default:1786str = "Reserved";1787break;1788}17891790print_field("%s (0x%2.2x)", att_opcode_to_str(pdu->request),1791pdu->request);1792print_field("Handle: 0x%4.4x", btohs(pdu->handle));1793print_field("Error: %s (0x%2.2x)", str, pdu->error);1794}17951796static void att_exchange_mtu_req(const struct l2cap_frame *frame)1797{1798const struct bt_l2cap_att_exchange_mtu_req *pdu = frame->data;17991800print_field("Client RX MTU: %d", btohs(pdu->mtu));1801}18021803static void att_exchange_mtu_rsp(const struct l2cap_frame *frame)1804{1805const struct bt_l2cap_att_exchange_mtu_rsp *pdu = frame->data;18061807print_field("Server RX MTU: %d", btohs(pdu->mtu));1808}18091810static void att_find_info_req(const struct l2cap_frame *frame)1811{1812print_handle_range("Handle range", frame->data);1813}18141815static const char *att_format_str(uint8_t format)1816{1817switch (format) {1818case 0x01:1819return "UUID-16";1820case 0x02:1821return "UUID-128";1822default:1823return "unknown";1824}1825}18261827static uint16_t print_info_data_16(const uint16_t *data, uint16_t len)1828{1829while (len >= 4) {1830print_field("Handle: 0x%4.4x", bt_get_le16(data));1831print_uuid("UUID", data + 2, 2);1832data += 4;1833len -= 4;1834}18351836return len;1837}18381839static uint16_t print_info_data_128(const uint16_t *data, uint16_t len)1840{1841while (len >= 18) {1842print_field("Handle: 0x%4.4x", bt_get_le16(data));1843print_uuid("UUID", data + 2, 16);1844data += 18;1845len -= 18;1846}18471848return len;1849}18501851static void att_find_info_rsp(const struct l2cap_frame *frame)1852{1853const uint8_t *format = frame->data;1854uint16_t len;18551856print_field("Format: %s (0x%2.2x)", att_format_str(*format), *format);18571858if (*format == 0x01)1859len = print_info_data_16(frame->data + 1, frame->size - 1);1860else if (*format == 0x02)1861len = print_info_data_128(frame->data + 1, frame->size - 1);1862else1863len = frame->size - 1;18641865packet_hexdump(frame->data + (frame->size - len), len);1866}18671868static void att_find_by_type_val_req(const struct l2cap_frame *frame)1869{1870uint16_t type;18711872print_handle_range("Handle range", frame->data);18731874type = bt_get_le16(frame->data + 4);1875print_attribute_info(type, frame->data + 6, frame->size - 6);1876}18771878static void att_find_by_type_val_rsp(const struct l2cap_frame *frame)1879{1880const uint8_t *ptr = frame->data;1881uint16_t len = frame->size;18821883while (len >= 4) {1884print_handle_range("Handle range", ptr);1885ptr += 4;1886len -= 4;1887}18881889packet_hexdump(ptr, len);1890}18911892static void att_read_type_req(const struct l2cap_frame *frame)1893{1894print_handle_range("Handle range", frame->data);1895print_uuid("Attribute type", frame->data + 4, frame->size - 4);1896}18971898static void att_read_type_rsp(const struct l2cap_frame *frame)1899{1900const struct bt_l2cap_att_read_group_type_rsp *pdu = frame->data;19011902print_field("Attribute data length: %d", pdu->length);1903print_data_list("Attribute data list", pdu->length,1904frame->data + 1, frame->size - 1);1905}19061907static void att_read_req(const struct l2cap_frame *frame)1908{1909const struct bt_l2cap_att_read_req *pdu = frame->data;19101911print_field("Handle: 0x%4.4x", btohs(pdu->handle));1912}19131914static void att_read_rsp(const struct l2cap_frame *frame)1915{1916print_hex_field("Value", frame->data, frame->size);1917}19181919static void att_read_blob_req(const struct l2cap_frame *frame)1920{1921print_field("Handle: 0x%4.4x", bt_get_le16(frame->data));1922print_field("Offset: 0x%4.4x", bt_get_le16(frame->data + 2));1923}19241925static void att_read_blob_rsp(const struct l2cap_frame *frame)1926{1927packet_hexdump(frame->data, frame->size);1928}19291930static void att_read_multiple_req(const struct l2cap_frame *frame)1931{1932int i, count;19331934count = frame->size / 2;19351936for (i = 0; i < count; i++)1937print_field("Handle: 0x%4.4x",1938bt_get_le16(frame->data + (i * 2)));1939}19401941static void att_read_group_type_req(const struct l2cap_frame *frame)1942{1943print_handle_range("Handle range", frame->data);1944print_uuid("Attribute group type", frame->data + 4, frame->size - 4);1945}19461947static void att_read_group_type_rsp(const struct l2cap_frame *frame)1948{1949const struct bt_l2cap_att_read_group_type_rsp *pdu = frame->data;19501951print_field("Attribute data length: %d", pdu->length);1952print_data_list("Attribute data list", pdu->length,1953frame->data + 1, frame->size - 1);1954}19551956static void att_write_req(const struct l2cap_frame *frame)1957{1958print_field("Handle: 0x%4.4x", bt_get_le16(frame->data));1959print_hex_field(" Data", frame->data + 2, frame->size - 2);1960}19611962static void att_write_rsp(const struct l2cap_frame *frame)1963{1964}19651966static void att_prepare_write_req(const struct l2cap_frame *frame)1967{1968print_field("Handle: 0x%4.4x", bt_get_le16(frame->data));1969print_field("Offset: 0x%4.4x", bt_get_le16(frame->data + 2));1970print_hex_field(" Data", frame->data + 4, frame->size - 4);1971}19721973static void att_prepare_write_rsp(const struct l2cap_frame *frame)1974{1975print_field("Handle: 0x%4.4x", bt_get_le16(frame->data));1976print_field("Offset: 0x%4.4x", bt_get_le16(frame->data + 2));1977print_hex_field(" Data", frame->data + 4, frame->size - 4);1978}19791980static void att_execute_write_req(const struct l2cap_frame *frame)1981{1982uint8_t flags = *(uint8_t *) frame->data;1983const char *flags_str;19841985switch (flags) {1986case 0x00:1987flags_str = "Cancel all prepared writes";1988break;1989case 0x01:1990flags_str = "Immediately write all pending values";1991break;1992default:1993flags_str = "Unknown";1994break;1995}19961997print_field("Flags: %s (0x%02x)", flags_str, flags);1998}19992000static void att_handle_value_notify(const struct l2cap_frame *frame)2001{2002const struct bt_l2cap_att_handle_value_notify *pdu = frame->data;20032004print_field("Handle: 0x%4.4x", btohs(pdu->handle));2005print_hex_field(" Data", frame->data + 2, frame->size - 2);2006}20072008static void att_handle_value_ind(const struct l2cap_frame *frame)2009{2010const struct bt_l2cap_att_handle_value_ind *pdu = frame->data;20112012print_field("Handle: 0x%4.4x", btohs(pdu->handle));2013print_hex_field(" Data", frame->data + 2, frame->size - 2);2014}20152016static void att_handle_value_conf(const struct l2cap_frame *frame)2017{2018}20192020static void att_write_command(const struct l2cap_frame *frame)2021{2022print_field("Handle: 0x%4.4x", bt_get_le16(frame->data));2023print_hex_field(" Data", frame->data + 2, frame->size - 2);2024}20252026struct att_opcode_data {2027uint8_t opcode;2028const char *str;2029void (*func) (const struct l2cap_frame *frame);2030uint8_t size;2031bool fixed;2032};20332034static const struct att_opcode_data att_opcode_table[] = {2035{ 0x01, "Error Response",2036att_error_response, 4, true },2037{ 0x02, "Exchange MTU Request",2038att_exchange_mtu_req, 2, true },2039{ 0x03, "Exchange MTU Response",2040att_exchange_mtu_rsp, 2, true },2041{ 0x04, "Find Information Request",2042att_find_info_req, 4, true },2043{ 0x05, "Find Information Response",2044att_find_info_rsp, 5, false },2045{ 0x06, "Find By Type Value Request",2046att_find_by_type_val_req, 6, false },2047{ 0x07, "Find By Type Value Response",2048att_find_by_type_val_rsp, 4, false },2049{ 0x08, "Read By Type Request",2050att_read_type_req, 6, false },2051{ 0x09, "Read By Type Response",2052att_read_type_rsp, 3, false },2053{ 0x0a, "Read Request",2054att_read_req, 2, true },2055{ 0x0b, "Read Response",2056att_read_rsp, 0, false },2057{ 0x0c, "Read Blob Request",2058att_read_blob_req, 4, true },2059{ 0x0d, "Read Blob Response",2060att_read_blob_rsp, 0, false },2061{ 0x0e, "Read Multiple Request",2062att_read_multiple_req, 4, false },2063{ 0x0f, "Read Multiple Response" },2064{ 0x10, "Read By Group Type Request",2065att_read_group_type_req, 6, false },2066{ 0x11, "Read By Group Type Response",2067att_read_group_type_rsp, 4, false },2068{ 0x12, "Write Request" ,2069att_write_req, 2, false },2070{ 0x13, "Write Response",2071att_write_rsp, 0, true },2072{ 0x16, "Prepare Write Request",2073att_prepare_write_req, 4, false },2074{ 0x17, "Prepare Write Response",2075att_prepare_write_rsp, 4, false },2076{ 0x18, "Execute Write Request",2077att_execute_write_req, 1, true },2078{ 0x19, "Execute Write Response" },2079{ 0x1b, "Handle Value Notification",2080att_handle_value_notify, 2, false },2081{ 0x1d, "Handle Value Indication",2082att_handle_value_ind, 2, false },2083{ 0x1e, "Handle Value Confirmation",2084att_handle_value_conf, 0, true },2085{ 0x52, "Write Command",2086att_write_command, 2, false },2087{ 0xd2, "Signed Write Command" },2088{ }2089};20902091static const char *att_opcode_to_str(uint8_t opcode)2092{2093int i;20942095for (i = 0; att_opcode_table[i].str; i++) {2096if (att_opcode_table[i].opcode == opcode)2097return att_opcode_table[i].str;2098}20992100return "Unknown";2101}21022103static void att_packet(uint16_t index, bool in, uint16_t handle,2104uint16_t cid, const void *data, uint16_t size)2105{2106struct l2cap_frame frame;2107uint8_t opcode = *((const uint8_t *) data);2108const struct att_opcode_data *opcode_data = NULL;2109const char *opcode_color, *opcode_str;2110int i;21112112if (size < 1) {2113print_text(COLOR_ERROR, "malformed attribute packet");2114packet_hexdump(data, size);2115return;2116}21172118for (i = 0; att_opcode_table[i].str; i++) {2119if (att_opcode_table[i].opcode == opcode) {2120opcode_data = &att_opcode_table[i];2121break;2122}2123}21242125if (opcode_data) {2126if (opcode_data->func) {2127if (in)2128opcode_color = COLOR_MAGENTA;2129else2130opcode_color = COLOR_BLUE;2131} else2132opcode_color = COLOR_WHITE_BG;2133opcode_str = opcode_data->str;2134} else {2135opcode_color = COLOR_WHITE_BG;2136opcode_str = "Unknown";2137}21382139print_indent(6, opcode_color, "ATT: ", opcode_str, COLOR_OFF,2140" (0x%2.2x) len %d", opcode, size - 1);21412142if (!opcode_data || !opcode_data->func) {2143packet_hexdump(data + 1, size - 1);2144return;2145}21462147if (opcode_data->fixed) {2148if (size - 1 != opcode_data->size) {2149print_text(COLOR_ERROR, "invalid size");2150packet_hexdump(data + 1, size - 1);2151return;2152}2153} else {2154if (size - 1 < opcode_data->size) {2155print_text(COLOR_ERROR, "too short packet");2156packet_hexdump(data + 1, size - 1);2157return;2158}2159}21602161l2cap_frame_init(&frame, index, in, handle, cid, data + 1, size - 1);2162opcode_data->func(&frame);2163}21642165static void print_addr(const uint8_t *addr, uint8_t addr_type)2166{2167const char *str;21682169switch (addr_type) {2170case 0x00:2171print_field("Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",2172addr[5], addr[4], addr[3],2173addr[2], addr[1], addr[0]);2174break;2175case 0x01:2176switch ((addr[5] & 0xc0) >> 6) {2177case 0x00:2178str = "Non-Resolvable";2179break;2180case 0x01:2181str = "Resolvable";2182break;2183case 0x03:2184str = "Static";2185break;2186default:2187str = "Reserved";2188break;2189}21902191print_field("Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X"2192" (%s)", addr[5], addr[4], addr[3],2193addr[2], addr[1], addr[0], str);2194break;2195default:2196print_field("Address: %2.2X-%2.2X-%2.2X-%2.2X-%2.2X-%2.2X",2197addr[5], addr[4], addr[3],2198addr[2], addr[1], addr[0]);2199break;2200}2201}22022203static void print_addr_type(uint8_t addr_type)2204{2205const char *str;22062207switch (addr_type) {2208case 0x00:2209str = "Public";2210break;2211case 0x01:2212str = "Random";2213break;2214default:2215str = "Reserved";2216break;2217}22182219print_field("Address type: %s (0x%2.2x)", str, addr_type);2220}22212222static void print_smp_io_capa(uint8_t io_capa)2223{2224const char *str;22252226switch (io_capa) {2227case 0x00:2228str = "DisplayOnly";2229break;2230case 0x01:2231str = "DisplayYesNo";2232break;2233case 0x02:2234str = "KeyboardOnly";2235break;2236case 0x03:2237str = "NoInputNoOutput";2238break;2239case 0x04:2240str = "KeyboardDisplay";2241break;2242default:2243str = "Reserved";2244break;2245}22462247print_field("IO capability: %s (0x%2.2x)", str, io_capa);2248}22492250static void print_smp_oob_data(uint8_t oob_data)2251{2252const char *str;22532254switch (oob_data) {2255case 0x00:2256str = "Authentication data not present";2257break;2258case 0x01:2259str = "Authentication data from remote device present";2260break;2261default:2262str = "Reserved";2263break;2264}22652266print_field("OOB data: %s (0x%2.2x)", str, oob_data);2267}22682269static void print_smp_auth_req(uint8_t auth_req)2270{2271const char *str;22722273switch (auth_req & 0x03) {2274case 0x00:2275str = "No bonding";2276break;2277case 0x01:2278str = "Bonding";2279break;2280default:2281str = "Reserved";2282break;2283}22842285print_field("Authentication requirement: %s - %s (0x%2.2x)",2286str, (auth_req & 0x04) ? "MITM" : "No MITM", auth_req);2287}22882289static void smp_pairing_request(const struct l2cap_frame *frame)2290{2291const struct bt_l2cap_smp_pairing_request *pdu = frame->data;22922293print_smp_io_capa(pdu->io_capa);2294print_smp_oob_data(pdu->oob_data);2295print_smp_auth_req(pdu->auth_req);22962297print_field("Max encryption key size: %d", pdu->max_key_size);2298print_field("Initiator key distribution: 0x%2.2x", pdu->init_key_dist);2299print_field("Responder key distribution: 0x%2.2x", pdu->resp_key_dist);2300}23012302static void smp_pairing_response(const struct l2cap_frame *frame)2303{2304const struct bt_l2cap_smp_pairing_response *pdu = frame->data;23052306print_smp_io_capa(pdu->io_capa);2307print_smp_oob_data(pdu->oob_data);2308print_smp_auth_req(pdu->auth_req);23092310print_field("Max encryption key size: %d", pdu->max_key_size);2311print_field("Initiator key distribution: 0x%2.2x", pdu->init_key_dist);2312print_field("Responder key distribution: 0x%2.2x", pdu->resp_key_dist);2313}23142315static void smp_pairing_confirm(const struct l2cap_frame *frame)2316{2317const struct bt_l2cap_smp_pairing_confirm *pdu = frame->data;23182319print_hex_field("Confim value", pdu->value, 16);2320}23212322static void smp_pairing_random(const struct l2cap_frame *frame)2323{2324const struct bt_l2cap_smp_pairing_random *pdu = frame->data;23252326print_hex_field("Random value", pdu->value, 16);2327}23282329static void smp_pairing_failed(const struct l2cap_frame *frame)2330{2331const struct bt_l2cap_smp_pairing_failed *pdu = frame->data;2332const char *str;23332334switch (pdu->reason) {2335case 0x01:2336str = "Passkey entry failed";2337break;2338case 0x02:2339str = "OOB not available";2340break;2341case 0x03:2342str = "Authentication requirements";2343break;2344case 0x04:2345str = "Confirm value failed";2346break;2347case 0x05:2348str = "Pairing not supported";2349break;2350case 0x06:2351str = "Encryption key size";2352break;2353case 0x07:2354str = "Command not supported";2355break;2356case 0x08:2357str = "Unspecified reason";2358break;2359case 0x09:2360str = "Repeated attempts";2361break;2362case 0x0a:2363str = "Invalid parameters";2364break;2365default:2366str = "Reserved";2367break;2368}23692370print_field("Reason: %s (0x%2.2x)", str, pdu->reason);2371}23722373static void smp_encrypt_info(const struct l2cap_frame *frame)2374{2375const struct bt_l2cap_smp_encrypt_info *pdu = frame->data;23762377print_hex_field("Long term key", pdu->ltk, 16);2378}23792380static void smp_master_ident(const struct l2cap_frame *frame)2381{2382const struct bt_l2cap_smp_master_ident *pdu = frame->data;23832384print_field("EDIV: 0x%4.4x", btohs(pdu->ediv));2385print_field("Rand: 0x%16.16" PRIx64, btohll(pdu->rand));2386}23872388static void smp_ident_info(const struct l2cap_frame *frame)2389{2390const struct bt_l2cap_smp_ident_info *pdu = frame->data;23912392print_hex_field("Identity resolving key", pdu->irk, 16);2393}23942395static void smp_ident_addr_info(const struct l2cap_frame *frame)2396{2397const struct bt_l2cap_smp_ident_addr_info *pdu = frame->data;23982399print_addr_type(pdu->addr_type);2400print_addr(pdu->addr, pdu->addr_type);2401}24022403static void smp_signing_info(const struct l2cap_frame *frame)2404{2405const struct bt_l2cap_smp_signing_info *pdu = frame->data;24062407print_hex_field("Signature key", pdu->csrk, 16);2408}24092410static void smp_security_request(const struct l2cap_frame *frame)2411{2412const struct bt_l2cap_smp_security_request *pdu = frame->data;24132414print_smp_auth_req(pdu->auth_req);2415}24162417struct smp_opcode_data {2418uint8_t opcode;2419const char *str;2420void (*func) (const struct l2cap_frame *frame);2421uint8_t size;2422bool fixed;2423};24242425static const struct smp_opcode_data smp_opcode_table[] = {2426{ 0x01, "Pairing Request",2427smp_pairing_request, 6, true },2428{ 0x02, "Pairing Response",2429smp_pairing_response, 6, true },2430{ 0x03, "Pairing Confirm",2431smp_pairing_confirm, 16, true },2432{ 0x04, "Pairing Random",2433smp_pairing_random, 16, true },2434{ 0x05, "Pairing Failed",2435smp_pairing_failed, 1, true },2436{ 0x06, "Encryption Information",2437smp_encrypt_info, 16, true },2438{ 0x07, "Master Identification",2439smp_master_ident, 10, true },2440{ 0x08, "Identity Information",2441smp_ident_info, 16, true },2442{ 0x09, "Identity Address Information",2443smp_ident_addr_info, 7, true },2444{ 0x0a, "Signing Information",2445smp_signing_info, 16, true },2446{ 0x0b, "Security Request",2447smp_security_request, 1, true },2448{ }2449};24502451static void smp_packet(uint16_t index, bool in, uint16_t handle,2452uint16_t cid, const void *data, uint16_t size)2453{2454struct l2cap_frame frame;2455uint8_t opcode = *((const uint8_t *) data);2456const struct smp_opcode_data *opcode_data = NULL;2457const char *opcode_color, *opcode_str;2458int i;24592460if (size < 1) {2461print_text(COLOR_ERROR, "malformed attribute packet");2462packet_hexdump(data, size);2463return;2464}24652466for (i = 0; smp_opcode_table[i].str; i++) {2467if (smp_opcode_table[i].opcode == opcode) {2468opcode_data = &smp_opcode_table[i];2469break;2470}2471}24722473if (opcode_data) {2474if (opcode_data->func) {2475if (in)2476opcode_color = COLOR_MAGENTA;2477else2478opcode_color = COLOR_BLUE;2479} else2480opcode_color = COLOR_WHITE_BG;2481opcode_str = opcode_data->str;2482} else {2483opcode_color = COLOR_WHITE_BG;2484opcode_str = "Unknown";2485}24862487print_indent(6, opcode_color, "SMP: ", opcode_str, COLOR_OFF,2488" (0x%2.2x) len %d", opcode, size - 1);24892490if (!opcode_data || !opcode_data->func) {2491packet_hexdump(data + 1, size - 1);2492return;2493}24942495if (opcode_data->fixed) {2496if (size - 1 != opcode_data->size) {2497print_text(COLOR_ERROR, "invalid size");2498packet_hexdump(data + 1, size - 1);2499return;2500}2501} else {2502if (size - 1 < opcode_data->size) {2503print_text(COLOR_ERROR, "too short packet");2504packet_hexdump(data + 1, size - 1);2505return;2506}2507}25082509l2cap_frame_init(&frame, index, in, handle, cid, data + 1, size - 1);2510opcode_data->func(&frame);2511}25122513static void l2cap_frame(uint16_t index, bool in, uint16_t handle,2514uint16_t cid, const void *data, uint16_t size)2515{2516struct l2cap_frame frame;2517uint16_t psm, chan;2518uint8_t mode;25192520switch (cid) {2521case 0x0001:2522bredr_sig_packet(index, in, handle, cid, data, size);2523break;2524case 0x0002:2525connless_packet(index, in, handle, cid, data, size);2526break;2527case 0x0003:2528amp_packet(index, in, handle, cid, data, size);2529break;2530case 0x0004:2531att_packet(index, in, handle, cid, data, size);2532break;2533case 0x0005:2534le_sig_packet(index, in, handle, cid, data, size);2535break;2536case 0x0006:2537smp_packet(index, in, handle, cid, data, size);2538break;2539default:2540l2cap_frame_init(&frame, index, in, handle, cid, data, size);2541psm = get_psm(&frame);2542mode = get_mode(&frame);2543chan = get_chan(&frame);25442545print_indent(6, COLOR_CYAN, "Channel:", "", COLOR_OFF,2546" %d len %d [PSM %d mode %d] {chan %d}",2547cid, size, psm, mode, chan);25482549switch (psm) {2550case 0x0001:2551sdp_packet(&frame, chan);2552break;2553case 0x001f:2554att_packet(index, in, handle, cid, data, size);2555break;2556default:2557packet_hexdump(data, size);2558break;2559}2560break;2561}2562}25632564void l2cap_packet(uint16_t index, bool in, uint16_t handle, uint8_t flags,2565const void *data, uint16_t size)2566{2567const struct bt_l2cap_hdr *hdr = data;2568uint16_t len, cid;25692570if (index > MAX_INDEX - 1) {2571print_text(COLOR_ERROR, "controller index too large");2572packet_hexdump(data, size);2573return;2574}25752576switch (flags) {2577case 0x00: /* start of a non-automatically-flushable PDU */2578case 0x02: /* start of an automatically-flushable PDU */2579if (index_list[index].frag_len) {2580print_text(COLOR_ERROR, "unexpected start frame");2581packet_hexdump(data, size);2582clear_fragment_buffer(index);2583return;2584}25852586if (size < sizeof(*hdr)) {2587print_text(COLOR_ERROR, "frame too short");2588packet_hexdump(data, size);2589return;2590}25912592len = btohs(hdr->len);2593cid = btohs(hdr->cid);25942595data += sizeof(*hdr);2596size -= sizeof(*hdr);25972598if (len == size) {2599/* complete frame */2600l2cap_frame(index, in, handle, cid, data, len);2601return;2602}26032604if (size > len) {2605print_text(COLOR_ERROR, "frame too long");2606packet_hexdump(data, size);2607return;2608}26092610index_list[index].frag_buf = malloc(len);2611if (!index_list[index].frag_buf) {2612print_text(COLOR_ERROR, "failed buffer allocation");2613packet_hexdump(data, size);2614return;2615}26162617memcpy(index_list[index].frag_buf, data, size);2618index_list[index].frag_pos = size;2619index_list[index].frag_len = len - size;2620index_list[index].frag_cid = cid;2621break;26222623case 0x01: /* continuing fragment */2624if (!index_list[index].frag_len) {2625print_text(COLOR_ERROR, "unexpected continuation");2626packet_hexdump(data, size);2627return;2628}26292630if (size > index_list[index].frag_len) {2631print_text(COLOR_ERROR, "fragment too long");2632packet_hexdump(data, size);2633clear_fragment_buffer(index);2634return;2635}26362637memcpy(index_list[index].frag_buf +2638index_list[index].frag_pos, data, size);2639index_list[index].frag_pos += size;2640index_list[index].frag_len -= size;26412642if (!index_list[index].frag_len) {2643/* complete frame */2644l2cap_frame(index, in, handle,2645index_list[index].frag_cid,2646index_list[index].frag_buf,2647index_list[index].frag_pos);2648clear_fragment_buffer(index);2649return;2650}2651break;26522653case 0x03: /* complete automatically-flushable PDU */2654if (index_list[index].frag_len) {2655print_text(COLOR_ERROR, "unexpected complete frame");2656packet_hexdump(data, size);2657clear_fragment_buffer(index);2658return;2659}26602661if (size < sizeof(*hdr)) {2662print_text(COLOR_ERROR, "frame too short");2663packet_hexdump(data, size);2664return;2665}26662667len = btohs(hdr->len);2668cid = btohs(hdr->cid);26692670data += sizeof(*hdr);2671size -= sizeof(*hdr);26722673if (len != size) {2674print_text(COLOR_ERROR, "wrong frame size");2675packet_hexdump(data, size);2676return;2677}26782679/* complete frame */2680l2cap_frame(index, in, handle, cid, data, len);2681break;26822683default:2684print_text(COLOR_ERROR, "invalid packet flags (0x%2.2x)",2685flags);2686packet_hexdump(data, size);2687return;2688}2689}269026912692