Linux bluetooth development
 help / color / mirror / Atom feed
* Re: [PATCH 1/2] Bluetooth: Use min_t for calculating chan->imtu
From: Johan Hedberg @ 2013-12-06  5:07 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1386306115-30686-1-git-send-email-johan.hedberg@gmail.com>

Hi,

On Fri, Dec 06, 2013, johan.hedberg@gmail.com wrote:
> Since there's a nice convenient helper for calculating the minimum of
> two values, let's use that one.
> 
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> ---
>  net/bluetooth/l2cap_core.c | 6 +-----
>  1 file changed, 1 insertion(+), 5 deletions(-)
> 
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index 6e6f308af036..8f42cae96dc3 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -505,11 +505,7 @@ static void l2cap_le_flowctl_init(struct l2cap_chan *chan)
>  	chan->sdu_len = 0;
>  	chan->tx_credits = 0;
>  	chan->rx_credits = le_max_credits;
> -
> -	if (chan->imtu < L2CAP_LE_DEFAULT_MPS)
> -		chan->mps = chan->imtu;
> -	else
> -		chan->mps = L2CAP_LE_DEFAULT_MPS;
> +	chan->imtu = min_t(u16, chan->imtu, L2CAP_LE_DEFAULT_MPS);

Ignore this one. It should obviously be assigning to chan->mps and not
chan->imtu.

Johan

^ permalink raw reply

* Re: [PATCH v2 30/32] Bluetooth: Fix validating LE PSM values
From: Johan Hedberg @ 2013-12-06  5:05 UTC (permalink / raw)
  To: Anderson Lizardo; +Cc: BlueZ development
In-Reply-To: <CAJdJm_Pvc97a8i3vcO4NO0sDJFzUyJ3JOkGuwOyYL8Bi8RjE5A@mail.gmail.com>

Hi Lizardo,

On Thu, Dec 05, 2013, Anderson Lizardo wrote:
> On Thu, Dec 5, 2013 at 9:11 AM,  <johan.hedberg@gmail.com> wrote:
> > +static bool is_valid_psm(u16 psm, u8 dst_type)
> > +{
> > +       if (!psm)
> > +               return false;
> > +
> > +       if (bdaddr_type_is_le(dst_type))
> > +               return (psm < 0x00ff);
> 
> Shouldn't be "psm <= 0x00ff" here?

Yes, it should. I just sent two fix-up patches based on your feedback.
Thanks.

Johan

^ permalink raw reply

* [PATCH 2/2] Bluetooth: Fix valid LE PSM check
From: johan.hedberg @ 2013-12-06  5:01 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1386306115-30686-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

The range of valid LE PSMs is 0x0001-0x00ff so the check should be for
"less than or equal to" instead of "less than".

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/l2cap_core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 8f42cae96dc3..23c57b4cdbcb 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1851,7 +1851,7 @@ static bool is_valid_psm(u16 psm, u8 dst_type)
 		return false;
 
 	if (bdaddr_type_is_le(dst_type))
-		return (psm < 0x00ff);
+		return (psm <= 0x00ff);
 
 	/* PSM must be odd and lsb of upper byte must be 0 */
 	return ((psm & 0x0101) == 0x0001);
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH 1/2] Bluetooth: Use min_t for calculating chan->imtu
From: johan.hedberg @ 2013-12-06  5:01 UTC (permalink / raw)
  To: linux-bluetooth

From: Johan Hedberg <johan.hedberg@intel.com>

Since there's a nice convenient helper for calculating the minimum of
two values, let's use that one.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/l2cap_core.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 6e6f308af036..8f42cae96dc3 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -505,11 +505,7 @@ static void l2cap_le_flowctl_init(struct l2cap_chan *chan)
 	chan->sdu_len = 0;
 	chan->tx_credits = 0;
 	chan->rx_credits = le_max_credits;
-
-	if (chan->imtu < L2CAP_LE_DEFAULT_MPS)
-		chan->mps = chan->imtu;
-	else
-		chan->mps = L2CAP_LE_DEFAULT_MPS;
+	chan->imtu = min_t(u16, chan->imtu, L2CAP_LE_DEFAULT_MPS);
 
 	skb_queue_head_init(&chan->tx_q);
 }
-- 
1.8.4.2


^ permalink raw reply related

* Re: [RFC v3 00/12] LE auto connection and connection parameters
From: Marcel Holtmann @ 2013-12-06  4:40 UTC (permalink / raw)
  To: Andre Guedes; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <CACJA=fWLf7wAmgooAkmbH3e2R+AE9dbfutvbjTewkp+5bJkmeQ@mail.gmail.com>

Hi Andre,

> Ping.
> 
>> The main changes from the previous version are:
>>  * Debugfs interface to add auto connect address instead of new mgmt
>>    commands.
>>  * We always stop LE scanning in favor of connection establishment even if
>>    the controller supports scanning and connection at the same time.
>>  * Background scanning is now controlled in one single place (hci_update_
>>    background_scan function).
>>  * RCU was replaced by hdev->lock to protect hdev->le_conn_params list. After
>>    all the changes since the original version of this patch set, I realized
>>    we always operate on hdev->le_conn_params with hdev->lock held so there is
>>    no point in use RCU to protect this list.

can you send a re-based v4 against the latest bluetooth-next tree please.

Regards

Marcel


^ permalink raw reply

* Re: [PATCH v2 30/32] Bluetooth: Fix validating LE PSM values
From: Anderson Lizardo @ 2013-12-06  0:02 UTC (permalink / raw)
  To: Johan Hedberg; +Cc: BlueZ development
In-Reply-To: <1386249090-10236-31-git-send-email-johan.hedberg@gmail.com>

Hi Johan,

On Thu, Dec 5, 2013 at 9:11 AM,  <johan.hedberg@gmail.com> wrote:
> +static bool is_valid_psm(u16 psm, u8 dst_type)
> +{
> +       if (!psm)
> +               return false;
> +
> +       if (bdaddr_type_is_le(dst_type))
> +               return (psm < 0x00ff);

Shouldn't be "psm <= 0x00ff" here?

> +
> +       /* PSM must be odd and lsb of upper byte must be 0 */
> +       return ((psm & 0x0101) == 0x0001);
> +}
> +
>  int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
>                        bdaddr_t *dst, u8 dst_type)
>  {

Best Regards,
-- 
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil

^ permalink raw reply

* Re: [PATCH v2 00/32] Bluetooth: LE CoC support
From: Marcel Holtmann @ 2013-12-05 15:06 UTC (permalink / raw)
  To: Johan Hedberg; +Cc: linux-bluetooth@vger.kernel.org development
In-Reply-To: <1386249090-10236-1-git-send-email-johan.hedberg@gmail.com>

Hi Johan,

> Here's v2 of the patches with all comments taken into account.
> Additionally I've fixed the permissions of the debugfs files, fixed the
> credits calculation for max_credits == 1, and added a cleanup patch at
> the end of the set for simplifying l2cap_chan initialization for LE CoC.
> 
> I've also updated user space l2test now to support the new BT_SNDMTU and
> BT_RCVMTU socket options, i.e. the LE CoC functionality can now be
> tested using upstream l2test.
> 
> Johan
> 
> ----------------------------------------------------------------
> Johan Hedberg (32):
>      Bluetooth: Remove unnecessary braces from one-line if-statement
>      Bluetooth: Add module parameter to enable LE CoC support
>      Bluetooth: Update l2cap_global_chan_by_psm() to take a link type
>      Bluetooth: Allow l2cap_chan_check_security() to be used for LE links.
>      Bluetooth: Pass command length to LE signaling channel handlers
>      Bluetooth: Move LE L2CAP initiator procedure to its own function
>      Bluetooth: Add definitions for LE connection oriented channels
>      Bluetooth: Add initial code for LE L2CAP Connect Request
>      Bluetooth: Add smp_sufficient_security helper function
>      Bluetooth: Refactor L2CAP connect rejection to its own function
>      Bluetooth: Add basic LE L2CAP connect request receiving support
>      Bluetooth: Fix L2CAP channel closing for LE connections
>      Bluetooth: Add L2CAP Disconnect suppport for LE
>      Bluetooth: Make l2cap_le_sig_cmd logic consistent
>      Bluetooth: Add LE L2CAP flow control mode
>      Bluetooth: Track LE L2CAP credits in l2cap_chan
>      Bluetooth: Limit L2CAP_OPTIONS socket option usage with LE
>      Bluetooth: Add new BT_SNDMTU and BT_RCVMTU socket options
>      Bluetooth: Implement returning of LE L2CAP credits
>      Bluetooth: Add LE flow control discipline
>      Bluetooth: Reject LE CoC commands when the feature is not enabled
>      Bluetooth: Introduce L2CAP channel callback for suspending
>      Bluetooth: Add LE L2CAP segmentation support for outgoing data
>      Bluetooth: Implement LE L2CAP reassembly
>      Bluetooth: Fix LE L2CAP Connect Request handling together with SMP
>      Bluetooth: Fix suspending the L2CAP socket if we start with 0 credits
>      Bluetooth: Limit LE MPS to the MTU value
>      Bluetooth: Fix clearing of chan->omtu for LE CoC channels
>      Bluetooth: Fix CID ranges for LE CoC CID allocations
>      Bluetooth: Fix validating LE PSM values
>      Bluetooth: Add debugfs controls for LE CoC MPS and Credits
>      Bluetooth: Simplify l2cap_chan initialization for LE CoC
> 
> include/net/bluetooth/bluetooth.h |   3 +
> include/net/bluetooth/l2cap.h     |  45 +++
> net/bluetooth/l2cap_core.c        | 720 ++++++++++++++++++++++++++++++++++---
> net/bluetooth/l2cap_sock.c        | 157 +++++++-
> net/bluetooth/smp.c               |  16 +-
> net/bluetooth/smp.h               |   1 +
> 6 files changed, 873 insertions(+), 69 deletions(-)

all patches (including minor fixups) have been applied to bluetooth-next tree.

Regards

Marcel


^ permalink raw reply

* Re: [PATCH v2 1/6] android: Add android-tester
From: Luiz Augusto von Dentz @ 2013-12-05 15:00 UTC (permalink / raw)
  To: Grzegorz Kolodziejczyk; +Cc: linux-bluetooth@vger.kernel.org, Marcin Kraglak
In-Reply-To: <1385631770-3858-2-git-send-email-grzegorz.kolodziejczyk@tieto.com>

Hi Grzegorz,

On Thu, Nov 28, 2013 at 11:42 AM, Grzegorz Kolodziejczyk
<grzegorz.kolodziejczyk@tieto.com> wrote:
> From: Marcin Kraglak <marcin.kraglak@tieto.com>
>
> This commit add android-tester.c to tree and Makefile.am.
> This will contain set of unit tests for testing android daemon.
> ---
>  android/Makefile.am      |  4 ++++
>  android/android-tester.c | 21 +++++++++++++++++++++
>  2 files changed, 25 insertions(+)
>  create mode 100644 android/android-tester.c
>
> diff --git a/android/Makefile.am b/android/Makefile.am
> index 94d231f..9390422 100644
> --- a/android/Makefile.am
> +++ b/android/Makefile.am
> @@ -82,6 +82,10 @@ android_haltest_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android \
>
>  android_haltest_LDFLAGS = -pthread
>
> +noinst_PROGRAMS += android/android-tester
> +
> +android_android_tester_SOURCES = android/android-tester.c
> +
>  endif

You should probably add it to .gitignore as well. Also is this suppose
to be run in the host only or do we want to run in Android as well?

-- 
Luiz Augusto von Dentz

^ permalink raw reply

* Re: [PATCHv2 1/4] android/socket: Cleanup sockets on unregister
From: Luiz Augusto von Dentz @ 2013-12-05 14:51 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <1386085873-21715-2-git-send-email-Andrei.Emeltchenko.news@gmail.com>

Hi Andrei,

On Tue, Dec 3, 2013 at 5:51 PM, Andrei Emeltchenko
<Andrei.Emeltchenko.news@gmail.com> wrote:
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> This cleans up rfsock structures closing all sockets and making general cleanup
> for servers and for connections. This will be called form socket unregister.
> ---
>  android/socket.c | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/android/socket.c b/android/socket.c
> index c9eca44..9020874 100644
> --- a/android/socket.c
> +++ b/android/socket.c
> @@ -93,8 +93,10 @@ static struct rfcomm_sock *create_rfsock(int sock, int *hal_fd)
>         return rfsock;
>  }
>
> -static void cleanup_rfsock(struct rfcomm_sock *rfsock)
> +static void cleanup_rfsock(gpointer data)
>  {
> +       struct rfcomm_sock *rfsock = data;
> +
>         DBG("rfsock: %p fd %d real_sock %d chan %u",
>                 rfsock, rfsock->fd, rfsock->real_sock, rfsock->channel);
>
> @@ -936,5 +938,8 @@ void bt_socket_unregister(void)
>  {
>         DBG("");
>
> +       g_list_free_full(connections, cleanup_rfsock);
> +       g_list_free_full(servers, cleanup_rfsock);
> +
>         ipc_unregister(HAL_SERVICE_ID_SOCK);
>  }
> --
> 1.8.3.2

This one is now applied, please rebase make the changes we discussed
for the last 3.


-- 
Luiz Augusto von Dentz

^ permalink raw reply

* Re: [PATCH] all: Use G_SOURCE_REMOVE/G_SOURCE_CONTINUE macros
From: Johan Hedberg @ 2013-12-05 14:00 UTC (permalink / raw)
  To: Bastien Nocera, linux-bluetooth
In-Reply-To: <20131205133527.GA10825@x220.p-661hnu-f1>

Hi,

On Thu, Dec 05, 2013, Johan Hedberg wrote:
> On Wed, Nov 20, 2013, Bastien Nocera wrote:
> > 
> > Instead of TRUE/FALSE. This makes the source more readable.
> > ---
> >  attrib/gattrib.c                     |  2 +-
> >  attrib/gatttool.c                    |  2 +-
> >  configure.ac                         |  8 ++++++++
> >  gdbus/mainloop.c                     |  6 +++---
> >  gdbus/object.c                       |  2 +-
> >  gdbus/watch.c                        |  2 +-
> >  gobex/gobex.c                        |  4 ++--
> >  obexd/client/session.c               |  4 ++--
> >  obexd/client/transfer.c              |  6 +++---
> >  obexd/plugins/messages-dummy.c       |  2 +-
> >  obexd/plugins/messages-tracker.c     |  2 +-
> >  obexd/plugins/phonebook-dummy.c      |  6 +++---
> >  plugins/policy.c                     |  6 +++---
> >  profiles/audio/a2dp.c                | 16 ++++++++--------
> >  profiles/audio/avctp.c               | 12 ++++++------
> >  profiles/audio/avdtp.c               | 14 +++++++-------
> >  profiles/audio/avrcp.c               |  2 +-
> >  profiles/audio/player.c              |  4 ++--
> >  profiles/cyclingspeed/cyclingspeed.c |  2 +-
> >  profiles/health/hdp.c                |  4 ++--
> >  profiles/health/mcap.c               |  2 +-
> >  profiles/health/mcap_sync.c          | 18 +++++++++---------
> >  profiles/input/device.c              | 10 +++++-----
> >  profiles/network/connection.c        |  2 +-
> >  profiles/proximity/monitor.c         |  4 ++--
> >  profiles/sap/server.c                |  4 ++--
> >  src/adapter.c                        | 20 ++++++++++----------
> >  src/device.c                         | 16 ++++++++--------
> >  src/main.c                           |  4 ++--
> >  src/sdp-client.c                     |  2 +-
> >  src/shared/hciemu.c                  |  2 +-
> >  src/shared/tester.c                  | 18 +++++++++---------
> >  tools/btiotest.c                     |  6 +++---
> >  unit/test-gdbus-client.c             |  4 ++--
> >  unit/test-gobex-transfer.c           |  2 +-
> >  unit/test-gobex.c                    |  4 ++--
> >  unit/test-sdp.c                      |  2 +-
> >  37 files changed, 117 insertions(+), 109 deletions(-)
> 
> Applied. Thanks.

Correction, I had to take this back out because of the gdbus changes
which should at least be independent.

Johan

^ permalink raw reply

* [PATCH 2/2] android/audio: Add audio-hal initial skeleton
From: Lukasz Rymanowski @ 2013-12-05 13:59 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: luiz.dentz, Lukasz Rymanowski
In-Reply-To: <1386251995-12188-1-git-send-email-lukasz.rymanowski@tieto.com>

This patch adds audio module for A2DP.
Also adds empty callbacks for stream_out, stream_in and hw_device
methods.
---
 android/Android.mk  |  23 +++
 android/Makefile.am |  10 ++
 android/hal-audio.c | 436 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 469 insertions(+)
 create mode 100644 android/hal-audio.c

diff --git a/android/Android.mk b/android/Android.mk
index 549613c..ebc3219 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -203,3 +203,26 @@ LOCAL_MODULE_TAGS := eng
 LOCAL_MODULE := btmon
 
 include $(BUILD_EXECUTABLE)
+
+#
+# A2DP audio
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := hal-audio.c
+
+LOCAL_C_INCLUDES = \
+	$(call include-path-for, system-core) \
+	$(call include-path-for, libhardware) \
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+
+LOCAL_CFLAGS := $(BLUEZ_COMMON_CFLAGS) \
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := audio.a2dp.default
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/android/Makefile.am b/android/Makefile.am
index df04762..9349a61 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -83,6 +83,16 @@ android_haltest_CFLAGS = $(AM_CFLAGS) -I$(srcdir)/android \
 
 android_haltest_LDFLAGS = -pthread
 
+noinst_LTLIBRARIES += android/libaudio-internal.la
+
+android_libaudio_internal_la_SOURCES = android/hal-audio.c \
+					android/hardware/audio.h \
+					android/hardware/audio_effect.h \
+					android/hardware/hardware.h \
+					android/system/audio.h
+
+android_libaudio_internal_la_CPPFLAGS = -I$(srcdir)/android
+
 endif
 
 EXTRA_DIST += android/Android.mk android/hal-ipc-api.txt android/README \
diff --git a/android/hal-audio.c b/android/hal-audio.c
new file mode 100644
index 0000000..e98f317
--- /dev/null
+++ b/android/hal-audio.c
@@ -0,0 +1,436 @@
+/*
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <hardware/audio.h>
+#include <hardware/hardware.h>
+
+#include "hal-log.h"
+
+static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
+								size_t bytes)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static uint32_t out_get_sample_rate(const struct audio_stream *stream)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static size_t out_get_buffer_size(const struct audio_stream *stream)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static uint32_t out_get_channels(const struct audio_stream *stream)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static audio_format_t out_get_format(const struct audio_stream *stream)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static int out_set_format(struct audio_stream *stream, audio_format_t format)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static int out_standby(struct audio_stream *stream)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static int out_dump(const struct audio_stream *stream, int fd)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static char *out_get_parameters(const struct audio_stream *stream,
+							const char *keys)
+{
+	DBG("");
+	return strdup("");
+}
+
+static uint32_t out_get_latency(const struct audio_stream_out *stream)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static int out_set_volume(struct audio_stream_out *stream, float left,
+								float right)
+{
+	DBG("");
+	/* volume controlled in audioflinger mixer (digital) */
+	return -ENOSYS;
+}
+
+static int out_get_render_position(const struct audio_stream_out *stream,
+							uint32_t *dsp_frames)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static int out_add_audio_effect(const struct audio_stream *stream,
+							effect_handle_t effect)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static int out_remove_audio_effect(const struct audio_stream *stream,
+							effect_handle_t effect)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static uint32_t in_get_sample_rate(const struct audio_stream *stream)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static size_t in_get_buffer_size(const struct audio_stream *stream)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static uint32_t in_get_channels(const struct audio_stream *stream)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static audio_format_t in_get_format(const struct audio_stream *stream)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static int in_set_format(struct audio_stream *stream, audio_format_t format)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static int in_standby(struct audio_stream *stream)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static int in_dump(const struct audio_stream *stream, int fd)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static char *in_get_parameters(const struct audio_stream *stream,
+							const char *keys)
+{
+	DBG("");
+	return strdup("");
+}
+
+static int in_set_gain(struct audio_stream_in *stream, float gain)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
+								size_t bytes)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static int in_add_audio_effect(const struct audio_stream *stream,
+							effect_handle_t effect)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static int in_remove_audio_effect(const struct audio_stream *stream,
+							effect_handle_t effect)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static int adev_open_output_stream(struct audio_hw_device *dev,
+					audio_io_handle_t handle,
+					audio_devices_t devices,
+					audio_output_flags_t flags,
+					struct audio_config *config,
+					struct audio_stream_out **stream_out)
+
+{
+	struct audio_stream_out *out;
+
+	out = calloc(1, sizeof(struct audio_stream_out));
+	if (!out)
+		return -ENOMEM;
+
+	DBG("");
+
+	out->common.get_sample_rate = out_get_sample_rate;
+	out->common.set_sample_rate = out_set_sample_rate;
+	out->common.get_buffer_size = out_get_buffer_size;
+	out->common.get_channels = out_get_channels;
+	out->common.get_format = out_get_format;
+	out->common.set_format = out_set_format;
+	out->common.standby = out_standby;
+	out->common.dump = out_dump;
+	out->common.set_parameters = out_set_parameters;
+	out->common.get_parameters = out_get_parameters;
+	out->common.add_audio_effect = out_add_audio_effect;
+	out->common.remove_audio_effect = out_remove_audio_effect;
+	out->get_latency = out_get_latency;
+	out->set_volume = out_set_volume;
+	out->write = out_write;
+	out->get_render_position = out_get_render_position;
+
+	*stream_out = out;
+
+	return 0;
+}
+
+static void adev_close_output_stream(struct audio_hw_device *dev,
+					struct audio_stream_out *stream)
+{
+	DBG("");
+}
+
+static int adev_set_parameters(struct audio_hw_device *dev,
+							const char *kvpairs)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static char *adev_get_parameters(const struct audio_hw_device *dev,
+							const char *keys)
+{
+	DBG("");
+	return strdup("");
+}
+
+static int adev_init_check(const struct audio_hw_device *dev)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static int adev_set_master_volume(struct audio_hw_device *dev, float volume)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static int adev_set_mode(struct audio_hw_device *dev, int mode)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev,
+					const struct audio_config *config)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static int adev_open_input_stream(struct audio_hw_device *dev,
+						audio_io_handle_t handle,
+						audio_devices_t devices,
+						struct audio_config *config,
+					  struct audio_stream_in **stream_in)
+{
+	struct audio_stream_in *in;
+
+	DBG("");
+
+	in = calloc(1, sizeof(struct audio_stream_in));
+	if (!in)
+		return -ENOMEM;
+
+	in->common.get_sample_rate = in_get_sample_rate;
+	in->common.set_sample_rate = in_set_sample_rate;
+	in->common.get_buffer_size = in_get_buffer_size;
+	in->common.get_channels = in_get_channels;
+	in->common.get_format = in_get_format;
+	in->common.set_format = in_set_format;
+	in->common.standby = in_standby;
+	in->common.dump = in_dump;
+	in->common.set_parameters = in_set_parameters;
+	in->common.get_parameters = in_get_parameters;
+	in->common.add_audio_effect = in_add_audio_effect;
+	in->common.remove_audio_effect = in_remove_audio_effect;
+	in->set_gain = in_set_gain;
+	in->read = in_read;
+	in->get_input_frames_lost = in_get_input_frames_lost;
+
+	*stream_in = in;
+
+	return 0;
+}
+
+static void adev_close_input_stream(struct audio_hw_device *dev,
+					struct audio_stream_in *stream_in)
+{
+	DBG("");
+	free(stream_in);
+}
+
+static int adev_dump(const audio_hw_device_t *device, int fd)
+{
+	DBG("");
+	return -ENOSYS;
+}
+
+static int adev_close(hw_device_t *device)
+{
+	DBG("");
+	free(device);
+	return 0;
+}
+
+static int adev_open(const hw_module_t *module, const char *name,
+							hw_device_t **device)
+{
+	struct audio_hw_device *adev;
+
+	DBG("");
+
+	if (strcmp(name, AUDIO_HARDWARE_INTERFACE)) {
+		error("interface %s not matching [%s]", name,
+						AUDIO_HARDWARE_INTERFACE);
+		return -EINVAL;
+	}
+
+	adev = calloc(1, sizeof(struct audio_hw_device));
+	if (!adev)
+		return -ENOMEM;
+
+	adev->common.version = AUDIO_DEVICE_API_VERSION_CURRENT;
+	adev->common.module = (struct hw_module_t *) module;
+	adev->common.close = adev_close;
+
+	adev->init_check = adev_init_check;
+	adev->set_voice_volume = adev_set_voice_volume;
+	adev->set_master_volume = adev_set_master_volume;
+	adev->set_mode = adev_set_mode;
+	adev->set_mic_mute = adev_set_mic_mute;
+	adev->get_mic_mute = adev_get_mic_mute;
+	adev->set_parameters = adev_set_parameters;
+	adev->get_parameters = adev_get_parameters;
+	adev->get_input_buffer_size = adev_get_input_buffer_size;
+	adev->open_output_stream = adev_open_output_stream;
+	adev->close_output_stream = adev_close_output_stream;
+	adev->open_input_stream = adev_open_input_stream;
+	adev->close_input_stream = adev_close_input_stream;
+	adev->dump = adev_dump;
+
+	*device = &adev->common;
+
+	return 0;
+}
+
+static struct hw_module_methods_t hal_module_methods = {
+	.open = adev_open,
+};
+
+struct audio_module HAL_MODULE_INFO_SYM = {
+	.common = {
+	.tag = HARDWARE_MODULE_TAG,
+	.version_major = 1,
+	.version_minor = 0,
+	.id = AUDIO_HARDWARE_MODULE_ID,
+	.name = "A2DP Bluez HW HAL",
+	.author = "Intel Corporation",
+	.methods = &hal_module_methods,
+	},
+};
-- 
1.8.4


^ permalink raw reply related

* Re: [PATCHv2 2/4] android/socket Use 64K buffer for socket handling
From: Andrei Emeltchenko @ 2013-12-05 13:48 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <CABBYNZLzirtMJresKRYi9D-rJ8d0sJEXXDoP4X8ep=sUJv+ozQ@mail.gmail.com>

Hi Luiz,

On Thu, Dec 05, 2013 at 02:43:10PM +0200, Luiz Augusto von Dentz wrote:
> Hi Andrei,
> 
> On Tue, Dec 3, 2013 at 5:51 PM, Andrei Emeltchenko
> <Andrei.Emeltchenko.news@gmail.com> wrote:
> > From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> >
> > Make SOCKET_BUFFER define and use 0xFFFE instead of 1K.
> > The value 0XFFFE is what Android sends in OBEX Connect packet in
> > Maximum Packet Length field. Though OBEX specify meximum packet
> > length as 64K - 1 which is 0xFFFF.
> > ---
> >  android/socket.c | 6 ++++--
> >  1 file changed, 4 insertions(+), 2 deletions(-)
> >
> > diff --git a/android/socket.c b/android/socket.c
> > index 9020874..9ff9019 100644
> > --- a/android/socket.c
> > +++ b/android/socket.c
> > @@ -52,6 +52,8 @@
> >
> >  #define SVC_HINT_OBEX 0x10
> >
> > +#define SOCKET_BUFFER 0xFFFE
> > +
> >  static bdaddr_t adapter_addr;
> >
> >  /* Simple list of RFCOMM server sockets */
> > @@ -487,7 +489,7 @@ static gboolean sock_stack_event_cb(GIOChannel *io, GIOCondition cond,
> >                                                                 gpointer data)
> >  {
> >         struct rfcomm_sock *rfsock = data;
> > -       unsigned char buf[1024];
> > +       unsigned char buf[SOCKET_BUFFER];
> >         int len, sent;
> >
> >         if (cond & G_IO_HUP) {
> > @@ -526,7 +528,7 @@ static gboolean sock_rfcomm_event_cb(GIOChannel *io, GIOCondition cond,
> >                                                                 gpointer data)
> >  {
> >         struct rfcomm_sock *rfsock = data;
> > -       unsigned char buf[1024];
> > +       unsigned char buf[SOCKET_BUFFER];
> >         int len, sent;
> >
> >         if (cond & G_IO_HUP) {
> > --
> > 1.8.3.2
> 
> We need to be a bit more generic here, the socket HAL is not
> restricted to OBEX only, also it doesn't seems you are adjusting the
> buffer level of the sockets, 

it is in the following patch

> the buffer itself is just to copy between
> the sockets so we have to follow how much the sockets can
> transmit/receive not the other way around.

the idea is to copy data to socket buffers and then sleep.

> So it seems to me that we should either set the maximum MTU size we
> could use with RFCOMM (UINT16_MAX?) or read the MTU once connected
> (not sure if makes sense since it is SOCK_STREAM) and then allocate
> the same amount as buffer in a field in struct rfcomm_sock, also this
> needs then to be set back to socketpair with
> setsocketopt(SO_RCVBUF/SO_SNDBUF) so we minimize context switches and
> wakeups.

This can actually make more switches since RFCOMM packet size is
relatively small (990 bytes in my case). Maximum RFCOMM L2CAP MTU is 1013.

This is what we had before.

Best regards 
Andrei Emeltchenko 


^ permalink raw reply

* Re: [PATCH] all: Use G_SOURCE_REMOVE/G_SOURCE_CONTINUE macros
From: Johan Hedberg @ 2013-12-05 13:35 UTC (permalink / raw)
  To: Bastien Nocera; +Cc: linux-bluetooth
In-Reply-To: <1384937788.10231.5.camel@nuvo>

Hi Bastien,

On Wed, Nov 20, 2013, Bastien Nocera wrote:
> 
> Instead of TRUE/FALSE. This makes the source more readable.
> ---
>  attrib/gattrib.c                     |  2 +-
>  attrib/gatttool.c                    |  2 +-
>  configure.ac                         |  8 ++++++++
>  gdbus/mainloop.c                     |  6 +++---
>  gdbus/object.c                       |  2 +-
>  gdbus/watch.c                        |  2 +-
>  gobex/gobex.c                        |  4 ++--
>  obexd/client/session.c               |  4 ++--
>  obexd/client/transfer.c              |  6 +++---
>  obexd/plugins/messages-dummy.c       |  2 +-
>  obexd/plugins/messages-tracker.c     |  2 +-
>  obexd/plugins/phonebook-dummy.c      |  6 +++---
>  plugins/policy.c                     |  6 +++---
>  profiles/audio/a2dp.c                | 16 ++++++++--------
>  profiles/audio/avctp.c               | 12 ++++++------
>  profiles/audio/avdtp.c               | 14 +++++++-------
>  profiles/audio/avrcp.c               |  2 +-
>  profiles/audio/player.c              |  4 ++--
>  profiles/cyclingspeed/cyclingspeed.c |  2 +-
>  profiles/health/hdp.c                |  4 ++--
>  profiles/health/mcap.c               |  2 +-
>  profiles/health/mcap_sync.c          | 18 +++++++++---------
>  profiles/input/device.c              | 10 +++++-----
>  profiles/network/connection.c        |  2 +-
>  profiles/proximity/monitor.c         |  4 ++--
>  profiles/sap/server.c                |  4 ++--
>  src/adapter.c                        | 20 ++++++++++----------
>  src/device.c                         | 16 ++++++++--------
>  src/main.c                           |  4 ++--
>  src/sdp-client.c                     |  2 +-
>  src/shared/hciemu.c                  |  2 +-
>  src/shared/tester.c                  | 18 +++++++++---------
>  tools/btiotest.c                     |  6 +++---
>  unit/test-gdbus-client.c             |  4 ++--
>  unit/test-gobex-transfer.c           |  2 +-
>  unit/test-gobex.c                    |  4 ++--
>  unit/test-sdp.c                      |  2 +-
>  37 files changed, 117 insertions(+), 109 deletions(-)

Applied. Thanks.

Johan

^ permalink raw reply

* [PATCH v2 32/32] Bluetooth: Simplify l2cap_chan initialization for LE CoC
From: johan.hedberg @ 2013-12-05 13:11 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1386249090-10236-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

The values in l2cap_chan that are used for actually transmitting data
only need to be initialized right after we've received an L2CAP Connect
Request or just before we send one. The only thing that we need to
initialize though bind() and connect() is the chan->mode value. This way
all other initializations can be done in the l2cap_le_flowctl_init
function (which now becomes private to l2cap_core.c) and the
l2cap_le_flowctl_start function can be completely removed.

Also, since the l2cap_sock_init function initializes the imtu and omtu
to adequate values these do not need to be part of l2cap_le_flowctl_init.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 include/net/bluetooth/l2cap.h |  1 -
 net/bluetooth/l2cap_core.c    | 33 +++++++++++----------------------
 net/bluetooth/l2cap_sock.c    |  4 ++--
 3 files changed, 13 insertions(+), 25 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index ef6ca5fa8f5e..458245cd26fc 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -873,7 +873,6 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
 void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
 int l2cap_chan_check_security(struct l2cap_chan *chan);
 void l2cap_chan_set_defaults(struct l2cap_chan *chan);
-void l2cap_le_flowctl_init(struct l2cap_chan *chan);
 int l2cap_ertm_init(struct l2cap_chan *chan);
 void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
 void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 326d323ddfe3..08c7259c4ad7 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -500,9 +500,9 @@ void l2cap_chan_set_defaults(struct l2cap_chan *chan)
 
 void l2cap_le_flowctl_init(struct l2cap_chan *chan)
 {
-	chan->imtu = L2CAP_DEFAULT_MTU;
-	chan->omtu = L2CAP_LE_MIN_MTU;
-	chan->mode = L2CAP_MODE_LE_FLOWCTL;
+	chan->sdu = NULL;
+	chan->sdu_last_frag = NULL;
+	chan->sdu_len = 0;
 	chan->tx_credits = 0;
 	chan->rx_credits = le_max_credits;
 
@@ -510,6 +510,8 @@ void l2cap_le_flowctl_init(struct l2cap_chan *chan)
 		chan->mps = chan->imtu;
 	else
 		chan->mps = L2CAP_LE_DEFAULT_MPS;
+
+	skb_queue_head_init(&chan->tx_q);
 }
 
 void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
@@ -1208,31 +1210,14 @@ static void l2cap_move_done(struct l2cap_chan *chan)
 	}
 }
 
-static void l2cap_le_flowctl_start(struct l2cap_chan *chan)
-{
-	chan->sdu = NULL;
-	chan->sdu_last_frag = NULL;
-	chan->sdu_len = 0;
-
-	if (chan->imtu < L2CAP_LE_DEFAULT_MPS)
-		chan->mps = chan->imtu;
-	else
-		chan->mps = le_default_mps;
-
-	skb_queue_head_init(&chan->tx_q);
-
-	if (!chan->tx_credits)
-		chan->ops->suspend(chan);
-}
-
 static void l2cap_chan_ready(struct l2cap_chan *chan)
 {
 	/* This clears all conf flags, including CONF_NOT_COMPLETE */
 	chan->conf_state = 0;
 	__clear_chan_timer(chan);
 
-	if (chan->mode == L2CAP_MODE_LE_FLOWCTL)
-		l2cap_le_flowctl_start(chan);
+	if (chan->mode == L2CAP_MODE_LE_FLOWCTL && !chan->tx_credits)
+		chan->ops->suspend(chan);
 
 	chan->state = BT_CONNECTED;
 
@@ -1909,7 +1894,9 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
 
 	switch (chan->mode) {
 	case L2CAP_MODE_BASIC:
+		break;
 	case L2CAP_MODE_LE_FLOWCTL:
+		l2cap_le_flowctl_init(chan);
 		break;
 	case L2CAP_MODE_ERTM:
 	case L2CAP_MODE_STREAMING:
@@ -5661,6 +5648,8 @@ static int l2cap_le_connect_req(struct l2cap_conn *conn,
 		goto response_unlock;
 	}
 
+	l2cap_le_flowctl_init(chan);
+
 	bacpy(&chan->src, &conn->hcon->src);
 	bacpy(&chan->dst, &conn->hcon->dst);
 	chan->src_type = bdaddr_type(conn->hcon, conn->hcon->src_type);
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index f4471fd6e99e..cebeca136551 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -153,7 +153,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
 	chan->src_type = la.l2_bdaddr_type;
 
 	if (chan->psm && bdaddr_type_is_le(chan->src_type))
-		l2cap_le_flowctl_init(chan);
+		chan->mode = L2CAP_MODE_LE_FLOWCTL;
 
 	chan->state = BT_BOUND;
 	sk->sk_state = BT_BOUND;
@@ -226,7 +226,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr,
 	}
 
 	if (chan->psm && bdaddr_type_is_le(chan->src_type))
-		l2cap_le_flowctl_init(chan);
+		chan->mode = L2CAP_MODE_LE_FLOWCTL;
 
 	err = l2cap_chan_connect(chan, la.l2_psm, __le16_to_cpu(la.l2_cid),
 				 &la.l2_bdaddr, la.l2_bdaddr_type);
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH v2 31/32] Bluetooth: Add debugfs controls for LE CoC MPS and Credits
From: johan.hedberg @ 2013-12-05 13:11 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1386249090-10236-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

This patch adds entries to debugfs to control the values used for the
MPS and Credits for LE Flow Control Mode.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/l2cap_core.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index c638c280db40..326d323ddfe3 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -49,6 +49,9 @@ static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP | L2CAP_FC_CONNLESS, };
 static LIST_HEAD(chan_list);
 static DEFINE_RWLOCK(chan_list_lock);
 
+static u16 le_max_credits = L2CAP_LE_MAX_CREDITS;
+static u16 le_default_mps = L2CAP_LE_DEFAULT_MPS;
+
 static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
 				       u8 code, u8 ident, u16 dlen, void *data);
 static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
@@ -501,7 +504,7 @@ void l2cap_le_flowctl_init(struct l2cap_chan *chan)
 	chan->omtu = L2CAP_LE_MIN_MTU;
 	chan->mode = L2CAP_MODE_LE_FLOWCTL;
 	chan->tx_credits = 0;
-	chan->rx_credits = L2CAP_LE_MAX_CREDITS;
+	chan->rx_credits = le_max_credits;
 
 	if (chan->imtu < L2CAP_LE_DEFAULT_MPS)
 		chan->mps = chan->imtu;
@@ -1214,7 +1217,7 @@ static void l2cap_le_flowctl_start(struct l2cap_chan *chan)
 	if (chan->imtu < L2CAP_LE_DEFAULT_MPS)
 		chan->mps = chan->imtu;
 	else
-		chan->mps = L2CAP_LE_DEFAULT_MPS;
+		chan->mps = le_default_mps;
 
 	skb_queue_head_init(&chan->tx_q);
 
@@ -6829,10 +6832,10 @@ static void l2cap_chan_le_send_credits(struct l2cap_chan *chan)
 	/* We return more credits to the sender only after the amount of
 	 * credits falls below half of the initial amount.
 	 */
-	if (chan->rx_credits >= (L2CAP_LE_MAX_CREDITS + 1) / 2)
+	if (chan->rx_credits >= (le_max_credits + 1) / 2)
 		return;
 
-	return_credits = L2CAP_LE_MAX_CREDITS - chan->rx_credits;
+	return_credits = le_max_credits - chan->rx_credits;
 
 	BT_DBG("chan %p returning %u credits to sender", chan, return_credits);
 
@@ -7446,6 +7449,11 @@ int __init l2cap_init(void)
 	l2cap_debugfs = debugfs_create_file("l2cap", 0444, bt_debugfs,
 					    NULL, &l2cap_debugfs_fops);
 
+	debugfs_create_u16("l2cap_le_max_credits", 0466, bt_debugfs,
+			   &le_max_credits);
+	debugfs_create_u16("l2cap_le_default_mps", 0466, bt_debugfs,
+			   &le_default_mps);
+
 	return 0;
 }
 
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH v2 30/32] Bluetooth: Fix validating LE PSM values
From: johan.hedberg @ 2013-12-05 13:11 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1386249090-10236-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

LE PSM values have different ranges than those for BR/EDR. The valid
ranges for fixed, SIG assigned values is 0x0001-0x007f and for dynamic
PSM values 0x0080-0x00ff. We need to ensure that bind() and connect()
calls conform to these ranges when operating on LE CoC sockets.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/l2cap_core.c | 15 +++++++++++++--
 net/bluetooth/l2cap_sock.c | 40 +++++++++++++++++++++++++++++++---------
 2 files changed, 44 insertions(+), 11 deletions(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index e447bbedcabf..c638c280db40 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1861,6 +1861,18 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm,
 	return c1;
 }
 
+static bool is_valid_psm(u16 psm, u8 dst_type)
+{
+	if (!psm)
+		return false;
+
+	if (bdaddr_type_is_le(dst_type))
+		return (psm < 0x00ff);
+
+	/* PSM must be odd and lsb of upper byte must be 0 */
+	return ((psm & 0x0101) == 0x0001);
+}
+
 int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
 		       bdaddr_t *dst, u8 dst_type)
 {
@@ -1881,8 +1893,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
 
 	l2cap_chan_lock(chan);
 
-	/* PSM must be odd and lsb of upper byte must be 0 */
-	if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid &&
+	if (!is_valid_psm(__le16_to_cpu(psm), dst_type) && !cid &&
 	    chan->chan_type != L2CAP_CHAN_RAW) {
 		err = -EINVAL;
 		goto done;
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index c2424782c245..f4471fd6e99e 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -53,6 +53,32 @@ bool l2cap_is_socket(struct socket *sock)
 }
 EXPORT_SYMBOL(l2cap_is_socket);
 
+static int l2cap_validate_bredr_psm(u16 psm)
+{
+	/* PSM must be odd and lsb of upper byte must be 0 */
+	if ((psm & 0x0101) != 0x0001)
+		return -EINVAL;
+
+	/* Restrict usage of well-known PSMs */
+	if (psm < 0x1001 && !capable(CAP_NET_BIND_SERVICE))
+		return -EACCES;
+
+	return 0;
+}
+
+static int l2cap_validate_le_psm(u16 psm)
+{
+	/* Valid LE_PSM ranges are defined only until 0x00ff */
+	if (psm > 0x00ff)
+		return -EINVAL;
+
+	/* Restrict fixed, SIG assigned PSM values to CAP_NET_BIND_SERVICE */
+	if (psm <= 0x007f && !capable(CAP_NET_BIND_SERVICE))
+		return -EACCES;
+
+	return 0;
+}
+
 static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
 {
 	struct sock *sk = sock->sk;
@@ -94,17 +120,13 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
 	if (la.l2_psm) {
 		__u16 psm = __le16_to_cpu(la.l2_psm);
 
-		/* PSM must be odd and lsb of upper byte must be 0 */
-		if ((psm & 0x0101) != 0x0001) {
-			err = -EINVAL;
-			goto done;
-		}
+		if (la.l2_bdaddr_type == BDADDR_BREDR)
+			err = l2cap_validate_bredr_psm(psm);
+		else
+			err = l2cap_validate_le_psm(psm);
 
-		/* Restrict usage of well-known PSMs */
-		if (psm < 0x1001 && !capable(CAP_NET_BIND_SERVICE)) {
-			err = -EACCES;
+		if (err)
 			goto done;
-		}
 	}
 
 	if (la.l2_cid)
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH v2 29/32] Bluetooth: Fix CID ranges for LE CoC CID allocations
From: johan.hedberg @ 2013-12-05 13:11 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1386249090-10236-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

LE CoC used differend CIC ranges than BR/EDR L2CAP. The start of the
range is the same (0x0040) but the range ends at 0x007f (unlike BR/EDR
where it goes all the way to 0xffff).

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 include/net/bluetooth/l2cap.h | 1 +
 net/bluetooth/l2cap_core.c    | 9 +++++++--
 2 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index a4616eeeb8b5..ef6ca5fa8f5e 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -252,6 +252,7 @@ struct l2cap_conn_rsp {
 #define L2CAP_CID_SMP		0x0006
 #define L2CAP_CID_DYN_START	0x0040
 #define L2CAP_CID_DYN_END	0xffff
+#define L2CAP_CID_LE_DYN_END	0x007f
 
 /* connect/create channel results */
 #define L2CAP_CR_SUCCESS	0x0000
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index e6bf5ed16313..e447bbedcabf 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -213,9 +213,14 @@ int l2cap_add_scid(struct l2cap_chan *chan,  __u16 scid)
 
 static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
 {
-	u16 cid = L2CAP_CID_DYN_START;
+	u16 cid, dyn_end;
 
-	for (; cid < L2CAP_CID_DYN_END; cid++) {
+	if (conn->hcon->type == LE_LINK)
+		dyn_end = L2CAP_CID_LE_DYN_END;
+	else
+		dyn_end = L2CAP_CID_DYN_END;
+
+	for (cid = L2CAP_CID_DYN_START; cid < dyn_end; cid++) {
 		if (!__l2cap_get_chan_by_scid(conn, cid))
 			return cid;
 	}
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH v2 28/32] Bluetooth: Fix clearing of chan->omtu for LE CoC channels
From: johan.hedberg @ 2013-12-05 13:11 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1386249090-10236-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

The outgoing MTU should only be set upon channel creation to the initial
minimum value (23) or from a remote connect req/rsp PDU.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/l2cap_core.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index ce34f1518f96..e6bf5ed16313 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -516,12 +516,12 @@ void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 	switch (chan->chan_type) {
 	case L2CAP_CHAN_CONN_ORIENTED:
 		if (conn->hcon->type == LE_LINK) {
-			/* LE connection */
-			chan->omtu = L2CAP_DEFAULT_MTU;
-			if (chan->dcid == L2CAP_CID_ATT)
+			if (chan->dcid == L2CAP_CID_ATT) {
+				chan->omtu = L2CAP_DEFAULT_MTU;
 				chan->scid = L2CAP_CID_ATT;
-			else
+			} else {
 				chan->scid = l2cap_alloc_cid(conn);
+			}
 		} else {
 			/* Alloc CID for connection-oriented socket */
 			chan->scid = l2cap_alloc_cid(conn);
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH v2 27/32] Bluetooth: Limit LE MPS to the MTU value
From: johan.hedberg @ 2013-12-05 13:11 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1386249090-10236-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

It doesn't make sense to have an MPS value greater than the configured
MTU value since we will then not be able to fill up the packets to their
full possible size. We need to set the MPS both in flowctl_init()
as well as flowctl_start() since the imtu may change after init() but
start() is only called after we've sent the LE Connection Request PDU
which depends on having a valid MPS value.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/l2cap_core.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index b6dc613febd5..ce34f1518f96 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -497,6 +497,11 @@ void l2cap_le_flowctl_init(struct l2cap_chan *chan)
 	chan->mode = L2CAP_MODE_LE_FLOWCTL;
 	chan->tx_credits = 0;
 	chan->rx_credits = L2CAP_LE_MAX_CREDITS;
+
+	if (chan->imtu < L2CAP_LE_DEFAULT_MPS)
+		chan->mps = chan->imtu;
+	else
+		chan->mps = L2CAP_LE_DEFAULT_MPS;
 }
 
 void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
@@ -645,7 +650,7 @@ static void l2cap_chan_le_connect_reject(struct l2cap_chan *chan)
 
 	rsp.dcid    = cpu_to_le16(chan->scid);
 	rsp.mtu     = cpu_to_le16(chan->imtu);
-	rsp.mps     = __constant_cpu_to_le16(L2CAP_LE_DEFAULT_MPS);
+	rsp.mps     = cpu_to_le16(chan->mps);
 	rsp.credits = cpu_to_le16(chan->rx_credits);
 	rsp.result  = cpu_to_le16(result);
 
@@ -1201,6 +1206,11 @@ static void l2cap_le_flowctl_start(struct l2cap_chan *chan)
 	chan->sdu_last_frag = NULL;
 	chan->sdu_len = 0;
 
+	if (chan->imtu < L2CAP_LE_DEFAULT_MPS)
+		chan->mps = chan->imtu;
+	else
+		chan->mps = L2CAP_LE_DEFAULT_MPS;
+
 	skb_queue_head_init(&chan->tx_q);
 
 	if (!chan->tx_credits)
@@ -1232,7 +1242,7 @@ static void l2cap_le_connect(struct l2cap_chan *chan)
 	req.psm     = chan->psm;
 	req.scid    = cpu_to_le16(chan->scid);
 	req.mtu     = cpu_to_le16(chan->imtu);
-	req.mps     = __constant_cpu_to_le16(L2CAP_LE_DEFAULT_MPS);
+	req.mps     = cpu_to_le16(chan->mps);
 	req.credits = cpu_to_le16(chan->rx_credits);
 
 	chan->ident = l2cap_get_ident(conn);
@@ -3826,7 +3836,7 @@ void __l2cap_le_connect_rsp_defer(struct l2cap_chan *chan)
 
 	rsp.dcid    = cpu_to_le16(chan->scid);
 	rsp.mtu     = cpu_to_le16(chan->imtu);
-	rsp.mps     = __constant_cpu_to_le16(L2CAP_LE_DEFAULT_MPS);
+	rsp.mps     = cpu_to_le16(chan->mps);
 	rsp.credits = cpu_to_le16(chan->rx_credits);
 	rsp.result  = __constant_cpu_to_le16(L2CAP_CR_SUCCESS);
 
@@ -5669,7 +5679,7 @@ response_unlock:
 response:
 	if (chan) {
 		rsp.mtu = cpu_to_le16(chan->imtu);
-		rsp.mps = __constant_cpu_to_le16(L2CAP_LE_DEFAULT_MPS);
+		rsp.mps = cpu_to_le16(chan->mps);
 	} else {
 		rsp.mtu = 0;
 		rsp.mps = 0;
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH v2 26/32] Bluetooth: Fix suspending the L2CAP socket if we start with 0 credits
From: johan.hedberg @ 2013-12-05 13:11 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1386249090-10236-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

If the peer gives us zero credits in its connection request or response
we must call the suspend channel callback so the BT_SK_SUSPEND flag gets
set and user space is blocked from sending data to the socket.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/l2cap_core.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index ddb61564fe6a..b6dc613febd5 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1202,6 +1202,9 @@ static void l2cap_le_flowctl_start(struct l2cap_chan *chan)
 	chan->sdu_len = 0;
 
 	skb_queue_head_init(&chan->tx_q);
+
+	if (!chan->tx_credits)
+		chan->ops->suspend(chan);
 }
 
 static void l2cap_chan_ready(struct l2cap_chan *chan)
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH v2 25/32] Bluetooth: Fix LE L2CAP Connect Request handling together with SMP
From: johan.hedberg @ 2013-12-05 13:11 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1386249090-10236-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

Unlike BR/EDR, for LE when we're in the BT_CONNECT state we may or may
not have already have sent the Connect Request. This means that we need
some extra tracking of the request. This patch adds an extra channel
flag to prevent the request from being sent a second time.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 include/net/bluetooth/l2cap.h | 1 +
 net/bluetooth/l2cap_core.c    | 3 +++
 2 files changed, 4 insertions(+)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index c6c86d0e39c5..a4616eeeb8b5 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -695,6 +695,7 @@ enum {
 	FLAG_EXT_CTRL,
 	FLAG_EFS_ENABLE,
 	FLAG_DEFER_SETUP,
+	FLAG_LE_CONN_REQ_SENT,
 };
 
 enum {
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index ae90dd284c87..ddb61564fe6a 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -1223,6 +1223,9 @@ static void l2cap_le_connect(struct l2cap_chan *chan)
 	struct l2cap_conn *conn = chan->conn;
 	struct l2cap_le_conn_req req;
 
+	if (test_and_set_bit(FLAG_LE_CONN_REQ_SENT, &chan->flags))
+		return;
+
 	req.psm     = chan->psm;
 	req.scid    = cpu_to_le16(chan->scid);
 	req.mtu     = cpu_to_le16(chan->imtu);
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH v2 24/32] Bluetooth: Implement LE L2CAP reassembly
From: johan.hedberg @ 2013-12-05 13:11 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1386249090-10236-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

When receiving fragments over an LE Connection oriented Channel they
need to be collected up and eventually merged into a single SDU. This
patch adds the necessary code for collecting up the fragment skbs to the
channel context and passing them to the recv() callback when the entire
SDU has been received.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/l2cap_core.c | 79 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 76 insertions(+), 3 deletions(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 9869faa2904d..ae90dd284c87 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -6816,18 +6816,91 @@ static void l2cap_chan_le_send_credits(struct l2cap_chan *chan)
 
 static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
 {
-	if (!chan->rx_credits)
+	int err;
+
+	if (!chan->rx_credits) {
+		BT_ERR("No credits to receive LE L2CAP data");
 		return -ENOBUFS;
+	}
 
-	if (chan->imtu < skb->len)
+	if (chan->imtu < skb->len) {
+		BT_ERR("Too big LE L2CAP PDU");
 		return -ENOBUFS;
+	}
 
 	chan->rx_credits--;
 	BT_DBG("rx_credits %u -> %u", chan->rx_credits + 1, chan->rx_credits);
 
 	l2cap_chan_le_send_credits(chan);
 
-	return chan->ops->recv(chan, skb);
+	err = 0;
+
+	if (!chan->sdu) {
+		u16 sdu_len;
+
+		sdu_len = get_unaligned_le16(skb->data);
+		skb_pull(skb, L2CAP_SDULEN_SIZE);
+
+		BT_DBG("Start of new SDU. sdu_len %u skb->len %u imtu %u",
+		       sdu_len, skb->len, chan->imtu);
+
+		if (sdu_len > chan->imtu) {
+			BT_ERR("Too big LE L2CAP SDU length received");
+			err = -EMSGSIZE;
+			goto failed;
+		}
+
+		if (skb->len > sdu_len) {
+			BT_ERR("Too much LE L2CAP data received");
+			err = -EINVAL;
+			goto failed;
+		}
+
+		if (skb->len == sdu_len)
+			return chan->ops->recv(chan, skb);
+
+		chan->sdu = skb;
+		chan->sdu_len = sdu_len;
+		chan->sdu_last_frag = skb;
+
+		return 0;
+	}
+
+	BT_DBG("SDU fragment. chan->sdu->len %u skb->len %u chan->sdu_len %u",
+	       chan->sdu->len, skb->len, chan->sdu_len);
+
+	if (chan->sdu->len + skb->len > chan->sdu_len) {
+		BT_ERR("Too much LE L2CAP data received");
+		err = -EINVAL;
+		goto failed;
+	}
+
+	append_skb_frag(chan->sdu, skb, &chan->sdu_last_frag);
+	skb = NULL;
+
+	if (chan->sdu->len == chan->sdu_len) {
+		err = chan->ops->recv(chan, chan->sdu);
+		if (!err) {
+			chan->sdu = NULL;
+			chan->sdu_last_frag = NULL;
+			chan->sdu_len = 0;
+		}
+	}
+
+failed:
+	if (err) {
+		kfree_skb(skb);
+		kfree_skb(chan->sdu);
+		chan->sdu = NULL;
+		chan->sdu_last_frag = NULL;
+		chan->sdu_len = 0;
+	}
+
+	/* We can't return an error here since we took care of the skb
+	 * freeing internally. An error return would cause the caller to
+	 * do a double-free of the skb.
+	 */
+	return 0;
 }
 
 static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid,
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH v2 23/32] Bluetooth: Add LE L2CAP segmentation support for outgoing data
From: johan.hedberg @ 2013-12-05 13:11 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1386249090-10236-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

This patch adds segmentation support for outgoing data packets. Packets
are segmented based on the MTU and MPS values. The l2cap_chan struct
already contains many helpful variables from BR/EDR Enhanced L2CAP which
can be used for this.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/l2cap_core.c | 127 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 126 insertions(+), 1 deletion(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index ef9d22a3689a..9869faa2904d 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -607,6 +607,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
 		break;
 
 	case L2CAP_MODE_LE_FLOWCTL:
+		skb_queue_purge(&chan->tx_q);
 		break;
 
 	case L2CAP_MODE_ERTM:
@@ -1194,12 +1195,24 @@ static void l2cap_move_done(struct l2cap_chan *chan)
 	}
 }
 
+static void l2cap_le_flowctl_start(struct l2cap_chan *chan)
+{
+	chan->sdu = NULL;
+	chan->sdu_last_frag = NULL;
+	chan->sdu_len = 0;
+
+	skb_queue_head_init(&chan->tx_q);
+}
+
 static void l2cap_chan_ready(struct l2cap_chan *chan)
 {
 	/* This clears all conf flags, including CONF_NOT_COMPLETE */
 	chan->conf_state = 0;
 	__clear_chan_timer(chan);
 
+	if (chan->mode == L2CAP_MODE_LE_FLOWCTL)
+		l2cap_le_flowctl_start(chan);
+
 	chan->state = BT_CONNECTED;
 
 	chan->ops->ready(chan);
@@ -2521,6 +2534,89 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan,
 	return 0;
 }
 
+static struct sk_buff *l2cap_create_le_flowctl_pdu(struct l2cap_chan *chan,
+						   struct msghdr *msg,
+						   size_t len, u16 sdulen)
+{
+	struct l2cap_conn *conn = chan->conn;
+	struct sk_buff *skb;
+	int err, count, hlen;
+	struct l2cap_hdr *lh;
+
+	BT_DBG("chan %p len %zu", chan, len);
+
+	if (!conn)
+		return ERR_PTR(-ENOTCONN);
+
+	hlen = L2CAP_HDR_SIZE;
+
+	if (sdulen)
+		hlen += L2CAP_SDULEN_SIZE;
+
+	count = min_t(unsigned int, (conn->mtu - hlen), len);
+
+	skb = chan->ops->alloc_skb(chan, count + hlen,
+				   msg->msg_flags & MSG_DONTWAIT);
+	if (IS_ERR(skb))
+		return skb;
+
+	/* Create L2CAP header */
+	lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
+	lh->cid = cpu_to_le16(chan->dcid);
+	lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
+
+	if (sdulen)
+		put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
+
+	err = l2cap_skbuff_fromiovec(chan, msg, len, count, skb);
+	if (unlikely(err < 0)) {
+		kfree_skb(skb);
+		return ERR_PTR(err);
+	}
+
+	return skb;
+}
+
+static int l2cap_segment_le_sdu(struct l2cap_chan *chan,
+				struct sk_buff_head *seg_queue,
+				struct msghdr *msg, size_t len)
+{
+	struct sk_buff *skb;
+	size_t pdu_len;
+	u16 sdu_len;
+
+	BT_DBG("chan %p, msg %p, len %zu", chan, msg, len);
+
+	pdu_len = chan->conn->mtu - L2CAP_HDR_SIZE;
+
+	pdu_len = min_t(size_t, pdu_len, chan->remote_mps);
+
+	sdu_len = len;
+	pdu_len -= L2CAP_SDULEN_SIZE;
+
+	while (len > 0) {
+		if (len <= pdu_len)
+			pdu_len = len;
+
+		skb = l2cap_create_le_flowctl_pdu(chan, msg, pdu_len, sdu_len);
+		if (IS_ERR(skb)) {
+			__skb_queue_purge(seg_queue);
+			return PTR_ERR(skb);
+		}
+
+		__skb_queue_tail(seg_queue, skb);
+
+		len -= pdu_len;
+
+		if (sdu_len) {
+			sdu_len = 0;
+			pdu_len += L2CAP_SDULEN_SIZE;
+		}
+	}
+
+	return 0;
+}
+
 int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
 		    u32 priority)
 {
@@ -2543,10 +2639,39 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
 
 	switch (chan->mode) {
 	case L2CAP_MODE_LE_FLOWCTL:
+		/* Check outgoing MTU */
+		if (len > chan->omtu)
+			return -EMSGSIZE;
+
 		if (!chan->tx_credits)
 			return -EAGAIN;
 
-		/* fall through */
+		__skb_queue_head_init(&seg_queue);
+
+		err = l2cap_segment_le_sdu(chan, &seg_queue, msg, len);
+
+		if (chan->state != BT_CONNECTED) {
+			__skb_queue_purge(&seg_queue);
+			err = -ENOTCONN;
+		}
+
+		if (err)
+			return err;
+
+		skb_queue_splice_tail_init(&seg_queue, &chan->tx_q);
+
+		while (chan->tx_credits && !skb_queue_empty(&chan->tx_q)) {
+			l2cap_do_send(chan, skb_dequeue(&chan->tx_q));
+			chan->tx_credits--;
+		}
+
+		if (!chan->tx_credits)
+			chan->ops->suspend(chan);
+
+		err = len;
+
+		break;
+
 	case L2CAP_MODE_BASIC:
 		/* Check outgoing MTU */
 		if (len > chan->omtu)
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH v2 22/32] Bluetooth: Introduce L2CAP channel callback for suspending
From: johan.hedberg @ 2013-12-05 13:11 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1386249090-10236-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

Setting the BT_SK_SUSPEND socket flag from the L2CAP core is causing a
dependency on the socket. So instead of doing that, use a channel
callback into the socket handling to suspend.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 include/net/bluetooth/l2cap.h | 1 +
 net/bluetooth/l2cap_sock.c    | 9 +++++++++
 2 files changed, 10 insertions(+)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 8c59ed17ee90..c6c86d0e39c5 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -593,6 +593,7 @@ struct l2cap_ops {
 	void			(*ready) (struct l2cap_chan *chan);
 	void			(*defer) (struct l2cap_chan *chan);
 	void			(*resume) (struct l2cap_chan *chan);
+	void			(*suspend) (struct l2cap_chan *chan);
 	void			(*set_shutdown) (struct l2cap_chan *chan);
 	long			(*get_sndtimeo) (struct l2cap_chan *chan);
 	struct sk_buff		*(*alloc_skb) (struct l2cap_chan *chan,
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 9007def8c619..c2424782c245 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -1321,6 +1321,14 @@ static long l2cap_sock_get_sndtimeo_cb(struct l2cap_chan *chan)
 	return sk->sk_sndtimeo;
 }
 
+static void l2cap_sock_suspend_cb(struct l2cap_chan *chan)
+{
+	struct sock *sk = chan->data;
+
+	set_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags);
+	sk->sk_state_change(sk);
+}
+
 static struct l2cap_ops l2cap_chan_ops = {
 	.name		= "L2CAP Socket Interface",
 	.new_connection	= l2cap_sock_new_connection_cb,
@@ -1331,6 +1339,7 @@ static struct l2cap_ops l2cap_chan_ops = {
 	.ready		= l2cap_sock_ready_cb,
 	.defer		= l2cap_sock_defer_cb,
 	.resume		= l2cap_sock_resume_cb,
+	.suspend	= l2cap_sock_suspend_cb,
 	.set_shutdown	= l2cap_sock_set_shutdown_cb,
 	.get_sndtimeo	= l2cap_sock_get_sndtimeo_cb,
 	.alloc_skb	= l2cap_sock_alloc_skb_cb,
-- 
1.8.4.2


^ permalink raw reply related

* [PATCH v2 21/32] Bluetooth: Reject LE CoC commands when the feature is not enabled
From: johan.hedberg @ 2013-12-05 13:11 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1386249090-10236-1-git-send-email-johan.hedberg@gmail.com>

From: Johan Hedberg <johan.hedberg@intel.com>

Since LE CoC support needs to be enabled through a module option for now
we need to reject any related signaling PDUs in addition to rejecting
the creation of LE CoC sockets (which we already do).

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
 net/bluetooth/l2cap_core.c | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 7dd4aca46d44..ef9d22a3689a 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -5595,6 +5595,17 @@ static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
 {
 	int err = 0;
 
+	if (!enable_lecoc) {
+		switch (cmd->code) {
+		case L2CAP_LE_CONN_REQ:
+		case L2CAP_LE_CONN_RSP:
+		case L2CAP_LE_CREDITS:
+		case L2CAP_DISCONN_REQ:
+		case L2CAP_DISCONN_RSP:
+			return -EINVAL;
+		}
+	}
+
 	switch (cmd->code) {
 	case L2CAP_COMMAND_REJ:
 		break;
-- 
1.8.4.2


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox