* [RFC][PATCH 1/2] Implement broadcom patchram firmware loader
From: Jesse Sung @ 2012-08-14 14:24 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <cover.1344952391.git.jesse.sung@canonical.com>
[-- Attachment #1: Type: text/plain, Size: 44 bytes --]
This is a multi-part message in MIME format.
[-- Attachment #2: Type: text/plain, Size: 200 bytes --]
Signed-off-by: Wen-chien Jesse Sung <jesse.sung@canonical.com>
---
drivers/bluetooth/btusb.c | 109 ++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 103 insertions(+), 6 deletions(-)
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0001-Implement-broadcom-patchram-firmware-loader.patch --]
[-- Type: text/x-patch; name="0001-Implement-broadcom-patchram-firmware-loader.patch", Size: 5096 bytes --]
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index cef3bac..b60a2ae 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -23,6 +23,8 @@
#include <linux/module.h>
#include <linux/usb.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -47,6 +49,7 @@ static struct usb_driver btusb_driver;
#define BTUSB_BROKEN_ISOC 0x20
#define BTUSB_WRONG_SCO_MTU 0x40
#define BTUSB_ATH3012 0x80
+#define BTUSB_BCM_PATCHRAM 0x100
static struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */
@@ -93,13 +96,16 @@ static struct usb_device_id btusb_table[] = {
{ USB_DEVICE(0x0c10, 0x0000) },
/* Broadcom BCM20702A0 */
+ { USB_DEVICE(0x0489, 0xe031), .driver_info = BTUSB_BCM_PATCHRAM },
{ USB_DEVICE(0x0489, 0xe042) },
+ { USB_DEVICE(0x0a5c, 0x21d3), .driver_info = BTUSB_BCM_PATCHRAM },
+ { USB_DEVICE(0x0a5c, 0x21d7), .driver_info = BTUSB_BCM_PATCHRAM },
{ USB_DEVICE(0x0a5c, 0x21e3) },
- { USB_DEVICE(0x0a5c, 0x21e6) },
+ { USB_DEVICE(0x0a5c, 0x21e6), .driver_info = BTUSB_BCM_PATCHRAM },
{ USB_DEVICE(0x0a5c, 0x21e8) },
- { USB_DEVICE(0x0a5c, 0x21f3) },
- { USB_DEVICE(0x0a5c, 0x21f4) },
- { USB_DEVICE(0x413c, 0x8197) },
+ { USB_DEVICE(0x0a5c, 0x21f3), .driver_info = BTUSB_BCM_PATCHRAM },
+ { USB_DEVICE(0x0a5c, 0x21f4), .driver_info = BTUSB_BCM_PATCHRAM },
+ { USB_DEVICE(0x413c, 0x8197), .driver_info = BTUSB_BCM_PATCHRAM },
/* Foxconn - Hon Hai */
{ USB_DEVICE(0x0489, 0xe033) },
@@ -195,6 +201,37 @@ static struct usb_device_id blacklist_table[] = {
{ } /* Terminating entry */
};
+#define PATCHRAM_TIMEOUT 1000
+#define FW_0489_E031 "fw-0489_e031.hcd"
+#define FW_0A5C_21D3 "fw-0a5c_21d3.hcd"
+#define FW_0A5C_21D7 "fw-0a5c_21d7.hcd"
+#define FW_0A5C_21E6 "fw-0a5c_21e6.hcd"
+#define FW_0A5C_21F3 "fw-0a5c_21f3.hcd"
+#define FW_0A5C_21F4 "fw-0a5c_21f4.hcd"
+#define FW_413C_8197 "fw-413c_8197.hcd"
+
+MODULE_FIRMWARE(FW_0489_E031);
+MODULE_FIRMWARE(FW_0A5C_21D3);
+MODULE_FIRMWARE(FW_0A5C_21D7);
+MODULE_FIRMWARE(FW_0A5C_21E6);
+MODULE_FIRMWARE(FW_0A5C_21F3);
+MODULE_FIRMWARE(FW_0A5C_21F4);
+MODULE_FIRMWARE(FW_413C_8197);
+
+static struct usb_device_id patchram_table[] = {
+ /* Dell DW1704 */
+ { USB_DEVICE(0x0a5c, 0x21d3), .driver_info = (kernel_ulong_t) FW_0A5C_21D3 },
+ { USB_DEVICE(0x0a5c, 0x21d7), .driver_info = (kernel_ulong_t) FW_0A5C_21D7 },
+ /* Dell DW380 */
+ { USB_DEVICE(0x413c, 0x8197), .driver_info = (kernel_ulong_t) FW_413C_8197 },
+ /* FoxConn Hon Hai */
+ { USB_DEVICE(0x0489, 0xe031), .driver_info = (kernel_ulong_t) FW_0489_E031 },
+ /* Lenovo */
+ { USB_DEVICE(0x0a5c, 0x21e6), .driver_info = (kernel_ulong_t) FW_0A5C_21E6 },
+ { USB_DEVICE(0x0a5c, 0x21f3), .driver_info = (kernel_ulong_t) FW_0A5C_21F3 },
+ { USB_DEVICE(0x0a5c, 0x21f4), .driver_info = (kernel_ulong_t) FW_0A5C_21F4 },
+};
+
#define BTUSB_MAX_ISOC_FRAMES 10
#define BTUSB_INTR_RUNNING 0
@@ -912,6 +949,55 @@ static void btusb_waker(struct work_struct *work)
usb_autopm_put_interface(data->intf);
}
+static inline void load_patchram_fw(struct usb_device *udev, const struct usb_device_id *id)
+{
+ size_t pos = 0;
+ int err = 0;
+ const struct firmware *fw;
+
+ unsigned char reset_cmd[] = { 0x03, 0x0c, 0x00 };
+ unsigned char download_cmd[] = { 0x2e, 0xfc, 0x00 };
+
+ if (request_firmware(&fw, (const char *) id->driver_info, &udev->dev) < 0) {
+ BT_INFO("can't load firmware, may not work correctly");
+ return;
+ }
+
+ if (usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0, USB_TYPE_CLASS, 0, 0,
+ reset_cmd, sizeof(reset_cmd), PATCHRAM_TIMEOUT) < 0) {
+ err = -1;
+ goto out;
+ }
+ msleep(300);
+
+ if (usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0, USB_TYPE_CLASS, 0, 0,
+ download_cmd, sizeof(download_cmd), PATCHRAM_TIMEOUT) < 0) {
+ err = -1;
+ goto out;
+ }
+ msleep(300);
+
+ while (pos < fw->size) {
+ size_t len;
+ len = fw->data[pos + 2] + 3;
+ if ((pos + len > fw->size) ||
+ (usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0,
+ USB_TYPE_CLASS, 0, 0, (void *)fw->data + pos, len,
+ PATCHRAM_TIMEOUT) < 0)) {
+ err = -1;
+ goto out;
+ }
+ pos += len;
+ }
+
+ err = (usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0, USB_TYPE_CLASS, 0, 0,
+ reset_cmd, sizeof(reset_cmd), PATCHRAM_TIMEOUT) < 0);
+out:
+ if (err)
+ BT_INFO("fail to load firmware, may not work correctly");
+ release_firmware(fw);
+}
+
static int btusb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
@@ -1076,15 +1162,26 @@ static int btusb_probe(struct usb_interface *intf,
}
}
+ usb_set_intfdata(intf, data);
+
+ if (id->driver_info & BTUSB_BCM_PATCHRAM) {
+ const struct usb_device_id *match;
+ match = usb_match_id(intf, patchram_table);
+ if (match) {
+ btusb_open(hdev);
+ load_patchram_fw(interface_to_usbdev(intf), match);
+ btusb_close(hdev);
+ }
+ }
+
err = hci_register_dev(hdev);
if (err < 0) {
hci_free_dev(hdev);
+ usb_set_intfdata(intf, NULL);
kfree(data);
return err;
}
- usb_set_intfdata(intf, data);
-
return 0;
}
^ permalink raw reply related
* [RFC][PATCH 0/2] broadcom patchram firmware loader
From: Jesse Sung @ 2012-08-14 14:24 UTC (permalink / raw)
To: linux-bluetooth
[-- Attachment #1: Type: text/plain, Size: 44 bytes --]
This is a multi-part message in MIME format.
[-- Attachment #2: Type: text/plain, Size: 937 bytes --]
There is a user space firmware loading tool which can be found at
http://article.gmane.org/gmane.linux.bluez.kernel/17932
This tool requires hci device to do the firmware loading, but this
may cause some race condition between patchram tool and bluetoothd
or something that also works on hci interface.
Also it needs some hooks to make firmware loads after bootup, s3,
s4, rfkill, and device hotplug events. Implement this loader in kernel
module would make things more easier.
Wen-chien Jesse Sung (2):
Implement broadcom patchram firmware loader
Cache firmware images for later use
drivers/bluetooth/btusb.c | 154 ++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 147 insertions(+), 7 deletions(-)
--
1.7.9.5
--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH BlueZ v0] gdbus: Fix compilation error if macro "error" is defined
From: Jaganath Kanakkassery @ 2012-08-14 14:24 UTC (permalink / raw)
To: Lucas De Marchi; +Cc: linux-bluetooth
In-Reply-To: <CAMOw1v6_boNFVPeuujtzMp409Spd0cPV6-kxmvN31+W9TdgQpg@mail.gmail.com>
Hi,
--------------------------------------------------
From: "Lucas De Marchi" <lucas.demarchi@profusion.mobi>
Sent: Monday, August 13, 2012 7:33 PM
To: "Jaganath Kanakkassery" <jaganath.k@samsung.com>
Cc: <linux-bluetooth@vger.kernel.org>
Subject: Re: [PATCH BlueZ v0] gdbus: Fix compilation error if macro "error"
is defined
> On Wed, Aug 1, 2012 at 7:26 AM, Jaganath Kanakkassery
> <jaganath.k@samsung.com> wrote:
>> The variable "signature" used in error is not defined.
>> ---
>> v0 -> Made error message as per Lucas's suggestion
>>
>> gdbus/object.c | 4 ++--
>> 1 files changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/gdbus/object.c b/gdbus/object.c
>> index 900e7ab..9689006 100644
>> --- a/gdbus/object.c
>> +++ b/gdbus/object.c
>> @@ -645,8 +645,8 @@ static dbus_bool_t emit_signal_valist(DBusConnection
>> *conn,
>> goto fail;
>>
>> if (g_dbus_args_have_signature(args, signal) == FALSE) {
>> - error("%s.%s: expected signature'%s' but got '%s'",
>> - interface, name, args, signature);
>> + error("%s.%s: got unexpected signature '%s'", interface,
>> name,
>> +
>> dbus_message_get_signature(signal));
>> ret = FALSE;
>> goto fail;
>
> Ack.
>
> Lucas De Marchi
> --
Ping.
Thanks,
Jaganath
^ permalink raw reply
* Re: [PATCH] input: Implement idle timeout for fakehid
From: Jeff Hansen @ 2012-08-14 12:51 UTC (permalink / raw)
To: Bastien Nocera; +Cc: linux-bluetooth
In-Reply-To: <1344937850.2733.2.camel@novo.hadess.net>
On 08/14/12 03:50, Bastien Nocera wrote:
> On Mon, 2012-08-13 at 11:40 -0600, Jeff Hansen wrote:
>> (bump)
>>
>> The batteries on my BD remote would die in a few days without this
>> patch. The idle timeout needs to be enforced for fakehid devices as
>> well as normal HID devices.
> Except that the timeout is disabled by default for HID devices. I posted
> a patch that requires a little bit of work to get pushed last month or
> so.
>
Yes, of course it is disabled by default (which I don't understand, but
that's a separate issue). That is fine, but if a general timeout *is*
specified by the user, it should carry into fakehid devices as well as
normal HID devices.
Are there any bluez maintainers that can take a look at this patch?
Anything that needs to change?
-Jeff
--
---------------------------------------------------
"If someone's gotta do it, it might as well be me."
x@jeffhansen.com
^ permalink raw reply
* Re: sdp.h correction and update
From: Johan Hedberg @ 2012-08-14 11:44 UTC (permalink / raw)
To: Zoltan Csik; +Cc: linux-bluetooth
In-Reply-To: <CANM+e8yPJhe1anFTsTQYqmQf2k8BfRTgKrhsNkaWrRVdG=ybkA@mail.gmail.com>
Hi Zoltan,
On Tue, Jul 24, 2012, Zoltan Csik wrote:
> bluez-4.99\lib\sdp.h
> Line 98: #define VIDEO_CONF_SVCLASS_ID 0x110f
>
> doesn't match with the latest SIG assigned numbers list:
> "A/V_RemoteControlController 0x110F Audio/Video Remote Control Profile
> (AVRCP) Service Class NOTE: The AVRCP specification v1.3 and later
> require that 0x110E also be included in the ServiceClassIDList before
> 0x110F for backwards compatibility. "
>
> Also according to above referenced list there are some service
> class_ID definitions missing from sdp.h:
> Headset - HS 0x1131 Headset Profile (HSP)
> Message Access Server 0x1132 Message Access Profile (MAP)
> Message Notification Server 0x1133 Message Access Profile (MAP)
> Message Access Profile 0x1134 Message Access Profile (MAP)
> GNSS 0x1135 Global Navigation Satellite System
> Profile (GNSS)
> GNSS_Server 0x1136 Global Navigation Satellite System
> Profile (GNSS)
Could you send these fixes as proper git patches (git format-patch and
git send-email).
Johan
^ permalink raw reply
* Re: [PATCH BlueZ] mgmt: Add LE scanning callback
From: Johan Hedberg @ 2012-08-14 10:30 UTC (permalink / raw)
To: João Paulo Rechi Vita, linux-bluetooth, Claudio Takahasi
In-Reply-To: <20120814093605.GA5352@x220>
Hi,
On Tue, Aug 14, 2012, Johan Hedberg wrote:
> On Fri, Aug 03, 2012, João Paulo Rechi Vita wrote:
> > From: Claudio Takahasi <claudio.takahasi@openbossa.org>
> >
> > This patch adds a new callback to allow the adapter to control LE
> > scanning. The current approach uses the active scanning with default
> > windows and intervals defined by the core spec without any filtering.
> > ---
> > src/mgmt.c | 32 ++++++++++++++++++++++++++++++++
> > src/mgmt.h | 1 +
> > 2 files changed, 33 insertions(+)
> >
> > diff --git a/src/mgmt.c b/src/mgmt.c
> > index 8ae86d3..5ceeaa8 100644
> > --- a/src/mgmt.c
> > +++ b/src/mgmt.c
> > @@ -1999,6 +1999,38 @@ int mgmt_start_discovery(int index)
> > return 0;
> > }
> >
> > +int mgmt_start_scanning(int index)
> > +{
> > + char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_start_discovery)];
> > + struct mgmt_hdr *hdr = (void *) buf;
> > + struct mgmt_cp_start_discovery *cp = (void *) &buf[sizeof(*hdr)];
> > + struct controller_info *info = &controllers[index];
> > +
> > + DBG("index %d", index);
> > +
> > + info->discov_type = 0;
> > +
> > + if (mgmt_low_energy(info->current_settings)) {
> > + hci_set_bit(BDADDR_LE_PUBLIC, &info->discov_type);
> > + hci_set_bit(BDADDR_LE_RANDOM, &info->discov_type);
> > + }
>
> Shouldn't you just return an error here (e.g. -ENOTSUP) if LE is not
> supported/enabled?
>
> Have there been any patches sent that would use this API? At least I
> didn't see any after a quick scan of the mailing list.
I see that these users are part of the original thread sent on Jul 27th.
I got confused since you renamed the subjects in a way that there was no
other indication to the original thread except the References: header.
The point about returning an error still remains though.
Johan
^ permalink raw reply
* Re: [PATCH BlueZ] mgmt: print error message when start_discovery fails
From: Johan Hedberg @ 2012-08-14 10:28 UTC (permalink / raw)
To: João Paulo Rechi Vita, linux-bluetooth
In-Reply-To: <20120814094010.GB5352@x220>
Hi,
On Tue, Aug 14, 2012, Johan Hedberg wrote:
> On Fri, Aug 03, 2012, João Paulo Rechi Vita wrote:
> > If we fail to communicate with the MGMT socket is better to print the
> > error message on the mgmtops plugin, where it really happened, instead
> > of leaving this job to its users.
> > ---
> > src/adapter.c | 6 +-----
> > src/mgmt.c | 7 +++++--
> > 2 files changed, 6 insertions(+), 7 deletions(-)
>
> How do these two patches differ from patches 02/14 and 07/14 of the
> patch set that was sent on July 27th? Why were these two patches resent
> separately? A cover letter would have been quite useful here.
Nevermind. I see that they reference the original thread and are
probably updates based on received comments. Anyway, it would have been
clearer if you'd have added "v2" to the subject and kept the xx/yy
numbering.
Johan
^ permalink raw reply
* Re: [PATCH RESEND] Bluetooth: Add support for Apple MacBook Pro 9,2
From: Shea Levy @ 2012-08-14 10:25 UTC (permalink / raw)
To: linux-bluetooth@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, Johan Hedberg, Gustavo Padovan,
Marcel Holtmann, Shea Levy
In-Reply-To: <1344374463-21231-1-git-send-email-shea@shealevy.com>
Hi all,
Is there a problem with this patch?
Thanks,
Shea
On Aug 7, 2012, at 5:21 PM, Shea Levy <shea@shealevy.com> wrote:
> $ usb-devices
> <snip>
> T: Bus=3D04 Lev=3D04 Prnt=3D04 Port=3D02 Cnt=3D01 Dev#=3D 9 Spd=3D12 Mx=
Ch=3D 0
> D: Ver=3D 2.00 Cls=3Dff(vend.) Sub=3D01 Prot=3D01 MxPS=3D64 #Cfgs=3D 1
> P: Vendor=3D05ac ProdID=3D821d Rev=3D00.86
> S: Manufacturer=3DApple Inc.
> S: Product=3DBluetooth USB Host Controller
> C: #Ifs=3D 4 Cfg#=3D 1 Atr=3De0 MxPwr=3D0mA
> I: If#=3D 0 Alt=3D 0 #EPs=3D 3 Cls=3Dff(vend.) Sub=3D01 Prot=3D01 Driver=3D=
btusb
> I: If#=3D 1 Alt=3D 0 #EPs=3D 2 Cls=3De0(wlcon) Sub=3D01 Prot=3D01 Driver=3D=
btusb
> I: If#=3D 2 Alt=3D 0 #EPs=3D 2 Cls=3Dff(vend.) Sub=3Dff Prot=3Dff Driver=3D=
(none)
> I: If#=3D 3 Alt=3D 0 #EPs=3D 0 Cls=3Dfe(app. ) Sub=3D01 Prot=3D01 Driver=3D=
(none)
> <snip>
>=20
> Signed-off-by: Shea Levy <shea@shealevy.com>
> ---
> drivers/bluetooth/btusb.c | 3 +++
> 1 file changed, 3 insertions(+)
>=20
> diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
> index f637c25..038acc7 100644
> --- a/drivers/bluetooth/btusb.c
> +++ b/drivers/bluetooth/btusb.c
> @@ -73,6 +73,9 @@ static struct usb_device_id btusb_table[] =3D {
> /* Apple MacBookPro8,2 */
> { USB_DEVICE(0x05ac, 0x821a) },
>=20
> + /* Apple MacBookPro9,2 */
> + { USB_DEVICE(0x05ac, 0x821d) },
> +
> /* Apple MacMini5,1 */
> { USB_DEVICE(0x05ac, 0x8281) },
>=20
> --=20
> 1.7.11
>=20
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth"=
in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [RFCv0 04/21] Bluetooth: Process create response and connect response identically
From: Andrei Emeltchenko @ 2012-08-14 10:12 UTC (permalink / raw)
To: Mat Martineau; +Cc: linux-bluetooth, gustavo, pkrystad
In-Reply-To: <1343260274-11953-5-git-send-email-mathewm@codeaurora.org>
Hi Mat,
On Wed, Jul 25, 2012 at 04:50:56PM -0700, Mat Martineau wrote:
...
> -static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
> - struct l2cap_cmd_hdr *cmd, void *data)
> -{
> - BT_DBG("conn %p", conn);
> -
> - return l2cap_connect_rsp(conn, cmd, data);
> -}
> -
> static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
> u16 icid, u16 result)
> {
> @@ -4249,6 +4241,7 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
> break;
>
> case L2CAP_CONN_RSP:
> + case L2CAP_CREATE_CHAN_RSP:
> err = l2cap_connect_rsp(conn, cmd, data);
...
We might rename l2cap_connect_rsp to something like
l2cap_connect_create_rsp
Best regards
Andrei Emeltchenko
^ permalink raw reply
* Re: [PATCH v2 01/13] Heart Rate Profile API
From: Johan Hedberg @ 2012-08-14 9:56 UTC (permalink / raw)
To: Rafal Garbat; +Cc: linux-bluetooth, Santiago Carot-Nemesio
In-Reply-To: <1344870497-6929-2-git-send-email-rafal.garbat@tieto.com>
Hi,
On Mon, Aug 13, 2012, Rafal Garbat wrote:
> +Heart Rate Profile hierarchy
> +============================
> +
> +Service org.bluez
> +Interface org.bluez.HeartRate
> +Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
> +
> +Methods dict GetProperties()
> +
> + Returns all properties for the interface. See the
> + Properties section for the available properties.
> +
> + RegisterWatcher(object agent)
> +
> + Registers a watcher to monitor heart rate measurements.
> +
> + Possible Errors: org.bluez.Error.InvalidArguments
I'm wondering if it wouldn't make more sense to have these
RegisterWatcher APIs (thermometer, heart rate, others?) per-adapter
instead of per-device. That would be much friendlier to applications in
that they wouldn't need to separately search for paired/configured
devices supporting a specific service. Moving this to be per-adapter
would also mean that the first parameter of the Watcher methods would be
the object path of which device is in question.
Johan
^ permalink raw reply
* Re: [PATCH] input: Implement idle timeout for fakehid
From: Bastien Nocera @ 2012-08-14 9:50 UTC (permalink / raw)
To: Jeff Hansen; +Cc: linux-bluetooth
In-Reply-To: <50293C10.2000305@jeffhansen.com>
On Mon, 2012-08-13 at 11:40 -0600, Jeff Hansen wrote:
> (bump)
>
> The batteries on my BD remote would die in a few days without this
> patch. The idle timeout needs to be enforced for fakehid devices as
> well as normal HID devices.
Except that the timeout is disabled by default for HID devices. I posted
a patch that requires a little bit of work to get pushed last month or
so.
^ permalink raw reply
* Re: [PATCH BlueZ 0/3] HoG: Add support for non-HID services encapsulated in the HID protocol
From: Johan Hedberg @ 2012-08-14 9:44 UTC (permalink / raw)
To: João Paulo Rechi Vita; +Cc: linux-bluetooth
In-Reply-To: <1344860596-30617-1-git-send-email-jprvita@openbossa.org>
Hi João Paulo,
On Mon, Aug 13, 2012, João Paulo Rechi Vita wrote:
> The HID protocol support encapsulating non-HID service data as reports. This
> patches adds support for this feature for HoG devices.
>
> João Paulo Rechi Vita (3):
> gatt: Add a new descriptor UUID
> hog: discover External Report Reference descriptor
> hog: discover the non-HID service characteristic
>
> attrib/gatt.h | 1 +
> profiles/input/hog_device.c | 96 ++++++++++++++++++++++++++++++++++++++-------
> 2 files changed, 83 insertions(+), 14 deletions(-)
All three patches have been applied. Thanks.
Johan
^ permalink raw reply
* Re: [PATCH BlueZ] mgmt: print error message when start_discovery fails
From: Johan Hedberg @ 2012-08-14 9:40 UTC (permalink / raw)
To: João Paulo Rechi Vita; +Cc: linux-bluetooth
In-Reply-To: <1344004954-2762-1-git-send-email-jprvita@openbossa.org>
Hi,
On Fri, Aug 03, 2012, João Paulo Rechi Vita wrote:
> If we fail to communicate with the MGMT socket is better to print the
> error message on the mgmtops plugin, where it really happened, instead
> of leaving this job to its users.
> ---
> src/adapter.c | 6 +-----
> src/mgmt.c | 7 +++++--
> 2 files changed, 6 insertions(+), 7 deletions(-)
How do these two patches differ from patches 02/14 and 07/14 of the
patch set that was sent on July 27th? Why were these two patches resent
separately? A cover letter would have been quite useful here.
Johan
^ permalink raw reply
* Re: [PATCH BlueZ] mgmt: Add LE scanning callback
From: Johan Hedberg @ 2012-08-14 9:36 UTC (permalink / raw)
To: João Paulo Rechi Vita; +Cc: linux-bluetooth, Claudio Takahasi
In-Reply-To: <1344010717-4529-1-git-send-email-jprvita@openbossa.org>
Hi,
On Fri, Aug 03, 2012, João Paulo Rechi Vita wrote:
> From: Claudio Takahasi <claudio.takahasi@openbossa.org>
>
> This patch adds a new callback to allow the adapter to control LE
> scanning. The current approach uses the active scanning with default
> windows and intervals defined by the core spec without any filtering.
> ---
> src/mgmt.c | 32 ++++++++++++++++++++++++++++++++
> src/mgmt.h | 1 +
> 2 files changed, 33 insertions(+)
>
> diff --git a/src/mgmt.c b/src/mgmt.c
> index 8ae86d3..5ceeaa8 100644
> --- a/src/mgmt.c
> +++ b/src/mgmt.c
> @@ -1999,6 +1999,38 @@ int mgmt_start_discovery(int index)
> return 0;
> }
>
> +int mgmt_start_scanning(int index)
> +{
> + char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_start_discovery)];
> + struct mgmt_hdr *hdr = (void *) buf;
> + struct mgmt_cp_start_discovery *cp = (void *) &buf[sizeof(*hdr)];
> + struct controller_info *info = &controllers[index];
> +
> + DBG("index %d", index);
> +
> + info->discov_type = 0;
> +
> + if (mgmt_low_energy(info->current_settings)) {
> + hci_set_bit(BDADDR_LE_PUBLIC, &info->discov_type);
> + hci_set_bit(BDADDR_LE_RANDOM, &info->discov_type);
> + }
Shouldn't you just return an error here (e.g. -ENOTSUP) if LE is not
supported/enabled?
Have there been any patches sent that would use this API? At least I
didn't see any after a quick scan of the mailing list.
Johan
^ permalink raw reply
* Re: Backports mailing list
From: Sedat Dilek @ 2012-08-14 9:34 UTC (permalink / raw)
To: Luis R. Rodriguez
Cc: David Miller, linux-kernel, linux-wireless, linux-bluetooth,
lf_driver_backport, Julia Lawall, Jesper Andersen,
Ozan Çağlayan, Hauke Mehrtens
In-Reply-To: <CAB=NE6W_SQUJmAXaLesyRShtQ=Urz=w5Ks5jEXq_50bRge+PWQ@mail.gmail.com>
On Mon, Aug 13, 2012 at 10:42 PM, Luis R. Rodriguez
<mcgrof@frijolero.org> wrote:
> David,
>
> The compat [0] / compat-wireless [1] [2] projects have received quite
> a bit of love of the years to the point we now have 3 subsystems
> backported: Ethernet, Bluetooth and 802.11. Ozan Çağlayan, a Linux
> Foundation Google Summer of Code student is folding in right now drm
> driver support. At the request of the community, specifically those
> part of the Linux Foundation driver working group [3], we are going to
> be renaming the project to compat-drivers soon after drm is integrated
> and will be housing documentation under the kernel.org infrastructure
> [4] under this new name. It'll take some time for us to migrate the
> documentation / releases but do not see major issues with that, it
> will just take a bit of time but hope to have it done for the next
> stable release based on the next kernel stable release. At this time
> for patches we do have a Linux Foundation mailing list but have had
> issues with it for a while now so we keep using linux-wireless for
> patches. Given that our focus is to always prioritize upstream and
> always try to work with solutions that ensure vendors are focusing on
> upstream solutions and prioritizing upstream [5] I was hoping we can
> get a mailing list set up on vger for the project, perhaps
> backports@vger.kernel.org, so we don't flood the other mailing lists
> with random kernel backport junk. Please let me know if this is
> reasonable.
>
> [0] https://github.com/mcgrof/compat
> [1] http://wireless.kernel.org/en/users/Download/
> [2] http://wireless.kernel.org/en/users/Download/stable/
> [3] http://www.linuxfoundation.org/collaborate/workgroups/driver-backport/group
> [4] https://backports.wiki.kernel.org
> [5] http://wireless.kernel.org/en/users/Download/stable/#Additional_patches_to_stable_releases
>
Hi,
I am wondering why people are not consistent in naming - here again a
good example.
The workgroup at Linux Foundation is called "driver-backport".
You (Luis) are talking about a rename to "compat-drivers".
And then the ML and wiki have the name "backports".
So "backports" is for me is a bit confusing!
That reminds me when I first read about "AAArgh64!!!" stuff which was
in the end called mips64 to keep consistency to other existing arches.
So, just to fool the world a bit more:
What about "linux-backports" or why didn't you keep the "driver-backport" name?
Just my 0.02EUR.
Regards,
- Sedat -
> Luis
> --
> To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [RFC v4 0/8] DBus OutOfBand API update
From: Johan Hedberg @ 2012-08-14 9:30 UTC (permalink / raw)
To: Szymon Janc; +Cc: linux-bluetooth
In-Reply-To: <1344854800-20972-1-git-send-email-szymon.janc@tieto.com>
Hi Szymon,
On Mon, Aug 13, 2012, Szymon Janc wrote:
> changes since V3:
> - remove of DeviceFound signal (rationale below)
> - remove of UUIDs from AddRemoteData dictionary
> - AlreadyPaired -> AlreadyExist error change
> - proposed implementation
>
>
> After some more thinking about OOB API I've decided that emitting
> DeviceFound signal when OOB data are provided is not the best thing to do.
>
> Typical usecase with dbusoob plugin is to provide oob data and either start
> pairing with CreatePairedDevice or wait for incoming pairing request. No need
> to emit DeviceFound as OOB provider is already aware of device address and can
> start pairing. If it doesn't provide pairing agent for device there will be
> fallback to adapter agent (which doesn't need to know anything about OOB
> channel).
>
>
> For UUIDs removal is similar - OOB provider already knows which UUIDs are
> supported by remote device and based on that can choose to pair or not. No
> need to provide that to bluetoothd as it would be only used in DeviceFound
> signal anyway.
>
> Comments are welcome.
>
> --
> BR
> Szymon Janc
>
> Szymon Janc (8):
> dbusoob: Update API
> dbusoob: Simplify remove_remote_data
> dbusoob: Change ReadLocalData to match new API
> dbusoob: Change AddRemoteData to match new API
> dbusoob: Add support for Class in AddRemoteData
> dbusoob: Add support for Name in AddRemoteData
> dbusoob: Reply with error if SSP is not supported
> Update test/test-oob to match new DBus OOB API
>
> doc/oob-api.txt | 59 ++++++++++++++--
> plugins/dbusoob.c | 193 +++++++++++++++++++++++++++++++++++++++++++++--------
> src/adapter.c | 5 ++
> src/adapter.h | 2 +
> src/mgmt.c | 7 ++
> src/mgmt.h | 2 +
> test/test-oob | 4 +-
> 7 files changed, 235 insertions(+), 37 deletions(-)
The patches look good to me and have now been applied upstream. Thanks.
Johan
^ permalink raw reply
* Re: [RFC 4/5] Bluetooth: Add set broadcaster MGMT command
From: Johan Hedberg @ 2012-08-14 9:13 UTC (permalink / raw)
To: Jefferson Delfes; +Cc: linux-bluetooth
In-Reply-To: <1344632507-21381-5-git-send-email-jefferson.delfes@openbossa.org>
Hi Jefferson,
On Fri, Aug 10, 2012, Jefferson Delfes wrote:
> --- a/net/bluetooth/mgmt.c
> +++ b/net/bluetooth/mgmt.c
> @@ -379,6 +379,7 @@ static u32 get_supported_settings(struct hci_dev *hdev)
> settings |= MGMT_SETTING_FAST_CONNECTABLE;
> settings |= MGMT_SETTING_DISCOVERABLE;
> settings |= MGMT_SETTING_PAIRABLE;
> + settings |= MGMT_SETTING_BROADCASTER;
Shouldn't this be behind the same conditional as MGMT_SETTING_LE? I.e.
only when hdev->features indicates LE support.
Johan
^ permalink raw reply
* [PATCH] Bluetooth: Failed attempt to fix rfcomm session refcnt
From: Dean Jenkins @ 2012-08-14 8:40 UTC (permalink / raw)
To: linux-bluetooth
This pseudo commit is based on my analysis of the implementation failure
of the rfcomm session refcnt.
This commit fixes the fundamental mistake of not setting the rfcomm
session refcnt to 1 before adding the session structure to the session
list.
Remove the broken workarounds that erroneously use the DLC data channel
initiator flag. Only the session termination events need be tracked.
Remove unnecessary calls to refcomm_session_hold() and
refcomm_session_put() where protection mechanisms already exist or
protection is not requried.
Use refcomm_session_put() in rfcomm_session_close() and
rfcomm_recv_ua() to indicate that the session can be deleted. These are
the events that identify that the session can be deleted.
Use refcomm_session_hold() and refcomm_session_put() in
rfcomm_process_sessions() to protect premature deletion of the rfcomm
session. The session may become deleted when the refcomm_session_put()
is called, this is the only place where the session will be deleted
unless a malfunction of the refcnt occurs.
However, the rfcomm session refcnt concept is fatally flawed because
the refcnt cannot prevent rfcomm_session_close() being called twice or
when rfcomm_recv_ua() calls refcomm_session_put() followed by
rfcomm_session_close() in rfcomm_process_rx().
The flaw is because multiple events can cause the session to finish
and these events are not mutually exclusive so the refcnt is
decremented too many times. These events come from the rfcomm control
channel and the socket layer, and both are independently capable of
demanding the session be terminated.
Instead of a refcnt, suggest using a flag to indicate that the session
is pending deletion or add a flag to inidicate that the session has
been deleted. This provides logical locking so the session can only be
deleted once. A flag would also make the code more readable.
I hope that this pseudo commit makes the explanation clearer to explain
why the rfcomm session refcnt concept does not work.
Signed-off-by: Dean Jenkins <djenkins@mvista.com>
---
net/bluetooth/rfcomm/core.c | 67 ++++++++++++++++++-------------------------
1 file changed, 28 insertions(+), 39 deletions(-)
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 8a60238..882842b 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -263,16 +263,15 @@ static void rfcomm_session_set_timer(struct rfcomm_session *s, long timeout)
{
BT_DBG("session %p state %ld timeout %ld", s, s->state, timeout);
- if (!mod_timer(&s->timer, jiffies + timeout))
- rfcomm_session_hold(s);
+ mod_timer(&s->timer, jiffies + timeout);
}
static void rfcomm_session_clear_timer(struct rfcomm_session *s)
{
BT_DBG("session %p state %ld", s, s->state);
- if (timer_pending(&s->timer) && del_timer(&s->timer))
- rfcomm_session_put(s);
+ if (timer_pending(&s->timer))
+ del_timer(&s->timer);
}
/* ---- RFCOMM DLCs ---- */
@@ -350,8 +349,6 @@ static void rfcomm_dlc_link(struct rfcomm_session *s, struct rfcomm_dlc *d)
{
BT_DBG("dlc %p session %p", d, s);
- rfcomm_session_hold(s);
-
rfcomm_session_clear_timer(s);
rfcomm_dlc_hold(d);
list_add(&d->list, &s->dlcs);
@@ -370,8 +367,6 @@ static void rfcomm_dlc_unlink(struct rfcomm_dlc *d)
if (list_empty(&s->dlcs))
rfcomm_session_set_timer(s, RFCOMM_IDLE_TIMEOUT);
-
- rfcomm_session_put(s);
}
static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci)
@@ -618,6 +613,8 @@ static struct rfcomm_session *rfcomm_session_add(struct socket *sock, int state)
return NULL;
}
+ /* rfcomm session refcnt must be 1 before adding to the session list */
+ rfcomm_session_hold(s);
list_add(&s->list, &session_list);
return s;
@@ -631,9 +628,6 @@ static void rfcomm_session_del(struct rfcomm_session *s)
list_del(&s->list);
- if (state == BT_CONNECTED)
- rfcomm_send_disc(s, 0);
-
rfcomm_session_clear_timer(s);
sock_release(s->sock);
kfree(s);
@@ -665,8 +659,6 @@ static void rfcomm_session_close(struct rfcomm_session *s, int err)
BT_DBG("session %p state %ld err %d", s, s->state, err);
- rfcomm_session_hold(s);
-
s->state = BT_CLOSED;
/* Close all dlcs */
@@ -677,6 +669,8 @@ static void rfcomm_session_close(struct rfcomm_session *s, int err)
}
rfcomm_session_clear_timer(s);
+
+ /* indicate rfcomm session can be deleted */
rfcomm_session_put(s);
}
@@ -1164,18 +1158,8 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
break;
case BT_DISCONN:
- /* rfcomm_session_put is called later so don't do
- * anything here otherwise we will mess up the session
- * reference counter:
- *
- * (a) when we are the initiator dlc_unlink will drive
- * the reference counter to 0 (there is no initial put
- * after session_add)
- *
- * (b) when we are not the initiator rfcomm_rx_process
- * will explicitly call put to balance the initial hold
- * done after session add.
- */
+ /* indicate rfcomm session can be deleted */
+ rfcomm_session_put(s);
break;
}
}
@@ -1875,12 +1859,22 @@ static inline void rfcomm_process_rx(struct rfcomm_session *s)
kfree_skb(skb);
}
- if (sk->sk_state == BT_CLOSED) {
- if (!s->initiator)
- rfcomm_session_put(s);
-
+/*
+ * The rfcomm session refcnt fails to protect the possibility of deleting the
+ * session twice because the refcnt cannot determine whether the session has
+ * already been deleted. If the refcnt is 1 here (normally refcnt is 2 here)
+ * because the rfcomm channel has disconnected via DISC-UA then failure occurs
+ * later in rfcomm_process_sessions() if the session becomes deleted when the
+ * socket state transistions to BT_CLOSED. This is because the refcnt is
+ * decremented too many times due to 2 events that demand the session to be
+ * deleted.
+ *
+ * A better solution is to use a flag instead of a refcnt. A flag allows
+ * 1 or more events to trigger the deletion of the session. The refcnt cannot
+ * manage multiple independent events.
+ */
+ if (sk->sk_state == BT_CLOSED)
rfcomm_session_close(s, sk->sk_err);
- }
}
static inline void rfcomm_accept_connection(struct rfcomm_session *s)
@@ -1905,8 +1899,6 @@ static inline void rfcomm_accept_connection(struct rfcomm_session *s)
s = rfcomm_session_add(nsock, BT_OPEN);
if (s) {
- rfcomm_session_hold(s);
-
/* We should adjust MTU on incoming sessions.
* L2CAP MTU minus UIH header and FCS. */
s->mtu = min(l2cap_pi(nsock->sk)->chan->omtu,
@@ -1951,6 +1943,8 @@ static inline void rfcomm_process_sessions(void)
struct rfcomm_session *s;
s = list_entry(p, struct rfcomm_session, list);
+ rfcomm_session_hold(s);
+
if (test_and_clear_bit(RFCOMM_TIMED_OUT, &s->flags)) {
s->state = BT_DISCONN;
rfcomm_send_disc(s, 0);
@@ -1960,11 +1954,10 @@ static inline void rfcomm_process_sessions(void)
if (s->state == BT_LISTEN) {
rfcomm_accept_connection(s);
+ rfcomm_session_put(s);
continue;
}
- rfcomm_session_hold(s);
-
switch (s->state) {
case BT_BOUND:
rfcomm_check_connection(s);
@@ -1977,6 +1970,7 @@ static inline void rfcomm_process_sessions(void)
rfcomm_process_dlcs(s);
+ /* rfcomm_session_del() is called here when refcnt goes to 0 */
rfcomm_session_put(s);
}
@@ -2027,7 +2021,6 @@ static int rfcomm_add_listener(bdaddr_t *ba)
if (!s)
goto failed;
- rfcomm_session_hold(s);
return 0;
failed:
sock_release(sock);
@@ -2085,8 +2078,6 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
if (!s)
return;
- rfcomm_session_hold(s);
-
list_for_each_safe(p, n, &s->dlcs) {
d = list_entry(p, struct rfcomm_dlc, list);
@@ -2118,8 +2109,6 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
set_bit(RFCOMM_AUTH_REJECT, &d->flags);
}
- rfcomm_session_put(s);
-
rfcomm_schedule();
}
--
1.7.10.1
^ permalink raw reply related
* Re: Backports mailing list
From: David Miller @ 2012-08-14 4:12 UTC (permalink / raw)
To: mcgrof
Cc: linux-kernel, linux-wireless, linux-bluetooth, lf_driver_backport,
julia.lawall, jespera, ozancag, hauke
In-Reply-To: <CAB=NE6W_SQUJmAXaLesyRShtQ=Urz=w5Ks5jEXq_50bRge+PWQ@mail.gmail.com>
From: "Luis R. Rodriguez" <mcgrof@frijolero.org>
Date: Mon, 13 Aug 2012 13:42:53 -0700
> I was hoping we can get a mailing list set up on vger for the
> project, perhaps backports@vger.kernel.org, so we don't flood the
> other mailing lists with random kernel backport junk. Please let me
> know if this is reasonable.
It would have been so much easier if you simply just asked for this
instead of giving me a life story of all of these projects to read.
backports@vger.kernel.org has been created
^ permalink raw reply
* Backports mailing list
From: Luis R. Rodriguez @ 2012-08-13 20:42 UTC (permalink / raw)
To: David Miller
Cc: linux-kernel, linux-wireless, linux-bluetooth, lf_driver_backport,
Julia Lawall, Jesper Andersen, Ozan Çağlayan,
Hauke Mehrtens
David,
The compat [0] / compat-wireless [1] [2] projects have received quite
a bit of love of the years to the point we now have 3 subsystems
backported: Ethernet, Bluetooth and 802.11. Ozan Çağlayan, a Linux
Foundation Google Summer of Code student is folding in right now drm
driver support. At the request of the community, specifically those
part of the Linux Foundation driver working group [3], we are going to
be renaming the project to compat-drivers soon after drm is integrated
and will be housing documentation under the kernel.org infrastructure
[4] under this new name. It'll take some time for us to migrate the
documentation / releases but do not see major issues with that, it
will just take a bit of time but hope to have it done for the next
stable release based on the next kernel stable release. At this time
for patches we do have a Linux Foundation mailing list but have had
issues with it for a while now so we keep using linux-wireless for
patches. Given that our focus is to always prioritize upstream and
always try to work with solutions that ensure vendors are focusing on
upstream solutions and prioritizing upstream [5] I was hoping we can
get a mailing list set up on vger for the project, perhaps
backports@vger.kernel.org, so we don't flood the other mailing lists
with random kernel backport junk. Please let me know if this is
reasonable.
[0] https://github.com/mcgrof/compat
[1] http://wireless.kernel.org/en/users/Download/
[2] http://wireless.kernel.org/en/users/Download/stable/
[3] http://www.linuxfoundation.org/collaborate/workgroups/driver-backport/group
[4] https://backports.wiki.kernel.org
[5] http://wireless.kernel.org/en/users/Download/stable/#Additional_patches_to_stable_releases
Luis
^ permalink raw reply
* [PATCH BlueZ v2 4/4] replay: Add config file parser and skip action
From: Anton Weber @ 2012-08-13 18:34 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Anton Weber
In-Reply-To: <1344882885-23631-1-git-send-email-ant@antweb.me>
Add support for config files to manipulate the loaded sequence.
A config file can be specified with the new -c command line parameter.
The config syntax is:
scope attr=value[,attr=value,...]
e.g.:
all delta=300,action=replay
1-4 action=emulate
1 delta=500
HCI_EVT_0x0e delta=0
HCI_CMD_0x03|0x0003 action=emulate
HCI_ACL action=replay
The inital version supports the attributes delta and action and
all scope types shown in the example.
HCISEQ_ACTION_SKIP allows to skip a packet in the sequence.
The action can be set in config files using "action=skip".
---
v1 -> v2: delete_type_cfg() was using an outdated number of entries when
freeing type_cfg.cmd[]
Makefile.tools | 1 +
tools/replay/config-parser.c | 506 ++++++++++++++++++++++++++++++++++++++++++
tools/replay/config-parser.h | 36 +++
tools/replay/hciseq.h | 3 +-
tools/replay/main.c | 117 +++++++++-
tools/replay/main.h | 2 -
6 files changed, 661 insertions(+), 4 deletions(-)
create mode 100644 tools/replay/config-parser.c
create mode 100644 tools/replay/config-parser.h
diff --git a/Makefile.tools b/Makefile.tools
index 8b3c8d8..ba2db00 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -72,6 +72,7 @@ emulator_btvirt_SOURCES = emulator/main.c monitor/bt.h \
tools_replay_btreplay_SOURCES = tools/replay/main.h tools/replay/main.c \
tools/replay/hciseq.h tools/replay/hciseq.c \
tools/replay/time.h tools/replay/time.c \
+ tools/replay/config-parser.h tools/replay/config-parser.c \
monitor/packet.h monitor/packet.c \
monitor/btsnoop.h monitor/btsnoop.c \
monitor/control.h monitor/control.c \
diff --git a/tools/replay/config-parser.c b/tools/replay/config-parser.c
new file mode 100644
index 0000000..5219eb9
--- /dev/null
+++ b/tools/replay/config-parser.c
@@ -0,0 +1,506 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ * Copyright (C) 2012 Anton Weber <ant@antweb.me>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <sys/time.h>
+
+#include "config-parser.h"
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "monitor/bt.h"
+
+#define MAXLINE 128
+#define MAX_ATTR_KEY 32
+#define MAX_ATTR_VAL 32
+
+static struct hciseq_list *seq;
+static struct hciseq_type_cfg *type_cfg;
+
+static bool verbose;
+static int line;
+
+struct scope_list {
+ struct scope_node *head;
+};
+
+struct scope_node {
+ int pos;
+ struct hciseq_attr *attr;
+ struct scope_node *next;
+};
+
+struct attr_list {
+ struct attr_node *head;
+};
+
+struct attr_node {
+ char key[MAX_ATTR_KEY];
+ char val[MAX_ATTR_VAL];
+ struct attr_node *next;
+};
+
+static void attr_list_delete(struct attr_list *list)
+{
+ struct attr_node *node, *next;
+
+ if (list == NULL)
+ return;
+
+ node = list->head;
+ free(list);
+ while (node != NULL) {
+ next = node->next;
+ free(node);
+ node = next;
+ }
+}
+
+static void scope_list_delete(struct scope_list *list)
+{
+ struct scope_node *node, *next;
+
+ if (list == NULL)
+ return;
+
+ node = list->head;
+ free(list);
+ while (node != NULL) {
+ next = node->next;
+ free(node);
+ node = next;
+ }
+}
+
+static struct attr_list *parse_attrstr(char *attrstr)
+{
+ struct attr_list *list = NULL;
+ struct attr_node *node;
+ char *res;
+
+ do {
+ if (list == NULL) {
+ if ((res = strtok(attrstr, "=")) == NULL) {
+ /* nothing to parse */
+ return NULL;
+ }
+
+ list = malloc(sizeof(*list));
+ node = malloc(sizeof(*node));
+ list->head = node;
+ } else {
+ if ((res = strtok(NULL, "=")) == NULL) {
+ /* nothing left to parse */
+ break;
+ }
+
+ node->next = malloc(sizeof(*node));
+ node = node->next;
+ }
+
+ strncpy(node->key, res, sizeof(node->key));
+ node->key[sizeof(node->key) - 1] = '\0';
+
+ if ((res = strtok(NULL, ",")) == NULL) {
+ fprintf(stderr, "Invalid attribute");
+ goto err;
+ }
+ strncpy(node->val, res, sizeof(node->val));
+ node->val[sizeof(node->val) - 1] = '\0';
+
+ node->next = NULL;
+ } while (res != NULL);
+
+ return list;
+
+err:
+ attr_list_delete(list);
+ return NULL;
+}
+
+static int apply_attr(struct scope_node *scope_node,
+ struct attr_list *list)
+{
+ struct attr_node *attr_node = list->head;
+ struct hciseq_attr *attr = scope_node->attr;
+ long lval;
+
+ while (attr_node != NULL) {
+ if (strcmp(attr_node->key, "delta") == 0) {
+ /* delta */
+ lval = strtol(attr_node->val, NULL, 10);
+ if (errno == ERANGE || errno == EINVAL)
+ return 1;
+
+ if (verbose) {
+ printf("\t[%d] set delta to %ld\n",
+ scope_node->pos, lval);
+ }
+
+ attr->ts_diff.tv_sec = 0;
+ attr->ts_diff.tv_usec = lval;
+ } else if (strcmp(attr_node->key, "action") == 0) {
+ /* action */
+ if (strcmp(attr_node->val, "replay") == 0) {
+ lval = HCISEQ_ACTION_REPLAY;
+ if (verbose)
+ printf("\t[%d] set action to 'replay'\n",
+ scope_node->pos);
+ } else if (strcmp(attr_node->val, "emulate") == 0) {
+ lval = HCISEQ_ACTION_EMULATE;
+ if (verbose)
+ printf("\t[%d] set action to 'emulate'\n",
+ scope_node->pos);
+ } else if (strcmp(attr_node->val, "skip") == 0) {
+ lval = HCISEQ_ACTION_SKIP;
+ if (verbose)
+ printf("\t[%d] set action to 'skip'\n",
+ scope_node->pos);
+ } else {
+ return 1;
+ }
+
+ attr->action = lval;
+ }
+
+ attr_node = attr_node->next;
+ }
+
+ return 0;
+}
+
+static int apply_attr_scope(struct scope_list *scope,
+ struct attr_list *attr)
+{
+ struct scope_node *node = scope->head;
+
+ while (node != NULL) {
+ apply_attr(node, attr);
+ node = node->next;
+ }
+
+ return 0;
+}
+
+static struct scope_list *get_scope_range(int from, int to)
+{
+ struct scope_list *list = NULL;
+ struct scope_node *scope_node;
+ struct hciseq_node *seq_node = seq->current;
+ int pos = 1;
+
+ /* forward to 'from' */
+ while (pos < from) {
+ seq_node = seq_node->next;
+ pos++;
+ }
+
+ /* create scope list for range */
+ while (pos <= to) {
+ if (verbose)
+ printf("\tadd packet [%d]\n", pos);
+
+ if (list == NULL) {
+ list = malloc(sizeof(*list));
+ scope_node = malloc(sizeof(*scope_node));
+ list->head = scope_node;
+ } else {
+ scope_node->next = malloc(sizeof(*scope_node));
+ scope_node = scope_node->next;
+ }
+ scope_node->attr = seq_node->attr;
+ scope_node->pos = pos;
+ scope_node->next = NULL;
+
+ seq_node = seq_node->next;
+ pos++;
+ }
+
+ return list;
+}
+
+static struct scope_list *get_scope_type(uint8_t type, void *filter1,
+ void *filter2)
+{
+ struct scope_list *list = NULL;
+ struct scope_node *scope_node;
+ struct hciseq_node *seq_node = seq->current;
+ uint16_t opcode, node_opcode;
+ uint8_t node_ogf, ogf = 0x00;
+ uint16_t node_ocf, ocf = 0x0000;
+ uint8_t node_evt, evt = 0x00;
+ bool match;
+ int pos = 1;
+ struct hciseq_attr *attr;
+
+ if (type == BT_H4_CMD_PKT) {
+ ogf = *((uint8_t *) filter1);
+ ocf = *((uint16_t *) filter2);
+ opcode = cmd_opcode_pack(ogf, ocf);
+
+ if (opcode > 0x2FFF) {
+ attr = NULL;
+ } else {
+ attr = type_cfg->cmd[opcode];
+ if (attr == NULL) {
+ attr = malloc(sizeof(*attr));
+ type_cfg->cmd[opcode] = attr;
+ }
+ }
+ } else if (type == BT_H4_EVT_PKT) {
+ evt = *((uint8_t *) filter1);
+ attr = type_cfg->evt[evt];
+
+ if (attr == NULL) {
+ attr = malloc(sizeof(*attr));
+ type_cfg->evt[evt] = attr;
+ }
+ } else if (type == BT_H4_ACL_PKT) {
+ attr = type_cfg->acl;
+ if (attr == NULL) {
+ attr = malloc(sizeof(*attr));
+ type_cfg->acl = attr;
+ }
+ } else {
+ attr = NULL;
+ }
+
+ /* add matching packets in sequence */
+ while (seq_node != NULL) {
+ match = false;
+ if (((uint8_t *) seq_node->frame->data)[0] == type) {
+ if (type == BT_H4_CMD_PKT) {
+ node_opcode = *((uint16_t *)
+ (seq_node->frame->data + 1));
+ node_ogf = cmd_opcode_ogf(node_opcode);
+ node_ocf = cmd_opcode_ocf(node_opcode);
+ if (node_ogf == ogf && node_ocf == ocf)
+ match = true;
+ } else if (type == BT_H4_EVT_PKT) {
+ node_evt = ((uint8_t *) seq_node->frame->data)[1];
+ if (evt == node_evt)
+ match = true;
+ } else if (type == BT_H4_ACL_PKT) {
+ match = true;
+ }
+ }
+
+ if (match) {
+ if (verbose)
+ printf("\tadd packet [%d]\n", pos);
+
+ if (list == NULL) {
+ list = malloc(sizeof(*list));
+ scope_node = malloc(sizeof(*scope_node));
+ list->head = scope_node;
+ } else {
+ scope_node->next = malloc(sizeof(*scope_node));
+ scope_node = scope_node->next;
+ }
+ scope_node->attr = seq_node->attr;
+ scope_node->pos = pos;
+ scope_node->next = NULL;
+ }
+ seq_node = seq_node->next;
+ pos++;
+ }
+
+ /* add type config */
+ if (attr != NULL) {
+ if (list == NULL) {
+ list = malloc(sizeof(*list));
+ scope_node = malloc(sizeof(*scope_node));
+ list->head = scope_node;
+ } else {
+ scope_node->next = malloc(sizeof(*scope_node));
+ scope_node = scope_node->next;
+ }
+
+ scope_node->attr = attr;
+ scope_node->pos = 0;
+ scope_node->next = NULL;
+ }
+
+ return list;
+}
+
+static int parse_line(char *buf)
+{
+ char *scopestr, *attrstr;
+ struct scope_list *scope_list = NULL;
+ struct attr_list *attr_list;
+ uint8_t evt, ogf;
+ uint16_t ocf;
+ char *res;
+ int from, to;
+
+ line++;
+
+ /* split line into scope and attributes */
+ if ((scopestr = strtok(buf, " ")) == NULL)
+ return 1;
+
+ if ((attrstr = strtok(NULL, "\n")) == NULL)
+ return 1;
+
+ if (verbose)
+ printf("Parsing scope (%s)\n", scopestr);
+
+ if (strcmp(scopestr, "all") == 0) {
+ if (verbose)
+ printf("\tadd all\n");
+
+ scope_list = get_scope_range(0, seq->len);
+ } else if ((strncmp(scopestr, "HCI_", 4) == 0) && strlen(scopestr) >= 7) {
+ /* make sure scopestr is at least 7 chars long, so we can check for HCI_XXX */
+
+ if (strncmp(scopestr + 4, "ACL", 3) == 0) {
+ /* scope is HCI_ACL */
+ if (verbose)
+ printf("\tadd all HCI ACL data packets:");
+
+ scope_list = get_scope_type(BT_H4_ACL_PKT, NULL, NULL);
+ } else if (strncmp(scopestr + 4, "CMD", 3) == 0) {
+ /* scope is HCI_CMD_
+ * length must be exactly 19 (e.g. HCI_CMD_0x03|0x0003) */
+ if (strlen(scopestr) != 19 || scopestr[12] != '|')
+ return 1;
+
+ if (sscanf(scopestr + 8, "0x%2hhx", &ogf) <= 0)
+ return 1;
+
+ if (sscanf(scopestr + 13, "0x%4hx", &ocf) <= 0)
+ return 1;
+
+ if (verbose)
+ printf("\tadd all HCI command packets with opcode (0x%2.2x|0x%4.4x):\n",
+ ogf, ocf);
+
+ scope_list = get_scope_type(BT_H4_CMD_PKT, &ogf, &ocf);
+ } else if (strncmp(scopestr + 4, "EVT", 3) == 0) {
+ /* scope is CMD_EVT_
+ * length must be exactly 12 (e.g. HCI_EVT_0x0e) */
+ if (strlen(scopestr) != 12)
+ return 1;
+
+ if (sscanf(scopestr + 8, "0x%2hhx", &evt) <= 0)
+ return 1;
+
+ if (verbose)
+ printf("\tadd all HCI event packets with event type (0x%2.2x):\n",
+ evt);
+
+ scope_list = get_scope_type(BT_H4_EVT_PKT, &evt, NULL);
+ }
+ } else if (scopestr[0] >= 48 || scopestr[0] <= 57) {
+ /* first char is a digit */
+ if ((res = strtok(scopestr, "-")) == NULL)
+ return 1;
+
+ from = atoi(res);
+ if (from <= 0)
+ return 1;
+
+ if ((res = strtok(NULL, ":")) == NULL) {
+ /* just one packet */
+ if (verbose)
+ printf("\tadd packet single packet\n");
+
+ scope_list = get_scope_range(from, from);
+ } else {
+ /* range */
+ to = atoi(res);
+ if (to > seq->len)
+ return 1;
+
+ if (verbose)
+ printf("\tadd packets %d to %d\n", from, to);
+
+ scope_list = get_scope_range(from, to);
+ }
+
+ }
+
+ if (verbose)
+ printf("Parsing attributes (%s)\n", attrstr);
+
+ if ((attr_list = parse_attrstr(attrstr)) == NULL) {
+ return 1;
+ }
+
+ if (scope_list != NULL) {
+ apply_attr_scope(scope_list, attr_list);
+ scope_list_delete(scope_list);
+ } else {
+ if (verbose)
+ printf("Empty scope, skipping\n");
+ }
+
+ attr_list_delete(attr_list);
+
+ return 0;
+}
+
+int parse_config(char *path, struct hciseq_list *_seq,
+ struct hciseq_type_cfg *_type_cfg, bool _verbose)
+{
+ char *buf;
+ FILE *file;
+
+ seq = _seq;
+ type_cfg = _type_cfg;
+ verbose = _verbose;
+ line = 0;
+
+ printf("Reading config file...\n");
+
+ buf = malloc(sizeof(char) * MAXLINE);
+ if (buf == NULL) {
+ fprintf(stderr, "Failed to allocate buffer\n");
+ return 1;
+ }
+
+ if ((file = fopen(path, "r")) == NULL) {
+ perror("Failed to open config file");
+ return 1;
+ }
+
+ while (fgets(buf, MAXLINE, file) != NULL) {
+ if (parse_line(buf)) {
+ fprintf(stderr, "Error parsing config file - line %d\n",
+ line);
+ free(buf);
+ return 1;
+ }
+ }
+
+ printf("Done\n\n");
+ fclose(file);
+ free(buf);
+
+ return 0;
+}
diff --git a/tools/replay/config-parser.h b/tools/replay/config-parser.h
new file mode 100644
index 0000000..265628d
--- /dev/null
+++ b/tools/replay/config-parser.h
@@ -0,0 +1,36 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ * Copyright (C) 2012 Anton Weber <ant@antweb.me>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "hciseq.h"
+
+struct hciseq_type_cfg {
+ struct hciseq_attr *cmd[9216]; /*
+ * opcodes 0x0000 - 0x23FF
+ * (OGF 0x01 - 0x08)
+ */
+ struct hciseq_attr *evt[256]; /* events 0x00 - 0xFF */
+ struct hciseq_attr *acl;
+};
+
+int parse_config(char *path, struct hciseq_list *_seq,
+ struct hciseq_type_cfg *_type_cfg, bool _verbose);
diff --git a/tools/replay/hciseq.h b/tools/replay/hciseq.h
index 1454147..fa589a3 100644
--- a/tools/replay/hciseq.h
+++ b/tools/replay/hciseq.h
@@ -43,7 +43,8 @@ struct frame {
enum hciseq_action {
HCISEQ_ACTION_REPLAY = 0,
- HCISEQ_ACTION_EMULATE = 1
+ HCISEQ_ACTION_EMULATE = 1,
+ HCISEQ_ACTION_SKIP = 2
};
struct hciseq_list {
diff --git a/tools/replay/main.c b/tools/replay/main.c
index b80eb7f..b9597be 100644
--- a/tools/replay/main.c
+++ b/tools/replay/main.c
@@ -41,6 +41,7 @@
#include "main.h"
#include "time.h"
+#include "config-parser.h"
#include "lib/bluetooth.h"
#include "lib/hci.h"
#include "emulator/btdev.h"
@@ -56,6 +57,7 @@
#define TIMING_DELTA 1
static struct hciseq_list dumpseq;
+static struct hciseq_type_cfg type_cfg;
static int fd;
static int pos = 1;
@@ -281,6 +283,35 @@ static void btdev_recv(struct frame *frm)
btdev_receive_h4(btdev, frm->data, frm->data_len);
}
+static struct hciseq_attr *get_type_attr(struct frame *frm)
+{
+ uint8_t pkt_type = ((const uint8_t *) frm->data)[0];
+ uint16_t opcode;
+ uint8_t evt;
+
+ switch (pkt_type) {
+ case BT_H4_CMD_PKT:
+ opcode = *((uint16_t *) (frm->data + 1));
+ if (opcode > 0x2FFF)
+ return NULL;
+ return type_cfg.cmd[opcode];
+ case BT_H4_EVT_PKT:
+ evt = *((uint8_t *) (frm->data + 1));
+
+ /* use attributes of opcode for 'Command Complete' events */
+ if (evt == 0x0e) {
+ opcode = *((uint16_t *) (frm->data + 4));
+ return type_cfg.cmd[opcode];
+ }
+
+ return type_cfg.evt[evt];
+ case BT_H4_ACL_PKT:
+ return type_cfg.acl;
+ default:
+ return NULL;
+ }
+}
+
static bool check_match(struct frame *l, struct frame *r, char *msg)
{
uint8_t type_l = ((const uint8_t *) l->data)[0];
@@ -341,6 +372,7 @@ static bool process_in()
{
static struct frame frm;
static uint8_t data[HCI_MAX_FRAME_SIZE];
+ struct hciseq_attr *attr;
int n;
bool match;
char msg[MAX_MSG];
@@ -362,6 +394,38 @@ static bool process_in()
msg[0] = '\0';
match = check_match(dumpseq.current->frame, &frm, msg);
+ /* check type config */
+ attr = get_type_attr(&frm);
+ if (attr != NULL) {
+ if (attr->action == HCISEQ_ACTION_SKIP) {
+ if (match) {
+ printf("[%4d/%4d] SKIPPING\n", pos,
+ dumpseq.len);
+ return 1;
+ } else {
+ printf("[ Unknown ] %s\n ",
+ msg);
+ dump_frame(&frm);
+ printf(" SKIPPING\n");
+ return 0;
+ }
+ }
+ if (attr->action == HCISEQ_ACTION_EMULATE) {
+ if (match) {
+ printf("[%4d/%4d] EMULATING\n", pos,
+ dumpseq.len);
+ } else {
+ printf("[ Unknown ] %s\n ",
+ msg);
+ printf("EMULATING\n");
+ }
+
+ btdev_recv(&frm);
+
+ return match;
+ }
+ }
+
/* process packet if match */
if (match) {
printf("[%4d/%4d] ", pos, dumpseq.len);
@@ -381,12 +445,20 @@ static bool process_in()
static bool process_out()
{
uint8_t pkt_type;
+ struct hciseq_attr *attr;
/* emulator sends response automatically */
if (dumpseq.current->attr->action == HCISEQ_ACTION_EMULATE) {
return 1;
}
+ /* use type config if set */
+ attr = get_type_attr(dumpseq.current->frame);
+ if (attr != NULL) {
+ if (attr->action == HCISEQ_ACTION_SKIP || attr->action == HCISEQ_ACTION_EMULATE)
+ return true;
+ }
+
pkt_type = ((const uint8_t *) dumpseq.current->frame->data)[0];
switch (pkt_type) {
@@ -412,6 +484,15 @@ static void process()
gettimeofday(&last, NULL);
do {
+ if (dumpseq.current->attr->action == HCISEQ_ACTION_SKIP) {
+ printf("[%4d/%4d] SKIPPING\n ", pos,
+ dumpseq.len);
+ dump_frame(dumpseq.current->frame);
+ dumpseq.current = dumpseq.current->next;
+ pos++;
+ continue;
+ }
+
/* delay */
if (timing == TIMING_DELTA) {
/* consider exec time of process_out()/process_in() */
@@ -485,6 +566,19 @@ static void delete_list()
}
}
+static void delete_type_cfg()
+{
+ int i;
+
+ for (i = 0; i < 9216; i++) {
+ free(type_cfg.cmd[i]);
+ }
+ for (i = 0; i < 256; i++) {
+ free(type_cfg.evt[i]);
+ }
+ free(type_cfg.acl);
+}
+
static void usage(void)
{
printf("hcireplay - Bluetooth replayer\n"
@@ -493,6 +587,7 @@ static void usage(void)
"\t-d, --timing={none|delta} Specify timing mode\n"
"\t-m, --factor=<value> Use timing modifier\n"
"\t-t, --timeout=<value> Use timeout when receiving\n"
+ "\t-c, --config=<file> Use config file\n"
"\t-v, --verbose Enable verbose output\n"
"\t --version Give version information\n"
"\t --help Give a short usage message\n");
@@ -502,6 +597,7 @@ static const struct option main_options[] = {
{"timing", required_argument, NULL, 'd'},
{"factor", required_argument, NULL, 'm'},
{"timeout", required_argument, NULL, 't'},
+ {"config", required_argument, NULL, 'c'},
{"verbose", no_argument, NULL, 'v'},
{"version", no_argument, NULL, 'V'},
{"help", no_argument, NULL, 'H'},
@@ -512,11 +608,12 @@ int main(int argc, char *argv[])
{
int dumpfd;
int i;
+ char *config = NULL;
while (1) {
int opt;
- opt = getopt_long(argc, argv, "d:m:t:v",
+ opt = getopt_long(argc, argv, "d:m:t:c:v",
main_options, NULL);
if (opt < 0)
break;
@@ -535,6 +632,9 @@ int main(int argc, char *argv[])
case 't':
timeout = atoi(optarg);
break;
+ case 'c':
+ config = optarg;
+ break;
case 'v':
verbose = true;
break;
@@ -572,6 +672,20 @@ int main(int argc, char *argv[])
dumpseq.current = dumpseq.frames;
calc_rel_ts(&dumpseq);
+ /* init type config */
+ for (i = 0; i < 9216; i++)
+ type_cfg.cmd[i] = NULL;
+ for (i = 0; i < 256; i++)
+ type_cfg.evt[i] = NULL;
+ type_cfg.acl = NULL;
+
+ if (config != NULL) {
+ if (parse_config(config, &dumpseq, &type_cfg, verbose)) {
+ vhci_close();
+ return 1;
+ }
+ }
+
/* init emulator */
btdev = btdev_create(0);
btdev_set_send_handler(btdev, btdev_send, NULL);
@@ -595,6 +709,7 @@ int main(int argc, char *argv[])
vhci_close();
btdev_destroy(btdev);
delete_list();
+ delete_type_cfg();
printf("Terminating\n");
return EXIT_SUCCESS;
diff --git a/tools/replay/main.h b/tools/replay/main.h
index 2223789..e8b7365 100644
--- a/tools/replay/main.h
+++ b/tools/replay/main.h
@@ -23,8 +23,6 @@
*
*/
-#include "hciseq.h"
-
struct btsnoop_hdr {
uint8_t id[8]; /* Identification Pattern */
uint32_t version; /* Version Number = 1 */
--
1.7.9.5
^ permalink raw reply related
* [PATCH BlueZ v2 3/4] replay: Add emulation support
From: Anton Weber @ 2012-08-13 18:34 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Anton Weber
In-Reply-To: <1344882885-23631-1-git-send-email-ant@antweb.me>
Integrate emulator so it can process selected packets instead of
replaying them from the sequence. The behaviour is controlled
through the action attribute in hciseq_attr.
If set to HCISEQ_ACTION_EMULATE, hcireplay will use the emulator
to process the packet automatically instead of replaying it.
HCISEQ_ACTION_REPLAY keeps the previous behaviour and replays the
packet using the dump file.
---
Makefile.tools | 1 +
tools/replay/hciseq.h | 1 +
tools/replay/main.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 51 insertions(+), 3 deletions(-)
diff --git a/Makefile.tools b/Makefile.tools
index 6767300..8b3c8d8 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -76,6 +76,7 @@ tools_replay_btreplay_SOURCES = tools/replay/main.h tools/replay/main.c \
monitor/btsnoop.h monitor/btsnoop.c \
monitor/control.h monitor/control.c \
monitor/mainloop.h monitor/mainloop.c \
+ emulator/btdev.h emulator/btdev.c \
lib/hci.h
tools_replay_btreplay_LDADD = lib/libbluetooth-private.la
diff --git a/tools/replay/hciseq.h b/tools/replay/hciseq.h
index f9fe7c8..1454147 100644
--- a/tools/replay/hciseq.h
+++ b/tools/replay/hciseq.h
@@ -43,6 +43,7 @@ struct frame {
enum hciseq_action {
HCISEQ_ACTION_REPLAY = 0,
+ HCISEQ_ACTION_EMULATE = 1
};
struct hciseq_list {
diff --git a/tools/replay/main.c b/tools/replay/main.c
index 578936f..b80eb7f 100644
--- a/tools/replay/main.c
+++ b/tools/replay/main.c
@@ -43,6 +43,7 @@
#include "time.h"
#include "lib/bluetooth.h"
#include "lib/hci.h"
+#include "emulator/btdev.h"
#include "monitor/bt.h"
#include "monitor/btsnoop.h"
#include "monitor/control.h"
@@ -69,6 +70,8 @@ static int timing = TIMING_NONE;
static double factor = 1;
static bool verbose = false;
+static struct btdev *btdev;
+
static inline int read_n(int fd, char *buf, int len)
{
int t = 0, w;
@@ -250,6 +253,34 @@ static int recv_frm(int fd, struct frame *frm)
return n;
}
+static void btdev_send(const void *data, uint16_t len, void *user_data)
+{
+ struct frame frm;
+ static void* tmpdata = NULL;
+
+ /* copy data so we respect 'const' qualifier */
+ if(tmpdata == NULL)
+ tmpdata = malloc(HCI_MAX_FRAME_SIZE);
+
+ memcpy(tmpdata, data, len);
+
+ frm.data = tmpdata;
+ frm.len = len;
+ frm.data_len = len;
+ frm.in = 1;
+ printf("[Emulator ] ");
+ dump_frame(&frm);
+ send_frm(&frm);
+}
+
+static void btdev_recv(struct frame *frm)
+{
+ frm->in = 0;
+ printf("[Emulator ] ");
+ dump_frame(frm);
+ btdev_receive_h4(btdev, frm->data, frm->data_len);
+}
+
static bool check_match(struct frame *l, struct frame *r, char *msg)
{
uint8_t type_l = ((const uint8_t *) l->data)[0];
@@ -332,11 +363,16 @@ static bool process_in()
match = check_match(dumpseq.current->frame, &frm, msg);
/* process packet if match */
- if (match)
+ if (match) {
printf("[%4d/%4d] ", pos, dumpseq.len);
- else
- printf("[ Unknown ] %s\n ", msg);
+ if (dumpseq.current->attr->action == HCISEQ_ACTION_EMULATE) {
+ btdev_recv(&frm);
+ return true;
+ }
+ } else {
+ printf("[ Unknown ] %s\n ", msg);
+ }
dump_frame(&frm);
return match;
@@ -346,6 +382,11 @@ static bool process_out()
{
uint8_t pkt_type;
+ /* emulator sends response automatically */
+ if (dumpseq.current->attr->action == HCISEQ_ACTION_EMULATE) {
+ return 1;
+ }
+
pkt_type = ((const uint8_t *) dumpseq.current->frame->data)[0];
switch (pkt_type) {
@@ -531,6 +572,10 @@ int main(int argc, char *argv[])
dumpseq.current = dumpseq.frames;
calc_rel_ts(&dumpseq);
+ /* init emulator */
+ btdev = btdev_create(0);
+ btdev_set_send_handler(btdev, btdev_send, NULL);
+
gettimeofday(&start, NULL);
/*
@@ -548,6 +593,7 @@ int main(int argc, char *argv[])
process();
vhci_close();
+ btdev_destroy(btdev);
delete_list();
printf("Terminating\n");
--
1.7.9.5
^ permalink raw reply related
* [PATCH BlueZ v2 2/4] replay: Add timing functionality
From: Anton Weber @ 2012-08-13 18:34 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Anton Weber
In-Reply-To: <1344882885-23631-1-git-send-email-ant@antweb.me>
Add -d parameter that lets user choose between two timing modes.
delta: use time difference between two packets for delay
none: no delay
Add -m parameter to specify a factor that multiplies delays in
delta timing mode.
Add -t parameter to set the epoll timeout when receiving packets.
---
Makefile.tools | 3 +-
tools/replay/hciseq.c | 53 ++++++++++++++++++++++++++++
tools/replay/hciseq.h | 23 +++++++++++++
tools/replay/main.c | 56 +++++++++++++++++++++++++++++-
tools/replay/main.h | 21 +-----------
tools/replay/time.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++
tools/replay/time.h | 31 +++++++++++++++++
7 files changed, 256 insertions(+), 22 deletions(-)
create mode 100644 tools/replay/hciseq.c
create mode 100644 tools/replay/time.c
create mode 100644 tools/replay/time.h
diff --git a/Makefile.tools b/Makefile.tools
index 4a3aca5..6767300 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -70,7 +70,8 @@ emulator_btvirt_SOURCES = emulator/main.c monitor/bt.h \
emulator/btdev.h emulator/btdev.c
tools_replay_btreplay_SOURCES = tools/replay/main.h tools/replay/main.c \
- tools/replay/hciseq.h \
+ tools/replay/hciseq.h tools/replay/hciseq.c \
+ tools/replay/time.h tools/replay/time.c \
monitor/packet.h monitor/packet.c \
monitor/btsnoop.h monitor/btsnoop.c \
monitor/control.h monitor/control.c \
diff --git a/tools/replay/hciseq.c b/tools/replay/hciseq.c
new file mode 100644
index 0000000..8b24264
--- /dev/null
+++ b/tools/replay/hciseq.c
@@ -0,0 +1,53 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ * Copyright (C) 2012 Anton Weber <ant@antweb.me>
+ * Copyright (C) 2011-2012 Intel Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "hciseq.h"
+#include "time.h"
+#include "monitor/bt.h"
+
+void calc_rel_ts(struct hciseq_list *seq)
+{
+ struct timeval start;
+ struct hciseq_node *tmp;
+
+ start = seq->current->frame->ts;
+ tmp = seq->current;
+
+ /* first packet */
+ tmp->attr->ts_rel.tv_sec = 0;
+ tmp->attr->ts_rel.tv_usec = 0;
+ tmp->attr->ts_diff.tv_sec = 0;
+ tmp->attr->ts_diff.tv_usec = 0;
+
+ while (tmp->next != NULL) {
+ timeval_diff(&tmp->next->frame->ts, &start,
+ &tmp->next->attr->ts_rel);
+ timeval_diff(&tmp->next->frame->ts, &tmp->frame->ts,
+ &tmp->next->attr->ts_diff);
+ tmp = tmp->next;
+ }
+}
diff --git a/tools/replay/hciseq.h b/tools/replay/hciseq.h
index bf953cd..f9fe7c8 100644
--- a/tools/replay/hciseq.h
+++ b/tools/replay/hciseq.h
@@ -22,6 +22,25 @@
*
*/
+struct frame {
+ void *data;
+ uint32_t data_len;
+ void *ptr;
+ uint32_t len;
+ uint16_t dev_id;
+ uint8_t in;
+ uint8_t master;
+ uint16_t handle;
+ uint16_t cid;
+ uint16_t num;
+ uint8_t dlci;
+ uint8_t channel;
+ unsigned long flags;
+ struct timeval ts;
+ int pppdump_fd;
+ int audio_fd;
+};
+
enum hciseq_action {
HCISEQ_ACTION_REPLAY = 0,
};
@@ -33,6 +52,8 @@ struct hciseq_list {
};
struct hciseq_attr {
+ struct timeval ts_rel;
+ struct timeval ts_diff;
enum hciseq_action action;
};
@@ -41,3 +62,5 @@ struct hciseq_node {
struct hciseq_node *next;
struct hciseq_attr *attr;
};
+
+void calc_rel_ts(struct hciseq_list *seq);
diff --git a/tools/replay/main.c b/tools/replay/main.c
index 509d968..578936f 100644
--- a/tools/replay/main.c
+++ b/tools/replay/main.c
@@ -37,8 +37,10 @@
#include <unistd.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
+#include <sys/time.h>
#include "main.h"
+#include "time.h"
#include "lib/bluetooth.h"
#include "lib/hci.h"
#include "monitor/bt.h"
@@ -49,16 +51,22 @@
#define MAX_EPOLL_EVENTS 1
#define MAX_MSG 128
+#define TIMING_NONE 0
+#define TIMING_DELTA 1
+
static struct hciseq_list dumpseq;
static int fd;
static int pos = 1;
static int skipped = 0;
+static struct timeval start;
static int epoll_fd;
static struct epoll_event epoll_event;
static int timeout = -1;
+static int timing = TIMING_NONE;
+static double factor = 1;
static bool verbose = false;
static inline int read_n(int fd, char *buf, int len)
@@ -313,6 +321,10 @@ static bool process_in()
if (n < 0) {
perror("Could not receive\n");
return false;
+ } else if (n == 0) {
+ printf("[%4d/%4d] Timeout\n", pos, dumpseq.len);
+ skipped++;
+ return true;
}
/* is this the packet in the sequence? */
@@ -353,9 +365,29 @@ static bool process_out()
static void process()
{
+ struct timeval last, last_diff;
+ __useconds_t delay;
bool processed;
+ gettimeofday(&last, NULL);
do {
+ /* delay */
+ if (timing == TIMING_DELTA) {
+ /* consider exec time of process_out()/process_in() */
+ get_timeval_passed(&last, &last_diff);
+ if (timeval_cmp(&dumpseq.current->attr->ts_diff, &last_diff) >= 0) {
+ delay = timeval_diff(&dumpseq.current->attr->ts_diff,
+ &last_diff, NULL);
+ delay *= factor;
+ if (usleep(delay) == -1)
+ printf("Delay failed\n");
+ } else {
+ /* exec time was longer than delay */
+ printf("Packet delay - processing previous packet took longer than recorded time difference\n");
+ }
+ gettimeofday(&last, NULL);
+ }
+
if (dumpseq.current->frame->in == 1)
processed = process_out();
else
@@ -417,12 +449,18 @@ static void usage(void)
printf("hcireplay - Bluetooth replayer\n"
"Usage:\thcireplay-client [options] file...\n"
"options:\n"
+ "\t-d, --timing={none|delta} Specify timing mode\n"
+ "\t-m, --factor=<value> Use timing modifier\n"
+ "\t-t, --timeout=<value> Use timeout when receiving\n"
"\t-v, --verbose Enable verbose output\n"
"\t --version Give version information\n"
"\t --help Give a short usage message\n");
}
static const struct option main_options[] = {
+ {"timing", required_argument, NULL, 'd'},
+ {"factor", required_argument, NULL, 'm'},
+ {"timeout", required_argument, NULL, 't'},
{"verbose", no_argument, NULL, 'v'},
{"version", no_argument, NULL, 'V'},
{"help", no_argument, NULL, 'H'},
@@ -437,12 +475,25 @@ int main(int argc, char *argv[])
while (1) {
int opt;
- opt = getopt_long(argc, argv, "v",
+ opt = getopt_long(argc, argv, "d:m:t:v",
main_options, NULL);
if (opt < 0)
break;
switch (opt) {
+ case 'd':
+ if (!strcmp(optarg, "none"))
+ timing = TIMING_NONE;
+ else if (!strcmp(optarg, "delta"))
+ timing = TIMING_DELTA;
+
+ break;
+ case 'm':
+ factor = atof(optarg);
+ break;
+ case 't':
+ timeout = atoi(optarg);
+ break;
case 'v':
verbose = true;
break;
@@ -478,6 +529,9 @@ int main(int argc, char *argv[])
}
}
dumpseq.current = dumpseq.frames;
+ calc_rel_ts(&dumpseq);
+
+ gettimeofday(&start, NULL);
/*
* make sure we open the interface after parsing
diff --git a/tools/replay/main.h b/tools/replay/main.h
index d80deec..2223789 100644
--- a/tools/replay/main.h
+++ b/tools/replay/main.h
@@ -42,23 +42,4 @@ struct btsnoop_pkt {
} __attribute__ ((packed));
#define BTSNOOP_PKT_SIZE (sizeof(struct btsnoop_pkt))
-static uint8_t btsnoop_id[] = { 0x62, 0x74, 0x73, 0x6e, 0x6f, 0x6f, 0x70, 0x00 };
-
-struct frame {
- void *data;
- uint32_t data_len;
- void *ptr;
- uint32_t len;
- uint16_t dev_id;
- uint8_t in;
- uint8_t master;
- uint16_t handle;
- uint16_t cid;
- uint16_t num;
- uint8_t dlci;
- uint8_t channel;
- unsigned long flags;
- struct timeval ts;
- int pppdump_fd;
- int audio_fd;
-};
+uint8_t btsnoop_id[] = { 0x62, 0x74, 0x73, 0x6e, 0x6f, 0x6f, 0x70, 0x00 };
diff --git a/tools/replay/time.c b/tools/replay/time.c
new file mode 100644
index 0000000..029501a
--- /dev/null
+++ b/tools/replay/time.c
@@ -0,0 +1,91 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ * Copyright (C) 2012 Anton Weber <ant@antweb.me>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stdlib.h>
+#include <sys/time.h>
+
+#include "time.h"
+
+/*
+ * Adjust timeval structs to make sure usec difference is not negative
+ * see http://www.gnu.org/software/libc/manual/html_node/Elapsed-Time.html
+ */
+void timeval_adjust_usec(struct timeval *l, struct timeval *r) {
+ int tmpsec;
+
+ if (r->tv_usec > l->tv_usec) {
+ tmpsec = (r->tv_usec - l->tv_usec) / 1000000 + 1;
+ r->tv_sec += tmpsec;
+ r->tv_usec -= 1000000 * tmpsec;
+ }
+
+ if ((l->tv_usec - r->tv_usec) > 1000000) {
+ tmpsec = (l->tv_usec - r->tv_usec) / 1000000;
+ r->tv_sec -= tmpsec;
+ r->tv_usec += 1000000 * tmpsec;
+ }
+}
+
+__useconds_t
+timeval_diff(struct timeval *l, struct timeval *r, struct timeval *diff)
+{
+ static struct timeval tmp;
+
+ timeval_adjust_usec(l, r);
+
+ /* use local variable if we only need return value */
+ if (diff == NULL)
+ diff = &tmp;
+
+ diff->tv_sec = l->tv_sec - r->tv_sec;
+ diff->tv_usec = l->tv_usec - r->tv_usec;
+
+ return (diff->tv_sec * 1000000) + diff->tv_usec;
+}
+
+int timeval_cmp(struct timeval *l, struct timeval *r)
+{
+ timeval_adjust_usec(l, r);
+
+ if (l->tv_sec > r->tv_sec) {
+ return 1;
+ } else if (l->tv_sec < r->tv_sec) {
+ return -1;
+ } else {
+ if (l->tv_usec > r->tv_usec)
+ return 1;
+ else if (l->tv_usec < r->tv_usec)
+ return -1;
+ else
+ return 0;
+ }
+}
+
+inline __useconds_t
+get_timeval_passed(struct timeval *since, struct timeval *diff)
+{
+ struct timeval now;
+
+ gettimeofday(&now, NULL);
+
+ return timeval_diff(&now, since, diff);
+}
diff --git a/tools/replay/time.h b/tools/replay/time.h
new file mode 100644
index 0000000..0c876a4
--- /dev/null
+++ b/tools/replay/time.h
@@ -0,0 +1,31 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ * Copyright (C) 2012 Anton Weber <ant@antweb.me>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+void timeval_adjust_usec(struct timeval *l, struct timeval *r);
+
+__useconds_t
+timeval_diff(struct timeval *l, struct timeval *r, struct timeval *diff);
+
+int timeval_cmp(struct timeval *l, struct timeval *r);
+
+inline __useconds_t
+ get_timeval_passed(struct timeval *since, struct timeval *diff);
--
1.7.9.5
^ permalink raw reply related
* [PATCH BlueZ v2 1/4] replay: Add initial version of replay tool
From: Anton Weber @ 2012-08-13 18:34 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Anton Weber
In-Reply-To: <1344533773-12914-1-git-send-email-ant@antweb.me>
This utility uses a VHCI interface to simulate HCI traffic from
a recorded scenario. It reads packets from BTSnoop dump files and
replays them on the virtual interface.
It is meant as a debugging tool that allows to investigate problems
with particular controllers and Bluetooth hardware on other system
configurations.
---
v1 -> v2: File header check for "btsnoop" string incorrectly returned
failure on return value 0 instead of !=0
.gitignore | 1 +
Makefile.tools | 12 +-
tools/replay/hciseq.h | 43 +++++
tools/replay/main.c | 501 +++++++++++++++++++++++++++++++++++++++++++++++++
tools/replay/main.h | 64 +++++++
5 files changed, 620 insertions(+), 1 deletion(-)
create mode 100644 tools/replay/hciseq.h
create mode 100644 tools/replay/main.c
create mode 100644 tools/replay/main.h
diff --git a/.gitignore b/.gitignore
index 38318cd..d53e266 100644
--- a/.gitignore
+++ b/.gitignore
@@ -87,6 +87,7 @@ unit/test-eir
tools/btmgmt
monitor/btmon
emulator/btvirt
+tools/replay/btreplay
doc/*.bak
doc/*.stamp
diff --git a/Makefile.tools b/Makefile.tools
index 5579b86..4a3aca5 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -50,7 +50,7 @@ tools_ppporc_LDADD = lib/libbluetooth-private.la
tools_hcieventmask_LDADD = lib/libbluetooth-private.la
-noinst_PROGRAMS += tools/btmgmt monitor/btmon emulator/btvirt
+noinst_PROGRAMS += tools/btmgmt monitor/btmon emulator/btvirt tools/replay/btreplay
tools_btmgmt_SOURCES = tools/btmgmt.c src/glib-helper.c
tools_btmgmt_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@
@@ -69,6 +69,16 @@ emulator_btvirt_SOURCES = emulator/main.c monitor/bt.h \
emulator/vhci.h emulator/vhci.c \
emulator/btdev.h emulator/btdev.c
+tools_replay_btreplay_SOURCES = tools/replay/main.h tools/replay/main.c \
+ tools/replay/hciseq.h \
+ monitor/packet.h monitor/packet.c \
+ monitor/btsnoop.h monitor/btsnoop.c \
+ monitor/control.h monitor/control.c \
+ monitor/mainloop.h monitor/mainloop.c \
+ lib/hci.h
+
+tools_replay_btreplay_LDADD = lib/libbluetooth-private.la
+
if READLINE
bin_PROGRAMS += attrib/gatttool
diff --git a/tools/replay/hciseq.h b/tools/replay/hciseq.h
new file mode 100644
index 0000000..bf953cd
--- /dev/null
+++ b/tools/replay/hciseq.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ * Copyright (C) 2012 Anton Weber <ant@antweb.me>
+ * Copyright (C) 2011-2012 Intel Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+enum hciseq_action {
+ HCISEQ_ACTION_REPLAY = 0,
+};
+
+struct hciseq_list {
+ struct hciseq_node *frames;
+ struct hciseq_node *current;
+ int len;
+};
+
+struct hciseq_attr {
+ enum hciseq_action action;
+};
+
+struct hciseq_node {
+ struct frame *frame;
+ struct hciseq_node *next;
+ struct hciseq_attr *attr;
+};
diff --git a/tools/replay/main.c b/tools/replay/main.c
new file mode 100644
index 0000000..509d968
--- /dev/null
+++ b/tools/replay/main.c
@@ -0,0 +1,501 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ * Copyright (C) 2012 Anton Weber <ant@antweb.me>
+ * Copyright (C) 2011-2012 Intel Corporation
+ * Copyright (C) 2000-2002 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2003-2011 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/epoll.h>
+#include <sys/ioctl.h>
+
+#include "main.h"
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "monitor/bt.h"
+#include "monitor/btsnoop.h"
+#include "monitor/control.h"
+#include "monitor/packet.h"
+
+#define MAX_EPOLL_EVENTS 1
+#define MAX_MSG 128
+
+static struct hciseq_list dumpseq;
+
+static int fd;
+static int pos = 1;
+static int skipped = 0;
+
+static int epoll_fd;
+static struct epoll_event epoll_event;
+
+static int timeout = -1;
+static bool verbose = false;
+
+static inline int read_n(int fd, char *buf, int len)
+{
+ int t = 0, w;
+
+ while (len > 0) {
+ w = read(fd, buf, len);
+ if (w < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ return -1;
+ } else if (w == 0) {
+ return 0;
+ }
+
+ len -= w;
+ buf += w;
+ t += w;
+ }
+
+ return t;
+}
+
+static int
+parse_btsnoop(int fd, struct frame *frm, struct btsnoop_hdr *hdr)
+{
+ struct btsnoop_pkt pkt;
+ uint8_t pkt_type;
+ uint64_t ts;
+ int n;
+
+ n = read_n(fd, (void *) &pkt, BTSNOOP_PKT_SIZE);
+ if (n < 0)
+ return -1;
+ else if (n == 0)
+ return 0;
+
+ switch (ntohl(hdr->type)) {
+ case 1001:
+ if (ntohl(pkt.flags) & 0x02) {
+ if (ntohl(pkt.flags) & 0x01)
+ pkt_type = HCI_EVENT_PKT;
+ else
+ pkt_type = HCI_COMMAND_PKT;
+ } else
+ pkt_type = HCI_ACLDATA_PKT;
+
+ ((uint8_t *) frm->data)[0] = pkt_type;
+
+ frm->data_len = ntohl(pkt.len) + 1;
+ n = read_n(fd, frm->data + 1, frm->data_len - 1);
+ break;
+
+ case 1002:
+ frm->data_len = ntohl(pkt.len);
+ n = read_n(fd, frm->data, frm->data_len);
+ break;
+ }
+
+ frm->in = ntohl(pkt.flags) & 0x01;
+ ts = ntoh64(pkt.ts) - 0x00E03AB44A676000ll;
+ frm->ts.tv_sec = (ts / 1000000ll) + 946684800ll;
+ frm->ts.tv_usec = ts % 1000000ll;
+
+ return n;
+}
+
+static int parse_dump(int fd, struct hciseq_list *seq)
+{
+ struct frame *frm;
+ struct btsnoop_hdr bh;
+ int n, count;
+ struct hciseq_node *nodeptr, *last;
+
+ last = seq->current;
+
+ /* read BTSnoop header once */
+ if (read_n(fd, (void *) &bh, BTSNOOP_HDR_SIZE) != BTSNOOP_HDR_SIZE)
+ return -1;
+
+ /* check for "btsnoop" string in header */
+ if (memcmp(bh.id, btsnoop_id, sizeof(btsnoop_id)) != 0)
+ return -1;
+
+ count = seq->len;
+ while (1) {
+ frm = malloc(sizeof(*frm));
+ frm->data = malloc(HCI_MAX_FRAME_SIZE);
+
+ n = parse_btsnoop(fd, frm, &bh);
+ if (n <= 0) {
+ free(frm->data);
+ free(frm);
+ return n;
+ }
+
+ frm->ptr = frm->data;
+ frm->len = frm->data_len;
+
+ nodeptr = malloc(sizeof(*nodeptr));
+ nodeptr->frame = frm;
+ nodeptr->attr = malloc(sizeof(*nodeptr->attr));
+ nodeptr->attr->action = HCISEQ_ACTION_REPLAY;
+
+ if (last == NULL)
+ seq->frames = nodeptr;
+ else
+ last->next = nodeptr;
+
+ last = nodeptr;
+ nodeptr->next = NULL;
+ seq->len = ++count;
+ }
+
+ return 0;
+}
+
+static void dump_frame(struct frame *frm)
+{
+ struct timeval tv;
+ uint8_t pkt_type;
+
+ gettimeofday(&tv, NULL);
+
+ pkt_type = ((const uint8_t *) frm->data)[0];
+ switch (pkt_type) {
+ case BT_H4_CMD_PKT:
+ packet_hci_command(&tv, 0x00, frm->data + 1,
+ frm->data_len - 1);
+ break;
+ case BT_H4_EVT_PKT:
+ packet_hci_event(&tv, 0x00, frm->data + 1,
+ frm->data_len - 1);
+ break;
+ case BT_H4_ACL_PKT:
+ if (frm->in)
+ packet_hci_acldata(&tv, 0x00, 0x01,
+ frm->data + 1,
+ frm->data_len - 1);
+ else
+ packet_hci_acldata(&tv, 0x00, 0x00,
+ frm->data + 1,
+ frm->data_len - 1);
+ break;
+ default:
+ //TODO: raw dump
+ break;
+ }
+}
+
+static int send_frm(struct frame *frm)
+{
+ return write(fd, frm->data, frm->data_len);
+}
+
+static int recv_frm(int fd, struct frame *frm)
+{
+ int i, n;
+ int nevs;
+ uint8_t buf[HCI_MAX_FRAME_SIZE];
+ struct epoll_event ev[MAX_EPOLL_EVENTS];
+
+ nevs = epoll_wait(epoll_fd, ev, MAX_EPOLL_EVENTS, timeout);
+ if (nevs < 0)
+ return -1;
+ else if (nevs == 0)
+ return 0;
+
+ for (i = 0; i < nevs; i++) {
+ if (ev[i].events & (EPOLLERR | EPOLLHUP))
+ return -1;
+
+ n = read(fd, (void *) &buf, HCI_MAX_FRAME_SIZE);
+ if (n > 0) {
+ memcpy(frm->data, buf, n);
+ frm->data_len = n;
+ }
+ }
+
+ return n;
+}
+
+static bool check_match(struct frame *l, struct frame *r, char *msg)
+{
+ uint8_t type_l = ((const uint8_t *) l->data)[0];
+ uint8_t type_r = ((const uint8_t *) r->data)[0];
+ uint16_t opcode_l, opcode_r;
+ uint8_t evt_l, evt_r;
+
+ if (type_l != type_r) {
+ snprintf(msg, MAX_MSG,
+ "! Wrong packet type - expected (0x%2.2x), was (0x%2.2x)",
+ type_l, type_r);
+ return false;
+ }
+
+ switch (type_l) {
+ case BT_H4_CMD_PKT:
+ opcode_l = *((uint16_t *) (l->data + 1));
+ opcode_r = *((uint16_t *) (r->data + 1));
+ if (opcode_l != opcode_r) {
+ snprintf(msg, MAX_MSG,
+ "! Wrong opcode - expected (0x%2.2x|0x%4.4x), was (0x%2.2x|0x%4.4x)",
+ cmd_opcode_ogf(opcode_l),
+ cmd_opcode_ocf(opcode_l),
+ cmd_opcode_ogf(opcode_r),
+ cmd_opcode_ocf(opcode_r));
+ return false;
+ } else {
+ return true;
+ }
+ case BT_H4_EVT_PKT:
+ evt_l = *((uint8_t *) (l->data + 1));
+ evt_r = *((uint8_t *) (r->data + 1));
+ if (evt_l != evt_r) {
+ snprintf(msg, MAX_MSG,
+ "! Wrong event type - expected (0x%2.2x), was (0x%2.2x)",
+ evt_l, evt_r);
+ return false;
+ } else {
+ return true;
+ }
+ case BT_H4_ACL_PKT:
+ if (l->data_len != r->data_len)
+ return false;
+
+ return memcmp(l->data, r->data, l->data_len) == 0;
+ default:
+ snprintf(msg, MAX_MSG, "! Unknown packet type (0x%2.2x)",
+ type_l);
+
+ if (l->data_len != r->data_len)
+ return false;
+
+ return memcmp(l->data, r->data, l->data_len) == 0;
+ }
+}
+
+static bool process_in()
+{
+ static struct frame frm;
+ static uint8_t data[HCI_MAX_FRAME_SIZE];
+ int n;
+ bool match;
+ char msg[MAX_MSG];
+
+ frm.data = &data;
+ frm.ptr = frm.data;
+
+ n = recv_frm(fd, &frm);
+ if (n < 0) {
+ perror("Could not receive\n");
+ return false;
+ }
+
+ /* is this the packet in the sequence? */
+ msg[0] = '\0';
+ match = check_match(dumpseq.current->frame, &frm, msg);
+
+ /* process packet if match */
+ if (match)
+ printf("[%4d/%4d] ", pos, dumpseq.len);
+ else
+ printf("[ Unknown ] %s\n ", msg);
+
+ dump_frame(&frm);
+
+ return match;
+}
+
+static bool process_out()
+{
+ uint8_t pkt_type;
+
+ pkt_type = ((const uint8_t *) dumpseq.current->frame->data)[0];
+
+ switch (pkt_type) {
+ case BT_H4_EVT_PKT:
+ case BT_H4_ACL_PKT:
+ printf("[%4d/%4d] ", pos, dumpseq.len);
+ dump_frame(dumpseq.current->frame);
+ send_frm(dumpseq.current->frame);
+ break;
+ default:
+ printf("Unsupported packet 0x%2.2x\n", pkt_type);
+ break;
+ }
+
+ return true;
+}
+
+static void process()
+{
+ bool processed;
+
+ do {
+ if (dumpseq.current->frame->in == 1)
+ processed = process_out();
+ else
+ processed = process_in();
+
+ if (processed) {
+ dumpseq.current = dumpseq.current->next;
+ pos++;
+ }
+ } while (dumpseq.current != NULL);
+
+ printf("Done\n");
+ printf("Processed %d out of %d\n", dumpseq.len - skipped,
+ dumpseq.len);
+}
+
+static int vhci_open()
+{
+ fd = open("/dev/vhci", O_RDWR | O_NONBLOCK);
+ epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+ if (epoll_fd < 0)
+ return -1;
+
+ epoll_event.events = EPOLLIN;
+ epoll_event.data.fd = fd;
+
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD,
+ epoll_event.data.fd, &epoll_event) < 0) {
+ return -1;
+ }
+
+ return fd;
+}
+
+static int vhci_close()
+{
+ epoll_ctl(epoll_fd, EPOLL_CTL_DEL, epoll_event.data.fd, NULL);
+ return close(fd);
+}
+
+static void delete_list()
+{
+ struct hciseq_node *node, *tmp;
+
+ node = dumpseq.frames;
+ while (node != NULL) {
+ tmp = node;
+ node = node->next;
+
+ free(tmp->frame->data);
+ free(tmp->frame);
+ free(tmp->attr);
+ free(tmp);
+ }
+}
+
+static void usage(void)
+{
+ printf("hcireplay - Bluetooth replayer\n"
+ "Usage:\thcireplay-client [options] file...\n"
+ "options:\n"
+ "\t-v, --verbose Enable verbose output\n"
+ "\t --version Give version information\n"
+ "\t --help Give a short usage message\n");
+}
+
+static const struct option main_options[] = {
+ {"verbose", no_argument, NULL, 'v'},
+ {"version", no_argument, NULL, 'V'},
+ {"help", no_argument, NULL, 'H'},
+ {}
+};
+
+int main(int argc, char *argv[])
+{
+ int dumpfd;
+ int i;
+
+ while (1) {
+ int opt;
+
+ opt = getopt_long(argc, argv, "v",
+ main_options, NULL);
+ if (opt < 0)
+ break;
+
+ switch (opt) {
+ case 'v':
+ verbose = true;
+ break;
+ case 'V':
+ printf("%s\n", VERSION);
+ return EXIT_SUCCESS;
+ case 'H':
+ usage();
+ return EXIT_SUCCESS;
+ default:
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (optind >= argc) {
+ usage();
+ return EXIT_FAILURE;
+ }
+
+ dumpseq.current = NULL;
+ dumpseq.frames = NULL;
+ for (i = optind; i < argc; i++) {
+ dumpfd = open(argv[i], O_RDONLY);
+ if (dumpfd < 0) {
+ perror("Failed to open dump file");
+ return EXIT_FAILURE;
+ }
+
+ if (parse_dump(dumpfd, &dumpseq) < 0) {
+ fprintf(stderr, "Error parsing dump file\n");
+ vhci_close();
+ return EXIT_FAILURE;
+ }
+ }
+ dumpseq.current = dumpseq.frames;
+
+ /*
+ * make sure we open the interface after parsing
+ * through all files so we can start without delay
+ */
+ fd = vhci_open();
+ if (fd < 0) {
+ perror("Failed to open VHCI interface");
+ return EXIT_FAILURE;
+ }
+
+ printf("Running\n");
+
+ process();
+
+ vhci_close();
+ delete_list();
+ printf("Terminating\n");
+
+ return EXIT_SUCCESS;
+}
diff --git a/tools/replay/main.h b/tools/replay/main.h
new file mode 100644
index 0000000..d80deec
--- /dev/null
+++ b/tools/replay/main.h
@@ -0,0 +1,64 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ * Copyright (C) 2012 Anton Weber <ant@antweb.me>
+ * Copyright (C) 2011-2012 Intel Corporation
+ * Copyright (C) 2000-2002 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2003-2011 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "hciseq.h"
+
+struct btsnoop_hdr {
+ uint8_t id[8]; /* Identification Pattern */
+ uint32_t version; /* Version Number = 1 */
+ uint32_t type; /* Datalink Type */
+} __attribute__ ((packed));
+#define BTSNOOP_HDR_SIZE (sizeof(struct btsnoop_hdr))
+
+struct btsnoop_pkt {
+ uint32_t size; /* Original Length */
+ uint32_t len; /* Included Length */
+ uint32_t flags; /* Packet Flags */
+ uint32_t drops; /* Cumulative Drops */
+ uint64_t ts; /* Timestamp microseconds */
+ uint8_t data[0]; /* Packet Data */
+} __attribute__ ((packed));
+#define BTSNOOP_PKT_SIZE (sizeof(struct btsnoop_pkt))
+
+static uint8_t btsnoop_id[] = { 0x62, 0x74, 0x73, 0x6e, 0x6f, 0x6f, 0x70, 0x00 };
+
+struct frame {
+ void *data;
+ uint32_t data_len;
+ void *ptr;
+ uint32_t len;
+ uint16_t dev_id;
+ uint8_t in;
+ uint8_t master;
+ uint16_t handle;
+ uint16_t cid;
+ uint16_t num;
+ uint8_t dlci;
+ uint8_t channel;
+ unsigned long flags;
+ struct timeval ts;
+ int pppdump_fd;
+ int audio_fd;
+};
--
1.7.9.5
^ permalink raw reply related
* [PATCH] input: Implement idle timeout for fakehid
From: Jeff Hansen @ 2012-08-13 17:40 UTC (permalink / raw)
To: linux-bluetooth
[-- Attachment #1: Type: text/plain, Size: 174 bytes --]
(bump)
The batteries on my BD remote would die in a few days without this
patch. The idle timeout needs to be enforced for fakehid devices as
well as normal HID devices.
[-- Attachment #2: 0001-input-Implement-idle-timeout-for-fakehid.patch --]
[-- Type: text/x-patch, Size: 2950 bytes --]
>From a96f67cb6268e34e677e5d288f2c3b89acfca7fe Mon Sep 17 00:00:00 2001
From: Jeff Hansen <x@jeffhansen.com>
Date: Tue, 31 Jul 2012 22:45:23 -0600
Subject: [PATCH] input: Implement idle timeout for fakehid.
The batteries on my BD remote would die in a few days without this patch.
Signed-off-by: Jeff Hansen <x@jeffhansen.com>
---
input/device.c | 6 ++++++
input/device.h | 4 ++++
input/fakehid.c | 18 ++++++++++++++++++
3 files changed, 28 insertions(+), 0 deletions(-)
diff --git a/input/device.c b/input/device.c
index 0ab63c0..ae11a13 100644
--- a/input/device.c
+++ b/input/device.c
@@ -609,6 +609,7 @@ static int hidp_add_connection(const struct input_device *idev,
fake->disconnect = fake_hid_disconnect;
fake->priv = fake_hid;
fake->idev = idev;
+ fake->timeout = iconn->timeout * 1000;
fake = fake_hid_connadd(fake, iconn->intr_io, fake_hid);
if (fake == NULL)
err = -ENOMEM;
@@ -1257,3 +1258,8 @@ int input_device_close_channels(const bdaddr_t *src, const bdaddr_t *dst)
return 0;
}
+
+void input_device_request_disconnect(const struct input_device *idev)
+{
+ device_request_disconnect(idev->device, NULL);
+}
diff --git a/input/device.h b/input/device.h
index 14c0f97..416cc9c 100644
--- a/input/device.h
+++ b/input/device.h
@@ -40,6 +40,8 @@ struct fake_input {
int (*disconnect) (struct input_conn *iconn);
void *priv;
const struct input_device *idev;
+ guint idle_timeout;
+ uint32_t timeout;
};
int fake_input_register(DBusConnection *conn, struct btd_device *device,
@@ -54,3 +56,5 @@ int input_device_unregister(const char *path, const char *uuid);
int input_device_set_channel(const bdaddr_t *src, const bdaddr_t *dst, int psm,
GIOChannel *io);
int input_device_close_channels(const bdaddr_t *src, const bdaddr_t *dst);
+
+void input_device_request_disconnect(const struct input_device *idev);
diff --git a/input/fakehid.c b/input/fakehid.c
index b809870..0407ae3 100644
--- a/input/fakehid.c
+++ b/input/fakehid.c
@@ -208,6 +208,13 @@ error:
return -1;
}
+static gboolean ps3remote_idle(gpointer data)
+{
+ struct fake_input *fake = data;
+ input_device_request_disconnect(fake->idev);
+ return FALSE;
+}
+
static gboolean ps3remote_event(GIOChannel *chan, GIOCondition cond,
gpointer data)
{
@@ -218,6 +225,13 @@ static gboolean ps3remote_event(GIOChannel *chan, GIOCondition cond,
char buff[50];
int fd;
+ if (fake->idle_timeout) {
+ g_source_remove(fake->idle_timeout);
+ fake->idle_timeout = 0;
+ }
+ if (fake->timeout)
+ fake->idle_timeout = g_timeout_add(fake->timeout, ps3remote_idle, fake);
+
if (cond & G_IO_NVAL)
return FALSE;
@@ -337,6 +351,10 @@ static gboolean fake_hid_common_connect(struct fake_input *fake, GError **err)
static int fake_hid_common_disconnect(struct fake_input *fake)
{
+ if (fake->idle_timeout) {
+ g_source_remove(fake->idle_timeout);
+ fake->idle_timeout = 0;
+ }
return 0;
}
--
1.7.8.6
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox