| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772 |
- // SPDX-License-Identifier: LGPL-2.1-or-later
- /*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2015 Andrzej Kaczmarek <andrzej.kaczmarek@codecoup.pl>
- *
- *
- */
- #ifdef HAVE_CONFIG_H
- #include <config.h>
- #endif
- #define _GNU_SOURCE
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "lib/bluetooth.h"
- #include "src/shared/util.h"
- #include "bt.h"
- #include "packet.h"
- #include "display.h"
- #include "l2cap.h"
- #include "avdtp.h"
- #include "a2dp.h"
- /* Message Types */
- #define AVDTP_MSG_TYPE_COMMAND 0x00
- #define AVDTP_MSG_TYPE_GENERAL_REJECT 0x01
- #define AVDTP_MSG_TYPE_RESPONSE_ACCEPT 0x02
- #define AVDTP_MSG_TYPE_RESPONSE_REJECT 0x03
- /* Signal Identifiers */
- #define AVDTP_DISCOVER 0x01
- #define AVDTP_GET_CAPABILITIES 0x02
- #define AVDTP_SET_CONFIGURATION 0x03
- #define AVDTP_GET_CONFIGURATION 0x04
- #define AVDTP_RECONFIGURE 0x05
- #define AVDTP_OPEN 0x06
- #define AVDTP_START 0x07
- #define AVDTP_CLOSE 0x08
- #define AVDTP_SUSPEND 0x09
- #define AVDTP_ABORT 0x0a
- #define AVDTP_SECURITY_CONTROL 0x0b
- #define AVDTP_GET_ALL_CAPABILITIES 0x0c
- #define AVDTP_DELAYREPORT 0x0d
- /* Service Categories */
- #define AVDTP_MEDIA_TRANSPORT 0x01
- #define AVDTP_REPORTING 0x02
- #define AVDTP_RECOVERY 0x03
- #define AVDTP_CONTENT_PROTECTION 0x04
- #define AVDTP_HEADER_COMPRESSION 0x05
- #define AVDTP_MULTIPLEXING 0x06
- #define AVDTP_MEDIA_CODEC 0x07
- #define AVDTP_DELAY_REPORTING 0x08
- struct avdtp_frame {
- uint8_t hdr;
- uint8_t sig_id;
- struct l2cap_frame l2cap_frame;
- };
- static inline bool is_configuration_sig_id(uint8_t sig_id)
- {
- return (sig_id == AVDTP_SET_CONFIGURATION) ||
- (sig_id == AVDTP_GET_CONFIGURATION) ||
- (sig_id == AVDTP_RECONFIGURE);
- }
- static const char *msgtype2str(uint8_t msgtype)
- {
- switch (msgtype) {
- case 0:
- return "Command";
- case 1:
- return "General Reject";
- case 2:
- return "Response Accept";
- case 3:
- return "Response Reject";
- }
- return "";
- }
- static const char *sigid2str(uint8_t sigid)
- {
- switch (sigid) {
- case AVDTP_DISCOVER:
- return "Discover";
- case AVDTP_GET_CAPABILITIES:
- return "Get Capabilities";
- case AVDTP_SET_CONFIGURATION:
- return "Set Configuration";
- case AVDTP_GET_CONFIGURATION:
- return "Get Configuration";
- case AVDTP_RECONFIGURE:
- return "Reconfigure";
- case AVDTP_OPEN:
- return "Open";
- case AVDTP_START:
- return "Start";
- case AVDTP_CLOSE:
- return "Close";
- case AVDTP_SUSPEND:
- return "Suspend";
- case AVDTP_ABORT:
- return "Abort";
- case AVDTP_SECURITY_CONTROL:
- return "Security Control";
- case AVDTP_GET_ALL_CAPABILITIES:
- return "Get All Capabilities";
- case AVDTP_DELAYREPORT:
- return "Delay Report";
- default:
- return "Reserved";
- }
- }
- static const char *error2str(uint8_t error)
- {
- switch (error) {
- case 0x01:
- return "BAD_HEADER_FORMAT";
- case 0x11:
- return "BAD_LENGTH";
- case 0x12:
- return "BAD_ACP_SEID";
- case 0x13:
- return "SEP_IN_USE";
- case 0x14:
- return "SEP_NOT_IN_USER";
- case 0x17:
- return "BAD_SERV_CATEGORY";
- case 0x18:
- return "BAD_PAYLOAD_FORMAT";
- case 0x19:
- return "NOT_SUPPORTED_COMMAND";
- case 0x1a:
- return "INVALID_CAPABILITIES";
- case 0x22:
- return "BAD_RECOVERY_TYPE";
- case 0x23:
- return "BAD_MEDIA_TRANSPORT_FORMAT";
- case 0x25:
- return "BAD_RECOVERY_FORMAT";
- case 0x26:
- return "BAD_ROHC_FORMAT";
- case 0x27:
- return "BAD_CP_FORMAT";
- case 0x28:
- return "BAD_MULTIPLEXING_FORMAT";
- case 0x29:
- return "UNSUPPORTED_CONFIGURATION";
- case 0x31:
- return "BAD_STATE";
- default:
- return "Unknown";
- }
- }
- static const char *mediatype2str(uint8_t media_type)
- {
- switch (media_type) {
- case 0x00:
- return "Audio";
- case 0x01:
- return "Video";
- case 0x02:
- return "Multimedia";
- default:
- return "Reserved";
- }
- }
- static const char *mediacodec2str(uint8_t codec)
- {
- switch (codec) {
- case 0x00:
- return "SBC";
- case 0x01:
- return "MPEG-1,2 Audio";
- case 0x02:
- return "MPEG-2,4 AAC";
- case 0x04:
- return "ATRAC Family";
- case 0xff:
- return "Non-A2DP";
- default:
- return "Reserved";
- }
- }
- static const char *cptype2str(uint8_t cp)
- {
- switch (cp) {
- case 0x0001:
- return "DTCP";
- case 0x0002:
- return "SCMS-T";
- default:
- return "Reserved";
- }
- }
- static const char *servicecat2str(uint8_t service_cat)
- {
- switch (service_cat) {
- case AVDTP_MEDIA_TRANSPORT:
- return "Media Transport";
- case AVDTP_REPORTING:
- return "Reporting";
- case AVDTP_RECOVERY:
- return "Recovery";
- case AVDTP_CONTENT_PROTECTION:
- return "Content Protection";
- case AVDTP_HEADER_COMPRESSION:
- return "Header Compression";
- case AVDTP_MULTIPLEXING:
- return "Multiplexing";
- case AVDTP_MEDIA_CODEC:
- return "Media Codec";
- case AVDTP_DELAY_REPORTING:
- return "Delay Reporting";
- default:
- return "Reserved";
- }
- }
- static bool avdtp_reject_common(struct avdtp_frame *avdtp_frame)
- {
- struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
- uint8_t error;
- if (!l2cap_frame_get_u8(frame, &error))
- return false;
- print_field("Error code: %s (0x%02x)", error2str(error), error);
- return true;
- }
- static bool service_content_protection(struct avdtp_frame *avdtp_frame,
- uint8_t losc)
- {
- struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
- uint16_t type = 0;
- if (losc < 2)
- return false;
- if (!l2cap_frame_get_le16(frame, &type))
- return false;
- losc -= 2;
- print_field("%*cContent Protection Type: %s (0x%04x)", 2, ' ',
- cptype2str(type), type);
- /* TODO: decode protection specific information */
- packet_hexdump(frame->data, losc);
- l2cap_frame_pull(frame, frame, losc);
- return true;
- }
- static bool service_media_codec(struct avdtp_frame *avdtp_frame, uint8_t losc)
- {
- struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
- uint8_t type = 0;
- uint8_t codec = 0;
- if (losc < 2)
- return false;
- l2cap_frame_get_u8(frame, &type);
- l2cap_frame_get_u8(frame, &codec);
- losc -= 2;
- print_field("%*cMedia Type: %s (0x%02x)", 2, ' ',
- mediatype2str(type >> 4), type >> 4);
- print_field("%*cMedia Codec: %s (0x%02x)", 2, ' ',
- mediacodec2str(codec), codec);
- if (is_configuration_sig_id(avdtp_frame->sig_id))
- return a2dp_codec_cfg(codec, losc, frame);
- else
- return a2dp_codec_cap(codec, losc, frame);
- }
- static bool decode_capabilities(struct avdtp_frame *avdtp_frame)
- {
- struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
- uint8_t service_cat;
- uint8_t losc;
- while (l2cap_frame_get_u8(frame, &service_cat)) {
- print_field("Service Category: %s (0x%02x)",
- servicecat2str(service_cat), service_cat);
- if (!l2cap_frame_get_u8(frame, &losc))
- return false;
- if (frame->size < losc)
- return false;
- switch (service_cat) {
- case AVDTP_CONTENT_PROTECTION:
- if (!service_content_protection(avdtp_frame, losc))
- return false;
- break;
- case AVDTP_MEDIA_CODEC:
- if (!service_media_codec(avdtp_frame, losc))
- return false;
- break;
- case AVDTP_MEDIA_TRANSPORT:
- case AVDTP_REPORTING:
- case AVDTP_RECOVERY:
- case AVDTP_HEADER_COMPRESSION:
- case AVDTP_MULTIPLEXING:
- case AVDTP_DELAY_REPORTING:
- default:
- packet_hexdump(frame->data, losc);
- l2cap_frame_pull(frame, frame, losc);
- }
- }
- return true;
- }
- static bool avdtp_discover(struct avdtp_frame *avdtp_frame)
- {
- struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
- uint8_t type = avdtp_frame->hdr & 0x03;
- uint8_t seid;
- uint8_t info;
- switch (type) {
- case AVDTP_MSG_TYPE_COMMAND:
- return true;
- case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
- while (l2cap_frame_get_u8(frame, &seid)) {
- print_field("ACP SEID: %d", seid >> 2);
- if (!l2cap_frame_get_u8(frame, &info))
- return false;
- print_field("%*cMedia Type: %s (0x%02x)", 2, ' ',
- mediatype2str(info >> 4), info >> 4);
- print_field("%*cSEP Type: %s (0x%02x)", 2, ' ',
- info & 0x08 ? "SNK" : "SRC",
- (info >> 3) & 0x01);
- print_field("%*cIn use: %s", 2, ' ',
- seid & 0x02 ? "Yes" : "No");
- }
- return true;
- case AVDTP_MSG_TYPE_RESPONSE_REJECT:
- return avdtp_reject_common(avdtp_frame);
- }
- return false;
- }
- static bool avdtp_get_capabilities(struct avdtp_frame *avdtp_frame)
- {
- struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
- uint8_t type = avdtp_frame->hdr & 0x03;
- uint8_t seid;
- switch (type) {
- case AVDTP_MSG_TYPE_COMMAND:
- if (!l2cap_frame_get_u8(frame, &seid))
- return false;
- print_field("ACP SEID: %d", seid >> 2);
- return true;
- case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
- return decode_capabilities(avdtp_frame);
- case AVDTP_MSG_TYPE_RESPONSE_REJECT:
- return avdtp_reject_common(avdtp_frame);
- }
- return false;
- }
- static bool avdtp_set_configuration(struct avdtp_frame *avdtp_frame)
- {
- struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
- uint8_t type = avdtp_frame->hdr & 0x03;
- uint8_t acp_seid, int_seid;
- uint8_t service_cat;
- switch (type) {
- case AVDTP_MSG_TYPE_COMMAND:
- if (!l2cap_frame_get_u8(frame, &acp_seid))
- return false;
- print_field("ACP SEID: %d", acp_seid >> 2);
- if (!l2cap_frame_get_u8(frame, &int_seid))
- return false;
- print_field("INT SEID: %d", int_seid >> 2);
- return decode_capabilities(avdtp_frame);
- case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
- return true;
- case AVDTP_MSG_TYPE_RESPONSE_REJECT:
- if (!l2cap_frame_get_u8(frame, &service_cat))
- return false;
- print_field("Service Category: %s (0x%02x)",
- servicecat2str(service_cat), service_cat);
- return avdtp_reject_common(avdtp_frame);
- }
- return false;
- }
- static bool avdtp_get_configuration(struct avdtp_frame *avdtp_frame)
- {
- struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
- uint8_t type = avdtp_frame->hdr & 0x03;
- uint8_t seid;
- switch (type) {
- case AVDTP_MSG_TYPE_COMMAND:
- if (!l2cap_frame_get_u8(frame, &seid))
- return false;
- print_field("ACP SEID: %d", seid >> 2);
- return true;
- case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
- return decode_capabilities(avdtp_frame);
- case AVDTP_MSG_TYPE_RESPONSE_REJECT:
- return avdtp_reject_common(avdtp_frame);
- }
- return false;
- }
- static bool avdtp_reconfigure(struct avdtp_frame *avdtp_frame)
- {
- struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
- uint8_t type = avdtp_frame->hdr & 0x03;
- uint8_t seid;
- uint8_t service_cat;
- switch (type) {
- case AVDTP_MSG_TYPE_COMMAND:
- if (!l2cap_frame_get_u8(frame, &seid))
- return false;
- print_field("ACP SEID: %d", seid >> 2);
- return decode_capabilities(avdtp_frame);
- case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
- return true;
- case AVDTP_MSG_TYPE_RESPONSE_REJECT:
- if (!l2cap_frame_get_u8(frame, &service_cat))
- return false;
- print_field("Service Category: %s (0x%02x)",
- servicecat2str(service_cat), service_cat);
- return avdtp_reject_common(avdtp_frame);
- }
- return false;
- }
- static bool avdtp_open(struct avdtp_frame *avdtp_frame)
- {
- struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
- uint8_t type = avdtp_frame->hdr & 0x03;
- uint8_t seid;
- switch (type) {
- case AVDTP_MSG_TYPE_COMMAND:
- if (!l2cap_frame_get_u8(frame, &seid))
- return false;
- print_field("ACP SEID: %d", seid >> 2);
- return true;
- case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
- return true;
- case AVDTP_MSG_TYPE_RESPONSE_REJECT:
- return avdtp_reject_common(avdtp_frame);
- }
- return false;
- }
- static bool avdtp_start(struct avdtp_frame *avdtp_frame)
- {
- struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
- uint8_t type = avdtp_frame->hdr & 0x03;
- uint8_t seid;
- switch (type) {
- case AVDTP_MSG_TYPE_COMMAND:
- if (!l2cap_frame_get_u8(frame, &seid))
- return false;
- print_field("ACP SEID: %d", seid >> 2);
- while (l2cap_frame_get_u8(frame, &seid))
- print_field("ACP SEID: %d", seid >> 2);
- return true;
- case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
- return true;
- case AVDTP_MSG_TYPE_RESPONSE_REJECT:
- if (!l2cap_frame_get_u8(frame, &seid))
- return false;
- print_field("ACP SEID: %d", seid >> 2);
- return avdtp_reject_common(avdtp_frame);
- }
- return false;
- }
- static bool avdtp_close(struct avdtp_frame *avdtp_frame)
- {
- struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
- uint8_t type = avdtp_frame->hdr & 0x03;
- uint8_t seid;
- switch (type) {
- case AVDTP_MSG_TYPE_COMMAND:
- if (!l2cap_frame_get_u8(frame, &seid))
- return false;
- print_field("ACP SEID: %d", seid >> 2);
- return true;
- case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
- return true;
- case AVDTP_MSG_TYPE_RESPONSE_REJECT:
- return avdtp_reject_common(avdtp_frame);
- }
- return false;
- }
- static bool avdtp_suspend(struct avdtp_frame *avdtp_frame)
- {
- struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
- uint8_t type = avdtp_frame->hdr & 0x03;
- uint8_t seid;
- switch (type) {
- case AVDTP_MSG_TYPE_COMMAND:
- if (!l2cap_frame_get_u8(frame, &seid))
- return false;
- print_field("ACP SEID: %d", seid >> 2);
- while (l2cap_frame_get_u8(frame, &seid))
- print_field("ACP SEID: %d", seid >> 2);
- return true;
- case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
- return true;
- case AVDTP_MSG_TYPE_RESPONSE_REJECT:
- if (!l2cap_frame_get_u8(frame, &seid))
- return false;
- print_field("ACP SEID: %d", seid >> 2);
- return avdtp_reject_common(avdtp_frame);
- }
- return false;
- }
- static bool avdtp_abort(struct avdtp_frame *avdtp_frame)
- {
- struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
- uint8_t type = avdtp_frame->hdr & 0x03;
- uint8_t seid;
- switch (type) {
- case AVDTP_MSG_TYPE_COMMAND:
- if (!l2cap_frame_get_u8(frame, &seid))
- return false;
- print_field("ACP SEID: %d", seid >> 2);
- return true;
- case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
- return true;
- }
- return false;
- }
- static bool avdtp_security_control(struct avdtp_frame *avdtp_frame)
- {
- struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
- uint8_t type = avdtp_frame->hdr & 0x03;
- uint8_t seid;
- switch (type) {
- case AVDTP_MSG_TYPE_COMMAND:
- if (!l2cap_frame_get_u8(frame, &seid))
- return false;
- print_field("ACP SEID: %d", seid >> 2);
- /* TODO: decode more information */
- packet_hexdump(frame->data, frame->size);
- return true;
- case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
- /* TODO: decode more information */
- packet_hexdump(frame->data, frame->size);
- return true;
- case AVDTP_MSG_TYPE_RESPONSE_REJECT:
- return avdtp_reject_common(avdtp_frame);
- }
- return false;
- }
- static bool avdtp_delayreport(struct avdtp_frame *avdtp_frame)
- {
- struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
- uint8_t type = avdtp_frame->hdr & 0x03;
- uint8_t seid;
- uint16_t delay;
- switch (type) {
- case AVDTP_MSG_TYPE_COMMAND:
- if (!l2cap_frame_get_u8(frame, &seid))
- return false;
- print_field("ACP SEID: %d", seid >> 2);
- if (!l2cap_frame_get_be16(frame, &delay))
- return false;
- print_field("Delay: %d.%dms", delay / 10, delay % 10);
- return true;
- case AVDTP_MSG_TYPE_RESPONSE_ACCEPT:
- return true;
- case AVDTP_MSG_TYPE_RESPONSE_REJECT:
- return avdtp_reject_common(avdtp_frame);
- }
- return false;
- }
- static bool avdtp_signalling_packet(struct avdtp_frame *avdtp_frame)
- {
- struct l2cap_frame *frame = &avdtp_frame->l2cap_frame;
- const char *pdu_color;
- uint8_t hdr;
- uint8_t sig_id;
- uint8_t nosp = 0;
- if (frame->in)
- pdu_color = COLOR_MAGENTA;
- else
- pdu_color = COLOR_BLUE;
- if (!l2cap_frame_get_u8(frame, &hdr))
- return false;
- avdtp_frame->hdr = hdr;
- /* Continue Packet || End Packet */
- if (((hdr & 0x0c) == 0x08) || ((hdr & 0x0c) == 0x0c)) {
- /* TODO: handle fragmentation */
- packet_hexdump(frame->data, frame->size);
- return true;
- }
- /* Start Packet */
- if ((hdr & 0x0c) == 0x04) {
- if (!l2cap_frame_get_u8(frame, &nosp))
- return false;
- }
- if (!l2cap_frame_get_u8(frame, &sig_id))
- return false;
- sig_id &= 0x3f;
- avdtp_frame->sig_id = sig_id;
- print_indent(6, pdu_color, "AVDTP: ", sigid2str(sig_id), COLOR_OFF,
- " (0x%02x) %s (0x%02x) type 0x%02x label %d nosp %d",
- sig_id, msgtype2str(hdr & 0x03), hdr & 0x03,
- hdr & 0x0c, hdr >> 4, nosp);
- /* Start Packet */
- if ((hdr & 0x0c) == 0x04) {
- /* TODO: handle fragmentation */
- packet_hexdump(frame->data, frame->size);
- return true;
- }
- switch (sig_id) {
- case AVDTP_DISCOVER:
- return avdtp_discover(avdtp_frame);
- case AVDTP_GET_CAPABILITIES:
- case AVDTP_GET_ALL_CAPABILITIES:
- return avdtp_get_capabilities(avdtp_frame);
- case AVDTP_SET_CONFIGURATION:
- return avdtp_set_configuration(avdtp_frame);
- case AVDTP_GET_CONFIGURATION:
- return avdtp_get_configuration(avdtp_frame);
- case AVDTP_RECONFIGURE:
- return avdtp_reconfigure(avdtp_frame);
- case AVDTP_OPEN:
- return avdtp_open(avdtp_frame);
- case AVDTP_START:
- return avdtp_start(avdtp_frame);
- case AVDTP_CLOSE:
- return avdtp_close(avdtp_frame);
- case AVDTP_SUSPEND:
- return avdtp_suspend(avdtp_frame);
- case AVDTP_ABORT:
- return avdtp_abort(avdtp_frame);
- case AVDTP_SECURITY_CONTROL:
- return avdtp_security_control(avdtp_frame);
- case AVDTP_DELAYREPORT:
- return avdtp_delayreport(avdtp_frame);
- }
- packet_hexdump(frame->data, frame->size);
- return true;
- }
- void avdtp_packet(const struct l2cap_frame *frame)
- {
- struct avdtp_frame avdtp_frame;
- bool ret;
- l2cap_frame_pull(&avdtp_frame.l2cap_frame, frame, 0);
- switch (frame->seq_num) {
- case 1:
- ret = avdtp_signalling_packet(&avdtp_frame);
- break;
- default:
- if (packet_has_filter(PACKET_FILTER_SHOW_A2DP_STREAM))
- packet_hexdump(frame->data, frame->size);
- return;
- }
- if (!ret) {
- print_text(COLOR_ERROR, "PDU malformed");
- packet_hexdump(frame->data, frame->size);
- }
- }
|