Blame monitor/bnep.c

Packit 34410b
/*
Packit 34410b
 *
Packit 34410b
 *  BlueZ - Bluetooth protocol stack for Linux
Packit 34410b
 *
Packit 34410b
 *  Copyright (C) 2011-2014  Intel Corporation
Packit 34410b
 *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
Packit 34410b
 *
Packit 34410b
 *
Packit 34410b
 *  This library is free software; you can redistribute it and/or
Packit 34410b
 *  modify it under the terms of the GNU Lesser General Public
Packit 34410b
 *  License as published by the Free Software Foundation; either
Packit 34410b
 *  version 2.1 of the License, or (at your option) any later version.
Packit 34410b
 *
Packit 34410b
 *  This library is distributed in the hope that it will be useful,
Packit 34410b
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 34410b
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 34410b
 *  Lesser General Public License for more details.
Packit 34410b
 *
Packit 34410b
 *  You should have received a copy of the GNU Lesser General Public
Packit 34410b
 *  License along with this library; if not, write to the Free Software
Packit 34410b
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
Packit 34410b
 *
Packit 34410b
 */
Packit 34410b
Packit 34410b
#ifdef HAVE_CONFIG_H
Packit 34410b
#include <config.h>
Packit 34410b
#endif
Packit 34410b
Packit 34410b
#define _GNU_SOURCE
Packit 34410b
#include <stdio.h>
Packit 34410b
#include <stdlib.h>
Packit 34410b
#include <string.h>
Packit 34410b
#include <ctype.h>
Packit 34410b
#include <inttypes.h>
Packit 34410b
Packit 34410b
#include "lib/bluetooth.h"
Packit 34410b
#include "lib/uuid.h"
Packit 34410b
Packit 34410b
#include "src/shared/util.h"
Packit 34410b
#include "bt.h"
Packit 34410b
#include "packet.h"
Packit 34410b
#include "display.h"
Packit 34410b
#include "l2cap.h"
Packit 34410b
#include "keys.h"
Packit 34410b
#include "sdp.h"
Packit 34410b
#include "bnep.h"
Packit 34410b
Packit 34410b
#define GET_PKT_TYPE(type) (type & 0x7f)
Packit 34410b
#define GET_EXTENSION(type) (type & 0x80)
Packit 34410b
Packit 34410b
/* BNEP Extension Type */
Packit 34410b
#define BNEP_EXTENSION_CONTROL		0x00
Packit 34410b
Packit 34410b
#define BNEP_CONTROL			0x01
Packit 34410b
Packit 34410b
uint16_t proto = 0x0000;
Packit 34410b
Packit 34410b
struct bnep_frame {
Packit 34410b
	uint8_t type;
Packit 34410b
	int extension;
Packit 34410b
	struct l2cap_frame l2cap_frame;
Packit 34410b
};
Packit 34410b
Packit 34410b
static bool get_macaddr(struct bnep_frame *bnep_frame, char *str)
Packit 34410b
{
Packit 34410b
	uint8_t addr[6];
Packit 34410b
	struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
Packit 34410b
	int i;
Packit 34410b
Packit 34410b
	for (i = 0; i < 6; i++)
Packit 34410b
		if (!l2cap_frame_get_u8(frame, &addr[i]))
Packit 34410b
			return false;
Packit 34410b
Packit 34410b
	sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
Packit 34410b
		addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
Packit 34410b
Packit 34410b
	return true;
Packit 34410b
}
Packit 34410b
Packit 34410b
static bool bnep_general(struct bnep_frame *bnep_frame,
Packit 34410b
					uint8_t indent,	int hdr_len)
Packit 34410b
{
Packit 34410b
	struct l2cap_frame *frame;
Packit 34410b
	char src_addr[20], dest_addr[20];
Packit 34410b
Packit 34410b
	if (!get_macaddr(bnep_frame, dest_addr))
Packit 34410b
		return false;
Packit 34410b
Packit 34410b
	if (!get_macaddr(bnep_frame, src_addr))
Packit 34410b
		return false;
Packit 34410b
Packit 34410b
	frame = &bnep_frame->l2cap_frame;
Packit 34410b
Packit 34410b
	if (!l2cap_frame_get_be16(frame, &proto))
Packit 34410b
		return false;
Packit 34410b
Packit 34410b
	print_field("%*cdst %s src %s [proto 0x%04x] ", indent,
Packit 34410b
					' ', dest_addr, src_addr, proto);
Packit 34410b
Packit 34410b
	return true;
Packit 34410b
Packit 34410b
}
Packit 34410b
Packit 34410b
static bool cmd_nt_understood(struct bnep_frame *bnep_frame, uint8_t indent)
Packit 34410b
{
Packit 34410b
	struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
Packit 34410b
	uint8_t ptype;
Packit 34410b
Packit 34410b
	if (!l2cap_frame_get_u8(frame, &ptype))
Packit 34410b
		return false;
Packit 34410b
Packit 34410b
	print_field("%*cType: 0x%02x ", indent, ' ', ptype);
Packit 34410b
Packit 34410b
	return true;
Packit 34410b
}
Packit 34410b
Packit 34410b
static bool setup_conn_req(struct bnep_frame *bnep_frame, uint8_t indent)
Packit 34410b
{
Packit 34410b
Packit 34410b
	struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
Packit 34410b
	uint8_t uuid_size;
Packit 34410b
	uint32_t src_uuid = 0, dst_uuid = 0;
Packit 34410b
Packit 34410b
	if (!l2cap_frame_get_u8(frame, &uuid_size))
Packit 34410b
		return false;
Packit 34410b
Packit 34410b
	print_field("%*cSize: 0x%02x ", indent, ' ', uuid_size);
Packit 34410b
Packit 34410b
	switch (uuid_size) {
Packit 34410b
	case 2:
Packit 34410b
		if (!l2cap_frame_get_be16(frame, (uint16_t *) &dst_uuid))
Packit 34410b
			return false;
Packit 34410b
Packit 34410b
		if (!l2cap_frame_get_be16(frame, (uint16_t *) &src_uuid))
Packit 34410b
			return false;
Packit 34410b
		break;
Packit 34410b
	case 4:
Packit 34410b
		if (!l2cap_frame_get_be32(frame, &dst_uuid))
Packit 34410b
			return false;
Packit 34410b
Packit 34410b
		if (!l2cap_frame_get_be32(frame, &src_uuid))
Packit 34410b
			return false;
Packit 34410b
		break;
Packit 34410b
	case 16:
Packit 34410b
		if (!l2cap_frame_get_be32(frame, &dst_uuid))
Packit 34410b
			return false;
Packit 34410b
Packit 34410b
		l2cap_frame_pull(frame, frame, 12);
Packit 34410b
Packit 34410b
		if (!l2cap_frame_get_be32(frame, &src_uuid))
Packit 34410b
			return false;
Packit 34410b
Packit 34410b
		l2cap_frame_pull(frame, frame, 12);
Packit 34410b
		break;
Packit 34410b
	default:
Packit 34410b
		l2cap_frame_pull(frame, frame, (uuid_size * 2));
Packit 34410b
		return true;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	print_field("%*cDst: 0x%x(%s)", indent, ' ', dst_uuid,
Packit 34410b
						bt_uuid32_to_str(dst_uuid));
Packit 34410b
	print_field("%*cSrc: 0x%x(%s)", indent, ' ', src_uuid,
Packit 34410b
						bt_uuid32_to_str(src_uuid));
Packit 34410b
	return true;
Packit 34410b
}
Packit 34410b
Packit 34410b
static const char *value2str(uint16_t value)
Packit 34410b
{
Packit 34410b
	switch (value) {
Packit 34410b
	case 0x00:
Packit 34410b
		return "Operation Successful";
Packit 34410b
	case 0x01:
Packit 34410b
		return "Operation Failed - Invalid Dst Srv UUID";
Packit 34410b
	case 0x02:
Packit 34410b
		return "Operation Failed - Invalid Src Srv UUID";
Packit 34410b
	case 0x03:
Packit 34410b
		return "Operation Failed - Invalid Srv UUID size";
Packit 34410b
	case 0x04:
Packit 34410b
		return "Operation Failed - Conn not allowed";
Packit 34410b
	default:
Packit 34410b
		return "Unknown";
Packit 34410b
	}
Packit 34410b
}
Packit 34410b
Packit 34410b
static bool print_rsp_msg(struct bnep_frame *bnep_frame, uint8_t indent)
Packit 34410b
{
Packit 34410b
	struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
Packit 34410b
	uint16_t rsp_msg;
Packit 34410b
Packit 34410b
	if (!l2cap_frame_get_be16(frame, &rsp_msg))
Packit 34410b
		return false;
Packit 34410b
Packit 34410b
	print_field("%*cRsp msg: %s(0x%04x) ", indent, ' ',
Packit 34410b
					value2str(rsp_msg), rsp_msg);
Packit 34410b
Packit 34410b
	return true;
Packit 34410b
}
Packit 34410b
Packit 34410b
static bool filter_nettype_req(struct bnep_frame *bnep_frame, uint8_t indent)
Packit 34410b
{
Packit 34410b
	struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
Packit 34410b
	uint16_t length, start_range, end_range;
Packit 34410b
	int i;
Packit 34410b
Packit 34410b
	if (!l2cap_frame_get_be16(frame, &length))
Packit 34410b
		return false;
Packit 34410b
Packit 34410b
	print_field("%*cLength: 0x%04x", indent, ' ', length);
Packit 34410b
Packit 34410b
	for (i = 0; i < length / 4; i++) {
Packit 34410b
Packit 34410b
		if (!l2cap_frame_get_be16(frame, &start_range))
Packit 34410b
			return false;
Packit 34410b
Packit 34410b
		if (!l2cap_frame_get_be16(frame, &end_range))
Packit 34410b
			return false;
Packit 34410b
Packit 34410b
		print_field("%*c0x%04x - 0x%04x", indent, ' ',
Packit 34410b
						start_range, end_range);
Packit 34410b
	}
Packit 34410b
Packit 34410b
	return true;
Packit 34410b
}
Packit 34410b
Packit 34410b
static bool filter_multaddr_req(struct bnep_frame *bnep_frame, uint8_t indent)
Packit 34410b
{
Packit 34410b
	struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
Packit 34410b
	uint16_t length;
Packit 34410b
	char start_addr[20], end_addr[20];
Packit 34410b
	int i;
Packit 34410b
Packit 34410b
	if (!l2cap_frame_get_be16(frame, &length))
Packit 34410b
		return false;
Packit 34410b
Packit 34410b
	print_field("%*cLength: 0x%04x", indent, ' ', length);
Packit 34410b
Packit 34410b
	for (i = 0; i < length / 12; i++) {
Packit 34410b
Packit 34410b
		if (!get_macaddr(bnep_frame, start_addr))
Packit 34410b
			return false;
Packit 34410b
Packit 34410b
		if (!get_macaddr(bnep_frame, end_addr))
Packit 34410b
			return false;
Packit 34410b
Packit 34410b
		print_field("%*c%s - %s", indent, ' ', start_addr, end_addr);
Packit 34410b
	}
Packit 34410b
Packit 34410b
	return true;
Packit 34410b
}
Packit 34410b
Packit 34410b
struct bnep_control_data {
Packit 34410b
	uint8_t type;
Packit 34410b
	const char *str;
Packit 34410b
	bool (*func) (struct bnep_frame *frame, uint8_t indent);
Packit 34410b
};
Packit 34410b
Packit 34410b
static const struct bnep_control_data bnep_control_table[] = {
Packit 34410b
	{ 0x00, "Command Not Understood",	cmd_nt_understood	},
Packit 34410b
	{ 0x01, "Setup Conn Req",		setup_conn_req		},
Packit 34410b
	{ 0x02, "Setup Conn Rsp",		print_rsp_msg		},
Packit 34410b
	{ 0x03, "Filter NetType Set",		filter_nettype_req	},
Packit 34410b
	{ 0x04, "Filter NetType Rsp",		print_rsp_msg		},
Packit 34410b
	{ 0x05, "Filter MultAddr Set",		filter_multaddr_req	},
Packit 34410b
	{ 0x06, "Filter MultAddr Rsp",		print_rsp_msg		},
Packit 34410b
	{ }
Packit 34410b
};
Packit 34410b
Packit 34410b
static bool bnep_control(struct bnep_frame *bnep_frame,
Packit 34410b
					uint8_t indent,	int hdr_len)
Packit 34410b
{
Packit 34410b
	uint8_t ctype;
Packit 34410b
	struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
Packit 34410b
	const struct bnep_control_data *bnep_control_data = NULL;
Packit 34410b
	const char *type_str;
Packit 34410b
	int i;
Packit 34410b
Packit 34410b
	if (!l2cap_frame_get_u8(frame, &ctype))
Packit 34410b
		return false;
Packit 34410b
Packit 34410b
	for (i = 0; bnep_control_table[i].str; i++) {
Packit 34410b
		if (bnep_control_table[i].type == ctype) {
Packit 34410b
			bnep_control_data = &bnep_control_table[i];
Packit 34410b
			break;
Packit 34410b
		}
Packit 34410b
	}
Packit 34410b
Packit 34410b
	if (bnep_control_data)
Packit 34410b
		type_str = bnep_control_data->str;
Packit 34410b
	else
Packit 34410b
		type_str = "Unknown control type";
Packit 34410b
Packit 34410b
	print_field("%*c%s (0x%02x) ", indent, ' ', type_str, ctype);
Packit 34410b
Packit 34410b
	if (!bnep_control_data || !bnep_control_data->func) {
Packit 34410b
		packet_hexdump(frame->data, hdr_len - 1);
Packit 34410b
		l2cap_frame_pull(frame, frame, hdr_len - 1);
Packit 34410b
		goto done;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	if (!bnep_control_data->func(bnep_frame, indent+2))
Packit 34410b
		return false;
Packit 34410b
Packit 34410b
done:
Packit 34410b
	return true;
Packit 34410b
}
Packit 34410b
Packit 34410b
static bool bnep_compressed(struct bnep_frame *bnep_frame,
Packit 34410b
					uint8_t indent,	int hdr_len)
Packit 34410b
{
Packit 34410b
Packit 34410b
	struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
Packit 34410b
Packit 34410b
	if (!l2cap_frame_get_be16(frame, &proto))
Packit 34410b
		return false;
Packit 34410b
Packit 34410b
	print_field("%*c[proto 0x%04x] ", indent, ' ', proto);
Packit 34410b
Packit 34410b
	return true;
Packit 34410b
}
Packit 34410b
Packit 34410b
static bool bnep_src_only(struct bnep_frame *bnep_frame,
Packit 34410b
					uint8_t indent,	int hdr_len)
Packit 34410b
{
Packit 34410b
Packit 34410b
	struct l2cap_frame *frame;
Packit 34410b
	char src_addr[20];
Packit 34410b
Packit 34410b
	if (!get_macaddr(bnep_frame, src_addr))
Packit 34410b
		return false;
Packit 34410b
Packit 34410b
	frame = &bnep_frame->l2cap_frame;
Packit 34410b
Packit 34410b
	if (!l2cap_frame_get_be16(frame, &proto))
Packit 34410b
		return false;
Packit 34410b
Packit 34410b
	print_field("%*csrc %s [proto 0x%04x] ", indent,
Packit 34410b
					' ', src_addr, proto);
Packit 34410b
Packit 34410b
	return true;
Packit 34410b
}
Packit 34410b
Packit 34410b
static bool bnep_dst_only(struct bnep_frame *bnep_frame,
Packit 34410b
					uint8_t indent,	int hdr_len)
Packit 34410b
{
Packit 34410b
Packit 34410b
	struct l2cap_frame *frame;
Packit 34410b
	char dest_addr[20];
Packit 34410b
Packit 34410b
	if (!get_macaddr(bnep_frame, dest_addr))
Packit 34410b
		return false;
Packit 34410b
Packit 34410b
	frame = &bnep_frame->l2cap_frame;
Packit 34410b
Packit 34410b
	if (!l2cap_frame_get_be16(frame, &proto))
Packit 34410b
		return false;
Packit 34410b
Packit 34410b
	print_field("%*cdst %s [proto 0x%04x] ", indent,
Packit 34410b
					' ', dest_addr, proto);
Packit 34410b
Packit 34410b
	return true;
Packit 34410b
}
Packit 34410b
Packit 34410b
static bool bnep_eval_extension(struct bnep_frame *bnep_frame, uint8_t indent)
Packit 34410b
{
Packit 34410b
	struct l2cap_frame *frame = &bnep_frame->l2cap_frame;
Packit 34410b
	uint8_t type, length;
Packit 34410b
	int extension;
Packit 34410b
Packit 34410b
	if (!l2cap_frame_get_u8(frame, &type))
Packit 34410b
		return false;
Packit 34410b
Packit 34410b
	if (!l2cap_frame_get_u8(frame, &length))
Packit 34410b
		return false;
Packit 34410b
Packit 34410b
	extension = GET_EXTENSION(type);
Packit 34410b
	type = GET_PKT_TYPE(type);
Packit 34410b
Packit 34410b
	switch (type) {
Packit 34410b
	case BNEP_EXTENSION_CONTROL:
Packit 34410b
		print_field("%*cExt Control(0x%02x|%s) len 0x%02x", indent,
Packit 34410b
				' ', type, extension ? "1" : "0", length);
Packit 34410b
		if (!bnep_control(bnep_frame, indent+2, length))
Packit 34410b
			return false;
Packit 34410b
		break;
Packit 34410b
Packit 34410b
	default:
Packit 34410b
		print_field("%*cExt Unknown(0x%02x|%s) len 0x%02x", indent,
Packit 34410b
				' ', type, extension ? "1" : "0", length);
Packit 34410b
		packet_hexdump(frame->data, length);
Packit 34410b
		l2cap_frame_pull(frame, frame, length);
Packit 34410b
	}
Packit 34410b
Packit 34410b
	if (extension)
Packit 34410b
		if (!bnep_eval_extension(bnep_frame, indent))
Packit 34410b
			return false;
Packit 34410b
Packit 34410b
	return true;
Packit 34410b
}
Packit 34410b
Packit 34410b
struct bnep_data {
Packit 34410b
	uint8_t type;
Packit 34410b
	const char *str;
Packit 34410b
	bool (*func) (struct bnep_frame *frame, uint8_t indent, int hdr_len);
Packit 34410b
};
Packit 34410b
Packit 34410b
static const struct bnep_data bnep_table[] = {
Packit 34410b
	{ 0x00, "General Ethernet",		bnep_general	},
Packit 34410b
	{ 0x01, "Control",			bnep_control	},
Packit 34410b
	{ 0x02, "Compressed Ethernet",		bnep_compressed	},
Packit 34410b
	{ 0x03, "Compressed Ethernet SrcOnly",	bnep_src_only	},
Packit 34410b
	{ 0x04, "Compressed Ethernet DestOnly",	bnep_dst_only	},
Packit 34410b
	{ }
Packit 34410b
};
Packit 34410b
Packit 34410b
void bnep_packet(const struct l2cap_frame *frame)
Packit 34410b
{
Packit 34410b
	uint8_t type, indent = 1;
Packit 34410b
	struct bnep_frame bnep_frame;
Packit 34410b
	struct l2cap_frame *l2cap_frame;
Packit 34410b
	const struct bnep_data *bnep_data = NULL;
Packit 34410b
	const char *pdu_color, *pdu_str;
Packit 34410b
	int i;
Packit 34410b
Packit 34410b
	l2cap_frame_pull(&bnep_frame.l2cap_frame, frame, 0);
Packit 34410b
	l2cap_frame = &bnep_frame.l2cap_frame;
Packit 34410b
Packit 34410b
	if (!l2cap_frame_get_u8(l2cap_frame, &type))
Packit 34410b
		goto fail;
Packit 34410b
Packit 34410b
	bnep_frame.extension = GET_EXTENSION(type);
Packit 34410b
	bnep_frame.type = GET_PKT_TYPE(type);
Packit 34410b
Packit 34410b
	for (i = 0; bnep_table[i].str; i++) {
Packit 34410b
		if (bnep_table[i].type == bnep_frame.type) {
Packit 34410b
			bnep_data = &bnep_table[i];
Packit 34410b
			break;
Packit 34410b
		}
Packit 34410b
	}
Packit 34410b
Packit 34410b
	if (bnep_data) {
Packit 34410b
		if (bnep_data->func) {
Packit 34410b
			if (frame->in)
Packit 34410b
				pdu_color = COLOR_MAGENTA;
Packit 34410b
			else
Packit 34410b
				pdu_color = COLOR_BLUE;
Packit 34410b
		} else
Packit 34410b
			pdu_color = COLOR_WHITE_BG;
Packit 34410b
		pdu_str = bnep_data->str;
Packit 34410b
	} else {
Packit 34410b
		pdu_color = COLOR_WHITE_BG;
Packit 34410b
		pdu_str = "Unknown packet type";
Packit 34410b
	}
Packit 34410b
Packit 34410b
	print_indent(6, pdu_color, "BNEP: ", pdu_str, COLOR_OFF,
Packit 34410b
				" (0x%02x|%s)", bnep_frame.type,
Packit 34410b
				bnep_frame.extension ? "1" : "0");
Packit 34410b
Packit 34410b
	if (!bnep_data || !bnep_data->func) {
Packit 34410b
		packet_hexdump(l2cap_frame->data, l2cap_frame->size);
Packit 34410b
		return;
Packit 34410b
	}
Packit 34410b
Packit 34410b
	if (!bnep_data->func(&bnep_frame, indent, -1))
Packit 34410b
		goto fail;
Packit 34410b
Packit 34410b
	/* Extension info */
Packit 34410b
	if (bnep_frame.extension)
Packit 34410b
		if (!bnep_eval_extension(&bnep_frame, indent+2))
Packit 34410b
			goto fail;
Packit 34410b
Packit 34410b
	/* Control packet => No payload info */
Packit 34410b
	if (bnep_frame.type == BNEP_CONTROL)
Packit 34410b
		return;
Packit 34410b
Packit 34410b
	/* TODO: Handle BNEP IP packet */
Packit 34410b
	packet_hexdump(l2cap_frame->data, l2cap_frame->size);
Packit 34410b
Packit 34410b
	return;
Packit 34410b
Packit 34410b
fail:
Packit 34410b
	print_text(COLOR_ERROR, "frame too short");
Packit 34410b
	packet_hexdump(frame->data, frame->size);
Packit 34410b
}