| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798 |
- // SPDX-License-Identifier: LGPL-2.1-or-later
- /*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2011-2014 Intel Corporation
- * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #define _GNU_SOURCE
- #include <stdio.h>
- #include <inttypes.h>
- #include "src/shared/util.h"
- #include "display.h"
- #include "packet.h"
- #include "crc.h"
- #include "bt.h"
- #include "ll.h"
- #define COLOR_OPCODE COLOR_MAGENTA
- #define COLOR_OPCODE_UNKNOWN COLOR_WHITE_BG
- #define COLOR_UNKNOWN_OPTIONS_BIT COLOR_WHITE_BG
- #define MAX_CHANNEL 16
- struct channel_data {
- uint32_t access_addr;
- uint32_t crc_init;
- };
- static struct channel_data channel_list[MAX_CHANNEL];
- static void set_crc_init(uint32_t access_addr, uint32_t crc_init)
- {
- int i;
- for (i = 0; i < MAX_CHANNEL; i++) {
- if (channel_list[i].access_addr == 0x00000000 ||
- channel_list[i].access_addr == access_addr) {
- channel_list[i].access_addr = access_addr;
- channel_list[i].crc_init = crc_init;
- break;
- }
- }
- }
- static uint32_t get_crc_init(uint32_t access_addr)
- {
- int i;
- for (i = 0; i < MAX_CHANNEL; i++) {
- if (channel_list[i].access_addr == access_addr)
- return channel_list[i].crc_init;
- }
- return 0x00000000;
- }
- static void advertising_packet(const void *data, uint8_t size)
- {
- const uint8_t *ptr = data;
- uint8_t pdu_type, length, win_size, hop, sca;
- bool tx_add, rx_add;
- uint32_t access_addr, crc_init;
- uint16_t win_offset, interval, latency, timeout;
- const char *str;
- if (size < 2) {
- print_text(COLOR_ERROR, "packet too short");
- packet_hexdump(data, size);
- return;
- }
- pdu_type = ptr[0] & 0x0f;
- tx_add = !!(ptr[0] & 0x40);
- rx_add = !!(ptr[0] & 0x80);
- length = ptr[1] & 0x3f;
- switch (pdu_type) {
- case 0x00:
- str = "ADV_IND";
- break;
- case 0x01:
- str = "ADV_DIRECT_IND";
- break;
- case 0x02:
- str = "ADV_NONCONN_IND";
- break;
- case 0x03:
- str = "SCAN_REQ";
- break;
- case 0x04:
- str = "SCAN_RSP";
- break;
- case 0x05:
- str = "CONNECT_REQ";
- break;
- case 0x06:
- str = "ADV_SCAN_IND";
- break;
- default:
- str = "Reserved";
- break;
- }
- print_field("Type: %s (0x%2.2x)", str, pdu_type);
- print_field("TxAdd: %u", tx_add);
- print_field("RxAdd: %u", rx_add);
- print_field("Length: %u", length);
- if (length != size - 2) {
- print_text(COLOR_ERROR, "packet size mismatch");
- packet_hexdump(data + 2, size - 2);
- return;
- }
- switch (pdu_type) {
- case 0x00: /* ADV_IND */
- case 0x02: /* AVD_NONCONN_IND */
- case 0x06: /* ADV_SCAN_IND */
- case 0x04: /* SCAN_RSP */
- if (length < 6) {
- print_text(COLOR_ERROR, "payload too short");
- packet_hexdump(data + 2, length);
- return;
- }
- packet_print_addr("Advertiser address", data + 2, tx_add);
- packet_print_ad(data + 8, length - 6);
- break;
- case 0x01: /* ADV_DIRECT_IND */
- if (length < 12) {
- print_text(COLOR_ERROR, "payload too short");
- packet_hexdump(data + 2, length);
- return;
- }
- packet_print_addr("Advertiser address", data + 2, tx_add);
- packet_print_addr("Inititator address", data + 8, rx_add);
- break;
- case 0x03: /* SCAN_REQ */
- if (length < 12) {
- print_text(COLOR_ERROR, "payload too short");
- packet_hexdump(data + 2, length);
- return;
- }
- packet_print_addr("Scanner address", data + 2, tx_add);
- packet_print_addr("Advertiser address", data + 8, rx_add);
- break;
- case 0x05: /* CONNECT_REQ */
- if (length < 34) {
- print_text(COLOR_ERROR, "payload too short");
- packet_hexdump(data + 2, length);
- return;
- }
- packet_print_addr("Inititator address", data + 2, tx_add);
- packet_print_addr("Advertiser address", data + 8, rx_add);
- access_addr = ptr[14] | ptr[15] << 8 |
- ptr[16] << 16 | ptr[17] << 24;
- crc_init = ptr[18] | ptr[19] << 8 | ptr[20] << 16;
- print_field("Access address: 0x%8.8x", access_addr);
- print_field("CRC init: 0x%6.6x", crc_init);
- set_crc_init(access_addr, crc24_bit_reverse(crc_init));
- win_size = ptr[21];
- win_offset = ptr[22] | ptr[23] << 8;
- interval = ptr[24] | ptr[25] << 8;
- latency = ptr[26] | ptr[27] << 8;
- timeout = ptr[28] | ptr[29] << 8;
- print_field("Transmit window size: %u", win_size);
- print_field("Transmit window offset: %u", win_offset);
- print_field("Connection interval: %u", interval);
- print_field("Connection peripheral latency: %u", latency);
- print_field("Connection supervision timeout: %u", timeout);
- packet_print_channel_map_ll(ptr + 30);
- hop = ptr[35] & 0x1f;
- sca = (ptr[35] & 0xe0) >> 5;
- switch (sca) {
- case 0:
- str = "251 ppm to 500 ppm";
- break;
- case 1:
- str = "151 ppm to 250 ppm";
- break;
- case 2:
- str = "101 ppm to 150ppm";
- break;
- case 3:
- str = "76 ppm to 100 ppm";
- break;
- case 4:
- str = "51 ppm to 75 ppm";
- break;
- case 5:
- str = "31 ppm to 50 ppm";
- break;
- case 6:
- str = "21 ppm to 30 ppm";
- break;
- case 7:
- str = "0 ppm to 20 ppm";
- break;
- default:
- str = "Invalid";
- break;
- }
- print_field("Hop increment: %u", hop);
- print_field("Sleep clock accuracy: %s (%u)", str, sca);
- break;
- default:
- packet_hexdump(data + 2, length);
- break;
- }
- }
- static void data_packet(const void *data, uint8_t size, bool padded)
- {
- const uint8_t *ptr = data;
- uint8_t llid, length;
- bool nesn, sn, md;
- const char *str;
- if (size < 2) {
- print_text(COLOR_ERROR, "packet too short");
- packet_hexdump(data, size);
- return;
- }
- llid = ptr[0] & 0x03;
- nesn = !!(ptr[0] & 0x04);
- sn = !!(ptr[0] & 0x08);
- md = !!(ptr[0] & 0x10);
- length = ptr[1] & 0x1f;
- switch (llid) {
- case 0x01:
- if (length > 0)
- str = "Continuation fragement of L2CAP message";
- else
- str = "Empty message";
- break;
- case 0x02:
- str = "Start of L2CAP message";
- break;
- case 0x03:
- str = "Control";
- break;
- default:
- str = "Reserved";
- break;
- }
- print_field("LLID: %s (0x%2.2x)", str, llid);
- print_field("Next expected sequence number: %u", nesn);
- print_field("Sequence number: %u", sn);
- print_field("More data: %u", md);
- print_field("Length: %u", length);
- switch (llid) {
- case 0x03:
- llcp_packet(data + 2, size - 2, padded);
- break;
- default:
- packet_hexdump(data + 2, size - 2);
- break;
- }
- }
- void ll_packet(uint16_t frequency, const void *data, uint8_t size, bool padded)
- {
- const struct bt_ll_hdr *hdr = data;
- uint8_t channel = (frequency - 2402) / 2;
- uint32_t access_addr;
- char access_str[12];
- const char *channel_label, *channel_color;
- const uint8_t *pdu_data;
- uint8_t pdu_len;
- uint32_t pdu_crc, crc, crc_init;
- if (size < sizeof(*hdr)) {
- print_text(COLOR_ERROR, "packet missing header");
- packet_hexdump(data, size);
- return;
- }
- if (size < sizeof(*hdr) + 3) {
- print_text(COLOR_ERROR, "packet missing checksum");
- packet_hexdump(data, size);
- return;
- }
- if (hdr->preamble != 0xaa && hdr->preamble != 0x55) {
- print_text(COLOR_ERROR, "invalid preamble");
- packet_hexdump(data, size);
- return;
- }
- access_addr = le32_to_cpu(hdr->access_addr);
- pdu_data = data + sizeof(*hdr);
- pdu_len = size - sizeof(*hdr) - 3;
- pdu_crc = pdu_data[pdu_len + 0] | (pdu_data[pdu_len + 1] << 8) |
- (pdu_data[pdu_len + 2] << 16);
- if (access_addr == 0x8e89bed6) {
- channel_label = "Advertising channel: ";
- channel_color = COLOR_MAGENTA;
- } else {
- channel_label = "Data channel: ";
- channel_color = COLOR_CYAN;
- }
- sprintf(access_str, "0x%8.8x", access_addr);
- print_indent(6, channel_color, channel_label, access_str, COLOR_OFF,
- " (channel %d) len %d crc 0x%6.6x", channel, pdu_len, pdu_crc);
- if (access_addr == 0x8e89bed6)
- crc_init = 0xaaaaaa;
- else
- crc_init = get_crc_init(access_addr);
- if (crc_init) {
- crc = crc24_calculate(crc_init, pdu_data, pdu_len);
- if (crc != pdu_crc) {
- print_text(COLOR_ERROR, "invalid checksum");
- packet_hexdump(pdu_data, pdu_len);
- return;
- }
- } else
- print_text(COLOR_ERROR, "unknown access address");
- if (access_addr == 0x8e89bed6)
- advertising_packet(pdu_data, pdu_len);
- else
- data_packet(pdu_data, pdu_len, padded);
- }
- static void null_pdu(const void *data, uint8_t size)
- {
- }
- static void conn_update_req(const void *data, uint8_t size)
- {
- const struct bt_ll_conn_update_req *pdu = data;
- print_field("Transmit window size: %u", pdu->win_size);
- print_field("Transmit window offset: %u", le16_to_cpu(pdu->win_offset));
- print_field("Connection interval: %u", le16_to_cpu(pdu->interval));
- print_field("Connection peripheral latency: %u",
- le16_to_cpu(pdu->latency));
- print_field("Connection supervision timeout: %u",
- le16_to_cpu(pdu->timeout));
- print_field("Connection instant: %u", le16_to_cpu(pdu->instant));
- }
- static void channel_map_req(const void *data, uint8_t size)
- {
- const struct bt_ll_channel_map_req *pdu = data;
- packet_print_channel_map_ll(pdu->map);
- print_field("Connection instant: %u", le16_to_cpu(pdu->instant));
- }
- static void terminate_ind(const void *data, uint8_t size)
- {
- const struct bt_ll_terminate_ind *pdu = data;
- packet_print_error("Error code", pdu->error);
- }
- static void enc_req(const void *data, uint8_t size)
- {
- const struct bt_ll_enc_req *pdu = data;
- print_field("Rand: 0x%16.16" PRIx64, le64_to_cpu(pdu->rand));
- print_field("EDIV: 0x%4.4x", le16_to_cpu(pdu->ediv));
- print_field("SKD (central): 0x%16.16" PRIx64, le64_to_cpu(pdu->skd));
- print_field("IV (central): 0x%8.8x", le32_to_cpu(pdu->iv));
- }
- static void enc_rsp(const void *data, uint8_t size)
- {
- const struct bt_ll_enc_rsp *pdu = data;
- print_field("SKD (peripheral): 0x%16.16" PRIx64, le64_to_cpu(pdu->skd));
- print_field("IV (peripheral): 0x%8.8x", le32_to_cpu(pdu->iv));
- }
- static const char *opcode_to_string(uint8_t opcode);
- static void unknown_rsp(const void *data, uint8_t size)
- {
- const struct bt_ll_unknown_rsp *pdu = data;
- print_field("Unknown type: %s (0x%2.2x)",
- opcode_to_string(pdu->type), pdu->type);
- }
- static void feature_req(const void *data, uint8_t size)
- {
- const struct bt_ll_feature_req *pdu = data;
- packet_print_features_ll(pdu->features);
- }
- static void feature_rsp(const void *data, uint8_t size)
- {
- const struct bt_ll_feature_rsp *pdu = data;
- packet_print_features_ll(pdu->features);
- }
- static void version_ind(const void *data, uint8_t size)
- {
- const struct bt_ll_version_ind *pdu = data;
- packet_print_version("Version", pdu->version,
- "Subversion", le16_to_cpu(pdu->subversion));
- packet_print_company("Company", le16_to_cpu(pdu->company));
- }
- static void reject_ind(const void *data, uint8_t size)
- {
- const struct bt_ll_reject_ind *pdu = data;
- packet_print_error("Error code", pdu->error);
- }
- static void peripheral_feature_req(const void *data, uint8_t size)
- {
- const struct bt_ll_peripheral_feature_req *pdu = data;
- packet_print_features_ll(pdu->features);
- }
- static void reject_ind_ext(const void *data, uint8_t size)
- {
- const struct bt_ll_reject_ind_ext *pdu = data;
- print_field("Reject opcode: %u (0x%2.2x)", pdu->opcode, pdu->opcode);
- packet_print_error("Error code", pdu->error);
- }
- static void length_req_rsp(const void *data, uint8_t size)
- {
- const struct bt_ll_length *pdu = data;
- print_field("MaxRxOctets: %u", pdu->rx_len);
- print_field("MaxRxTime: %u", pdu->rx_time);
- print_field("MaxTxOctets: %u", pdu->tx_len);
- print_field("MaxtxTime: %u", pdu->tx_time);
- }
- static const struct bitfield_data le_phys[] = {
- { 0, "LE 1M" },
- { 1, "LE 2M" },
- { 2, "LE Coded"},
- { }
- };
- static void phy_req_rsp(const void *data, uint8_t size)
- {
- const struct bt_ll_phy *pdu = data;
- uint8_t mask;
- print_field("RX PHYs: 0x%2.2x", pdu->rx_phys);
- mask = print_bitfield(2, pdu->rx_phys, le_phys);
- if (mask)
- print_text(COLOR_UNKNOWN_OPTIONS_BIT, " Reserved"
- " (0x%2.2x)", mask);
- print_field("TX PHYs: 0x%2.2x", pdu->tx_phys);
- mask = print_bitfield(2, pdu->tx_phys, le_phys);
- if (mask)
- print_text(COLOR_UNKNOWN_OPTIONS_BIT, " Reserved"
- " (0x%2.2x)", mask);
- }
- static void phy_update_ind(const void *data, uint8_t size)
- {
- const struct bt_ll_phy_update_ind *pdu = data;
- uint8_t mask;
- print_field("C_TO_P_PHY: 0x%2.2x", pdu->c_phy);
- mask = print_bitfield(2, pdu->c_phy, le_phys);
- if (mask)
- print_text(COLOR_UNKNOWN_OPTIONS_BIT, " Reserved"
- " (0x%2.2x)", mask);
- print_field("P_TO_C_PHY: 0x%2.2x", pdu->p_phy);
- mask = print_bitfield(2, pdu->p_phy, le_phys);
- if (mask)
- print_text(COLOR_UNKNOWN_OPTIONS_BIT, " Reserved"
- " (0x%2.2x)", mask);
- print_field("Instant: 0x%4.4x", pdu->instant);
- }
- static void min_used_channels(const void *data, uint8_t size)
- {
- const struct bt_ll_min_used_channels *pdu = data;
- uint8_t mask;
- print_field("PHYS: 0x%2.2x", pdu->phys);
- mask = print_bitfield(2, pdu->phys, le_phys);
- if (mask)
- print_text(COLOR_UNKNOWN_OPTIONS_BIT, " Reserved"
- " (0x%2.2x)", mask);
- print_field("MinUsedChannels: 0x%2.2x", pdu->min_channels);
- }
- static void cte_req(const void *data, uint8_t size)
- {
- const struct bt_ll_cte_req *pdu = data;
- print_field("MinCTELenReq: 0x%2.2x", pdu->cte & 0xf8);
- print_field("CTETypeReq: 0x%2.2x", pdu->cte & 0x03);
- switch (pdu->cte & 0x03) {
- case 0x00:
- print_field(" AoA Constant Tone Extension");
- break;
- case 0x01:
- print_field(" AoD Constant Tone Extension with 1 μs slots");
- break;
- case 0x02:
- print_field(" AoD Constant Tone Extension with 2 μs slots");
- break;
- }
- }
- static void periodic_sync_ind(const void *data, uint8_t size)
- {
- const struct bt_ll_periodic_sync_ind *pdu = data;
- uint8_t mask;
- print_field("ID: 0x%4.4x", pdu->id);
- print_field("SyncInfo:");
- packet_hexdump(pdu->info, sizeof(pdu->info));
- print_field("connEventCount: 0x%4.4x", pdu->event_count);
- print_field("lastPaEventCounter: 0x%4.4x", pdu->last_counter);
- print_field("SID: 0x%2.2x", pdu->adv_info & 0xf0);
- print_field("AType: %s", pdu->adv_info & 0x08 ? "random" : "public");
- print_field("SCA: 0x%2.2x", pdu->adv_info & 0x07);
- print_field("PHY: 0x%2.2x", pdu->phy);
- mask = print_bitfield(2, pdu->phy, le_phys);
- if (mask)
- print_text(COLOR_UNKNOWN_OPTIONS_BIT, " Reserved"
- " (0x%2.2x)", mask);
- packet_print_addr("AdvA", pdu->adv_addr, pdu->adv_info & 0x08);
- print_field("syncConnEventCount: 0x%4.4x", pdu->sync_counter);
- }
- static void clock_acc_req_rsp(const void *data, uint8_t size)
- {
- const struct bt_ll_clock_acc *pdu = data;
- print_field("SCA: 0x%2.2x", pdu->sca);
- }
- static void cis_req(const void *data, uint8_t size)
- {
- const struct bt_ll_cis_req *cmd = data;
- uint32_t interval;
- uint8_t mask;
- print_field("CIG ID: 0x%2.2x", cmd->cig);
- print_field("CIS ID: 0x%2.2x", cmd->cis);
- print_field("Central to Peripheral PHY: 0x%2.2x", cmd->c_phy);
- mask = print_bitfield(2, cmd->c_phy, le_phys);
- if (mask)
- print_text(COLOR_UNKNOWN_OPTIONS_BIT, " Reserved"
- " (0x%2.2x)", mask);
- print_field("Peripheral To Central PHY: 0x%2.2x", cmd->p_phy);
- mask = print_bitfield(2, cmd->p_phy, le_phys);
- if (mask)
- print_text(COLOR_UNKNOWN_OPTIONS_BIT, " Reserved"
- " (0x%2.2x)", mask);
- print_field("Central to Peripheral Maximum SDU: %u", cmd->c_sdu);
- print_field("Peripheral to Central Maximum SDU: %u", cmd->p_sdu);
- memcpy(&interval, cmd->c_interval, sizeof(cmd->c_interval));
- print_field("Central to Peripheral Interval: 0x%6.6x",
- le32_to_cpu(interval));
- memcpy(&interval, cmd->p_interval, sizeof(cmd->p_interval));
- print_field("Peripheral to Central Interval: 0x%6.6x",
- le32_to_cpu(interval));
- print_field("Central to Peripheral Maximum PDU: %u", cmd->c_pdu);
- print_field("Peripheral to Central Maximum PDU: %u", cmd->p_pdu);
- print_field("Burst Number: %u us", cmd->bn);
- memcpy(&interval, cmd->sub_interval, sizeof(cmd->sub_interval));
- print_field("Sub-Interval: 0x%6.6x", le32_to_cpu(interval));
- print_field("Central to Peripheral Flush Timeout: %u", cmd->c_ft);
- print_field("Peripheral to Central Flush Timeout: %u", cmd->p_ft);
- print_field("ISO Interval: 0x%4.4x", le16_to_cpu(cmd->iso_interval));
- memcpy(&interval, cmd->offset_min, sizeof(cmd->offset_min));
- print_field("CIS Offset Minimum: 0x%6.6x", le32_to_cpu(interval));
- memcpy(&interval, cmd->offset_max, sizeof(cmd->offset_max));
- print_field("CIS Offset Maximum: 0x%6.6x", le32_to_cpu(interval));
- print_field("Connection Event Count: %u", cmd->conn_event_count);
- }
- static void cis_rsp(const void *data, uint8_t size)
- {
- const struct bt_ll_cis_rsp *rsp = data;
- uint32_t interval;
- memcpy(&interval, rsp->offset_min, sizeof(rsp->offset_min));
- print_field("CIS Offset Minimum: 0x%6.6x", le32_to_cpu(interval));
- memcpy(&interval, rsp->offset_max, sizeof(rsp->offset_max));
- print_field("CIS Offset Maximum: 0x%6.6x", le32_to_cpu(interval));
- print_field("Connection Event Count: %u", rsp->conn_event_count);
- }
- static void cis_ind(const void *data, uint8_t size)
- {
- const struct bt_ll_cis_ind *ind = data;
- uint32_t interval;
- print_field("CIS Access Address: 0x%4.4x", le32_to_cpu(ind->addr));
- memcpy(&interval, ind->cis_offset, sizeof(ind->cis_offset));
- print_field("CIS Offset: 0x%6.6x", le32_to_cpu(interval));
- memcpy(&interval, ind->cig_sync_delay, sizeof(ind->cig_sync_delay));
- print_field("CIG Synchronization Delay: 0x%6.6x",
- le32_to_cpu(interval));
- memcpy(&interval, ind->cis_sync_delay, sizeof(ind->cis_sync_delay));
- print_field("CIS Synchronization Delay: %u us",
- le32_to_cpu(interval));
- print_field("Connection Event Count: %u", ind->conn_event_count);
- }
- static void cis_term_ind(const void *data, uint8_t size)
- {
- const struct bt_ll_cis_term_ind *ind = data;
- print_field("CIG ID: 0x%2.2x", ind->cig);
- print_field("CIS ID: 0x%2.2x", ind->cis);
- packet_print_error("Reason", ind->reason);
- }
- struct llcp_data {
- uint8_t opcode;
- const char *str;
- void (*func) (const void *data, uint8_t size);
- uint8_t size;
- bool fixed;
- };
- static const struct llcp_data llcp_table[] = {
- { 0x00, "LL_CONNECTION_UPDATE_REQ", conn_update_req, 11, true },
- { 0x01, "LL_CHANNEL_MAP_REQ", channel_map_req, 7, true },
- { 0x02, "LL_TERMINATE_IND", terminate_ind, 1, true },
- { 0x03, "LL_ENC_REQ", enc_req, 22, true },
- { 0x04, "LL_ENC_RSP", enc_rsp, 12, true },
- { 0x05, "LL_START_ENC_REQ", null_pdu, 0, true },
- { 0x06, "LL_START_ENC_RSP", null_pdu, 0, true },
- { 0x07, "LL_UNKNOWN_RSP", unknown_rsp, 1, true },
- { 0x08, "LL_FEATURE_REQ", feature_req, 8, true },
- { 0x09, "LL_FEATURE_RSP", feature_rsp, 8, true },
- { 0x0a, "LL_PAUSE_ENC_REQ", null_pdu, 0, true },
- { 0x0b, "LL_PAUSE_ENC_RSP", null_pdu, 0, true },
- { 0x0c, "LL_VERSION_IND", version_ind, 5, true },
- { 0x0d, "LL_REJECT_IND", reject_ind, 1, true },
- { 0x0e, "LL_PERIPHERAL_FEATURE_REQ", peripheral_feature_req, 8, true },
- { 0x0f, "LL_CONNECTION_PARAM_REQ", NULL, 23, true },
- { 0x10, "LL_CONNECTION_PARAM_RSP", NULL, 23, true },
- { 0x11, "LL_REJECT_IND_EXT", reject_ind_ext, 2, true },
- { 0x12, "LL_PING_REQ", null_pdu, 0, true },
- { 0x13, "LL_PING_RSP", null_pdu, 0, true },
- { 0x14, "LL_LENGTH_REQ", length_req_rsp, 8, true },
- { 0x15, "LL_LENGTH_RSP", length_req_rsp, 8, true },
- { 0x16, "LL_PHY_REQ", phy_req_rsp, 2, true },
- { 0x17, "LL_PHY_RSP", phy_req_rsp, 2, true },
- { 0x18, "LL_PHY_UPDATE_IND", phy_update_ind, 4, true },
- { 0x19, "LL_MIN_USED_CHANNELS_IND", min_used_channels, 2, true },
- { 0x1a, "LL_CTE_REQ", cte_req, 1, true },
- { 0x1b, "LL_CTE_RSP", null_pdu, 0, true },
- { 0x1c, "LL_PERIODIC_SYNC_IND", periodic_sync_ind, 34, true },
- { 0x1d, "LL_CLOCK_ACCURACY_REQ", clock_acc_req_rsp, 1, true },
- { 0x1e, "LL_CLOCK_ACCURACY_RSP", clock_acc_req_rsp, 1, true },
- { BT_LL_CIS_REQ, "LL_CIS_REQ", cis_req,
- sizeof(struct bt_ll_cis_req), true },
- { BT_LL_CIS_RSP, "LL_CIS_RSP", cis_rsp,
- sizeof(struct bt_ll_cis_rsp), true },
- { BT_LL_CIS_IND, "LL_CIS_IND", cis_ind,
- sizeof(struct bt_ll_cis_ind), true },
- { BT_LL_CIS_TERMINATE_IND, "LL_CIS_TERMINATE_IND", cis_term_ind,
- sizeof(struct bt_ll_cis_term_ind),
- true },
- { }
- };
- static const char *opcode_to_string(uint8_t opcode)
- {
- int i;
- for (i = 0; llcp_table[i].str; i++) {
- if (llcp_table[i].opcode == opcode)
- return llcp_table[i].str;
- }
- return "Unknown";
- }
- void llcp_packet(const void *data, uint8_t size, bool padded)
- {
- uint8_t opcode = ((const uint8_t *) data)[0];
- const struct llcp_data *llcp_data = NULL;
- const char *opcode_color, *opcode_str;
- int i;
- for (i = 0; llcp_table[i].str; i++) {
- if (llcp_table[i].opcode == opcode) {
- llcp_data = &llcp_table[i];
- break;
- }
- }
- if (llcp_data) {
- if (llcp_data->func)
- opcode_color = COLOR_OPCODE;
- else
- opcode_color = COLOR_OPCODE_UNKNOWN;
- opcode_str = llcp_data->str;
- } else {
- opcode_color = COLOR_OPCODE_UNKNOWN;
- opcode_str = "Unknown";
- }
- print_indent(6, opcode_color, "", opcode_str, COLOR_OFF,
- " (0x%2.2x)", opcode);
- if (!llcp_data || !llcp_data->func) {
- packet_hexdump(data + 1, size - 1);
- return;
- }
- if (llcp_data->fixed && !padded) {
- if (size - 1 != llcp_data->size) {
- print_text(COLOR_ERROR, "invalid packet size");
- packet_hexdump(data + 1, size - 1);
- return;
- }
- } else {
- if (size - 1 < llcp_data->size) {
- print_text(COLOR_ERROR, "too short packet");
- packet_hexdump(data + 1, size - 1);
- return;
- }
- }
- llcp_data->func(data + 1, size - 1);
- }
|