1 // SPDX-License-Identifier: LGPL-2.1-or-later
4 * BlueZ - Bluetooth protocol stack for Linux
6 * Copyright (C) 2011-2014 Intel Corporation
7 * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
22 #include "lib/bluetooth.h"
25 #include "src/shared/util.h"
34 static char *cr_str[] = {
39 /* RFCOMM frame parsing macros */
40 #define CR_STR(type) cr_str[GET_CR(type)]
41 #define GET_LEN8(length) ((length & 0xfe) >> 1)
42 #define GET_LEN16(length) ((length & 0xfffe) >> 1)
43 #define GET_CR(type) ((type & 0x02) >> 1)
44 #define GET_PF(ctr) (((ctr) >> 4) & 0x1)
47 #define GET_V24_FC(sigs) ((sigs & 0x02) >> 1)
48 #define GET_V24_RTC(sigs) ((sigs & 0x04) >> 2)
49 #define GET_V24_RTR(sigs) ((sigs & 0x08) >> 3)
50 #define GET_V24_IC(sigs) ((sigs & 0x40) >> 6)
51 #define GET_V24_DV(sigs) ((sigs & 0x80) >> 7)
54 #define GET_RPN_DB(parity) (parity & 0x03)
55 #define GET_RPN_SB(parity) ((parity & 0x04) >> 2)
56 #define GET_RPN_PARITY(parity) ((parity & 0x08) >> 3)
57 #define GET_RPN_PTYPE(parity) ((parity & 0x30) >> 4)
58 #define GET_RPN_XIN(io) (io & 0x01)
59 #define GET_RPN_XOUT(io) ((io & 0x02) >> 1)
60 #define GET_RPN_RTRI(io) ((io & 0x04) >> 2)
61 #define GET_RPN_RTRO(io) ((io & 0x08) >> 3)
62 #define GET_RPN_RTCI(io) ((io & 0x10) >> 4)
63 #define GET_RPN_RTCO(io) ((io & 0x20) >> 5)
66 #define GET_ERROR(err) (err & 0x0f)
69 #define GET_FRM_TYPE(ctrl) ((ctrl & 0x0f))
70 #define GET_CRT_FLOW(ctrl) ((ctrl & 0xf0) >> 4)
71 #define GET_PRIORITY(prio) ((prio & 0x3f))
72 #define GET_PN_DLCI(dlci) ((dlci & 0x3f))
79 uint8_t credits; /* only for UIH frame */
112 struct rfcomm_frame {
113 struct rfcomm_lhdr hdr;
114 struct rfcomm_lmcc mcc;
115 struct l2cap_frame l2cap_frame;
118 static void print_rfcomm_hdr(struct rfcomm_frame *rfcomm_frame, uint8_t indent)
120 struct rfcomm_lhdr hdr = rfcomm_frame->hdr;
123 print_field("%*cAddress: 0x%2.2x cr %d dlci 0x%2.2x", indent, ' ',
124 hdr.address, GET_CR(hdr.address),
125 RFCOMM_GET_DLCI(hdr.address));
128 print_field("%*cControl: 0x%2.2x poll/final %d", indent, ' ',
129 hdr.control, GET_PF(hdr.control));
132 print_field("%*cLength: %d", indent, ' ', hdr.length);
133 print_field("%*cFCS: 0x%2.2x", indent, ' ', hdr.fcs);
136 static inline bool mcc_test(struct rfcomm_frame *rfcomm_frame, uint8_t indent)
138 struct l2cap_frame *frame = &rfcomm_frame->l2cap_frame;
141 printf("%*cTest Data: 0x ", indent, ' ');
143 while (frame->size > 1) {
144 if (!l2cap_frame_get_u8(frame, &data))
146 printf("%2.2x ", data);
153 static inline bool mcc_msc(struct rfcomm_frame *rfcomm_frame, uint8_t indent)
155 struct l2cap_frame *frame = &rfcomm_frame->l2cap_frame;
156 struct rfcomm_lmsc msc;
158 if (!l2cap_frame_get_u8(frame, &msc.dlci))
161 print_field("%*cdlci %d ", indent, ' ', RFCOMM_GET_DLCI(msc.dlci));
163 if (!l2cap_frame_get_u8(frame, &msc.v24_sig))
166 /* v24 control signals */
167 print_field("%*cfc %d rtc %d rtr %d ic %d dv %d", indent, ' ',
168 GET_V24_FC(msc.v24_sig), GET_V24_RTC(msc.v24_sig),
169 GET_V24_RTR(msc.v24_sig), GET_V24_IC(msc.v24_sig),
170 GET_V24_DV(msc.v24_sig));
176 * TODO: Implement the break signals decoding.
179 packet_hexdump(frame->data, frame->size);
185 static inline bool mcc_rpn(struct rfcomm_frame *rfcomm_frame, uint8_t indent)
187 struct l2cap_frame *frame = &rfcomm_frame->l2cap_frame;
188 struct rfcomm_rpn rpn;
190 if (!l2cap_frame_get_u8(frame, &rpn.dlci))
193 print_field("%*cdlci %d", indent, ' ', RFCOMM_GET_DLCI(rpn.dlci));
198 /* port value octets (optional) */
200 if (!l2cap_frame_get_u8(frame, &rpn.bit_rate))
203 if (!l2cap_frame_get_u8(frame, &rpn.parity))
206 if (!l2cap_frame_get_u8(frame, &rpn.io))
209 print_field("%*cbr %d db %d sb %d p %d pt %d xi %d xo %d", indent, ' ',
210 rpn.bit_rate, GET_RPN_DB(rpn.parity), GET_RPN_SB(rpn.parity),
211 GET_RPN_PARITY(rpn.parity), GET_RPN_PTYPE(rpn.parity),
212 GET_RPN_XIN(rpn.io), GET_RPN_XOUT(rpn.io));
214 if (!l2cap_frame_get_u8(frame, &rpn.xon))
217 if (!l2cap_frame_get_u8(frame, &rpn.xoff))
220 print_field("%*crtri %d rtro %d rtci %d rtco %d xon %d xoff %d",
221 indent, ' ', GET_RPN_RTRI(rpn.io), GET_RPN_RTRO(rpn.io),
222 GET_RPN_RTCI(rpn.io), GET_RPN_RTCO(rpn.io), rpn.xon,
225 if (!l2cap_frame_get_le16(frame, &rpn.pm))
228 print_field("%*cpm 0x%04x", indent, ' ', rpn.pm);
234 static inline bool mcc_rls(struct rfcomm_frame *rfcomm_frame, uint8_t indent)
236 struct l2cap_frame *frame = &rfcomm_frame->l2cap_frame;
237 struct rfcomm_rls rls;
239 if (!l2cap_frame_get_u8(frame, &rls.dlci))
242 if (!l2cap_frame_get_u8(frame, &rls.error))
245 print_field("%*cdlci %d error: %d", indent, ' ',
246 RFCOMM_GET_DLCI(rls.dlci), GET_ERROR(rls.error));
251 static inline bool mcc_pn(struct rfcomm_frame *rfcomm_frame, uint8_t indent)
253 struct l2cap_frame *frame = &rfcomm_frame->l2cap_frame;
257 /* rfcomm_pn struct is defined in rfcomm.h */
259 if (!l2cap_frame_get_u8(frame, &pn.dlci))
262 if (!l2cap_frame_get_u8(frame, &pn.flow_ctrl))
265 if (!l2cap_frame_get_u8(frame, &pn.priority))
268 print_field("%*cdlci %d frame_type %d credit_flow %d pri %d", indent,
269 ' ', GET_PN_DLCI(pn.dlci), GET_FRM_TYPE(pn.flow_ctrl),
270 GET_CRT_FLOW(pn.flow_ctrl), GET_PRIORITY(pn.priority));
272 if (!l2cap_frame_get_u8(frame, &pn.ack_timer))
275 if (!l2cap_frame_get_le16(frame, &mtu))
280 if (!l2cap_frame_get_u8(frame, &pn.max_retrans))
283 if (!l2cap_frame_get_u8(frame, &pn.credits))
286 print_field("%*cack_timer %d frame_size %d max_retrans %d credits %d",
287 indent, ' ', pn.ack_timer, pn.mtu, pn.max_retrans,
293 static inline bool mcc_nsc(struct rfcomm_frame *rfcomm_frame, uint8_t indent)
295 struct l2cap_frame *frame = &rfcomm_frame->l2cap_frame;
296 struct rfcomm_nsc nsc;
298 if (!l2cap_frame_get_u8(frame, &nsc.cmd_type))
301 print_field("%*ccr %d, mcc_cmd_type %x", indent, ' ',
302 GET_CR(nsc.cmd_type), RFCOMM_GET_MCC_TYPE(nsc.cmd_type));
312 static const struct mcc_data mcc_table[] = {
313 { 0x08, "Test Command" },
314 { 0x28, "Flow Control On Command" },
315 { 0x18, "Flow Control Off Command" },
316 { 0x38, "Modem Status Command" },
317 { 0x24, "Remote Port Negotiation Command" },
318 { 0x14, "Remote Line Status" },
319 { 0x20, "DLC Parameter Negotiation" },
320 { 0x04, "Non Supported Command" },
324 static inline bool mcc_frame(struct rfcomm_frame *rfcomm_frame, uint8_t indent)
326 uint8_t length, ex_length, type;
327 const char *type_str;
329 struct l2cap_frame *frame = &rfcomm_frame->l2cap_frame;
330 struct rfcomm_lmcc mcc;
331 const struct mcc_data *mcc_data = NULL;
333 if (!l2cap_frame_get_u8(frame, &mcc.type) ||
334 !l2cap_frame_get_u8(frame, &length))
337 if (RFCOMM_TEST_EA(length))
338 mcc.length = (uint16_t) GET_LEN8(length);
340 if (!l2cap_frame_get_u8(frame, &ex_length))
342 mcc.length = ((uint16_t) length << 8) | ex_length;
343 mcc.length = GET_LEN16(mcc.length);
346 type = RFCOMM_GET_MCC_TYPE(mcc.type);
348 for (i = 0; mcc_table[i].str; i++) {
349 if (mcc_table[i].type == type) {
350 mcc_data = &mcc_table[i];
356 type_str = mcc_data->str;
358 type_str = "Unknown";
360 print_field("%*cMCC Message type: %s %s (0x%2.2x)", indent, ' ',
361 type_str, CR_STR(mcc.type), type);
363 print_field("%*cLength: %d", indent+2, ' ', mcc.length);
365 rfcomm_frame->mcc = mcc;
369 return mcc_test(rfcomm_frame, indent+10);
371 return mcc_msc(rfcomm_frame, indent+2);
373 return mcc_rpn(rfcomm_frame, indent+2);
375 return mcc_rls(rfcomm_frame, indent+2);
377 return mcc_pn(rfcomm_frame, indent+2);
379 return mcc_nsc(rfcomm_frame, indent+2);
381 packet_hexdump(frame->data, frame->size);
387 static bool uih_frame(struct rfcomm_frame *rfcomm_frame, uint8_t indent)
390 struct l2cap_frame *frame = &rfcomm_frame->l2cap_frame;
391 struct rfcomm_lhdr *hdr = &rfcomm_frame->hdr;
393 if (!RFCOMM_GET_CHANNEL(hdr->address))
394 return mcc_frame(rfcomm_frame, indent);
396 /* fetching credits from UIH frame */
397 if (GET_PF(hdr->control)) {
398 if (!l2cap_frame_get_u8(frame, &credits))
400 hdr->credits = credits;
401 print_field("%*cCredits: %d", indent, ' ', hdr->credits);
404 packet_hexdump(frame->data, frame->size);
413 static const struct rfcomm_data rfcomm_table[] = {
414 { 0x2f, "Set Async Balance Mode (SABM)" },
415 { 0x63, "Unnumbered Ack (UA)" },
416 { 0x0f, "Disconnect Mode (DM)" },
417 { 0x43, "Disconnect (DISC)" },
418 { 0xef, "Unnumbered Info with Header Check (UIH)" },
422 void rfcomm_packet(const struct l2cap_frame *frame)
424 uint8_t ctype, length, ex_length, indent = 1;
425 const char *frame_str, *frame_color;
426 struct l2cap_frame *l2cap_frame, tmp_frame;
427 struct rfcomm_frame rfcomm_frame;
428 struct rfcomm_lhdr hdr;
429 const struct rfcomm_data *rfcomm_data = NULL;
432 l2cap_frame_pull(&rfcomm_frame.l2cap_frame, frame, 0);
434 l2cap_frame = &rfcomm_frame.l2cap_frame;
439 memset(&hdr, 0, sizeof(hdr));
440 if (!l2cap_frame_get_u8(l2cap_frame, &hdr.address) ||
441 !l2cap_frame_get_u8(l2cap_frame, &hdr.control) ||
442 !l2cap_frame_get_u8(l2cap_frame, &length))
445 /* length maybe 1 or 2 octets */
446 if (RFCOMM_TEST_EA(length))
447 hdr.length = (uint16_t) GET_LEN8(length);
449 if (!l2cap_frame_get_u8(l2cap_frame, &ex_length))
451 hdr.length = ((uint16_t)ex_length << 8) | length;
452 hdr.length = GET_LEN16(hdr.length);
455 if (!l2cap_frame->size)
458 l2cap_frame_pull(&tmp_frame, l2cap_frame, l2cap_frame->size-1);
460 if (!l2cap_frame_get_u8(&tmp_frame, &hdr.fcs))
463 /* Decoding frame type */
464 ctype = RFCOMM_GET_TYPE(hdr.control);
466 for (i = 0; rfcomm_table[i].str; i++) {
467 if (rfcomm_table[i].frame == ctype) {
468 rfcomm_data = &rfcomm_table[i];
475 frame_color = COLOR_MAGENTA;
477 frame_color = COLOR_BLUE;
478 frame_str = rfcomm_data->str;
480 frame_color = COLOR_WHITE_BG;
481 frame_str = "Unknown";
485 packet_hexdump(frame->data, frame->size);
489 print_indent(6, frame_color, "RFCOMM: ", frame_str, COLOR_OFF,
490 " (0x%2.2x)", ctype);
492 rfcomm_frame.hdr = hdr;
493 print_rfcomm_hdr(&rfcomm_frame, indent);
497 if (!uih_frame(&rfcomm_frame, indent))
503 print_text(COLOR_ERROR, "Frame too short");
504 packet_hexdump(frame->data, frame->size);