* [PATCH 8/8] android/pan: Move logic from HAL to daemon
From: Jakub Tyszkowski @ 2013-12-05 10:37 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386239837-4102-1-git-send-email-jakub.tyszkowski@tieto.com>
HAL should contain as little logic as possible, but we should be doing
these checks on daemon side anyway.
---
android/hal-pan.c | 14 --------------
android/pan.c | 19 +++++++++++++++++++
2 files changed, 19 insertions(+), 14 deletions(-)
diff --git a/android/hal-pan.c b/android/hal-pan.c
index ec52672..8c0f8d8 100644
--- a/android/hal-pan.c
+++ b/android/hal-pan.c
@@ -109,20 +109,6 @@ static bt_status_t pan_connect(const bt_bdaddr_t *bd_addr, int local_role,
if (!interface_ready())
return BT_STATUS_NOT_READY;
- switch (local_role) {
- case BTPAN_ROLE_PANNAP:
- if (remote_role != BTPAN_ROLE_PANU)
- return BT_STATUS_UNSUPPORTED;
- break;
- case BTPAN_ROLE_PANU:
- if (remote_role != BTPAN_ROLE_PANNAP &&
- remote_role != BTPAN_ROLE_PANU)
- return BT_STATUS_UNSUPPORTED;
- break;
- default:
- return BT_STATUS_UNSUPPORTED;
- }
-
memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
cmd.local_role = local_role;
cmd.remote_role = remote_role;
diff --git a/android/pan.c b/android/pan.c
index f6e0ca9..78a1055 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -200,6 +200,25 @@ static void bt_pan_connect(const void *buf, uint16_t len)
DBG("");
+ switch (cmd->local_role) {
+ case HAL_PAN_ROLE_NAP:
+ if (cmd->remote_role != HAL_PAN_ROLE_PANU) {
+ status = HAL_STATUS_UNSUPPORTED;
+ goto failed;
+ }
+ break;
+ case HAL_PAN_ROLE_PANU:
+ if (cmd->remote_role != HAL_PAN_ROLE_NAP &&
+ cmd->remote_role != HAL_PAN_ROLE_PANU) {
+ status = HAL_STATUS_UNSUPPORTED;
+ goto failed;
+ }
+ break;
+ default:
+ status = HAL_STATUS_UNSUPPORTED;
+ goto failed;
+ }
+
android2bdaddr(&cmd->bdaddr, &dst);
l = g_slist_find_custom(devices, &dst, device_cmp);
--
1.8.5
^ permalink raw reply related
* [PATCH 7/8] android/pan: Move logic from HAL layer to daemon
From: Jakub Tyszkowski @ 2013-12-05 10:37 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386239837-4102-1-git-send-email-jakub.tyszkowski@tieto.com>
HAL should contain as little logic as possible, but we should be doing
these checks on daemon side anyway.
---
android/hal-pan.c | 3 ---
android/pan.c | 16 ++++++++++++++--
2 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/android/hal-pan.c b/android/hal-pan.c
index 6aaf8af..ec52672 100644
--- a/android/hal-pan.c
+++ b/android/hal-pan.c
@@ -74,9 +74,6 @@ static bt_status_t pan_enable(int local_role)
if (!interface_ready())
return BT_STATUS_NOT_READY;
- if (!(local_role == BTPAN_ROLE_PANU || local_role == BTPAN_ROLE_PANNAP))
- return BT_STATUS_UNSUPPORTED;
-
cmd.local_role = local_role;
return hal_ipc_cmd(HAL_SERVICE_ID_PAN, HAL_OP_PAN_ENABLE,
diff --git a/android/pan.c b/android/pan.c
index fe6ee26..f6e0ca9 100644
--- a/android/pan.c
+++ b/android/pan.c
@@ -280,9 +280,21 @@ failed:
static void bt_pan_enable(const void *buf, uint16_t len)
{
- DBG("Not Implemented");
+ const struct hal_cmd_pan_enable *cmd = buf;
+ uint8_t status;
+
+ switch (cmd->local_role) {
+ case HAL_PAN_ROLE_PANU:
+ case HAL_PAN_ROLE_NAP:
+ DBG("Not Implemented");
+ status = HAL_STATUS_FAILED;
+ break;
+ default:
+ status = HAL_STATUS_UNSUPPORTED;
+ break;
+ }
- ipc_send_rsp(HAL_SERVICE_ID_PAN, HAL_OP_PAN_ENABLE, HAL_STATUS_FAILED);
+ ipc_send_rsp(HAL_SERVICE_ID_PAN, HAL_OP_PAN_ENABLE, status);
}
static void bt_pan_get_role(const void *buf, uint16_t len)
--
1.8.5
^ permalink raw reply related
* [PATCH 6/8] android/a2dp: Unregister ipc handlers if init fails
From: Jakub Tyszkowski @ 2013-12-05 10:37 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386239837-4102-1-git-send-email-jakub.tyszkowski@tieto.com>
Add ipc handlers cleanup if init fails. Send proper status if
already initialized.
---
android/hal-a2dp.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/android/hal-a2dp.c b/android/hal-a2dp.c
index cf39ba2..c898995 100644
--- a/android/hal-a2dp.c
+++ b/android/hal-a2dp.c
@@ -96,9 +96,13 @@ static bt_status_t disconnect(bt_bdaddr_t *bd_addr)
static bt_status_t init(btav_callbacks_t *callbacks)
{
struct hal_cmd_register_module cmd;
+ int ret;
DBG("");
+ if (interface_ready())
+ return BT_STATUS_DONE;
+
cbs = callbacks;
hal_ipc_register(HAL_SERVICE_ID_A2DP, ev_handlers,
@@ -106,8 +110,15 @@ static bt_status_t init(btav_callbacks_t *callbacks)
cmd.service_id = HAL_SERVICE_ID_A2DP;
- return hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE,
+ ret = hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE,
sizeof(cmd), &cmd, 0, NULL, NULL);
+
+ if (ret != BT_STATUS_SUCCESS) {
+ cbs = NULL;
+ hal_ipc_unregister(HAL_SERVICE_ID_A2DP);
+ }
+
+ return ret;
}
static void cleanup()
--
1.8.5
^ permalink raw reply related
* [PATCH 5/8] android/pan: Unregister ipc handlers if init fails
From: Jakub Tyszkowski @ 2013-12-05 10:37 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386239837-4102-1-git-send-email-jakub.tyszkowski@tieto.com>
Add ipc handlers cleanup if init fails. Send proper status if
already initialized.
---
android/hal-pan.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/android/hal-pan.c b/android/hal-pan.c
index e7b8a20..6aaf8af 100644
--- a/android/hal-pan.c
+++ b/android/hal-pan.c
@@ -152,9 +152,13 @@ static bt_status_t pan_disconnect(const bt_bdaddr_t *bd_addr)
static bt_status_t pan_init(const btpan_callbacks_t *callbacks)
{
struct hal_cmd_register_module cmd;
+ int ret;
DBG("");
+ if (interface_ready())
+ return BT_STATUS_DONE;
+
cbs = callbacks;
hal_ipc_register(HAL_SERVICE_ID_PAN, ev_handlers,
@@ -162,8 +166,15 @@ static bt_status_t pan_init(const btpan_callbacks_t *callbacks)
cmd.service_id = HAL_SERVICE_ID_PAN;
- return hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE,
+ ret = hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE,
sizeof(cmd), &cmd, 0, NULL, NULL);
+
+ if (ret != BT_STATUS_SUCCESS) {
+ cbs = NULL;
+ hal_ipc_unregister(HAL_SERVICE_ID_PAN);
+ }
+
+ return ret;
}
static void pan_cleanup()
--
1.8.5
^ permalink raw reply related
* [PATCH 4/8] android/hidhost: Unregister ipc handlers if init fails
From: Jakub Tyszkowski @ 2013-12-05 10:37 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386239837-4102-1-git-send-email-jakub.tyszkowski@tieto.com>
Add ipc handlers cleanup if init fails. Send proper status if
already initialized.
---
android/hal-hidhost.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/android/hal-hidhost.c b/android/hal-hidhost.c
index 0573006..6a6b682 100644
--- a/android/hal-hidhost.c
+++ b/android/hal-hidhost.c
@@ -363,9 +363,13 @@ static bt_status_t send_data(bt_bdaddr_t *bd_addr, char *data)
static bt_status_t init(bthh_callbacks_t *callbacks)
{
struct hal_cmd_register_module cmd;
+ int ret;
DBG("");
+ if (interface_ready())
+ return BT_STATUS_DONE;
+
/* store reference to user callbacks */
cbacks = callbacks;
@@ -374,8 +378,15 @@ static bt_status_t init(bthh_callbacks_t *callbacks)
cmd.service_id = HAL_SERVICE_ID_HIDHOST;
- return hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE,
+ ret = hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE,
sizeof(cmd), &cmd, 0, NULL, NULL);
+
+ if (ret != BT_STATUS_SUCCESS) {
+ cbacks = NULL;
+ hal_ipc_unregister(HAL_SERVICE_ID_HIDHOST);
+ }
+
+ return ret;
}
static void cleanup(void)
--
1.8.5
^ permalink raw reply related
* [PATCH 3/8] android: Fix sending status on bluetooth init if already initialized
From: Jakub Tyszkowski @ 2013-12-05 10:37 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386239837-4102-1-git-send-email-jakub.tyszkowski@tieto.com>
We should be sending BT_STATUS_DONE when calling init on already
initialized interface like Bluedroid does. This indicates that previosly
registered callbacks are still registered, not those passed with second
init call.
---
android/hal-bluetooth.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/android/hal-bluetooth.c b/android/hal-bluetooth.c
index 87d6fc7..7cac15c 100644
--- a/android/hal-bluetooth.c
+++ b/android/hal-bluetooth.c
@@ -373,7 +373,7 @@ static int init(bt_callbacks_t *callbacks)
DBG("");
if (interface_ready())
- return BT_STATUS_SUCCESS;
+ return BT_STATUS_DONE;
bt_hal_cbacks = callbacks;
--
1.8.5
^ permalink raw reply related
* [PATCH 2/8] android: Update haltest tool entry in README
From: Jakub Tyszkowski @ 2013-12-05 10:37 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386239837-4102-1-git-send-email-jakub.tyszkowski@tieto.com>
Update informations about 'adapter' interface being renamed to 'bluetooth' and
init being called on haltest startup by default.
---
android/README | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/android/README b/android/README
index 6c2c53f..68c3e9f 100644
--- a/android/README
+++ b/android/README
@@ -82,9 +82,12 @@ Testing tool
============
BT HAL test tools located in android/haltest is provided for HAL level testing
-of both Android daemon and HAL library. Start it and type 'adapter init' in
-prompt to initialize HAL library. On Android required bluetoothd service will
-be started automatically. On Linux it is required to start android/bluetoothd
-manually before init command timeout. To deinitialize HAL library and stop
-daemon type 'adapter cleanup'. Type 'help' for more information. Tab completion
-is also supported.
+of both Android daemon and HAL library. Start it with '-n' parameter and type
+'bluetooth init' in prompt to initialize HAL library. Running without parameter
+will make haltest try to initialize all services after start. On Android
+required bluetoothd service will be started automatically. On Linux it is
+required to start android/bluetoothd manually before init command timeout or
+use provided android/system-emulator, which takes care of launching daemon
+automatically on HAL library initialization. To deinitialize HAL library and
+stop daemon type 'bluetooth cleanup'. Type 'help' for more information. Tab
+completion is also supported.
--
1.8.5
^ permalink raw reply related
* [PATCH 1/8] android: Fix turning BT off during pairing
From: Jakub Tyszkowski @ 2013-12-05 10:37 UTC (permalink / raw)
To: linux-bluetooth
Not turning BT off in time due to actions queued in mgmt makes Android
unstable and locks Bluetooth UI controlls. This patch fixes this issue
by cancelling queued actions.
---
android/bluetooth.c | 22 +++++++++++++++++++++-
1 file changed, 21 insertions(+), 1 deletion(-)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index 6174b1f..e67864a 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -1982,6 +1982,9 @@ static void pair_device_complete(uint8_t status, uint16_t length,
DBG("status %u", status);
+ /*Data used for bond cancelling can be freed now*/
+ g_free(user_data);
+
/* On success bond state change will be send when new link key event
* is received */
if (status == MGMT_STATUS_SUCCESS)
@@ -1991,19 +1994,34 @@ static void pair_device_complete(uint8_t status, uint16_t length,
HAL_BOND_STATE_NONE);
}
+static void pair_device_cancelled(void *data)
+{
+ bdaddr_t *addr = data;
+
+ set_device_bond_state(addr, HAL_STATUS_FAILED, HAL_BOND_STATE_NONE);
+
+ g_free(data);
+}
+
static void handle_create_bond_cmd(const void *buf, uint16_t len)
{
const struct hal_cmd_create_bond *cmd = buf;
uint8_t status;
struct mgmt_cp_pair_device cp;
+ bdaddr_t *addr;
cp.io_cap = DEFAULT_IO_CAPABILITY;
cp.addr.type = BDADDR_BREDR;
android2bdaddr(cmd->bdaddr, &cp.addr.bdaddr);
+ addr = g_new(bdaddr_t, 1);
+ bacpy(addr, &cp.addr.bdaddr);
+
if (mgmt_send(mgmt_if, MGMT_OP_PAIR_DEVICE, adapter.index, sizeof(cp),
- &cp, pair_device_complete, NULL, NULL) == 0) {
+ &cp, pair_device_complete,
+ addr, pair_device_cancelled) == 0) {
status = HAL_STATUS_FAILED;
+ g_free(addr);
goto fail;
}
@@ -2253,6 +2271,8 @@ static void handle_disable_cmd(const void *buf, uint16_t len)
goto failed;
}
+ mgmt_cancel_index(mgmt_if, adapter.index);
+
if (!set_mode(MGMT_OP_SET_POWERED, 0x00)) {
status = HAL_STATUS_FAILED;
goto failed;
--
1.8.5
^ permalink raw reply related
* Re: [PATCH 19/31] Bluetooth: Implement returning of LE L2CAP credits
From: Vinicius Costa Gomes @ 2013-12-04 16:15 UTC (permalink / raw)
To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <1386166287-13693-20-git-send-email-johan.hedberg@gmail.com>
Hi Johan,
On 16:11 Wed 04 Dec, Johan Hedberg wrote:
> From: Johan Hedberg <johan.hedberg@intel.com>
>
> We should return credits to the remote side whenever they fall below a
> certain level (in our case under half of the initially given amount).
>
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> ---
> net/bluetooth/l2cap_core.c | 33 ++++++++++++++++++++++++++++++++-
> 1 file changed, 32 insertions(+), 1 deletion(-)
>
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index 8a1c528908fb..b99bdc53c57b 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -2542,8 +2542,10 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
> }
>
> switch (chan->mode) {
> - case L2CAP_MODE_BASIC:
> case L2CAP_MODE_LE_FLOWCTL:
> + chan->tx_credits--;
> + /* fall through */
I guess that this change makes more sense in the next commit, no?
> + case L2CAP_MODE_BASIC:
> /* Check outgoing MTU */
> if (len > chan->omtu)
> return -EMSGSIZE;
> @@ -6608,6 +6610,32 @@ drop:
> return 0;
> }
>
Cheers,
--
Vinicius
^ permalink raw reply
* Re: [PATCH 10/31] Bluetooth: Refactor L2CAP connect rejection to its own function
From: Vinicius Costa Gomes @ 2013-12-04 16:14 UTC (permalink / raw)
To: Johan Hedberg; +Cc: linux-bluetooth
In-Reply-To: <1386166287-13693-11-git-send-email-johan.hedberg@gmail.com>
Hi Johan,
On 16:11 Wed 04 Dec, Johan Hedberg wrote:
> From: Johan Hedberg <johan.hedberg@intel.com>
>
> We'll need to have a separate code patch for LE based connection
Nitpick: 'path' instead of 'patch'.
> rejection so it's cleaner to move out the response construction code
> into its own function (and later a second one for LE).
>
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Cheers,
--
Vinicius
^ permalink raw reply
* Re: [PATCHv1 0/2] Introduce default adapter property
From: Timo Müller @ 2013-12-04 15:39 UTC (permalink / raw)
To: Szymon Janc; +Cc: linux-bluetooth, Timo Mueller
In-Reply-To: <3146259.c398076Ovj@uw000953>
Hi Szymon,
Szymon Janc wrote, On 04.12.2013 09:32:
> Hi Timo,
>
>> From: Timo Mueller <timo.mueller@bmw-carit.de>
>>
>> Hi,
>>
>> the information about the default adapter is currently not available
>> through the D-Bus API of BlueZ. But as plugins can use this
>> information to choose the adapter they act upon it would be helpful
>> for users to be able to retrieve this information as well.
>>
>> For example the neard plugin uses this information to decide for which
>> adapter oob data is generated. Users could use the same information to
>> power the adapter before actually sending the oob data.
>
> I think this property is bluetoothd internal detail and should not be needed
> to be exported to user.
Alright. Is the default information needed at all? I might be missing
something but the default information seems to only be used by the
hostname, sixaxis and neard plugins. I don't know about sixaxis, but the
hostname plugin could also do without this information. If the neard
plugin would handle multiple adapters, then the default adapter property
could be dropped completely.
> If reason for this is scenario where multiple BT and
> NFC adapters are present and you need to match them in pairs, then proper
> solution would probably require extending neard agent interface. Neard plugin
> could be also made 'smarter' about multiple adapters eg. try to choose other
> controller if default one is not powered etc. Regarding changing power state
> of bt controller, I think this could be done by neard plugin itself (possible
> based on some static configuration or even runtime dbus setting...). It is on
> my 'TODO when have some spare time' list :)
Automatic powering, if enabled by 'configuration', sounds good to me.
Regarding the adapter selection, how about a runtime dbus setting to set
the adapter that the neard plugin is using? It could then behave as
bluetoothctl does right now. Choosing the first adapter on start and use
the selected adapter afterwards.
>
> It would be good if you could outline usecases you are trying to address with
> this change.
The use case was to only send the oob data when the device has not yet
been paired with the adapter that is used. On Android this wouldn't
interrupt the regular Android Beam behaviour (when sending an URL from
the browser for example). Of course this requires a unique ID that could
be requested via NFC and mapped to a BD_ADDR. Unfortunately this ID, as
just discussed in IRC, does not exist. So, admittedly this use case is
broken.
Best regards,
Timo
^ permalink raw reply
* Re: [RFC v3 00/12] LE auto connection and connection parameters
From: Andre Guedes @ 2013-12-04 14:35 UTC (permalink / raw)
To: linux-bluetooth@vger.kernel.org
In-Reply-To: <1384985340-2902-1-git-send-email-andre.guedes@openbossa.org>
Ping.
On Wed, Nov 20, 2013 at 7:08 PM, Andre Guedes
<andre.guedes@openbossa.org> wrote:
> Hi all,
>
> 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.
>
> In order to test the LE auto connection mechanism please follow the
> instructions below.
>
> To add a new auto connection address we write on le_auto_conn file following
> the format <address> <address type> <auto_connect>.
>
> The <address type> values are:
> * 0 for public address
> * 1 for random address
>
> The <auto_connect> values are (for more details see struct hci_conn_params):
> * 0 for disabled
> * 1 for always
> * 2 for link loss
>
> So for instance, if you want the kernel autonomously establishes connections
> with device AA:BB:CC:DD:EE:FF (public address) every time the device enters in
> connectable mode (starts advertising), you should run the command:
> $ echo "AA:BB:CC:DD:EE:FF 0 1" > /sys/kernel/debug/bluetooth/hci0/le_auto_conn
>
> To get the list of connection parameters configured in kernel, read the
> le_auto_conn file:
> $ cat /sys/kernel/debug/bluetooth/hci0/le_auto_conn
>
> Finally, to clear the connection parameters list, write an empty string:
> $ echo "" > /sys/kernel/debug/bluetooth/hci0/le_auto_conn
>
> Regards,
>
> Andre Guedes
>
>
> Andre Guedes (12):
> Bluetooth: Save connection interval parameters in hci_conn
> Bluetooth: Group list_head fields from strcut hci_dev together
> Bluetooth: Introduce connection parameters list
> Bluetooth: Use connection parameters if any
> Bluetooth: Stop scanning on LE connection
> Bluetooth: Introduce hdev->pend_le_conn list
> Bluetooth: Introduce LE auto connection infrastructure
> Bluetooth: Re-enable background scan in case of error
> Bluetooth: Temporarily stop background scanning on discovery
> Bluetooth: Auto connection and power on
> Bleutooth: Add support for auto connect options
> Bluetooth: Add le_auto_conn file on debugfs
>
> include/net/bluetooth/hci_core.h | 43 +++++-
> net/bluetooth/hci_conn.c | 39 ++++-
> net/bluetooth/hci_core.c | 318 +++++++++++++++++++++++++++++++++++++++
> net/bluetooth/hci_event.c | 60 ++++++++
> net/bluetooth/mgmt.c | 25 ++-
> 5 files changed, 473 insertions(+), 12 deletions(-)
>
> --
> 1.8.4
>
^ permalink raw reply
* [PATCH 31/31] Bluetooth: Add debugfs controls for LE CoC MPS and Credits
From: Johan Hedberg @ 2013-12-04 14:11 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386166287-13693-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 ccfee0194a2b..abcd17220706 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 / 2)
+ if (chan->rx_credits >= le_max_credits / 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", 0444, bt_debugfs,
+ &le_max_credits);
+ debugfs_create_u16("l2cap_le_default_mps", 0444, bt_debugfs,
+ &le_default_mps);
+
return 0;
}
--
1.8.4.2
^ permalink raw reply related
* [PATCH 30/31] Bluetooth: Fix validating LE PSM values
From: Johan Hedberg @ 2013-12-04 14:11 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386166287-13693-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 a1143127414a..ccfee0194a2b 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 29/31] Bluetooth: Fix CID ranges for LE CoC CID allocations
From: Johan Hedberg @ 2013-12-04 14:11 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386166287-13693-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 8a74b36273b9..a1143127414a 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 28/31] Bluetooth: Fix clearing of chan->omtu for LE CoC channels
From: Johan Hedberg @ 2013-12-04 14:11 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386166287-13693-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 58fbb78a703f..8a74b36273b9 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 27/31] Bluetooth: Limit LE MPS to the MTU value
From: Johan Hedberg @ 2013-12-04 14:11 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386166287-13693-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 20b8dcf05edd..58fbb78a703f 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 26/31] Bluetooth: Fix suspending the L2CAP socket if we start with 0 credits
From: Johan Hedberg @ 2013-12-04 14:11 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386166287-13693-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 0e3a6eac289c..20b8dcf05edd 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 25/31] Bluetooth: Fix LE L2CAP Connect Request handling together with SMP
From: Johan Hedberg @ 2013-12-04 14:11 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386166287-13693-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 eb6edbcc3ce3..0e3a6eac289c 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 24/31] Bluetooth: Implement LE L2CAP reassembly
From: Johan Hedberg @ 2013-12-04 14:11 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386166287-13693-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 2c591afccb51..eb6edbcc3ce3 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 23/31] Bluetooth: Add LE L2CAP segmentation support for outgoing data
From: Johan Hedberg @ 2013-12-04 14:11 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386166287-13693-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 b0287f57d534..2c591afccb51 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 22/31] Bluetooth: Introduce L2CAP channel callback for suspending
From: Johan Hedberg @ 2013-12-04 14:11 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386166287-13693-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 21/31] Bluetooth: Reject LE CoC commands when the feature is not enabled
From: Johan Hedberg @ 2013-12-04 14:11 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386166287-13693-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 fd3804dc8ca6..b0287f57d534 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
* [PATCH 20/31] Bluetooth: Add LE flow control discipline
From: Johan Hedberg @ 2013-12-04 14:11 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386166287-13693-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@intel.com>
This patch adds the necessary discipline for reacting to LE L2CAP
Credits packets, sending those packets, and modifying the known credits
accordingly.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
net/bluetooth/l2cap_core.c | 68 +++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 64 insertions(+), 4 deletions(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index b99bdc53c57b..fd3804dc8ca6 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -2543,7 +2543,9 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
switch (chan->mode) {
case L2CAP_MODE_LE_FLOWCTL:
- chan->tx_credits--;
+ if (!chan->tx_credits)
+ return -EAGAIN;
+
/* fall through */
case L2CAP_MODE_BASIC:
/* Check outgoing MTU */
@@ -5551,6 +5553,42 @@ response:
return 0;
}
+static inline int l2cap_le_credits(struct l2cap_conn *conn,
+ struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+ u8 *data)
+{
+ struct l2cap_le_credits *pkt;
+ struct l2cap_chan *chan;
+ u16 cid, credits;
+
+ if (cmd_len != sizeof(*pkt))
+ return -EPROTO;
+
+ pkt = (struct l2cap_le_credits *) data;
+ cid = __le16_to_cpu(pkt->cid);
+ credits = __le16_to_cpu(pkt->credits);
+
+ BT_DBG("cid 0x%4.4x credits 0x%4.4x", cid, credits);
+
+ chan = l2cap_get_chan_by_dcid(conn, cid);
+ if (!chan)
+ return -EBADSLT;
+
+ chan->tx_credits += credits;
+
+ 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->resume(chan);
+
+ l2cap_chan_unlock(chan);
+
+ return 0;
+}
+
static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len,
u8 *data)
@@ -5576,6 +5614,10 @@ static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
err = l2cap_le_connect_req(conn, cmd, cmd_len, data);
break;
+ case L2CAP_LE_CREDITS:
+ err = l2cap_le_credits(conn, cmd, cmd_len, data);
+ break;
+
case L2CAP_DISCONN_REQ:
err = l2cap_disconnect_req(conn, cmd, cmd_len, data);
break;
@@ -6636,6 +6678,22 @@ static void l2cap_chan_le_send_credits(struct l2cap_chan *chan)
l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CREDITS, sizeof(pkt), &pkt);
}
+static int l2cap_le_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
+{
+ if (!chan->rx_credits)
+ return -ENOBUFS;
+
+ if (chan->imtu < skb->len)
+ 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);
+}
+
static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid,
struct sk_buff *skb)
{
@@ -6666,9 +6724,11 @@ static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid,
switch (chan->mode) {
case L2CAP_MODE_LE_FLOWCTL:
- chan->rx_credits--;
- l2cap_chan_le_send_credits(chan);
- /* fall through */
+ if (l2cap_le_data_rcv(chan, skb) < 0)
+ goto drop;
+
+ goto done;
+
case L2CAP_MODE_BASIC:
/* If socket recv buffers overflows we drop data here
* which is *bad* because L2CAP has to be reliable.
--
1.8.4.2
^ permalink raw reply related
* [PATCH 19/31] Bluetooth: Implement returning of LE L2CAP credits
From: Johan Hedberg @ 2013-12-04 14:11 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386166287-13693-1-git-send-email-johan.hedberg@gmail.com>
From: Johan Hedberg <johan.hedberg@intel.com>
We should return credits to the remote side whenever they fall below a
certain level (in our case under half of the initially given amount).
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
net/bluetooth/l2cap_core.c | 33 ++++++++++++++++++++++++++++++++-
1 file changed, 32 insertions(+), 1 deletion(-)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 8a1c528908fb..b99bdc53c57b 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -2542,8 +2542,10 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
}
switch (chan->mode) {
- case L2CAP_MODE_BASIC:
case L2CAP_MODE_LE_FLOWCTL:
+ chan->tx_credits--;
+ /* fall through */
+ case L2CAP_MODE_BASIC:
/* Check outgoing MTU */
if (len > chan->omtu)
return -EMSGSIZE;
@@ -6608,6 +6610,32 @@ drop:
return 0;
}
+static void l2cap_chan_le_send_credits(struct l2cap_chan *chan)
+{
+ struct l2cap_conn *conn = chan->conn;
+ struct l2cap_le_credits pkt;
+ u16 return_credits;
+
+ /* 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 / 2)
+ return;
+
+ return_credits = L2CAP_LE_MAX_CREDITS - chan->rx_credits;
+
+ BT_DBG("chan %p returning %u credits to sender", chan, return_credits);
+
+ chan->rx_credits += return_credits;
+
+ pkt.cid = cpu_to_le16(chan->scid);
+ pkt.credits = cpu_to_le16(return_credits);
+
+ chan->ident = l2cap_get_ident(conn);
+
+ l2cap_send_cmd(conn, chan->ident, L2CAP_LE_CREDITS, sizeof(pkt), &pkt);
+}
+
static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid,
struct sk_buff *skb)
{
@@ -6638,6 +6666,9 @@ static void l2cap_data_channel(struct l2cap_conn *conn, u16 cid,
switch (chan->mode) {
case L2CAP_MODE_LE_FLOWCTL:
+ chan->rx_credits--;
+ l2cap_chan_le_send_credits(chan);
+ /* fall through */
case L2CAP_MODE_BASIC:
/* If socket recv buffers overflows we drop data here
* which is *bad* because L2CAP has to be reliable.
--
1.8.4.2
^ 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