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"
35 #define GET_PKT_TYPE(type) (type & 0x7f)
36 #define GET_EXTENSION(type) (type & 0x80)
38 /* BNEP Extension Type */
39 #define BNEP_EXTENSION_CONTROL 0x00
41 #define BNEP_CONTROL 0x01
43 uint16_t proto = 0x0000;
48 struct l2cap_frame l2cap_frame;
51 static bool get_macaddr(struct bnep_frame *bnep_frame, char *str)
54 struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
57 for (i = 0; i < 6; i++)
58 if (!l2cap_frame_get_u8(frame, &addr[i]))
61 sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
62 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
67 static bool bnep_general(struct bnep_frame *bnep_frame,
68 uint8_t indent, int hdr_len)
70 struct l2cap_frame *frame;
71 char src_addr[20], dest_addr[20];
73 if (!get_macaddr(bnep_frame, dest_addr))
76 if (!get_macaddr(bnep_frame, src_addr))
79 frame = &bnep_frame->l2cap_frame;
81 if (!l2cap_frame_get_be16(frame, &proto))
84 print_field("%*cdst %s src %s [proto 0x%04x] ", indent,
85 ' ', dest_addr, src_addr, proto);
91 static bool cmd_nt_understood(struct bnep_frame *bnep_frame, uint8_t indent)
93 struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
96 if (!l2cap_frame_get_u8(frame, &ptype))
99 print_field("%*cType: 0x%02x ", indent, ' ', ptype);
104 static bool setup_conn_req(struct bnep_frame *bnep_frame, uint8_t indent)
107 struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
109 uint32_t src_uuid = 0, dst_uuid = 0;
111 if (!l2cap_frame_get_u8(frame, &uuid_size))
114 print_field("%*cSize: 0x%02x ", indent, ' ', uuid_size);
118 if (!l2cap_frame_get_be16(frame, (uint16_t *) &dst_uuid))
121 if (!l2cap_frame_get_be16(frame, (uint16_t *) &src_uuid))
125 if (!l2cap_frame_get_be32(frame, &dst_uuid))
128 if (!l2cap_frame_get_be32(frame, &src_uuid))
132 if (!l2cap_frame_get_be32(frame, &dst_uuid))
135 l2cap_frame_pull(frame, frame, 12);
137 if (!l2cap_frame_get_be32(frame, &src_uuid))
140 l2cap_frame_pull(frame, frame, 12);
143 l2cap_frame_pull(frame, frame, (uuid_size * 2));
147 print_field("%*cDst: 0x%x(%s)", indent, ' ', dst_uuid,
148 bt_uuid32_to_str(dst_uuid));
149 print_field("%*cSrc: 0x%x(%s)", indent, ' ', src_uuid,
150 bt_uuid32_to_str(src_uuid));
154 static const char *value2str(uint16_t value)
158 return "Operation Successful";
160 return "Operation Failed - Invalid Dst Srv UUID";
162 return "Operation Failed - Invalid Src Srv UUID";
164 return "Operation Failed - Invalid Srv UUID size";
166 return "Operation Failed - Conn not allowed";
172 static bool print_rsp_msg(struct bnep_frame *bnep_frame, uint8_t indent)
174 struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
177 if (!l2cap_frame_get_be16(frame, &rsp_msg))
180 print_field("%*cRsp msg: %s(0x%04x) ", indent, ' ',
181 value2str(rsp_msg), rsp_msg);
186 static bool filter_nettype_req(struct bnep_frame *bnep_frame, uint8_t indent)
188 struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
189 uint16_t length, start_range, end_range;
192 if (!l2cap_frame_get_be16(frame, &length))
195 print_field("%*cLength: 0x%04x", indent, ' ', length);
197 for (i = 0; i < length / 4; i++) {
199 if (!l2cap_frame_get_be16(frame, &start_range))
202 if (!l2cap_frame_get_be16(frame, &end_range))
205 print_field("%*c0x%04x - 0x%04x", indent, ' ',
206 start_range, end_range);
212 static bool filter_multaddr_req(struct bnep_frame *bnep_frame, uint8_t indent)
214 struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
216 char start_addr[20], end_addr[20];
219 if (!l2cap_frame_get_be16(frame, &length))
222 print_field("%*cLength: 0x%04x", indent, ' ', length);
224 for (i = 0; i < length / 12; i++) {
226 if (!get_macaddr(bnep_frame, start_addr))
229 if (!get_macaddr(bnep_frame, end_addr))
232 print_field("%*c%s - %s", indent, ' ', start_addr, end_addr);
238 struct bnep_control_data {
241 bool (*func) (struct bnep_frame *frame, uint8_t indent);
244 static const struct bnep_control_data bnep_control_table[] = {
245 { 0x00, "Command Not Understood", cmd_nt_understood },
246 { 0x01, "Setup Conn Req", setup_conn_req },
247 { 0x02, "Setup Conn Rsp", print_rsp_msg },
248 { 0x03, "Filter NetType Set", filter_nettype_req },
249 { 0x04, "Filter NetType Rsp", print_rsp_msg },
250 { 0x05, "Filter MultAddr Set", filter_multaddr_req },
251 { 0x06, "Filter MultAddr Rsp", print_rsp_msg },
255 static bool bnep_control(struct bnep_frame *bnep_frame,
256 uint8_t indent, int hdr_len)
259 struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
260 const struct bnep_control_data *bnep_control_data = NULL;
261 const char *type_str;
264 if (!l2cap_frame_get_u8(frame, &ctype))
267 for (i = 0; bnep_control_table[i].str; i++) {
268 if (bnep_control_table[i].type == ctype) {
269 bnep_control_data = &bnep_control_table[i];
274 if (bnep_control_data)
275 type_str = bnep_control_data->str;
277 type_str = "Unknown control type";
279 print_field("%*c%s (0x%02x) ", indent, ' ', type_str, ctype);
281 if (!bnep_control_data || !bnep_control_data->func) {
282 packet_hexdump(frame->data, hdr_len - 1);
283 l2cap_frame_pull(frame, frame, hdr_len - 1);
287 if (!bnep_control_data->func(bnep_frame, indent+2))
294 static bool bnep_compressed(struct bnep_frame *bnep_frame,
295 uint8_t indent, int hdr_len)
298 struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
300 if (!l2cap_frame_get_be16(frame, &proto))
303 print_field("%*c[proto 0x%04x] ", indent, ' ', proto);
308 static bool bnep_src_only(struct bnep_frame *bnep_frame,
309 uint8_t indent, int hdr_len)
312 struct l2cap_frame *frame;
315 if (!get_macaddr(bnep_frame, src_addr))
318 frame = &bnep_frame->l2cap_frame;
320 if (!l2cap_frame_get_be16(frame, &proto))
323 print_field("%*csrc %s [proto 0x%04x] ", indent,
324 ' ', src_addr, proto);
329 static bool bnep_dst_only(struct bnep_frame *bnep_frame,
330 uint8_t indent, int hdr_len)
333 struct l2cap_frame *frame;
336 if (!get_macaddr(bnep_frame, dest_addr))
339 frame = &bnep_frame->l2cap_frame;
341 if (!l2cap_frame_get_be16(frame, &proto))
344 print_field("%*cdst %s [proto 0x%04x] ", indent,
345 ' ', dest_addr, proto);
350 static bool bnep_eval_extension(struct bnep_frame *bnep_frame, uint8_t indent)
352 struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
353 uint8_t type, length;
356 if (!l2cap_frame_get_u8(frame, &type))
359 if (!l2cap_frame_get_u8(frame, &length))
362 extension = GET_EXTENSION(type);
363 type = GET_PKT_TYPE(type);
366 case BNEP_EXTENSION_CONTROL:
367 print_field("%*cExt Control(0x%02x|%s) len 0x%02x", indent,
368 ' ', type, extension ? "1" : "0", length);
369 if (!bnep_control(bnep_frame, indent+2, length))
374 print_field("%*cExt Unknown(0x%02x|%s) len 0x%02x", indent,
375 ' ', type, extension ? "1" : "0", length);
376 packet_hexdump(frame->data, length);
377 l2cap_frame_pull(frame, frame, length);
381 if (!bnep_eval_extension(bnep_frame, indent))
390 bool (*func) (struct bnep_frame *frame, uint8_t indent, int hdr_len);
393 static const struct bnep_data bnep_table[] = {
394 { 0x00, "General Ethernet", bnep_general },
395 { 0x01, "Control", bnep_control },
396 { 0x02, "Compressed Ethernet", bnep_compressed },
397 { 0x03, "Compressed Ethernet SrcOnly", bnep_src_only },
398 { 0x04, "Compressed Ethernet DestOnly", bnep_dst_only },
402 void bnep_packet(const struct l2cap_frame *frame)
404 uint8_t type, indent = 1;
405 struct bnep_frame bnep_frame;
406 struct l2cap_frame *l2cap_frame;
407 const struct bnep_data *bnep_data = NULL;
408 const char *pdu_color, *pdu_str;
411 l2cap_frame_pull(&bnep_frame.l2cap_frame, frame, 0);
412 l2cap_frame = &bnep_frame.l2cap_frame;
414 if (!l2cap_frame_get_u8(l2cap_frame, &type))
417 bnep_frame.extension = GET_EXTENSION(type);
418 bnep_frame.type = GET_PKT_TYPE(type);
420 for (i = 0; bnep_table[i].str; i++) {
421 if (bnep_table[i].type == bnep_frame.type) {
422 bnep_data = &bnep_table[i];
428 if (bnep_data->func) {
430 pdu_color = COLOR_MAGENTA;
432 pdu_color = COLOR_BLUE;
434 pdu_color = COLOR_WHITE_BG;
435 pdu_str = bnep_data->str;
437 pdu_color = COLOR_WHITE_BG;
438 pdu_str = "Unknown packet type";
441 print_indent(6, pdu_color, "BNEP: ", pdu_str, COLOR_OFF,
442 " (0x%02x|%s)", bnep_frame.type,
443 bnep_frame.extension ? "1" : "0");
445 if (!bnep_data || !bnep_data->func) {
446 packet_hexdump(l2cap_frame->data, l2cap_frame->size);
450 if (!bnep_data->func(&bnep_frame, indent, -1))
454 if (bnep_frame.extension)
455 if (!bnep_eval_extension(&bnep_frame, indent+2))
458 /* Control packet => No payload info */
459 if (bnep_frame.type == BNEP_CONTROL)
462 /* TODO: Handle BNEP IP packet */
463 packet_hexdump(l2cap_frame->data, l2cap_frame->size);
468 print_text(COLOR_ERROR, "frame too short");
469 packet_hexdump(frame->data, frame->size);