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/sdp.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 <string.h>31#include <inttypes.h>3233#include <bluetooth/bluetooth.h>3435#include "bt.h"36#include "packet.h"37#include "display.h"38#include "l2cap.h"39#include "uuid.h"40#include "sdp.h"4142#define MAX_TID 164344struct tid_data {45bool inuse;46uint16_t tid;47uint16_t channel;48uint8_t cont[17];49};5051static struct tid_data tid_list[MAX_TID];5253static struct tid_data *get_tid(uint16_t tid, uint16_t channel)54{55int i, n = -1;5657for (i = 0; i < MAX_TID; i++) {58if (!tid_list[i].inuse) {59if (n < 0)60n = i;61continue;62}6364if (tid_list[i].tid == tid && tid_list[i].channel == channel)65return &tid_list[i];66}6768if (n < 0)69return NULL;7071tid_list[n].inuse = true;72tid_list[n].tid = tid;73tid_list[n].channel = channel;7475return &tid_list[n];76}7778static void clear_tid(struct tid_data *tid)79{80if (tid)81tid->inuse = false;82}8384static void print_uint(uint8_t indent, const uint8_t *data, uint32_t size)85{86switch (size) {87case 1:88print_field("%*c0x%2.2x", indent, ' ', data[0]);89break;90case 2:91print_field("%*c0x%4.4x", indent, ' ', bt_get_be16(data));92break;93case 4:94print_field("%*c0x%8.8x", indent, ' ', bt_get_be32(data));95break;96case 8:97print_field("%*c0x%16.16" PRIx64, indent, ' ',98bt_get_be64(data));99break;100default:101packet_hexdump(data, size);102break;103}104}105106static void print_sint(uint8_t indent, const uint8_t *data, uint32_t size)107{108packet_hexdump(data, size);109}110111static void print_uuid(uint8_t indent, const uint8_t *data, uint32_t size)112{113switch (size) {114case 2:115print_field("%*c%s (0x%4.4x)", indent, ' ',116uuid16_to_str(bt_get_be16(data)), bt_get_be16(data));117break;118case 4:119print_field("%*c%s (0x%8.8x)", indent, ' ',120uuid32_to_str(bt_get_be32(data)), bt_get_be32(data));121break;122case 16:123/* BASE_UUID = 00000000-0000-1000-8000-00805F9B34FB */124print_field("%*c%8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.4x",125indent, ' ',126bt_get_be32(data), bt_get_be16(data + 4),127bt_get_be16(data + 6), bt_get_be16(data + 8),128bt_get_be16(data + 10), bt_get_be32(data + 12));129if (bt_get_be16(data + 4) == 0x0000 &&130bt_get_be16(data + 6) == 0x1000 &&131bt_get_be16(data + 8) == 0x8000 &&132bt_get_be16(data + 10) == 0x0080 &&133bt_get_be32(data + 12) == 0x5F9B34FB)134print_field("%*c%s", indent, ' ',135uuid32_to_str(bt_get_be32(data)));136break;137default:138packet_hexdump(data, size);139break;140}141}142143static void print_string(uint8_t indent, const uint8_t *data, uint32_t size)144{145char *str = alloca(size + 1);146147str[size] = '\0';148strncpy(str, (const char *) data, size);149150print_field("%*c%s [len %d]", indent, ' ', str, size);151}152153static void print_boolean(uint8_t indent, const uint8_t *data, uint32_t size)154{155print_field("%*c%s", indent, ' ', data[0] ? "true" : "false");156}157158#define SIZES(args...) ((uint8_t[]) { args, 0xff } )159160static struct {161uint8_t value;162uint8_t *sizes;163bool recurse;164const char *str;165void (*print) (uint8_t indent, const uint8_t *data, uint32_t size);166} type_table[] = {167{ 0, SIZES(0), false, "Nil" },168{ 1, SIZES(0, 1, 2, 3, 4), false, "Unsigned Integer", print_uint },169{ 2, SIZES(0, 1, 2, 3, 4), false, "Signed Integer", print_sint },170{ 3, SIZES(1, 2, 4), false, "UUID", print_uuid },171{ 4, SIZES(5, 6, 7), false, "String", print_string },172{ 5, SIZES(0), false, "Boolean", print_boolean },173{ 6, SIZES(5, 6, 7), true, "Sequence" },174{ 7, SIZES(5, 6, 7), true, "Alternative" },175{ 8, SIZES(5, 6, 7), false, "URL", print_string },176{ }177};178179static struct {180uint8_t index;181uint8_t bits;182uint8_t size;183const char *str;184} size_table[] = {185{ 0, 0, 1, "1 byte" },186{ 1, 0, 2, "2 bytes" },187{ 2, 0, 4, "4 bytes" },188{ 3, 0, 8, "8 bytes" },189{ 4, 0, 16, "16 bytes" },190{ 5, 8, 0, "8 bits" },191{ 6, 16, 0, "16 bits" },192{ 7, 32, 0, "32 bits" },193{ }194};195196static bool valid_size(uint8_t size, uint8_t *sizes)197{198int i;199200for (i = 0; sizes[i] != 0xff; i++) {201if (sizes[i] == size)202return true;203}204205return false;206}207208static uint8_t get_bits(const uint8_t *data, uint32_t size)209{210int i;211212for (i = 0; size_table[i].str; i++) {213if (size_table[i].index == (data[0] & 0x07))214return size_table[i].bits;215}216217return 0;218}219220static uint32_t get_size(const uint8_t *data, uint32_t size)221{222int i;223224for (i = 0; size_table[i].str; i++) {225if (size_table[i].index == (data[0] & 0x07)) {226switch (size_table[i].bits) {227case 0:228if ((data[0] & 0xf8) == 0)229return 0;230else231return size_table[i].size;232case 8:233return data[1];234case 16:235return bt_get_be16(data + 1);236case 32:237return bt_get_be32(data + 1);238default:239return 0;240}241}242}243244return 0;245}246247static void decode_data_elements(uint32_t position, uint8_t indent,248const uint8_t *data, uint32_t size,249void (*print_func) (uint32_t, uint8_t, uint8_t,250const uint8_t *, uint32_t))251252{253uint32_t datalen, elemlen, extrabits;254int i;255256if (!size)257return;258259extrabits = get_bits(data, size);260261if (size < 1 + (extrabits / 8)) {262print_text(COLOR_ERROR, "data element descriptor too short");263packet_hexdump(data, size);264return;265}266267datalen = get_size(data, size);268269if (size < 1 + (extrabits / 8) + datalen) {270print_text(COLOR_ERROR, "data element size too short");271packet_hexdump(data, size);272return;273}274275elemlen = 1 + (extrabits / 8) + datalen;276277for (i = 0; type_table[i].str; i++) {278uint8_t type = (data[0] & 0xf8) >> 3;279280if (type_table[i].value != type)281continue;282283if (print_func) {284print_func(position, indent, type,285data + 1 + (extrabits / 8), datalen);286break;287}288289print_field("%*c%s (%d) with %u byte%s [%u extra bits] len %u",290indent, ' ', type_table[i].str, type,291datalen, datalen == 1 ? "" : "s",292extrabits, elemlen);293if (!valid_size(data[0] & 0x07, type_table[i].sizes)) {294print_text(COLOR_ERROR, "invalid data element size");295packet_hexdump(data + 1 + (extrabits / 8), datalen);296break;297}298299if (type_table[i].recurse)300decode_data_elements(0, indent + 2,301data + 1 + (extrabits / 8), datalen,302print_func);303else if (type_table[i].print)304type_table[i].print(indent + 2,305data + 1 + (extrabits / 8), datalen);306break;307}308309data += elemlen;310size -= elemlen;311312decode_data_elements(position + 1, indent, data, size, print_func);313}314315static uint32_t get_bytes(const uint8_t *data, uint32_t size)316{317switch (data[0] & 0x07) {318case 5:319return 2 + data[1];320case 6:321return 3 + bt_get_be16(data + 1);322case 7:323return 5 + bt_get_be32(data + 1);324}325326return 0;327}328329static struct {330uint16_t id;331const char *str;332} attribute_table[] = {333{ 0x0000, "Service Record Handle" },334{ 0x0001, "Service Class ID List" },335{ 0x0002, "Service Record State" },336{ 0x0003, "Service ID" },337{ 0x0004, "Protocol Descriptor List" },338{ 0x0005, "Browse Group List" },339{ 0x0006, "Language Base Attribute ID List" },340{ 0x0007, "Service Info Time To Live" },341{ 0x0008, "Service Availability" },342{ 0x0009, "Bluetooth Profile Descriptor List" },343{ 0x000a, "Documentation URL" },344{ 0x000b, "Client Executable URL" },345{ 0x000c, "Icon URL" },346{ 0x000d, "Additional Protocol Descriptor List" },347{ }348};349350static void print_attr(uint32_t position, uint8_t indent, uint8_t type,351const uint8_t *data, uint32_t size)352{353int i;354355if ((position % 2) == 0) {356uint16_t id = bt_get_be16(data);357const char *str = "Unknown";358359for (i = 0; attribute_table[i].str; i++) {360if (attribute_table[i].id == id)361str = attribute_table[i].str;362}363364print_field("%*cAttribute: %s (0x%4.4x) [len %d]",365indent, ' ', str, id, size);366return;367}368369for (i = 0; type_table[i].str; i++) {370if (type_table[i].value != type)371continue;372373if (type_table[i].recurse)374decode_data_elements(0, indent + 2, data, size, NULL);375else if (type_table[i].print)376type_table[i].print(indent + 2, data, size);377break;378}379}380381static void print_attr_list(uint32_t position, uint8_t indent, uint8_t type,382const uint8_t *data, uint32_t size)383{384print_field("%*cAttribute list: [len %d] {position %d}",385indent, ' ', size, position);386387decode_data_elements(0, indent + 2, data, size, print_attr);388}389390static void print_attr_lists(uint32_t position, uint8_t indent, uint8_t type,391const uint8_t *data, uint32_t size)392{393decode_data_elements(0, indent, data, size, print_attr_list);394}395396static void print_continuation(const uint8_t *data, uint16_t size)397{398if (data[0] != size - 1) {399print_text(COLOR_ERROR, "invalid continuation state");400packet_hexdump(data, size);401return;402}403404print_field("Continuation state: %d", data[0]);405packet_hexdump(data + 1, size - 1);406}407408static void store_continuation(struct tid_data *tid,409const uint8_t *data, uint16_t size)410{411memcpy(tid->cont, data, size);412print_continuation(data, size);413}414415#define MAX_CONT 8416417struct cont_data {418uint16_t channel;419uint8_t cont[17];420void *data;421uint32_t size;422};423424static struct cont_data cont_list[MAX_CONT];425426static void handle_continuation(struct tid_data *tid, bool nested,427uint16_t bytes, const uint8_t *data, uint16_t size)428{429uint8_t *newdata;430int i, n = -1;431432if (bytes + 1 > size) {433print_text(COLOR_ERROR, "missing continuation state");434return;435}436437if (tid->cont[0] == 0x00 && data[bytes] == 0x00) {438decode_data_elements(0, 2, data, bytes,439nested ? print_attr_lists : print_attr_list);440441print_continuation(data + bytes, size - bytes);442return;443}444445for (i = 0; i < MAX_CONT; i++) {446if (cont_list[i].cont[0] == 0x00) {447if (n < 0)448n = i;449continue;450}451452if (cont_list[i].channel != tid->channel)453continue;454455if (cont_list[i].cont[0] != tid->cont[0])456continue;457458if (!memcmp(cont_list[i].cont + 1,459tid->cont + 1, tid->cont[0])) {460n = i;461break;462}463}464465print_continuation(data + bytes, size - bytes);466467if (n < 0)468return;469470newdata = realloc(cont_list[n].data, cont_list[n].size + bytes);471if (!newdata) {472print_text(COLOR_ERROR, "failed buffer allocation");473free(cont_list[n].data);474cont_list[n].data = NULL;475cont_list[n].size = 0;476return;477}478479cont_list[n].channel = tid->channel;480cont_list[n].data = newdata;481482if (bytes > 0) {483memcpy(cont_list[n].data + cont_list[n].size, data, bytes);484cont_list[n].size += bytes;485}486487if (data[bytes] == 0x00) {488print_field("Combined attribute bytes: %d", cont_list[n].size);489490decode_data_elements(0, 2, cont_list[n].data, cont_list[n].size,491nested ? print_attr_lists : print_attr_list);492493free(cont_list[n].data);494cont_list[n].data = NULL;495cont_list[n].size = 0;496} else497memcpy(cont_list[i].cont, data + bytes, data[bytes] + 1);498}499500static uint16_t common_rsp(const struct l2cap_frame *frame,501struct tid_data *tid)502{503uint16_t bytes;504505if (frame->size < 2) {506print_text(COLOR_ERROR, "invalid size");507packet_hexdump(frame->data, frame->size);508return 0;509}510511bytes = bt_get_be16(frame->data);512print_field("Attribute bytes: %d", bytes);513514if (bytes > frame->size - 2) {515print_text(COLOR_ERROR, "invalid attribute size");516packet_hexdump(frame->data + 2, frame->size - 2);517return 0;518}519520return bytes;521}522523static void error_rsp(const struct l2cap_frame *frame, struct tid_data *tid)524{525uint16_t error;526527clear_tid(tid);528529if (frame->size < 2) {530print_text(COLOR_ERROR, "invalid size");531packet_hexdump(frame->data, frame->size);532return;533}534535error = bt_get_be16(frame->data);536537print_field("Error code: 0x%2.2x", error);538}539540static void service_req(const struct l2cap_frame *frame, struct tid_data *tid)541{542uint32_t search_bytes;543544search_bytes = get_bytes(frame->data, frame->size);545print_field("Search pattern: [len %d]", search_bytes);546547if (search_bytes + 2 > frame->size) {548print_text(COLOR_ERROR, "invalid search list length");549packet_hexdump(frame->data, frame->size);550return;551}552553decode_data_elements(0, 2, frame->data, search_bytes, NULL);554555print_field("Max record count: %d",556bt_get_be16(frame->data + search_bytes));557558print_continuation(frame->data + search_bytes + 2,559frame->size - search_bytes - 2);560}561562static void service_rsp(const struct l2cap_frame *frame, struct tid_data *tid)563{564uint16_t count;565int i;566567clear_tid(tid);568569if (frame->size < 4) {570print_text(COLOR_ERROR, "invalid size");571packet_hexdump(frame->data, frame->size);572return;573}574575count = bt_get_be16(frame->data + 2);576577print_field("Total record count: %d", bt_get_be16(frame->data));578print_field("Current record count: %d", count);579580for (i = 0; i < count; i++)581print_field("Record handle: 0x%4.4x",582bt_get_be32(frame->data + 4 + (i * 4)));583584print_continuation(frame->data + 4 + (count * 4),585frame->size - 4 - (count * 4));586}587588static void attr_req(const struct l2cap_frame *frame, struct tid_data *tid)589{590uint32_t attr_bytes;591592if (frame->size < 6) {593print_text(COLOR_ERROR, "invalid size");594packet_hexdump(frame->data, frame->size);595return;596}597598print_field("Record handle: 0x%4.4x", bt_get_be32(frame->data));599print_field("Max attribute bytes: %d", bt_get_be16(frame->data + 4));600601attr_bytes = get_bytes(frame->data + 6, frame->size - 6);602print_field("Attribute list: [len %d]", attr_bytes);603604if (attr_bytes + 6 > frame->size) {605print_text(COLOR_ERROR, "invalid attribute list length");606packet_hexdump(frame->data, frame->size);607return;608}609610decode_data_elements(0, 2, frame->data + 6, attr_bytes, NULL);611612store_continuation(tid, frame->data + 6 + attr_bytes,613frame->size - 6 - attr_bytes);614}615616static void attr_rsp(const struct l2cap_frame *frame, struct tid_data *tid)617{618uint16_t bytes;619620bytes = common_rsp(frame, tid);621622handle_continuation(tid, false, bytes,623frame->data + 2, frame->size - 2);624625clear_tid(tid);626}627628static void search_attr_req(const struct l2cap_frame *frame,629struct tid_data *tid)630{631uint32_t search_bytes, attr_bytes;632633search_bytes = get_bytes(frame->data, frame->size);634print_field("Search pattern: [len %d]", search_bytes);635636if (search_bytes + 2 > frame->size) {637print_text(COLOR_ERROR, "invalid search list length");638packet_hexdump(frame->data, frame->size);639return;640}641642decode_data_elements(0, 2, frame->data, search_bytes, NULL);643644print_field("Max record count: %d",645bt_get_be16(frame->data + search_bytes));646647attr_bytes = get_bytes(frame->data + search_bytes + 2,648frame->size - search_bytes - 2);649print_field("Attribute list: [len %d]", attr_bytes);650651decode_data_elements(0, 2, frame->data + search_bytes + 2,652attr_bytes, NULL);653654store_continuation(tid, frame->data + search_bytes + 2 + attr_bytes,655frame->size - search_bytes - 2 - attr_bytes);656}657658static void search_attr_rsp(const struct l2cap_frame *frame,659struct tid_data *tid)660{661uint16_t bytes;662663bytes = common_rsp(frame, tid);664665handle_continuation(tid, true, bytes, frame->data + 2, frame->size - 2);666667clear_tid(tid);668}669670struct sdp_data {671uint8_t pdu;672const char *str;673void (*func) (const struct l2cap_frame *frame, struct tid_data *tid);674};675676static const struct sdp_data sdp_table[] = {677{ 0x01, "Error Response", error_rsp },678{ 0x02, "Service Search Request", service_req },679{ 0x03, "Service Search Response", service_rsp },680{ 0x04, "Service Attribute Request", attr_req },681{ 0x05, "Service Attribute Response", attr_rsp },682{ 0x06, "Service Search Attribute Request", search_attr_req },683{ 0x07, "Service Search Attribute Response", search_attr_rsp },684{ }685};686687void sdp_packet(const struct l2cap_frame *frame, uint16_t channel)688{689uint8_t pdu;690uint16_t tid, plen;691struct l2cap_frame sdp_frame;692struct tid_data *tid_info;693const struct sdp_data *sdp_data = NULL;694const char *pdu_color, *pdu_str;695696int i;697698if (frame->size < 5) {699print_text(COLOR_ERROR, "frame too short");700packet_hexdump(frame->data, frame->size);701return;702}703704pdu = *((uint8_t *) frame->data);705tid = bt_get_be16(frame->data + 1);706plen = bt_get_be16(frame->data + 3);707708if (frame->size != plen + 5) {709print_text(COLOR_ERROR, "invalid frame size");710packet_hexdump(frame->data, frame->size);711return;712}713714for (i = 0; sdp_table[i].str; i++) {715if (sdp_table[i].pdu == pdu) {716sdp_data = &sdp_table[i];717break;718}719}720721if (sdp_data) {722if (sdp_data->func) {723if (frame->in)724pdu_color = COLOR_MAGENTA;725else726pdu_color = COLOR_BLUE;727} else728pdu_color = COLOR_WHITE_BG;729pdu_str = sdp_data->str;730} else {731pdu_color = COLOR_WHITE_BG;732pdu_str = "Unknown";733}734735print_indent(6, pdu_color, "SDP: ", pdu_str, COLOR_OFF,736" (0x%2.2x) tid %d len %d", pdu, tid, plen);737738if (!sdp_data || !sdp_data->func) {739packet_hexdump(frame->data + 5, frame->size - 5);740return;741}742743tid_info = get_tid(tid, channel);744745l2cap_frame_pull(&sdp_frame, frame, 5);746sdp_data->func(&sdp_frame, tid_info);747}748749750