3 * BlueZ - Bluetooth protocol stack for Linux
5 * Copyright (C) 2011-2014 Intel Corporation
6 * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
35 #include "lib/bluetooth.h"
37 #include "src/shared/util.h"
47 #define GET_PKT_TYPE(type) (type & 0x7f)
48 #define GET_EXTENSION(type) (type & 0x80)
50 /* BNEP Extension Type */
51 #define BNEP_EXTENSION_CONTROL 0x00
53 #define BNEP_CONTROL 0x01
55 uint16_t proto = 0x0000;
60 struct l2cap_frame l2cap_frame;
63 static bool get_macaddr(struct bnep_frame *bnep_frame, char *str)
66 struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
69 for (i = 0; i < 6; i++)
70 if (!l2cap_frame_get_u8(frame, &addr[i]))
73 sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
74 addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
79 static bool bnep_general(struct bnep_frame *bnep_frame,
80 uint8_t indent, int hdr_len)
82 struct l2cap_frame *frame;
83 char src_addr[20], dest_addr[20];
85 if (!get_macaddr(bnep_frame, dest_addr))
88 if (!get_macaddr(bnep_frame, src_addr))
91 frame = &bnep_frame->l2cap_frame;
93 if (!l2cap_frame_get_be16(frame, &proto))
96 print_field("%*cdst %s src %s [proto 0x%04x] ", indent,
97 ' ', dest_addr, src_addr, proto);
103 static bool cmd_nt_understood(struct bnep_frame *bnep_frame, uint8_t indent)
105 struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
108 if (!l2cap_frame_get_u8(frame, &ptype))
111 print_field("%*cType: 0x%02x ", indent, ' ', ptype);
116 static bool setup_conn_req(struct bnep_frame *bnep_frame, uint8_t indent)
119 struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
121 uint32_t src_uuid = 0, dst_uuid = 0;
123 if (!l2cap_frame_get_u8(frame, &uuid_size))
126 print_field("%*cSize: 0x%02x ", indent, ' ', uuid_size);
130 if (!l2cap_frame_get_be16(frame, (uint16_t *) &dst_uuid))
133 if (!l2cap_frame_get_be16(frame, (uint16_t *) &src_uuid))
137 if (!l2cap_frame_get_be32(frame, &dst_uuid))
140 if (!l2cap_frame_get_be32(frame, &src_uuid))
144 if (!l2cap_frame_get_be32(frame, &dst_uuid))
147 l2cap_frame_pull(frame, frame, 12);
149 if (!l2cap_frame_get_be32(frame, &src_uuid))
152 l2cap_frame_pull(frame, frame, 12);
155 l2cap_frame_pull(frame, frame, (uuid_size * 2));
159 print_field("%*cDst: 0x%x(%s)", indent, ' ', dst_uuid,
160 uuid32_to_str(dst_uuid));
161 print_field("%*cSrc: 0x%x(%s)", indent, ' ', src_uuid,
162 uuid32_to_str(src_uuid));
166 static const char *value2str(uint16_t value)
170 return "Operation Successful";
172 return "Operation Failed - Invalid Dst Srv UUID";
174 return "Operation Failed - Invalid Src Srv UUID";
176 return "Operation Failed - Invalid Srv UUID size";
178 return "Operation Failed - Conn not allowed";
184 static bool print_rsp_msg(struct bnep_frame *bnep_frame, uint8_t indent)
186 struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
189 if (!l2cap_frame_get_be16(frame, &rsp_msg))
192 print_field("%*cRsp msg: %s(0x%04x) ", indent, ' ',
193 value2str(rsp_msg), rsp_msg);
198 static bool filter_nettype_req(struct bnep_frame *bnep_frame, uint8_t indent)
200 struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
201 uint16_t length, start_range, end_range;
204 if (!l2cap_frame_get_be16(frame, &length))
207 print_field("%*cLength: 0x%04x", indent, ' ', length);
209 for (i = 0; i < length / 4; i++) {
211 if (!l2cap_frame_get_be16(frame, &start_range))
214 if (!l2cap_frame_get_be16(frame, &end_range))
217 print_field("%*c0x%04x - 0x%04x", indent, ' ',
218 start_range, end_range);
224 static bool filter_multaddr_req(struct bnep_frame *bnep_frame, uint8_t indent)
226 struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
228 char start_addr[20], end_addr[20];
231 if (!l2cap_frame_get_be16(frame, &length))
234 print_field("%*cLength: 0x%04x", indent, ' ', length);
236 for (i = 0; i < length / 12; i++) {
238 if (!get_macaddr(bnep_frame, start_addr))
241 if (!get_macaddr(bnep_frame, end_addr))
244 print_field("%*c%s - %s", indent, ' ', start_addr, end_addr);
250 struct bnep_control_data {
253 bool (*func) (struct bnep_frame *frame, uint8_t indent);
256 static const struct bnep_control_data bnep_control_table[] = {
257 { 0x00, "Command Not Understood", cmd_nt_understood },
258 { 0x01, "Setup Conn Req", setup_conn_req },
259 { 0x02, "Setup Conn Rsp", print_rsp_msg },
260 { 0x03, "Filter NetType Set", filter_nettype_req },
261 { 0x04, "Filter NetType Rsp", print_rsp_msg },
262 { 0x05, "Filter MultAddr Set", filter_multaddr_req },
263 { 0x06, "Filter MultAddr Rsp", print_rsp_msg },
267 static bool bnep_control(struct bnep_frame *bnep_frame,
268 uint8_t indent, int hdr_len)
271 struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
272 const struct bnep_control_data *bnep_control_data = NULL;
273 const char *type_str;
276 if (!l2cap_frame_get_u8(frame, &ctype))
279 for (i = 0; bnep_control_table[i].str; i++) {
280 if (bnep_control_table[i].type == ctype) {
281 bnep_control_data = &bnep_control_table[i];
286 if (bnep_control_data)
287 type_str = bnep_control_data->str;
289 type_str = "Unknown control type";
291 print_field("%*c%s (0x%02x) ", indent, ' ', type_str, ctype);
293 if (!bnep_control_data || !bnep_control_data->func) {
294 packet_hexdump(frame->data, hdr_len - 1);
295 l2cap_frame_pull(frame, frame, hdr_len - 1);
299 if (!bnep_control_data->func(bnep_frame, indent+2))
306 static bool bnep_compressed(struct bnep_frame *bnep_frame,
307 uint8_t indent, int hdr_len)
310 struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
312 if (!l2cap_frame_get_be16(frame, &proto))
315 print_field("%*c[proto 0x%04x] ", indent, ' ', proto);
320 static bool bnep_src_only(struct bnep_frame *bnep_frame,
321 uint8_t indent, int hdr_len)
324 struct l2cap_frame *frame;
327 if (!get_macaddr(bnep_frame, src_addr))
330 frame = &bnep_frame->l2cap_frame;
332 if (!l2cap_frame_get_be16(frame, &proto))
335 print_field("%*csrc %s [proto 0x%04x] ", indent,
336 ' ', src_addr, proto);
341 static bool bnep_dst_only(struct bnep_frame *bnep_frame,
342 uint8_t indent, int hdr_len)
345 struct l2cap_frame *frame;
348 if (!get_macaddr(bnep_frame, dest_addr))
351 frame = &bnep_frame->l2cap_frame;
353 if (!l2cap_frame_get_be16(frame, &proto))
356 print_field("%*cdst %s [proto 0x%04x] ", indent,
357 ' ', dest_addr, proto);
362 static bool bnep_eval_extension(struct bnep_frame *bnep_frame, uint8_t indent)
364 struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
365 uint8_t type, length;
368 if (!l2cap_frame_get_u8(frame, &type))
371 if (!l2cap_frame_get_u8(frame, &length))
374 extension = GET_EXTENSION(type);
375 type = GET_PKT_TYPE(type);
378 case BNEP_EXTENSION_CONTROL:
379 print_field("%*cExt Control(0x%02x|%s) len 0x%02x", indent,
380 ' ', type, extension ? "1" : "0", length);
381 if (!bnep_control(bnep_frame, indent+2, length))
386 print_field("%*cExt Unknown(0x%02x|%s) len 0x%02x", indent,
387 ' ', type, extension ? "1" : "0", length);
388 packet_hexdump(frame->data, length);
389 l2cap_frame_pull(frame, frame, length);
393 if (!bnep_eval_extension(bnep_frame, indent))
402 bool (*func) (struct bnep_frame *frame, uint8_t indent, int hdr_len);
405 static const struct bnep_data bnep_table[] = {
406 { 0x00, "General Ethernet", bnep_general },
407 { 0x01, "Control", bnep_control },
408 { 0x02, "Compressed Ethernet", bnep_compressed },
409 { 0x03, "Compressed Ethernet SrcOnly", bnep_src_only },
410 { 0x04, "Compressed Ethernet DestOnly", bnep_dst_only },
414 void bnep_packet(const struct l2cap_frame *frame)
416 uint8_t type, indent = 1;
417 struct bnep_frame bnep_frame;
418 struct l2cap_frame *l2cap_frame;
419 const struct bnep_data *bnep_data = NULL;
420 const char *pdu_color, *pdu_str;
423 l2cap_frame_pull(&bnep_frame.l2cap_frame, frame, 0);
424 l2cap_frame = &bnep_frame.l2cap_frame;
426 if (!l2cap_frame_get_u8(l2cap_frame, &type))
429 bnep_frame.extension = GET_EXTENSION(type);
430 bnep_frame.type = GET_PKT_TYPE(type);
432 for (i = 0; bnep_table[i].str; i++) {
433 if (bnep_table[i].type == bnep_frame.type) {
434 bnep_data = &bnep_table[i];
440 if (bnep_data->func) {
442 pdu_color = COLOR_MAGENTA;
444 pdu_color = COLOR_BLUE;
446 pdu_color = COLOR_WHITE_BG;
447 pdu_str = bnep_data->str;
449 pdu_color = COLOR_WHITE_BG;
450 pdu_str = "Unknown packet type";
453 print_indent(6, pdu_color, "BNEP: ", pdu_str, COLOR_OFF,
454 " (0x%02x|%s)", bnep_frame.type,
455 bnep_frame.extension ? "1" : "0");
457 if (!bnep_data || !bnep_data->func) {
458 packet_hexdump(l2cap_frame->data, l2cap_frame->size);
462 if (!bnep_data->func(&bnep_frame, indent, -1))
466 if (bnep_frame.extension)
467 if (!bnep_eval_extension(&bnep_frame, indent+2))
470 /* Control packet => No payload info */
471 if (bnep_frame.type == BNEP_CONTROL)
474 /* TODO: Handle BNEP IP packet */
475 packet_hexdump(l2cap_frame->data, l2cap_frame->size);
480 print_text(COLOR_ERROR, "frame too short");
481 packet_hexdump(frame->data, frame->size);