* Re: [PATCH] compat: fix system crash on 2.6.35 when flushing work
From: Zefir Kurtisi @ 2012-08-13 11:15 UTC (permalink / raw)
To: C. McPherson; +Cc: mcgrof, lf_driver_backport, linux-wireless, linux-bluetooth
In-Reply-To: <5027D79E.9050607@verizon.net>
On 08/12/2012 06:19 PM, C. McPherson wrote:
> Zefir:
> Thanks a lot for this reference. All my systems are running Ubuntu
> 10.04/10.10. I was updating our compat-wireless with the stable
> compat-wireless 3.5
> and came across this crash in our testing lab. I added your patch and
> the stable compat-wireless 3.5 is now working with our Ubuntu.
>
> -Tex
>
>
Hi Tex,
the fix Hauke provided is the correct one. The QH I posted was a lucky
punch that for some reason prevented the system crashing without
resolving the issue.
^ permalink raw reply
* Re: [PATCH BlueZ V5 1/5] AVRCP: Add TG Record to support AVRCP Browsing
From: Luiz Augusto von Dentz @ 2012-08-13 11:27 UTC (permalink / raw)
To: Vani-dineshbhai PATEL; +Cc: User Name, Joohi, Vani
In-Reply-To: <1344591300-1003-1-git-send-email-vani.patel@stericsson.com>
Hi Vani,
On Fri, Aug 10, 2012 at 12:35 PM, Vani-dineshbhai PATEL
<vani.patel@stericsson.com> wrote:
> From: Vani Patel <vani.patel@stericsson.com>
>
> Adds SDP record to support browsing
> ---
> audio/avctp.c | 4 ++--
> audio/avctp.h | 3 ++-
> audio/avrcp.c | 25 +++++++++++++++++++++----
> 3 files changed, 25 insertions(+), 7 deletions(-)
>
> diff --git a/audio/avctp.c b/audio/avctp.c
> index 074eabd..a20dba9 100644
> --- a/audio/avctp.c
> +++ b/audio/avctp.c
> @@ -802,7 +802,7 @@ static GIOChannel *avctp_server_socket(const bdaddr_t *src, gboolean master)
> io = bt_io_listen(BT_IO_L2CAP, NULL, avctp_confirm_cb, NULL,
> NULL, &err,
> BT_IO_OPT_SOURCE_BDADDR, src,
> - BT_IO_OPT_PSM, AVCTP_PSM,
> + BT_IO_OPT_PSM, AVCTP_CONTROL_PSM,
> BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
> BT_IO_OPT_MASTER, master,
> BT_IO_OPT_INVALID);
> @@ -1090,7 +1090,7 @@ struct avctp *avctp_connect(const bdaddr_t *src, const bdaddr_t *dst)
> io = bt_io_connect(BT_IO_L2CAP, avctp_connect_cb, session, NULL, &err,
> BT_IO_OPT_SOURCE_BDADDR, &session->server->src,
> BT_IO_OPT_DEST_BDADDR, &session->dst,
> - BT_IO_OPT_PSM, AVCTP_PSM,
> + BT_IO_OPT_PSM, AVCTP_CONTROL_PSM,
> BT_IO_OPT_INVALID);
> if (err) {
> avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
> diff --git a/audio/avctp.h b/audio/avctp.h
> index d0cbd97..34b0c1c 100644
> --- a/audio/avctp.h
> +++ b/audio/avctp.h
> @@ -22,7 +22,8 @@
> *
> */
>
> -#define AVCTP_PSM 23
> +#define AVCTP_CONTROL_PSM 23
> +#define AVCTP_BROWSING_PSM 27
>
> #define AVC_MTU 512
> #define AVC_HEADER_LENGTH 3
> diff --git a/audio/avrcp.c b/audio/avrcp.c
> index d925365..ca40c1e 100644
> --- a/audio/avrcp.c
> +++ b/audio/avrcp.c
> @@ -190,7 +190,7 @@ static sdp_record_t *avrcp_ct_record(void)
> sdp_list_t *aproto, *proto[2];
> sdp_record_t *record;
> sdp_data_t *psm, *version, *features;
> - uint16_t lp = AVCTP_PSM;
> + uint16_t lp = AVCTP_CONTROL_PSM;
> uint16_t avrcp_ver = 0x0100, avctp_ver = 0x0103;
> uint16_t feat = ( AVRCP_FEATURE_CATEGORY_1 |
> AVRCP_FEATURE_CATEGORY_2 |
> @@ -252,13 +252,15 @@ static sdp_record_t *avrcp_ct_record(void)
>
> static sdp_record_t *avrcp_tg_record(void)
> {
> - sdp_list_t *svclass_id, *pfseq, *apseq, *root;
> + sdp_list_t *svclass_id, *pfseq, *apseq, *root, *apseq_browsing;
> uuid_t root_uuid, l2cap, avctp, avrtg;
> sdp_profile_desc_t profile[1];
> sdp_list_t *aproto, *proto[2];
> sdp_record_t *record;
> - sdp_data_t *psm, *version, *features;
> - uint16_t lp = AVCTP_PSM;
> + sdp_data_t *psm, *version, *features, *psm_browsing;
> + sdp_list_t *aproto_browsing, *proto_browsing[2] = {0};
> + uint16_t lp = AVCTP_CONTROL_PSM;
> + uint16_t lp_browsing = AVCTP_BROWSING_PSM;
> uint16_t avrcp_ver = 0x0104, avctp_ver = 0x0103;
> uint16_t feat = ( AVRCP_FEATURE_CATEGORY_1 |
> AVRCP_FEATURE_CATEGORY_2 |
According to the spec if we register the browsing channel we should
set it in feature bits, btw apparently apseq_browsing is leaking
please make sure you run your patches with valgrind/gdb to catch this
type of errors.
--
Luiz Augusto von Dentz
^ permalink raw reply
* RE: [PATCH BlueZ V5 1/5] AVRCP: Add TG Record to support AVRCP Browsing
From: Michal.Labedzki @ 2012-08-13 11:49 UTC (permalink / raw)
To: luiz.dentz, vani.patel; +Cc: linux-bluetooth, Joohi.rastogi, vani273
In-Reply-To: <CABBYNZLMLCpfd_GzUMvtND6m0JJsuKLDCiyzvQAZkBrsV5U7vw@mail.gmail.com>
Hi Luiz,
>> diff --git a/audio/avrcp.c b/audio/avrcp.c
>> index d925365..ca40c1e 100644
>> --- a/audio/avrcp.c
> +++ b/audio/avrcp.c
>> @@ -190,7 +190,7 @@ static sdp_record_t *avrcp_ct_record(void)
>> sdp_list_t *aproto, *proto[2];
>> sdp_record_t *record;
>> sdp_data_t *psm, *version, *features;
>> - uint16_t lp = AVCTP_PSM;
>> + uint16_t lp = AVCTP_CONTROL_PSM;
>> uint16_t avrcp_ver = 0x0100, avctp_ver = 0x0103;
>> uint16_t feat = ( AVRCP_FEATURE_CATEGORY_1 |
>> AVRCP_FEATURE_CATEGORY_2 |
>> @@ -252,13 +252,15 @@ static sdp_record_t *avrcp_ct_record(void)
>>
>> static sdp_record_t *avrcp_tg_record(void)
>> {
>> - sdp_list_t *svclass_id, *pfseq, *apseq, *root;
> + sdp_list_t *svclass_id, *pfseq, *apseq, *root, *apseq_browsing;
>> uuid_t root_uuid, l2cap, avctp, avrtg;
>> sdp_profile_desc_t profile[1];
>> sdp_list_t *aproto, *proto[2];
>> sdp_record_t *record;
>> - sdp_data_t *psm, *version, *features;
>> - uint16_t lp = AVCTP_PSM;
>> + sdp_data_t *psm, *version, *features, *psm_browsing;
>> + sdp_list_t *aproto_browsing, *proto_browsing[2] = {0};
>> + uint16_t lp = AVCTP_CONTROL_PSM;
>> + uint16_t lp_browsing = AVCTP_BROWSING_PSM;
>> uint16_t avrcp_ver = 0x0104, avctp_ver = 0x0103;
>> uint16_t feat = ( AVRCP_FEATURE_CATEGORY_1 |
>> AVRCP_FEATURE_CATEGORY_2 |
>According to the spec if we register the browsing channel we should
>set it in feature bits, btw apparently apseq_browsing is leaking
>please make sure you run your patches with valgrind/gdb to catch this
>type of errors.
>
>--
>Luiz Augusto von Dentz
According to the specification we should not expose browsing in feature bits:
"*4: Bit 6 (Browsing supported) is not set based on category. Bit 6 in the SDP record shall only be set if
browsing of the "Media Player Virtual Filesystem" is supported."
So no GetFolderItems on VFS scope - no browsing.
Regards / Pozdrawiam
-------------------------------------------------------------------------------------------------------------
Michał Łabędzki
ASCII: Michal Labedzki
e-mail: michal.labedzki@tieto.com
office communicator: michal.labedzki@tieto.com
location: Poland, Wrocław, Legnicka 55F
room: 420
phone: +48 717 740 340
---
Tieto Corporation / Tieto Poland
http://www.tieto.com / http://www.tieto.pl
---
Tieto Poland spółka z ograniczoną odpowiedzialnością z siedzibą w Szczecinie, ul. Malczewskiego 26. Zarejestrowana w Sądzie Rejonowym Szczecin-Centrum w Szczecinie, XIII Wydział Gospodarczy Krajowego Rejestru Sądowego pod numerem 0000124858. NIP: 8542085557. REGON: 812023656. Kapitał zakładowy: 4 271500 PLN
________________________________________
^ permalink raw reply
* Re: [PATCH BlueZ V5 1/5] AVRCP: Add TG Record to support AVRCP Browsing
From: Luiz Augusto von Dentz @ 2012-08-13 12:15 UTC (permalink / raw)
To: Michal.Labedzki; +Cc: vani.patel, linux-bluetooth, Joohi.rastogi, vani273
In-Reply-To: <E50901D4F2CF69428D43141B7C8586792CF109BB8B@EXMB03.eu.tieto.com>
Hi Michal,
On Mon, Aug 13, 2012 at 2:49 PM, <Michal.Labedzki@tieto.com> wrote:
> According to the specification we should not expose browsing in feature bits:
> "*4: Bit 6 (Browsing supported) is not set based on category. Bit 6 in the SDP record shall only be set if
> browsing of the "Media Player Virtual Filesystem" is supported."
>
> So no GetFolderItems on VFS scope - no browsing.
Well since SDP actually rely on the player to support that feature so
we might actually make it always be set and if the player doesn't
support we return an error or empty list. The spec itself states that
PlayerFeatureBitmask should be used instead, so the way I interpreted
it is that Bit 6 is there to tell if the transport support that not
the player itself.
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: gstreamer a2dpSource plugin
From: Luiz Augusto von Dentz @ 2012-08-13 12:23 UTC (permalink / raw)
To: alistair.rodger; +Cc: linux-bluetooth
In-Reply-To: <5027DC19.8020505@ntlworld.com>
Hi,
On Sun, Aug 12, 2012 at 7:38 PM, alistair.rodger
<alistair.rodger@ntlworld.com> wrote:
> Hello,
>
> I am looking for some help getting audio out of the bluez stack using
> gstreamer? Are we still using an alsa source or should we be using the
> MediaTransport file descriptor.
>
> I am able to generate a sink file descriptor, using the simple-endpoint
> script, but don't know which gstreamer plugin to use.
>
> I am able stream to a device using the a2dpsink.
What do you mean by which plugin to use? You are using a2dpsink
already, I don't think I got what you want.
I normally test using the following pipeline:
gst-launch -v audiotestsrc ! audio/x-raw-int,channels=2 ! audioconvert
! sbcenc ! a2dpsink
transport=/org/bluez/{PID}/hci0/dev_AA_BB_CC_DD_EE_FF/fd0
--
Luiz Augusto von Dentz
^ permalink raw reply
* [PATCH BlueZ 0/3] HoG: Add support for non-HID services encapsulated in the HID protocol
From: João Paulo Rechi Vita @ 2012-08-13 12:23 UTC (permalink / raw)
To: linux-bluetooth; +Cc: João Paulo Rechi Vita
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(-)
--
1.7.11.2
^ permalink raw reply
* [PATCH BlueZ 1/3] gatt: Add a new descriptor UUID
From: João Paulo Rechi Vita @ 2012-08-13 12:23 UTC (permalink / raw)
To: linux-bluetooth; +Cc: João Paulo Rechi Vita
In-Reply-To: <1344860596-30617-1-git-send-email-jprvita@openbossa.org>
Add the UUID of the External Report Reference descriptor.
---
attrib/gatt.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/attrib/gatt.h b/attrib/gatt.h
index c7e79ab..aab93b6 100644
--- a/attrib/gatt.h
+++ b/attrib/gatt.h
@@ -46,6 +46,7 @@
#define GATT_CHARAC_FMT_UUID 0x2904
#define GATT_CHARAC_AGREG_FMT_UUID 0x2905
#define GATT_CHARAC_VALID_RANGE_UUID 0x2906
+#define GATT_EXTERNAL_REPORT_REFERENCE 0x2907
#define GATT_REPORT_REFERENCE 0x2908
/* Client Characteristic Configuration bit field */
--
1.7.11.2
^ permalink raw reply related
* [PATCH BlueZ 2/3] hog: discover External Report Reference descriptor
From: João Paulo Rechi Vita @ 2012-08-13 12:23 UTC (permalink / raw)
To: linux-bluetooth; +Cc: João Paulo Rechi Vita
In-Reply-To: <1344860596-30617-1-git-send-email-jprvita@openbossa.org>
Non-HID service data may be encapsulated on the HID protocol and
transfered as a HID Report. This descriptor is used to map a report
on the USB-HID descriptor that transports non-HID data to the
characteristic on a external service that will actually transport the
data on GATT devices.
---
profiles/input/hog_device.c | 54 +++++++++++++++++++++++++++++++++------------
1 file changed, 40 insertions(+), 14 deletions(-)
diff --git a/profiles/input/hog_device.c b/profiles/input/hog_device.c
index ffd7139..f4cf596 100644
--- a/profiles/input/hog_device.c
+++ b/profiles/input/hog_device.c
@@ -170,6 +170,23 @@ static void write_ccc(uint16_t handle, gpointer user_data)
report_ccc_written_cb, hogdev);
}
+static void external_report_reference_cb(guint8 status, const guint8 *pdu,
+ guint16 plen, gpointer user_data)
+{
+ if (status != 0) {
+ error("Read External Report Reference descriptor failed: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ if (plen != 3) {
+ error("Malformed ATT read response");
+ return;
+ }
+
+ DBG("External Report Reference read: 0x%02x 0x%02x", pdu[1], pdu[2]);
+}
+
static void report_reference_cb(guint8 status, const guint8 *pdu,
guint16 plen, gpointer user_data)
{
@@ -194,8 +211,8 @@ static void report_reference_cb(guint8 status, const guint8 *pdu,
static void discover_descriptor_cb(guint8 status, const guint8 *pdu,
guint16 len, gpointer user_data)
{
- struct report *report = user_data;
- struct hog_device *hogdev = report->hogdev;
+ struct report *report;
+ struct hog_device *hogdev;
struct att_data_list *list;
uint8_t format;
int i;
@@ -221,11 +238,22 @@ static void discover_descriptor_cb(guint8 status, const guint8 *pdu,
handle = att_get_u16(value);
uuid16 = att_get_u16(&value[2]);
- if (uuid16 == GATT_CLIENT_CHARAC_CFG_UUID)
- write_ccc(handle, hogdev);
- else if (uuid16 == GATT_REPORT_REFERENCE)
+ switch (uuid16) {
+ case GATT_CLIENT_CHARAC_CFG_UUID:
+ report = user_data;
+ write_ccc(handle, report->hogdev);
+ break;
+ case GATT_REPORT_REFERENCE:
+ report = user_data;
+ gatt_read_char(report->hogdev->attrib, handle, 0,
+ report_reference_cb, report);
+ break;
+ case GATT_EXTERNAL_REPORT_REFERENCE:
+ hogdev = user_data;
gatt_read_char(hogdev->attrib, handle, 0,
- report_reference_cb, report);
+ external_report_reference_cb, hogdev);
+ break;
+ }
}
done:
@@ -372,7 +400,7 @@ static void char_discovered_cb(GSList *chars, guint8 status, gpointer user_data)
bt_uuid_t report_uuid, report_map_uuid, info_uuid, proto_mode_uuid;
struct report *report;
GSList *l;
- uint16_t map_handle = 0, info_handle = 0, proto_mode_handle = 0;
+ uint16_t info_handle = 0, proto_mode_handle = 0;
if (status != 0) {
const char *str = att_ecode2str(status);
@@ -404,9 +432,11 @@ static void char_discovered_cb(GSList *chars, guint8 status, gpointer user_data)
hogdev->reports = g_slist_append(hogdev->reports,
report);
discover_descriptor(hogdev->attrib, chr, next, report);
- } else if (bt_uuid_cmp(&uuid, &report_map_uuid) == 0)
- map_handle = chr->value_handle;
- else if (bt_uuid_cmp(&uuid, &info_uuid) == 0)
+ } else if (bt_uuid_cmp(&uuid, &report_map_uuid) == 0) {
+ gatt_read_char(hogdev->attrib, chr->value_handle, 0,
+ report_map_read_cb, hogdev);
+ discover_descriptor(hogdev->attrib, chr, next, NULL);
+ } else if (bt_uuid_cmp(&uuid, &info_uuid) == 0)
info_handle = chr->value_handle;
else if (bt_uuid_cmp(&uuid, &proto_mode_uuid) == 0)
proto_mode_handle = chr->value_handle;
@@ -421,10 +451,6 @@ static void char_discovered_cb(GSList *chars, guint8 status, gpointer user_data)
if (info_handle)
gatt_read_char(hogdev->attrib, info_handle, 0,
info_read_cb, hogdev);
-
- if (map_handle)
- gatt_read_char(hogdev->attrib, map_handle, 0,
- report_map_read_cb, hogdev);
}
static void output_written_cb(guint8 status, const guint8 *pdu,
--
1.7.11.2
^ permalink raw reply related
* [PATCH BlueZ 3/3] hog: discover the non-HID service characteristic
From: João Paulo Rechi Vita @ 2012-08-13 12:23 UTC (permalink / raw)
To: linux-bluetooth; +Cc: João Paulo Rechi Vita
In-Reply-To: <1344860596-30617-1-git-send-email-jprvita@openbossa.org>
Find the characteristic by the UUID provided on the External Report
Reference descriptor and enable notifications for it. The characteristic
will be handled as a HID report and it's data processed through the uhid
device.
---
profiles/input/hog_device.c | 76 +++++++++++++++++++++++++++++++++++----------
1 file changed, 59 insertions(+), 17 deletions(-)
diff --git a/profiles/input/hog_device.c b/profiles/input/hog_device.c
index f4cf596..5a1de12 100644
--- a/profiles/input/hog_device.c
+++ b/profiles/input/hog_device.c
@@ -170,23 +170,6 @@ static void write_ccc(uint16_t handle, gpointer user_data)
report_ccc_written_cb, hogdev);
}
-static void external_report_reference_cb(guint8 status, const guint8 *pdu,
- guint16 plen, gpointer user_data)
-{
- if (status != 0) {
- error("Read External Report Reference descriptor failed: %s",
- att_ecode2str(status));
- return;
- }
-
- if (plen != 3) {
- error("Malformed ATT read response");
- return;
- }
-
- DBG("External Report Reference read: 0x%02x 0x%02x", pdu[1], pdu[2]);
-}
-
static void report_reference_cb(guint8 status, const guint8 *pdu,
guint16 plen, gpointer user_data)
{
@@ -208,6 +191,9 @@ static void report_reference_cb(guint8 status, const guint8 *pdu,
DBG("Report ID: 0x%02x Report type: 0x%02x", pdu[1], pdu[2]);
}
+static void external_report_reference_cb(guint8 status, const guint8 *pdu,
+ guint16 plen, gpointer user_data);
+
static void discover_descriptor_cb(guint8 status, const guint8 *pdu,
guint16 len, gpointer user_data)
{
@@ -274,6 +260,62 @@ static void discover_descriptor(GAttrib *attrib, struct gatt_char *chr,
gatt_find_info(attrib, start, end, discover_descriptor_cb, user_data);
}
+static void external_service_char_cb(GSList *chars, guint8 status,
+ gpointer user_data)
+{
+ struct hog_device *hogdev = user_data;
+ struct report *report;
+ GSList *l;
+
+ if (status != 0) {
+ const char *str = att_ecode2str(status);
+ DBG("Discover external service characteristic failed: %s", str);
+ return;
+ }
+
+ for (l = chars; l; l = g_slist_next(l)) {
+ struct gatt_char *chr, *next;
+
+ chr = l->data;
+ next = l->next ? l->next->data : NULL;
+
+ DBG("0x%04x UUID: %s properties: %02x",
+ chr->handle, chr->uuid, chr->properties);
+
+ report = g_new0(struct report, 1);
+ report->hogdev = hogdev;
+ report->decl = g_memdup(chr, sizeof(*chr));
+ hogdev->reports = g_slist_append(hogdev->reports, report);
+ discover_descriptor(hogdev->attrib, chr, next, report);
+ }
+}
+
+static void external_report_reference_cb(guint8 status, const guint8 *pdu,
+ guint16 plen, gpointer user_data)
+{
+ struct hog_device *hogdev = user_data;
+ uint16_t uuid16;
+ bt_uuid_t uuid;
+
+ if (status != 0) {
+ error("Read External Report Reference descriptor failed: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ if (plen != 3) {
+ error("Malformed ATT read response");
+ return;
+ }
+
+ uuid16 = att_get_u16(&pdu[1]);
+ DBG("External report reference read, external report characteristic "
+ "UUID: 0x%04x", uuid16);
+ bt_uuid16_create(&uuid, uuid16);
+ gatt_discover_char(hogdev->attrib, 0x00, 0xff, &uuid,
+ external_service_char_cb, hogdev);
+}
+
static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
gpointer user_data)
{
--
1.7.11.2
^ permalink raw reply related
* [RFCv3 00/20] Bluetooth: Create AMP physical link
From: Andrei Emeltchenko @ 2012-08-13 13:50 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1340981212-21709-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
This set of patches enhances A2MP protocol and creates physical
link between AMP controllers. This is further iteration towards
Bluetooth High Speed.
Changes:
* v3: Remove workqueue from callback processing; change callback functions
names according to reviewers recommendations; create global amp_mgr_list to
have lookup to amp manager, physical and logical links so for those HCI events
which might be identified by __handler__ we have lookup; remove extensive
hexdump from gen_amp_key.
* v2: Fix typos and bugs, add functionality: now physical connection
might be established.
* v1: Fix typos, change debug prints, refactor code for better
splitting functionality.
Andrei Emeltchenko (19):
Bluetooth: General HCI callback implementation
Bluetooth: Add callback clear to ops->teardown
Bluetooth: AMP: Use HCI callback for Read AMP Info
Bluetooth: AMP: Use HCI callback to Read Loc AMP Assoc
Bluetooth: A2MP: Process Discover Response
Bluetooth: AMP: Physical link struct definitions
Bluetooth: AMP: Remote AMP ctrl definitions
Bluetooth: AMP: Use phylink in create/disc phylink req
Bluetooth: A2MP: Process A2MP Getinfo Rsp
Bluetooth: A2MP: Process A2MP Get AMP Assoc Rsp
Bluetooth: A2MP: Create A2MP workqueue
Bluetooth: Choose connection based on capabilities
Bluetooth: AMP: Add AMP key calculation
Bluetooth: AMP: Create Physical Link
Bluetooth: AMP: Write remote AMP Assoc
Bluetooth: A2MP: Add fallback to normal l2cap init sequence
Bluetooth: A2MP: Create amp_mgr global list
Bluetooth: AMP: Process Chan Selected event
Bluetooth: AMP: Process physical link complete event
Dmitry Kasatkin (1):
Bluetooth: Add function to derive AMP key using hmac
include/net/bluetooth/a2mp.h | 16 ++
include/net/bluetooth/amp.h | 27 +++
include/net/bluetooth/hci.h | 3 +
include/net/bluetooth/hci_core.h | 42 +++++
include/net/bluetooth/l2cap.h | 1 +
include/net/bluetooth/pal.h | 58 +++++++
net/bluetooth/Kconfig | 1 +
net/bluetooth/Makefile | 2 +-
net/bluetooth/a2mp.c | 345 +++++++++++++++++++++++++++++++++++---
net/bluetooth/amp.c | 294 ++++++++++++++++++++++++++++++++
net/bluetooth/hci_core.c | 106 ++++++++++++
net/bluetooth/hci_event.c | 139 ++++++++++++++-
net/bluetooth/l2cap_core.c | 39 ++++-
net/bluetooth/pal.c | 330 ++++++++++++++++++++++++++++++++++++
14 files changed, 1374 insertions(+), 29 deletions(-)
create mode 100644 include/net/bluetooth/amp.h
create mode 100644 include/net/bluetooth/pal.h
create mode 100644 net/bluetooth/amp.c
create mode 100644 net/bluetooth/pal.c
--
1.7.9.5
^ permalink raw reply
* [RFCv3 01/20] Bluetooth: General HCI callback implementation
From: Andrei Emeltchenko @ 2012-08-13 13:50 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1344865838-9165-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Add general HCI callback implementation. Can be used for executing
HCI commands from A2MP protocol.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
include/net/bluetooth/hci_core.h | 25 +++++++++
net/bluetooth/hci_core.c | 107 ++++++++++++++++++++++++++++++++++++++
2 files changed, 132 insertions(+)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 41d9439..0985014 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -124,6 +124,17 @@ struct le_scan_params {
#define HCI_MAX_SHORT_NAME_LENGTH 10
+struct hci_dev;
+
+struct hci_cb_cmd {
+ struct list_head list;
+ u16 opcode;
+ u8 status;
+ void *opt;
+ void (*cb)(struct hci_dev *hdev, struct hci_cb_cmd *cmd);
+ void (*destructor)(struct hci_dev *hdev, struct hci_cb_cmd *cmd);
+};
+
#define NUM_REASSEMBLY 4
struct hci_dev {
struct list_head list;
@@ -236,6 +247,9 @@ struct hci_dev {
struct list_head mgmt_pending;
+ struct mutex cb_list_lock;
+ struct list_head cb_list;
+
struct discovery_state discovery;
struct hci_conn_hash conn_hash;
struct list_head blacklist;
@@ -1092,5 +1106,16 @@ int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window,
int hci_cancel_le_scan(struct hci_dev *hdev);
u8 bdaddr_to_le(u8 bdaddr_type);
+struct hci_cb_cmd *hci_callback_find(struct hci_dev *hdev, __u16 opcode);
+int hci_callback_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen,
+ void *param,
+ void (*cb)(struct hci_dev *hdev,
+ struct hci_cb_cmd *cmd),
+ void *opt,
+ void (*destructor)(struct hci_dev *hdev,
+ struct hci_cb_cmd *cmd),
+ gfp_t flags);
+void hci_callback_remove(struct hci_dev *hdev, struct hci_cb_cmd *cmd);
+void hci_callback_process(struct hci_dev *hdev, __u16 opcode, u8 status);
#endif /* __HCI_CORE_H */
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 28bab9d..ecc8644 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -36,6 +36,7 @@
static void hci_rx_work(struct work_struct *work);
static void hci_cmd_work(struct work_struct *work);
static void hci_tx_work(struct work_struct *work);
+static void hci_callback_clear(struct hci_dev *hdev);
/* HCI device list */
LIST_HEAD(hci_dev_list);
@@ -1645,6 +1646,7 @@ struct hci_dev *hci_alloc_dev(void)
mutex_init(&hdev->lock);
mutex_init(&hdev->req_lock);
+ mutex_init(&hdev->cb_list_lock);
INIT_LIST_HEAD(&hdev->mgmt_pending);
INIT_LIST_HEAD(&hdev->blacklist);
@@ -1652,6 +1654,7 @@ struct hci_dev *hci_alloc_dev(void)
INIT_LIST_HEAD(&hdev->link_keys);
INIT_LIST_HEAD(&hdev->long_term_keys);
INIT_LIST_HEAD(&hdev->remote_oob_data);
+ INIT_LIST_HEAD(&hdev->cb_list);
INIT_WORK(&hdev->rx_work, hci_rx_work);
INIT_WORK(&hdev->cmd_work, hci_cmd_work);
@@ -1817,6 +1820,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
hci_link_keys_clear(hdev);
hci_smp_ltks_clear(hdev);
hci_remote_oob_data_clear(hdev);
+ hci_callback_clear(hdev);
hci_dev_unlock(hdev);
hci_dev_put(hdev);
@@ -2118,6 +2122,109 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param)
return 0;
}
+static int hci_callback_add(struct hci_dev *hdev, __u16 opcode,
+ void (*cb)(struct hci_dev *hdev,
+ struct hci_cb_cmd *cmd),
+ void *opt,
+ void (*destructor)(struct hci_dev *hdev,
+ struct hci_cb_cmd *cmd),
+ gfp_t flags)
+{
+ struct hci_cb_cmd *cmd;
+
+ cmd = kmalloc(sizeof(*cmd), flags);
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->cb = cb;
+ cmd->opcode = opcode;
+ cmd->opt = opt;
+ cmd->status = 0;
+ cmd->destructor = destructor;
+
+ mutex_lock(&hdev->cb_list_lock);
+ list_add(&cmd->list, &hdev->cb_list);
+ mutex_unlock(&hdev->cb_list_lock);
+
+ return 0;
+}
+
+struct hci_cb_cmd *hci_callback_find(struct hci_dev *hdev, __u16 opcode)
+{
+ struct hci_cb_cmd *cmd;
+
+ mutex_lock(&hdev->cb_list_lock);
+ list_for_each_entry(cmd, &hdev->cb_list, list)
+ if (cmd->opcode == opcode) {
+ mutex_unlock(&hdev->cb_list_lock);
+ return cmd;
+ }
+ mutex_unlock(&hdev->cb_list_lock);
+
+ return NULL;
+}
+
+void hci_callback_remove(struct hci_dev *hdev, struct hci_cb_cmd *cmd)
+{
+ BT_DBG("%s remove cmd %p", hdev->name, cmd);
+
+ mutex_lock(&hdev->cb_list_lock);
+ list_del(&cmd->list);
+ mutex_unlock(&hdev->cb_list_lock);
+
+ if (cmd->destructor) {
+ cmd->destructor(hdev, cmd);
+ } else {
+ kfree(cmd->opt);
+ kfree(cmd);
+ }
+}
+
+static void hci_callback_clear(struct hci_dev *hdev)
+{
+ struct hci_cb_cmd *cmd, *tmp;
+
+ list_for_each_entry_safe(cmd, tmp, &hdev->cb_list, list)
+ hci_callback_remove(hdev, cmd);
+}
+
+/* Send HCI command with callback */
+int hci_callback_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen,
+ void *param,
+ void (*cb)(struct hci_dev *hdev,
+ struct hci_cb_cmd *cmd),
+ void *opt,
+ void (*destructor)(struct hci_dev *hdev,
+ struct hci_cb_cmd *cmd),
+ gfp_t flags)
+{
+ int ret;
+
+ if (!cb)
+ return -EINVAL;
+
+ ret = hci_callback_add(hdev, opcode, cb, opt, destructor, flags);
+ if (ret)
+ return ret;
+
+ return hci_send_cmd(hdev, opcode, plen, param);
+}
+
+void hci_callback_process(struct hci_dev *hdev, __u16 opcode, u8 status)
+{
+ struct hci_cb_cmd *cmd;
+
+ cmd = hci_callback_find(hdev, opcode);
+ if (!cmd)
+ return;
+
+ cmd->status = status;
+ cmd->cb(hdev, cmd);
+
+ hci_callback_remove(hdev, cmd);
+ hci_dev_put(hdev);
+}
+
/* Get data from the previously sent command */
void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode)
{
--
1.7.9.5
^ permalink raw reply related
* [RFCv3 02/20] Bluetooth: Add callback clear to ops->teardown
From: Andrei Emeltchenko @ 2012-08-13 13:50 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1344865838-9165-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
ops->teardown takes care about deleting queued callbacks for all AMP
controllers.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
include/net/bluetooth/hci_core.h | 1 +
net/bluetooth/a2mp.c | 17 ++++++++++++++++-
net/bluetooth/hci_core.c | 3 +--
3 files changed, 18 insertions(+), 3 deletions(-)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 0985014..ccbf01d 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1117,5 +1117,6 @@ int hci_callback_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen,
gfp_t flags);
void hci_callback_remove(struct hci_dev *hdev, struct hci_cb_cmd *cmd);
void hci_callback_process(struct hci_dev *hdev, __u16 opcode, u8 status);
+void hci_callback_clear(struct hci_dev *hdev);
#endif /* __HCI_CORE_H */
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 44ef201..3d872db 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -444,16 +444,31 @@ static struct sk_buff *a2mp_chan_alloc_skb_cb(struct l2cap_chan *chan,
return bt_skb_alloc(len, GFP_KERNEL);
}
+static void a2mp_chan_teardown_cb(struct l2cap_chan *chan, int err)
+{
+ struct hci_dev *hdev, *tmp;
+
+ BT_DBG("chan %p", chan);
+
+ list_for_each_entry_safe(hdev, tmp, &hci_dev_list, list) {
+ hci_dev_hold(hdev);
+ /* Iterate through AMP controllers */
+ if (hdev->amp_type == HCI_AMP)
+ hci_callback_clear(hdev);
+ hci_dev_put(hdev);
+ }
+}
+
static struct l2cap_ops a2mp_chan_ops = {
.name = "L2CAP A2MP channel",
.recv = a2mp_chan_recv_cb,
.close = a2mp_chan_close_cb,
.state_change = a2mp_chan_state_change_cb,
.alloc_skb = a2mp_chan_alloc_skb_cb,
+ .teardown = a2mp_chan_teardown_cb,
/* Not implemented for A2MP */
.new_connection = l2cap_chan_no_new_connection,
- .teardown = l2cap_chan_no_teardown,
.ready = l2cap_chan_no_ready,
};
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index ecc8644..60ba01f 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -36,7 +36,6 @@
static void hci_rx_work(struct work_struct *work);
static void hci_cmd_work(struct work_struct *work);
static void hci_tx_work(struct work_struct *work);
-static void hci_callback_clear(struct hci_dev *hdev);
/* HCI device list */
LIST_HEAD(hci_dev_list);
@@ -2180,7 +2179,7 @@ void hci_callback_remove(struct hci_dev *hdev, struct hci_cb_cmd *cmd)
}
}
-static void hci_callback_clear(struct hci_dev *hdev)
+void hci_callback_clear(struct hci_dev *hdev)
{
struct hci_cb_cmd *cmd, *tmp;
--
1.7.9.5
^ permalink raw reply related
* [RFCv3 03/20] Bluetooth: AMP: Use HCI callback for Read AMP Info
From: Andrei Emeltchenko @ 2012-08-13 13:50 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1344865838-9165-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
When receiving A2MP Get Info Request execute Read Local AMP Info HCI
command to AMP controller with callback to be executed upon receiving
command complete event. Callback will handle A2MP Get Info Response.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
include/net/bluetooth/a2mp.h | 1 +
include/net/bluetooth/amp.h | 19 +++++++++++++
net/bluetooth/Makefile | 2 +-
net/bluetooth/a2mp.c | 28 +++++++++---------
net/bluetooth/amp.c | 64 ++++++++++++++++++++++++++++++++++++++++++
net/bluetooth/hci_event.c | 6 +++-
6 files changed, 104 insertions(+), 16 deletions(-)
create mode 100644 include/net/bluetooth/amp.h
create mode 100644 net/bluetooth/amp.c
diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index 6a76e0a..ec77ddc 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -122,5 +122,6 @@ void amp_mgr_get(struct amp_mgr *mgr);
int amp_mgr_put(struct amp_mgr *mgr);
struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
struct sk_buff *skb);
+void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data);
#endif /* __A2MP_H */
diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h
new file mode 100644
index 0000000..ec7bea7
--- /dev/null
+++ b/include/net/bluetooth/amp.h
@@ -0,0 +1,19 @@
+/*
+ Copyright (c) 2011,2012 Intel Corp.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 and
+ only version 2 as published by the Free Software Foundation.
+
+ 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.
+*/
+
+#ifndef __AMP_H
+#define __AMP_H
+
+void amp_read_loc_info(struct hci_dev *hdev, struct amp_mgr *mgr);
+
+#endif /* __AMP_H */
diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
index fa6d94a..dea6a28 100644
--- a/net/bluetooth/Makefile
+++ b/net/bluetooth/Makefile
@@ -10,4 +10,4 @@ obj-$(CONFIG_BT_HIDP) += hidp/
bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
- a2mp.o
+ a2mp.o amp.o
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 3d872db..3580f3d 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -16,6 +16,7 @@
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
#include <net/bluetooth/a2mp.h>
+#include <net/bluetooth/amp.h>
/* A2MP build & send command helper functions */
static struct a2mp_cmd *__a2mp_build(u8 code, u8 ident, u16 len, void *data)
@@ -37,8 +38,7 @@ static struct a2mp_cmd *__a2mp_build(u8 code, u8 ident, u16 len, void *data)
return cmd;
}
-static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
- void *data)
+void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data)
{
struct l2cap_chan *chan = mgr->a2mp_chan;
struct a2mp_cmd *cmd;
@@ -189,24 +189,24 @@ static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
BT_DBG("id %d", req->id);
- rsp.id = req->id;
- rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
-
hdev = hci_dev_get(req->id);
- if (hdev && hdev->amp_type != HCI_BREDR) {
- rsp.status = 0;
- rsp.total_bw = cpu_to_le32(hdev->amp_total_bw);
- rsp.max_bw = cpu_to_le32(hdev->amp_max_bw);
- rsp.min_latency = cpu_to_le32(hdev->amp_min_latency);
- rsp.pal_cap = cpu_to_le16(hdev->amp_pal_cap);
- rsp.assoc_size = cpu_to_le16(hdev->amp_assoc_size);
- }
+ if (!hdev)
+ goto send_err;
- if (hdev)
+ if (hdev->dev_type != HCI_BREDR) {
+ amp_read_loc_info(hdev, mgr);
+ goto done;
+ } else {
hci_dev_put(hdev);
+ }
+
+send_err:
+ rsp.id = req->id;
+ rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
a2mp_send(mgr, A2MP_GETINFO_RSP, hdr->ident, sizeof(rsp), &rsp);
+done:
skb_pull(skb, sizeof(*req));
return 0;
}
diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c
new file mode 100644
index 0000000..f26a014
--- /dev/null
+++ b/net/bluetooth/amp.c
@@ -0,0 +1,64 @@
+/*
+ Copyright (c) 2011,2012 Intel Corp.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 and
+ only version 2 as published by the Free Software Foundation.
+
+ 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.
+*/
+
+#include <linux/workqueue.h>
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/a2mp.h>
+#include <net/bluetooth/amp.h>
+
+static void amp_read_loc_info_complete_cb(struct hci_dev *hdev,
+ struct hci_cb_cmd *cmd)
+{
+ struct amp_mgr *mgr = cmd->opt;
+ struct a2mp_info_rsp rsp;
+
+ BT_DBG("%s cmd %p mgr %p", hdev->name, cmd, cmd->opt);
+
+ rsp.id = hdev->id;
+ rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+
+ if (hdev->amp_type != HCI_BREDR) {
+ rsp.status = 0;
+ rsp.total_bw = cpu_to_le32(hdev->amp_total_bw);
+ rsp.max_bw = cpu_to_le32(hdev->amp_max_bw);
+ rsp.min_latency = cpu_to_le32(hdev->amp_min_latency);
+ rsp.pal_cap = cpu_to_le16(hdev->amp_pal_cap);
+ rsp.assoc_size = cpu_to_le16(hdev->amp_assoc_size);
+ }
+
+ a2mp_send(mgr, A2MP_GETINFO_RSP, mgr->ident, sizeof(rsp), &rsp);
+}
+
+static void cb_destructor(struct hci_dev *hdev, struct hci_cb_cmd *cmd)
+{
+ struct amp_mgr *mgr = cmd->opt;
+
+ BT_DBG("Destructor cmd %p mgr %p", cmd, mgr);
+
+ hci_dev_put(hdev);
+ amp_mgr_put(mgr);
+ kfree(cmd);
+}
+
+void amp_read_loc_info(struct hci_dev *hdev, struct amp_mgr *mgr)
+{
+ BT_DBG("%s mgr %p", hdev->name, mgr);
+
+ amp_mgr_get(mgr);
+
+ hci_callback_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL,
+ amp_read_loc_info_complete_cb, mgr,
+ cb_destructor, GFP_KERNEL);
+}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index f3a4568..0468ab0 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -29,6 +29,7 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/a2mp.h>
/* Handle HCI Event packets */
@@ -845,7 +846,7 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
if (rp->status)
- return;
+ goto process_cb;
hdev->amp_status = rp->amp_status;
hdev->amp_total_bw = __le32_to_cpu(rp->total_bw);
@@ -859,6 +860,9 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
hdev->amp_max_flush_to = __le32_to_cpu(rp->max_flush_to);
hci_req_complete(hdev, HCI_OP_READ_LOCAL_AMP_INFO, rp->status);
+
+process_cb:
+ hci_callback_process(hdev, HCI_OP_READ_LOCAL_AMP_INFO, rp->status);
}
static void hci_cc_delete_stored_link_key(struct hci_dev *hdev,
--
1.7.9.5
^ permalink raw reply related
* [RFCv3 04/20] Bluetooth: AMP: Use HCI callback to Read Loc AMP Assoc
From: Andrei Emeltchenko @ 2012-08-13 13:50 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1344865838-9165-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
When receiving A2MP Get AMP Assoc Request execute Read Local AMP Assoc
HCI command to AMP controller. If the AMP Assoc data is larger then it
can fit to HCI event only fragment is read. When all fragments are read
A2MP Get AMP Assoc Response is run from HCI callback.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
include/net/bluetooth/amp.h | 2 ++
include/net/bluetooth/hci.h | 2 ++
include/net/bluetooth/hci_core.h | 8 +++++
net/bluetooth/a2mp.c | 13 +++++----
net/bluetooth/amp.c | 60 ++++++++++++++++++++++++++++++++++++++
net/bluetooth/hci_event.c | 41 ++++++++++++++++++++++++++
6 files changed, 120 insertions(+), 6 deletions(-)
diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h
index ec7bea7..e861675 100644
--- a/include/net/bluetooth/amp.h
+++ b/include/net/bluetooth/amp.h
@@ -15,5 +15,7 @@
#define __AMP_H
void amp_read_loc_info(struct hci_dev *hdev, struct amp_mgr *mgr);
+void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle);
+void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr);
#endif /* __AMP_H */
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 23cf413..7335fe1 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -33,6 +33,8 @@
#define HCI_LINK_KEY_SIZE 16
#define HCI_AMP_LINK_KEY_SIZE (2 * HCI_LINK_KEY_SIZE)
+#define HCI_MAX_AMP_ASSOC_SIZE 672
+
/* HCI dev events */
#define HCI_DEV_REG 1
#define HCI_DEV_UNREG 2
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index ccbf01d..2094e02 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -135,6 +135,12 @@ struct hci_cb_cmd {
void (*destructor)(struct hci_dev *hdev, struct hci_cb_cmd *cmd);
};
+struct amp_assoc {
+ __u16 len;
+ __u16 offset;
+ __u8 data[HCI_MAX_AMP_ASSOC_SIZE];
+};
+
#define NUM_REASSEMBLY 4
struct hci_dev {
struct list_head list;
@@ -188,6 +194,8 @@ struct hci_dev {
__u32 amp_max_flush_to;
__u32 amp_be_flush_to;
+ struct amp_assoc loc_assoc;
+
__u8 flow_ctl_mode;
unsigned int auto_accept_delay;
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 3580f3d..3468599 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -230,15 +230,16 @@ static int a2mp_getampassoc_req(struct amp_mgr *mgr, struct sk_buff *skb,
a2mp_send(mgr, A2MP_GETAMPASSOC_RSP, hdr->ident, sizeof(rsp),
&rsp);
- goto clean;
- }
- /* Placeholder for HCI Read AMP Assoc */
+ if (hdev)
+ hci_dev_put(hdev);
-clean:
- if (hdev)
- hci_dev_put(hdev);
+ goto done;
+ }
+
+ amp_read_loc_assoc(hdev, mgr);
+done:
skb_pull(skb, sizeof(*req));
return 0;
}
diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c
index f26a014..725a9f0 100644
--- a/net/bluetooth/amp.c
+++ b/net/bluetooth/amp.c
@@ -62,3 +62,63 @@ void amp_read_loc_info(struct hci_dev *hdev, struct amp_mgr *mgr)
amp_read_loc_info_complete_cb, mgr,
cb_destructor, GFP_KERNEL);
}
+
+void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle)
+{
+ struct hci_cp_read_local_amp_assoc cp;
+ struct amp_assoc *loc_assoc = &hdev->loc_assoc;
+
+ BT_DBG("%s handle %d", hdev->name, phy_handle);
+
+ cp.phy_handle = phy_handle;
+ cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
+ cp.len_so_far = cpu_to_le16(loc_assoc->offset);
+
+ hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
+}
+
+static void amp_read_loc_assoc_complete_cb(struct hci_dev *hdev,
+ struct hci_cb_cmd *cmd)
+{
+ struct amp_mgr *mgr = cmd->opt;
+ struct amp_assoc *loc_assoc = &hdev->loc_assoc;
+ struct a2mp_amp_assoc_rsp *rsp;
+ size_t len;
+
+ BT_DBG("%s cmd %p", hdev->name, cmd);
+
+ len = sizeof(struct a2mp_amp_assoc_rsp) + loc_assoc->len;
+ rsp = kzalloc(len, GFP_KERNEL);
+ if (!rsp)
+ return;
+
+ rsp->id = hdev->id;
+
+ if (cmd->status) {
+ rsp->status = A2MP_STATUS_INVALID_CTRL_ID;
+ goto send;
+ }
+
+ rsp->status = A2MP_STATUS_SUCCESS;
+ memcpy(rsp->amp_assoc, loc_assoc->data, loc_assoc->len);
+
+send:
+ a2mp_send(mgr, A2MP_GETAMPASSOC_RSP, mgr->ident, len, rsp);
+ kfree(rsp);
+}
+
+void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr)
+{
+ struct hci_cp_read_local_amp_assoc cp;
+
+ memset(&hdev->loc_assoc, 0, sizeof(struct amp_assoc));
+ memset(&cp, 0, sizeof(cp));
+
+ cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
+
+ amp_mgr_get(mgr);
+
+ hci_callback_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp),
+ &cp, amp_read_loc_assoc_complete_cb, mgr,
+ cb_destructor, GFP_KERNEL);
+}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 0468ab0..5f68c70 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -30,6 +30,7 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/a2mp.h>
+#include <net/bluetooth/amp.h>
/* Handle HCI Event packets */
@@ -865,6 +866,42 @@ process_cb:
hci_callback_process(hdev, HCI_OP_READ_LOCAL_AMP_INFO, rp->status);
}
+static void hci_cc_read_local_amp_assoc(struct hci_dev *hdev,
+ struct sk_buff *skb)
+{
+ struct hci_rp_read_local_amp_assoc *rp = (void *) skb->data;
+ struct amp_assoc *assoc = &hdev->loc_assoc;
+ size_t rem_len, frag_len;
+
+ BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+ if (rp->status)
+ goto process_cb;
+
+ frag_len = skb->len - sizeof(*rp);
+ rem_len = __le16_to_cpu(rp->rem_len);
+
+ if (rem_len > frag_len) {
+ BT_DBG("frag_len %d rem_len %d", frag_len, rem_len);
+
+ memcpy(assoc->data + assoc->offset, rp->frag, frag_len);
+ assoc->offset += frag_len;
+
+ /* Read other fragments */
+ amp_read_loc_assoc_frag(hdev, rp->phy_handle);
+
+ return;
+ }
+
+ memcpy(assoc->data + assoc->offset, rp->frag, rem_len);
+ assoc->len = assoc->offset + rem_len;
+ assoc->offset = 0;
+
+process_cb:
+ /* Run callback when all fragments received */
+ hci_callback_process(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, rp->status);
+}
+
static void hci_cc_delete_stored_link_key(struct hci_dev *hdev,
struct sk_buff *skb)
{
@@ -2281,6 +2318,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cc_read_local_amp_info(hdev, skb);
break;
+ case HCI_OP_READ_LOCAL_AMP_ASSOC:
+ hci_cc_read_local_amp_assoc(hdev, skb);
+ break;
+
case HCI_OP_DELETE_STORED_LINK_KEY:
hci_cc_delete_stored_link_key(hdev, skb);
break;
--
1.7.9.5
^ permalink raw reply related
* [RFCv3 05/20] Bluetooth: A2MP: Process Discover Response
From: Andrei Emeltchenko @ 2012-08-13 13:50 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1344865838-9165-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
When receiving A2MP Discover Response send A2MP Get Info Request
for each AMP controller in the discovery list.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
net/bluetooth/a2mp.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 61 insertions(+), 1 deletion(-)
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 3468599..a264f22 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -63,6 +63,14 @@ void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data)
kfree(cmd);
}
+static u8 __next_ident(struct amp_mgr *mgr)
+{
+ if (++mgr->ident == 0)
+ mgr->ident = 1;
+
+ return mgr->ident;
+}
+
static inline void __a2mp_cl_bredr(struct a2mp_cl *cl)
{
cl->id = 0;
@@ -161,6 +169,55 @@ static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb,
return 0;
}
+static int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
+ struct a2mp_cmd *hdr)
+{
+ struct a2mp_discov_rsp *rsp = (void *) skb->data;
+ u16 len = le16_to_cpu(hdr->len);
+ struct a2mp_cl *cl;
+ u16 ext_feat;
+
+ if (len < sizeof(*rsp))
+ return -EINVAL;
+
+ len -= sizeof(*rsp);
+ skb_pull(skb, sizeof(*rsp));
+
+ ext_feat = le16_to_cpu(rsp->ext_feat);
+
+ BT_DBG("mtu %d efm 0x%4.4x", le16_to_cpu(rsp->mtu), ext_feat);
+
+ /* check that packet is not broken for now */
+ while (ext_feat & A2MP_FEAT_EXT) {
+ if (len < sizeof(ext_feat))
+ return -EINVAL;
+
+ ext_feat = get_unaligned_le16(skb->data);
+ BT_DBG("efm 0x%4.4x", ext_feat);
+ len -= sizeof(ext_feat);
+ skb_pull(skb, sizeof(ext_feat));
+ }
+
+ cl = (void *) skb->data;
+ while (len >= sizeof(*cl)) {
+ BT_DBG("Remote AMP id %d type %d status %d", cl->id, cl->type,
+ cl->status);
+
+ if (cl->id != HCI_BREDR_ID && cl->type == HCI_AMP) {
+ struct a2mp_info_req req;
+
+ req.id = cl->id;
+ a2mp_send(mgr, A2MP_GETINFO_REQ, __next_ident(mgr),
+ sizeof(req), &req);
+ }
+
+ len -= sizeof(*cl);
+ cl = (void *) skb_pull(skb, sizeof(*cl));
+ }
+
+ return 0;
+}
+
static int a2mp_change_notify(struct amp_mgr *mgr, struct sk_buff *skb,
struct a2mp_cmd *hdr)
{
@@ -378,8 +435,11 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
err = a2mp_discphyslink_req(mgr, skb, hdr);
break;
- case A2MP_CHANGE_RSP:
case A2MP_DISCOVER_RSP:
+ err = a2mp_discover_rsp(mgr, skb, hdr);
+ break;
+
+ case A2MP_CHANGE_RSP:
case A2MP_GETINFO_RSP:
case A2MP_GETAMPASSOC_RSP:
case A2MP_CREATEPHYSLINK_RSP:
--
1.7.9.5
^ permalink raw reply related
* [RFCv3 06/20] Bluetooth: AMP: Physical link struct definitions
From: Andrei Emeltchenko @ 2012-08-13 13:50 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1344865838-9165-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Define physical link structure. Physical links are managed by AMP
manager inside amp_mgr structure and represent AMP physical links.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
include/net/bluetooth/a2mp.h | 3 +
include/net/bluetooth/pal.h | 42 +++++++++++++
net/bluetooth/Makefile | 2 +-
net/bluetooth/a2mp.c | 6 ++
net/bluetooth/pal.c | 141 ++++++++++++++++++++++++++++++++++++++++++
5 files changed, 193 insertions(+), 1 deletion(-)
create mode 100644 include/net/bluetooth/pal.h
create mode 100644 net/bluetooth/pal.c
diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index ec77ddc..012f573 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -26,6 +26,9 @@ struct amp_mgr {
__u8 ident;
__u8 handle;
unsigned long flags;
+
+ struct list_head phy_links;
+ struct mutex phy_links_lock;
};
struct a2mp_cmd {
diff --git a/include/net/bluetooth/pal.h b/include/net/bluetooth/pal.h
new file mode 100644
index 0000000..201c501
--- /dev/null
+++ b/include/net/bluetooth/pal.h
@@ -0,0 +1,42 @@
+/*
+ Copyright (c) 2011,2012 Intel Corp.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 and
+ only version 2 as published by the Free Software Foundation.
+
+ 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.
+*/
+
+#ifndef __PAL_H
+#define __PAL_H
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/l2cap.h>
+#include <net/bluetooth/a2mp.h>
+#include <net/bluetooth/amp.h>
+
+struct phy_link {
+ struct list_head list;
+ __u8 local_id;
+ __u8 remote_id;
+ __u8 state;
+ __u8 amp_role;
+ __u8 handle;
+ struct amp_mgr *mgr;
+ struct amp_assoc rem_assoc;
+ struct kref kref;
+};
+
+struct phy_link *phylink_add(struct amp_mgr *mgr, u8 local_id, u8 remote_id,
+ u8 *rem_assoc, u16 assoc_size);
+struct phy_link *phylink_lookup(struct amp_mgr *mgr, u8 local_id, u8 remote_id);
+int phylink_put(struct phy_link *plink);
+void phylink_get(struct phy_link *plink);
+void phylink_list_flush(struct amp_mgr *mgr);
+
+#endif /* __PAL_H */
diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
index dea6a28..3f76fc2 100644
--- a/net/bluetooth/Makefile
+++ b/net/bluetooth/Makefile
@@ -10,4 +10,4 @@ obj-$(CONFIG_BT_HIDP) += hidp/
bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
- a2mp.o amp.o
+ a2mp.o amp.o pal.o
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index a264f22..3df7cb5 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -17,6 +17,7 @@
#include <net/bluetooth/l2cap.h>
#include <net/bluetooth/a2mp.h>
#include <net/bluetooth/amp.h>
+#include <net/bluetooth/pal.h>
/* A2MP build & send command helper functions */
static struct a2mp_cmd *__a2mp_build(u8 code, u8 ident, u16 len, void *data)
@@ -594,6 +595,7 @@ static void amp_mgr_destroy(struct kref *kref)
BT_DBG("mgr %p", mgr);
+ phylink_list_flush(mgr);
kfree(mgr);
}
@@ -628,6 +630,10 @@ static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
conn->hcon->amp_mgr = mgr;
+ /* Phylink initialization */
+ INIT_LIST_HEAD(&mgr->phy_links);
+ mutex_init(&mgr->phy_links_lock);
+
kref_init(&mgr->kref);
return mgr;
diff --git a/net/bluetooth/pal.c b/net/bluetooth/pal.c
new file mode 100644
index 0000000..24fb3aa
--- /dev/null
+++ b/net/bluetooth/pal.c
@@ -0,0 +1,141 @@
+/*
+ Copyright (c) 2011,2012 Intel Corp.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 and
+ only version 2 as published by the Free Software Foundation.
+
+ 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.
+*/
+
+#include <net/bluetooth/pal.h>
+
+enum pal_states {
+ DISCONNECTED,
+ STARTING,
+ CONNECTING,
+ AUTHENTICATING,
+ CONNECTED,
+ DISCONNECTING
+};
+
+/* Physical Link interface */
+void phylink_get(struct phy_link *plink)
+{
+ BT_DBG("plink %p orig refcnt %d", plink,
+ atomic_read(&plink->kref.refcount));
+
+ kref_get(&plink->kref);
+}
+
+static void phylink_destroy(struct kref *kref)
+{
+ struct phy_link *plink = container_of(kref, struct phy_link, kref);
+
+ BT_DBG("plink %p", plink);
+
+ kfree(plink);
+}
+
+int phylink_put(struct phy_link *plink)
+{
+ BT_DBG("plink %p orig refcnt %d", plink,
+ atomic_read(&plink->kref.refcount));
+
+ return kref_put(&plink->kref, &phylink_destroy);
+}
+
+static u8 __next_handle(struct amp_mgr *mgr)
+{
+ if (++mgr->handle == 0)
+ mgr->handle = 1;
+
+ return mgr->handle;
+}
+
+struct phy_link *phylink_add(struct amp_mgr *mgr, u8 local_id, u8 remote_id,
+ u8 *rem_assoc, u16 assoc_size)
+{
+ struct phy_link *plink;
+
+ plink = kzalloc(sizeof(*plink), GFP_KERNEL);
+ if (!plink)
+ return NULL;
+
+ plink->local_id = local_id;
+ plink->remote_id = remote_id;
+ plink->mgr = mgr;
+ plink->handle = __next_handle(mgr);
+
+ plink->rem_assoc.len = min_t(u16, assoc_size, HCI_MAX_AMP_ASSOC_SIZE);
+ memcpy(plink->rem_assoc.data, rem_assoc, plink->rem_assoc.len);
+
+ plink->state = STARTING;
+
+ mutex_lock(&mgr->phy_links_lock);
+ list_add(&plink->list, &mgr->phy_links);
+ mutex_unlock(&mgr->phy_links_lock);
+
+ kref_init(&plink->kref);
+
+ BT_DBG("Physical link %p created", plink);
+
+ return plink;
+}
+
+void phylink_del(struct amp_mgr *mgr, struct phy_link *plink)
+{
+ BT_DBG("phylink %p", plink);
+
+ mutex_lock(&mgr->phy_links_lock);
+ list_del(&plink->list);
+ mutex_unlock(&mgr->phy_links_lock);
+
+ phylink_put(plink);
+}
+
+void phylink_list_flush(struct amp_mgr *mgr)
+{
+ struct phy_link *plink, *n;
+
+ BT_DBG("mgr %p", mgr);
+
+ mutex_lock(&mgr->phy_links_lock);
+ list_for_each_entry_safe(plink, n, &mgr->phy_links, list) {
+ list_del(&plink->list);
+ phylink_put(plink);
+ }
+ mutex_unlock(&mgr->phy_links_lock);
+}
+
+struct phy_link *phylink_lookup(struct amp_mgr *mgr, u8 local_id, u8 remote_id)
+{
+ struct phy_link *plink, *found = NULL;
+
+ mutex_lock(&mgr->phy_links_lock);
+ list_for_each_entry(plink, &mgr->phy_links, list) {
+ /* Closest match */
+ if (!remote_id && plink->local_id == local_id) {
+ found = plink;
+ break;
+ }
+ /* Exact match */
+ if (plink->local_id == local_id &&
+ plink->remote_id == remote_id) {
+ found = plink;
+ break;
+ }
+ }
+ mutex_unlock(&mgr->phy_links_lock);
+
+ BT_DBG("local_id %d remote_id %d plink %p", local_id, remote_id,
+ plink);
+
+ if (found)
+ phylink_get(plink);
+
+ return found;
+}
--
1.7.9.5
^ permalink raw reply related
* [RFCv3 07/20] Bluetooth: AMP: Remote AMP ctrl definitions
From: Andrei Emeltchenko @ 2012-08-13 13:50 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1344865838-9165-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Create remote AMP controllers structure. It is used to keep information
about discovered remote AMP controllers by A2MP protocol.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
include/net/bluetooth/a2mp.h | 3 ++
include/net/bluetooth/pal.h | 14 ++++++++
net/bluetooth/a2mp.c | 5 +++
net/bluetooth/pal.c | 81 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 103 insertions(+)
diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index 012f573..8ba236c 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -29,6 +29,9 @@ struct amp_mgr {
struct list_head phy_links;
struct mutex phy_links_lock;
+
+ struct list_head amp_ctrls;
+ struct mutex amp_ctrls_lock;
};
struct a2mp_cmd {
diff --git a/include/net/bluetooth/pal.h b/include/net/bluetooth/pal.h
index 201c501..3223ec2 100644
--- a/include/net/bluetooth/pal.h
+++ b/include/net/bluetooth/pal.h
@@ -32,6 +32,20 @@ struct phy_link {
struct kref kref;
};
+struct amp_ctrl {
+ struct list_head list;
+ struct kref kref;
+ __u8 id;
+ __u16 assoc_len_so_far;
+ __u16 assoc_rem_len;
+ __u16 assoc_len;
+ __u8 *assoc;
+};
+
+int amp_ctrl_put(struct amp_ctrl *ctrl);
+struct amp_ctrl *amp_ctrl_add(struct amp_mgr *mgr);
+struct amp_ctrl *amp_ctrl_lookup(struct amp_mgr *mgr, u8 id);
+void amp_ctrl_list_flush(struct amp_mgr *mgr);
struct phy_link *phylink_add(struct amp_mgr *mgr, u8 local_id, u8 remote_id,
u8 *rem_assoc, u16 assoc_size);
struct phy_link *phylink_lookup(struct amp_mgr *mgr, u8 local_id, u8 remote_id);
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 3df7cb5..f35d90f 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -595,6 +595,7 @@ static void amp_mgr_destroy(struct kref *kref)
BT_DBG("mgr %p", mgr);
+ amp_ctrl_list_flush(mgr);
phylink_list_flush(mgr);
kfree(mgr);
}
@@ -634,6 +635,10 @@ static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
INIT_LIST_HEAD(&mgr->phy_links);
mutex_init(&mgr->phy_links_lock);
+ /* Remote AMP ctrl list initialization */
+ INIT_LIST_HEAD(&mgr->amp_ctrls);
+ mutex_init(&mgr->amp_ctrls_lock);
+
kref_init(&mgr->kref);
return mgr;
diff --git a/net/bluetooth/pal.c b/net/bluetooth/pal.c
index 24fb3aa..335cbc3 100644
--- a/net/bluetooth/pal.c
+++ b/net/bluetooth/pal.c
@@ -22,6 +22,87 @@ enum pal_states {
DISCONNECTING
};
+/* Remote AMP Controllers handling */
+static void amp_ctrl_get(struct amp_ctrl *ctrl)
+{
+ BT_DBG("ctrl %p orig refcnt %d", ctrl,
+ atomic_read(&ctrl->kref.refcount));
+
+ kref_get(&ctrl->kref);
+}
+
+static void amp_ctrl_destroy(struct kref *kref)
+{
+ struct amp_ctrl *ctrl = container_of(kref, struct amp_ctrl, kref);
+
+ BT_DBG("ctrl %p", ctrl);
+
+ if (ctrl->assoc)
+ kfree(ctrl->assoc);
+
+ kfree(ctrl);
+}
+
+int amp_ctrl_put(struct amp_ctrl *ctrl)
+{
+ BT_DBG("ctrl %p orig refcnt %d", ctrl,
+ atomic_read(&ctrl->kref.refcount));
+
+ return kref_put(&ctrl->kref, &_ctrl_destroy);
+}
+
+struct amp_ctrl *amp_ctrl_add(struct amp_mgr *mgr)
+{
+ struct amp_ctrl *ctrl;
+
+ ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
+ if (!ctrl)
+ return NULL;
+
+ mutex_lock(&mgr->amp_ctrls_lock);
+ list_add(&ctrl->list, &mgr->amp_ctrls);
+ mutex_unlock(&mgr->amp_ctrls_lock);
+
+ kref_init(&ctrl->kref);
+
+ BT_DBG("mgr %p ctrl %p", mgr, ctrl);
+
+ return ctrl;
+}
+
+void amp_ctrl_list_flush(struct amp_mgr *mgr)
+{
+ struct amp_ctrl *ctrl, *n;
+
+ BT_DBG("mgr %p", mgr);
+
+ mutex_lock(&mgr->amp_ctrls_lock);
+ list_for_each_entry_safe(ctrl, n, &mgr->amp_ctrls, list) {
+ list_del(&ctrl->list);
+ amp_ctrl_put(ctrl);
+ }
+ mutex_unlock(&mgr->amp_ctrls_lock);
+}
+
+struct amp_ctrl *amp_ctrl_lookup(struct amp_mgr *mgr, u8 id)
+{
+ struct amp_ctrl *ctrl = NULL;
+
+ mutex_lock(&mgr->amp_ctrls_lock);
+ list_for_each_entry(ctrl, &mgr->amp_ctrls, list) {
+ if (ctrl->id == id)
+ break;
+ }
+ mutex_unlock(&mgr->amp_ctrls_lock);
+
+ BT_DBG("mgr %p id %d ctrl %p", mgr, id, ctrl);
+
+ if (ctrl)
+ amp_ctrl_get(ctrl);
+
+ return ctrl;
+}
+
/* Physical Link interface */
void phylink_get(struct phy_link *plink)
{
--
1.7.9.5
^ permalink raw reply related
* [RFCv3 08/20] Bluetooth: AMP: Use phylink in create/disc phylink req
From: Andrei Emeltchenko @ 2012-08-13 13:50 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1344865838-9165-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Use phy_link structure to keep track about physical connections.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
include/net/bluetooth/pal.h | 1 +
net/bluetooth/a2mp.c | 19 +++++++++++++++++++
2 files changed, 20 insertions(+)
diff --git a/include/net/bluetooth/pal.h b/include/net/bluetooth/pal.h
index 3223ec2..6ce1dfb 100644
--- a/include/net/bluetooth/pal.h
+++ b/include/net/bluetooth/pal.h
@@ -52,5 +52,6 @@ struct phy_link *phylink_lookup(struct amp_mgr *mgr, u8 local_id, u8 remote_id);
int phylink_put(struct phy_link *plink);
void phylink_get(struct phy_link *plink);
void phylink_list_flush(struct amp_mgr *mgr);
+void phylink_del(struct amp_mgr *mgr, struct phy_link *plink);
#endif /* __PAL_H */
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index f35d90f..3a0e3b8 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -309,6 +309,7 @@ static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
struct a2mp_physlink_rsp rsp;
struct hci_dev *hdev;
+ struct phy_link *plink;
if (le16_to_cpu(hdr->len) < sizeof(*req))
return -EINVAL;
@@ -326,6 +327,11 @@ static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
/* TODO process physlink create */
+ plink = phylink_add(mgr, rsp.local_id, rsp.remote_id, req->amp_assoc,
+ le16_to_cpu(hdr->len) - sizeof(*req));
+
+ BT_DBG("plink %p", plink);
+
rsp.status = A2MP_STATUS_SUCCESS;
send_rsp:
@@ -345,6 +351,7 @@ static int a2mp_discphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
struct a2mp_physlink_req *req = (void *) skb->data;
struct a2mp_physlink_rsp rsp;
struct hci_dev *hdev;
+ struct phy_link *plink;
if (le16_to_cpu(hdr->len) < sizeof(*req))
return -EINVAL;
@@ -361,8 +368,20 @@ static int a2mp_discphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
goto send_rsp;
}
+ plink = phylink_lookup(mgr, rsp.local_id, rsp.remote_id);
+ if (!plink) {
+ BT_ERR("No phys link exist");
+ rsp.status = A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS;
+ goto clean;
+ }
+
/* TODO Disconnect Phys Link here */
+ phylink_put(plink);
+
+ phylink_del(mgr, plink);
+
+clean:
hci_dev_put(hdev);
send_rsp:
--
1.7.9.5
^ permalink raw reply related
* [RFCv3 09/20] Bluetooth: A2MP: Process A2MP Getinfo Rsp
From: Andrei Emeltchenko @ 2012-08-13 13:50 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1344865838-9165-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Process A2MP Getinfo Response, send Get AMP Assoc Req.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
net/bluetooth/a2mp.c | 34 +++++++++++++++++++++++++++++++++-
1 file changed, 33 insertions(+), 1 deletion(-)
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 3a0e3b8..5a238df 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -269,6 +269,35 @@ done:
return 0;
}
+static int a2mp_getinfo_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
+ struct a2mp_cmd *hdr)
+{
+ struct a2mp_info_rsp *rsp = (struct a2mp_info_rsp *) skb->data;
+ struct a2mp_amp_assoc_req req;
+ struct amp_ctrl *ctrl;
+
+ if (le16_to_cpu(hdr->len) < sizeof(*rsp))
+ return -EINVAL;
+
+ BT_DBG("id %d status 0x%2.2x", rsp->id, rsp->status);
+
+ if (rsp->status)
+ return -EINVAL;
+
+ ctrl = amp_ctrl_add(mgr);
+ if (!ctrl)
+ return -ENOMEM;
+
+ ctrl->id = rsp->id;
+
+ req.id = rsp->id;
+ a2mp_send(mgr, A2MP_GETAMPASSOC_REQ, __next_ident(mgr), sizeof(req),
+ &req);
+
+ skb_pull(skb, sizeof(*rsp));
+ return 0;
+}
+
static int a2mp_getampassoc_req(struct amp_mgr *mgr, struct sk_buff *skb,
struct a2mp_cmd *hdr)
{
@@ -459,8 +488,11 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
err = a2mp_discover_rsp(mgr, skb, hdr);
break;
- case A2MP_CHANGE_RSP:
case A2MP_GETINFO_RSP:
+ err = a2mp_getinfo_rsp(mgr, skb, hdr);
+ break;
+
+ case A2MP_CHANGE_RSP:
case A2MP_GETAMPASSOC_RSP:
case A2MP_CREATEPHYSLINK_RSP:
case A2MP_DISCONNPHYSLINK_RSP:
--
1.7.9.5
^ permalink raw reply related
* [RFCv3 10/20] Bluetooth: A2MP: Process A2MP Get AMP Assoc Rsp
From: Andrei Emeltchenko @ 2012-08-13 13:50 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1344865838-9165-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
When receiving A2MP Get AMP Assoc Response save assoc data to remote
AMP controller list and prepare for creating physical link.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
net/bluetooth/a2mp.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 57 insertions(+), 1 deletion(-)
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index 5a238df..d582fc8 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -331,6 +331,59 @@ done:
return 0;
}
+static int a2mp_getampassoc_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
+ struct a2mp_cmd *hdr)
+{
+ struct a2mp_amp_assoc_rsp *rsp = (void *) skb->data;
+ u16 len = le16_to_cpu(hdr->len);
+ struct hci_dev *hdev;
+ struct amp_ctrl *ctrl;
+ struct phy_link *plink;
+
+ if (len < sizeof(*rsp))
+ return -EINVAL;
+
+ BT_DBG("id %d status 0x%2.2x assoc len %u", rsp->id, rsp->status,
+ len - sizeof(*rsp));
+
+ if (rsp->status)
+ return -EINVAL;
+
+ /* Save remote ASSOC data */
+ ctrl = amp_ctrl_lookup(mgr, rsp->id);
+ if (ctrl) {
+ u8 *assoc, assoc_len = len - sizeof(*rsp);
+
+ assoc = kzalloc(assoc_len, GFP_KERNEL);
+ if (!assoc) {
+ amp_ctrl_put(ctrl);
+ goto done;
+ }
+
+ memcpy(assoc, rsp->amp_assoc, assoc_len);
+ ctrl->assoc = assoc;
+ ctrl->assoc_len = assoc_len;
+ ctrl->assoc_rem_len = assoc_len;
+ ctrl->assoc_len_so_far = 0;
+
+ amp_ctrl_put(ctrl);
+ }
+
+ /* Create Phys Link */
+ hdev = hci_dev_get(rsp->id);
+ if (!hdev)
+ goto done;
+
+ plink = phylink_add(mgr, hdev->id, rsp->id, ctrl->assoc,
+ ctrl->assoc_len);
+
+ BT_DBG("Created plink %p: loc:%d -> rem:%d", plink, hdev->id, rsp->id);
+
+done:
+ skb_pull(skb, len);
+ return 0;
+}
+
static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
struct a2mp_cmd *hdr)
{
@@ -492,8 +545,11 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
err = a2mp_getinfo_rsp(mgr, skb, hdr);
break;
- case A2MP_CHANGE_RSP:
case A2MP_GETAMPASSOC_RSP:
+ err = a2mp_getampassoc_rsp(mgr, skb, hdr);
+ break;
+
+ case A2MP_CHANGE_RSP:
case A2MP_CREATEPHYSLINK_RSP:
case A2MP_DISCONNPHYSLINK_RSP:
err = a2mp_cmd_rsp(mgr, skb, hdr);
--
1.7.9.5
^ permalink raw reply related
* [RFCv3 11/20] Bluetooth: A2MP: Create A2MP workqueue
From: Andrei Emeltchenko @ 2012-08-13 13:50 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1344865838-9165-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Workqueue might be used for A2MP tasks which cannot be run from
L2CAP of HCI code due to unsafe locking scenarios. For example in
l2cap_security_cfm and l2cap_conn_start we need to discover and
create amp manager from the code surrounded with &conn->chan_lock
and &chan->lock.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
include/net/bluetooth/a2mp.h | 2 ++
net/bluetooth/a2mp.c | 38 ++++++++++++++++++++++++++++++++++++++
net/bluetooth/l2cap_core.c | 6 ++++++
3 files changed, 46 insertions(+)
diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index 8ba236c..345fbc6 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -129,5 +129,7 @@ int amp_mgr_put(struct amp_mgr *mgr);
struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
struct sk_buff *skb);
void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data);
+int a2mp_init(void);
+void a2mp_exit(void);
#endif /* __A2MP_H */
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index d582fc8..f331a81 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -19,6 +19,8 @@
#include <net/bluetooth/amp.h>
#include <net/bluetooth/pal.h>
+static struct workqueue_struct *amp_workqueue;
+
/* A2MP build & send command helper functions */
static struct a2mp_cmd *__a2mp_build(u8 code, u8 ident, u16 len, void *data)
{
@@ -766,3 +768,39 @@ struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
return mgr->a2mp_chan;
}
+
+void l2cap_discover_amp(struct l2cap_chan *chan)
+{
+ struct a2mp_discov_req req;
+ struct l2cap_conn *conn = chan->conn;
+ struct amp_mgr *mgr = conn->hcon->amp_mgr;
+
+ BT_DBG("%p", conn);
+
+ if (!mgr) {
+ mgr = amp_mgr_create(conn);
+ if (!mgr)
+ return;
+ }
+
+ mgr->bredr_chan = chan;
+
+ req.mtu = cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU);
+ req.ext_feat = 0;
+ a2mp_send(mgr, A2MP_DISCOVER_REQ, 1, sizeof(req), &req);
+}
+
+int a2mp_init(void)
+{
+ amp_workqueue = create_singlethread_workqueue("a2mp");
+ if (!amp_workqueue)
+ return -EPERM;
+
+ return 0;
+}
+
+void a2mp_exit(void)
+{
+ flush_workqueue(amp_workqueue);
+ destroy_workqueue(amp_workqueue);
+}
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 4dbbb79..d4e99d6 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -5730,11 +5730,17 @@ int __init l2cap_init(void)
BT_ERR("Failed to create L2CAP debug file");
}
+ if (enable_hs)
+ return a2mp_init();
+
return 0;
}
void l2cap_exit(void)
{
+ if (enable_hs)
+ a2mp_exit();
+
debugfs_remove(l2cap_debugfs);
l2cap_cleanup_sockets();
}
--
1.7.9.5
^ permalink raw reply related
* [RFCv3 12/20] Bluetooth: Choose connection based on capabilities
From: Andrei Emeltchenko @ 2012-08-13 13:50 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1344865838-9165-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Choose which L2CAP connection to establish by checking support
for HS and remote side supported features.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
include/net/bluetooth/a2mp.h | 2 ++
net/bluetooth/a2mp.c | 31 ++++++++++++++++++++++++++++---
net/bluetooth/l2cap_core.c | 31 +++++++++++++++++++++++++++----
3 files changed, 57 insertions(+), 7 deletions(-)
diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
index 345fbc6..f3f0d7e 100644
--- a/include/net/bluetooth/a2mp.h
+++ b/include/net/bluetooth/a2mp.h
@@ -22,6 +22,7 @@
struct amp_mgr {
struct l2cap_conn *l2cap_conn;
struct l2cap_chan *a2mp_chan;
+ struct l2cap_chan *bredr_chan;
struct kref kref;
__u8 ident;
__u8 handle;
@@ -129,6 +130,7 @@ int amp_mgr_put(struct amp_mgr *mgr);
struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
struct sk_buff *skb);
void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data);
+void a2mp_discover_amp(struct l2cap_chan *chan);
int a2mp_init(void);
void a2mp_exit(void);
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index f331a81..c252c63 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -769,18 +769,25 @@ struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
return mgr->a2mp_chan;
}
-void l2cap_discover_amp(struct l2cap_chan *chan)
+struct amp_work {
+ struct work_struct work;
+ struct l2cap_chan *chan;
+};
+
+static void a2mp_discover_amp_worker(struct work_struct *w)
{
- struct a2mp_discov_req req;
+ struct amp_work *work = (struct amp_work *) w;
+ struct l2cap_chan *chan = work->chan;
struct l2cap_conn *conn = chan->conn;
struct amp_mgr *mgr = conn->hcon->amp_mgr;
+ struct a2mp_discov_req req;
BT_DBG("%p", conn);
if (!mgr) {
mgr = amp_mgr_create(conn);
if (!mgr)
- return;
+ goto clean;
}
mgr->bredr_chan = chan;
@@ -788,6 +795,24 @@ void l2cap_discover_amp(struct l2cap_chan *chan)
req.mtu = cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU);
req.ext_feat = 0;
a2mp_send(mgr, A2MP_DISCOVER_REQ, 1, sizeof(req), &req);
+
+clean:
+ kfree(w);
+}
+
+void a2mp_discover_amp(struct l2cap_chan *chan)
+{
+ struct amp_work *work;
+
+ work = kmalloc(sizeof(*work), GFP_KERNEL);
+ if (!work)
+ return;
+
+ INIT_WORK(&work->work, a2mp_discover_amp_worker);
+ work->chan = chan;
+
+ if (!queue_work(amp_workqueue, &work->work))
+ kfree(work);
}
int a2mp_init(void)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index d4e99d6..a4a512e 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1005,6 +1005,18 @@ static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
}
+static bool __amp_capable(struct l2cap_chan *chan)
+{
+ struct l2cap_conn *conn = chan->conn;
+
+ if (enable_hs &&
+ chan->chan_policy == BT_CHANNEL_POLICY_AMP_PREFERRED &&
+ conn->fixed_chan_mask & L2CAP_FC_A2MP)
+ return true;
+ else
+ return false;
+}
+
static void l2cap_send_conn_req(struct l2cap_chan *chan)
{
struct l2cap_conn *conn = chan->conn;
@@ -1031,6 +1043,16 @@ static void l2cap_chan_ready(struct l2cap_chan *chan)
chan->ops->ready(chan);
}
+static void l2cap_choose_conn(struct l2cap_chan *chan)
+{
+ if (__amp_capable(chan)) {
+ BT_DBG("chan %p AMP capable: discover AMPs", chan);
+ a2mp_discover_amp(chan);
+ } else {
+ l2cap_send_conn_req(chan);
+ }
+}
+
static void l2cap_do_start(struct l2cap_chan *chan)
{
struct l2cap_conn *conn = chan->conn;
@@ -1045,8 +1067,9 @@ static void l2cap_do_start(struct l2cap_chan *chan)
return;
if (l2cap_chan_check_security(chan) &&
- __l2cap_no_conn_pending(chan))
- l2cap_send_conn_req(chan);
+ __l2cap_no_conn_pending(chan)) {
+ l2cap_choose_conn(chan);
+ }
} else {
struct l2cap_info_req req;
req.type = __constant_cpu_to_le16(L2CAP_IT_FEAT_MASK);
@@ -1142,7 +1165,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
continue;
}
- l2cap_send_conn_req(chan);
+ l2cap_choose_conn(chan);
} else if (chan->state == BT_CONNECT2) {
struct l2cap_conn_rsp rsp;
@@ -5526,7 +5549,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
if (chan->state == BT_CONNECT) {
if (!status) {
- l2cap_send_conn_req(chan);
+ l2cap_choose_conn(chan);
} else {
__set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
}
--
1.7.9.5
^ permalink raw reply related
* [RFCv3 13/20] Bluetooth: Add function to derive AMP key using hmac
From: Andrei Emeltchenko @ 2012-08-13 13:50 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1344865838-9165-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
hmac(sha256) will be used for AMP key generation.
Signed-off-by: Dmitry Kasatkin <dmitry.kasatkin@intel.com>
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
net/bluetooth/pal.c | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/net/bluetooth/pal.c b/net/bluetooth/pal.c
index 335cbc3..e766a98 100644
--- a/net/bluetooth/pal.c
+++ b/net/bluetooth/pal.c
@@ -12,6 +12,7 @@
*/
#include <net/bluetooth/pal.h>
+#include <crypto/hash.h>
enum pal_states {
DISCONNECTED,
@@ -220,3 +221,37 @@ struct phy_link *phylink_lookup(struct amp_mgr *mgr, u8 local_id, u8 remote_id)
return found;
}
+
+int hmac_sha256(u8 *key, u8 ksize, char *plaintext, u8 psize, u8 *output)
+{
+ int ret = 0;
+ struct crypto_shash *tfm;
+
+ if (!ksize)
+ return -EINVAL;
+
+ tfm = crypto_alloc_shash("hmac(sha256)", 0, 0);
+ if (IS_ERR(tfm)) {
+ BT_DBG("crypto_alloc_ahash failed: err %ld", PTR_ERR(tfm));
+ return PTR_ERR(tfm);
+ }
+
+ ret = crypto_shash_setkey(tfm, key, ksize);
+ if (ret) {
+ BT_DBG("crypto_ahash_setkey failed: err %d", ret);
+ } else {
+ struct {
+ struct shash_desc shash;
+ char ctx[crypto_shash_descsize(tfm)];
+ } desc;
+
+ desc.shash.tfm = tfm;
+ desc.shash.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+ ret = crypto_shash_digest(&desc.shash, plaintext, psize,
+ output);
+ }
+
+ crypto_free_shash(tfm);
+ return ret;
+}
--
1.7.9.5
^ permalink raw reply related
* [RFCv3 14/20] Bluetooth: AMP: Add AMP key calculation
From: Andrei Emeltchenko @ 2012-08-13 13:50 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1344865838-9165-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Function calculates AMP keys using hmac_sha256 helper. Calculated keys
are Generic AMP Link Key (gamp) and Dedicated AMP Link Key with
keyID "802b" for 802.11 PAL.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
include/net/bluetooth/pal.h | 1 +
net/bluetooth/Kconfig | 1 +
net/bluetooth/pal.c | 45 +++++++++++++++++++++++++++++++++++++++++++
3 files changed, 47 insertions(+)
diff --git a/include/net/bluetooth/pal.h b/include/net/bluetooth/pal.h
index 6ce1dfb..8799285 100644
--- a/include/net/bluetooth/pal.h
+++ b/include/net/bluetooth/pal.h
@@ -53,5 +53,6 @@ int phylink_put(struct phy_link *plink);
void phylink_get(struct phy_link *plink);
void phylink_list_flush(struct amp_mgr *mgr);
void phylink_del(struct amp_mgr *mgr, struct phy_link *plink);
+int phylink_gen_key(struct hci_conn *conn, u8 *data, u8 *len, u8 *type);
#endif /* __PAL_H */
diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig
index 3537d38..1c11d0d 100644
--- a/net/bluetooth/Kconfig
+++ b/net/bluetooth/Kconfig
@@ -11,6 +11,7 @@ menuconfig BT
select CRYPTO_BLKCIPHER
select CRYPTO_AES
select CRYPTO_ECB
+ select CRYPTO_SHA256
help
Bluetooth is low-cost, low-power, short-range wireless technology.
It was designed as a replacement for cables and other short-range
diff --git a/net/bluetooth/pal.c b/net/bluetooth/pal.c
index e766a98..b4eeb6a 100644
--- a/net/bluetooth/pal.c
+++ b/net/bluetooth/pal.c
@@ -255,3 +255,48 @@ int hmac_sha256(u8 *key, u8 ksize, char *plaintext, u8 psize, u8 *output)
crypto_free_shash(tfm);
return ret;
}
+
+int phylink_gen_key(struct hci_conn *conn, u8 *data, u8 *len, u8 *type)
+{
+ struct hci_dev *hdev = conn->hdev;
+ struct link_key *key;
+ u8 keybuf[HCI_AMP_LINK_KEY_SIZE];
+ u8 gamp_key[HCI_AMP_LINK_KEY_SIZE];
+ int err;
+
+ if (!hci_conn_check_link_mode(conn))
+ return -EACCES;
+
+ BT_DBG("conn %p key_type %d", conn, conn->key_type);
+
+ /* Legacy key */
+ if (conn->key_type < 3) {
+ BT_ERR("Legacy key type %d", conn->key_type);
+ return -EACCES;
+ }
+
+ *type = conn->key_type;
+ *len = HCI_AMP_LINK_KEY_SIZE;
+
+ key = hci_find_link_key(hdev, &conn->dst);
+
+ /* BR/EDR Link Key concatenated together with itself */
+ memcpy(&keybuf[0], key->val, HCI_LINK_KEY_SIZE);
+ memcpy(&keybuf[HCI_LINK_KEY_SIZE], key->val, HCI_LINK_KEY_SIZE);
+
+ /* Derive Generic AMP Link Key (gamp) */
+ err = hmac_sha256(keybuf, HCI_AMP_LINK_KEY_SIZE, "gamp", 4, gamp_key);
+ if (err) {
+ BT_ERR("Could not derive Generic AMP Key: err %d", err);
+ return err;
+ }
+
+ if (conn->key_type == HCI_LK_DEBUG_COMBINATION) {
+ BT_DBG("Use Generic AMP Key (gamp)");
+ memcpy(data, gamp_key, HCI_AMP_LINK_KEY_SIZE);
+ return err;
+ }
+
+ /* Derive Dedicated AMP Link Key: "802b" is 802.11 PAL keyID */
+ return hmac_sha256(gamp_key, HCI_AMP_LINK_KEY_SIZE, "802b", 4, data);
+}
--
1.7.9.5
^ permalink raw reply related
* [RFCv3 15/20] Bluetooth: AMP: Create Physical Link
From: Andrei Emeltchenko @ 2012-08-13 13:50 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1344865838-9165-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
When receiving A2MP Get AMP Assoc Response execute HCI Create Physical
Link to AMP controller. Define callback which will run when receiving
HCI Command Status.
Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
include/net/bluetooth/amp.h | 4 ++++
include/net/bluetooth/pal.h | 1 -
net/bluetooth/a2mp.c | 4 ++++
net/bluetooth/amp.c | 31 +++++++++++++++++++++++++++++++
net/bluetooth/hci_event.c | 11 +++++++++++
5 files changed, 50 insertions(+), 1 deletion(-)
diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h
index e861675..b376cc3 100644
--- a/include/net/bluetooth/amp.h
+++ b/include/net/bluetooth/amp.h
@@ -14,8 +14,12 @@
#ifndef __AMP_H
#define __AMP_H
+#include <net/bluetooth/pal.h>
+
void amp_read_loc_info(struct hci_dev *hdev, struct amp_mgr *mgr);
void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle);
void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr);
+void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
+ struct phy_link *plink);
#endif /* __AMP_H */
diff --git a/include/net/bluetooth/pal.h b/include/net/bluetooth/pal.h
index 8799285..d9eb87e 100644
--- a/include/net/bluetooth/pal.h
+++ b/include/net/bluetooth/pal.h
@@ -18,7 +18,6 @@
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
#include <net/bluetooth/a2mp.h>
-#include <net/bluetooth/amp.h>
struct phy_link {
struct list_head list;
diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
index c252c63..fedfdb9 100644
--- a/net/bluetooth/a2mp.c
+++ b/net/bluetooth/a2mp.c
@@ -378,9 +378,13 @@ static int a2mp_getampassoc_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
plink = phylink_add(mgr, hdev->id, rsp->id, ctrl->assoc,
ctrl->assoc_len);
+ if (!plink)
+ goto done;
BT_DBG("Created plink %p: loc:%d -> rem:%d", plink, hdev->id, rsp->id);
+ amp_create_phylink(hdev, mgr, plink);
+
done:
skb_pull(skb, len);
return 0;
diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c
index 725a9f0..7f2c0fa 100644
--- a/net/bluetooth/amp.c
+++ b/net/bluetooth/amp.c
@@ -17,6 +17,7 @@
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/a2mp.h>
#include <net/bluetooth/amp.h>
+#include <net/bluetooth/pal.h>
static void amp_read_loc_info_complete_cb(struct hci_dev *hdev,
struct hci_cb_cmd *cmd)
@@ -122,3 +123,33 @@ void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr)
&cp, amp_read_loc_assoc_complete_cb, mgr,
cb_destructor, GFP_KERNEL);
}
+
+static void amp_create_phylink_cs_cb(struct hci_dev *hdev,
+ struct hci_cb_cmd *cmd)
+{
+ struct amp_mgr *mgr = cmd->opt;
+
+ BT_DBG("mgr %p", mgr);
+
+ /* Write Remote AMP Assoc */
+}
+
+void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
+ struct phy_link *plink)
+{
+ struct hci_cp_create_phy_link cp;
+
+ cp.phy_handle = plink->handle;
+
+ if (phylink_gen_key(mgr->l2cap_conn->hcon, cp.key, &cp.key_len,
+ &cp.key_type)) {
+ BT_DBG("Cannot create link key");
+ return;
+ }
+
+ amp_mgr_get(mgr);
+
+ hci_callback_send_cmd(hdev, HCI_OP_CREATE_PHY_LINK, sizeof(cp), &cp,
+ amp_create_phylink_cs_cb, mgr, cb_destructor,
+ GFP_KERNEL);
+}
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 5f68c70..8110b94 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1685,6 +1685,13 @@ static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
BT_DBG("%s status 0x%2.2x", hdev->name, status);
}
+static void hci_cs_create_phylink(struct hci_dev *hdev, u8 status)
+{
+ BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+ hci_callback_process(hdev, HCI_OP_CREATE_PHY_LINK, status);
+}
+
static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
@@ -2475,6 +2482,10 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cs_le_start_enc(hdev, ev->status);
break;
+ case HCI_OP_CREATE_PHY_LINK:
+ hci_cs_create_phylink(hdev, ev->status);
+ break;
+
default:
BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);
break;
--
1.7.9.5
^ 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