* [PATCH] android: Fix build error for Android
From: Lukasz Rymanowski @ 2013-10-23 8:26 UTC (permalink / raw)
To: linux-bluetooth
Cc: johan.hedberg, andrei.emeltchenko, szymon.janc, Lukasz Rymanowski
Android uses functions and defines from sys/capability.h which
requires additional include
---
android/main.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/android/main.c b/android/main.c
index 988d08b..606baf2 100644
--- a/android/main.c
+++ b/android/main.c
@@ -52,6 +52,10 @@
#include "hal-msg.h"
#include "ipc.h"
+#if defined(ANDROID)
+#include <sys/capability.h>
+#endif
+
static GMainLoop *event_loop;
static struct mgmt *mgmt_if = NULL;
--
1.8.4
^ permalink raw reply related
* [PATCH v2 BlueZ 4/4] android: Add variable ROOT_PATH to Android.mk
From: Luiz Augusto von Dentz @ 2013-10-23 8:08 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1382515699-30338-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This makes it simpler to include files from other parts of the code.
---
android/Android.mk | 33 +++++++++++++++++----------------
1 file changed, 17 insertions(+), 16 deletions(-)
diff --git a/android/Android.mk b/android/Android.mk
index 4c87a9b..20064fe 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -1,7 +1,8 @@
LOCAL_PATH := $(call my-dir)
+ROOT_PATH := $(LOCAL_PATH)/..
# Retrieve BlueZ version from configure.ac file
-BLUEZ_VERSION := $(shell grep ^AC_INIT $(LOCAL_PATH)/../configure.ac | cpp -P -D'AC_INIT(_,v)=v')
+BLUEZ_VERSION := $(shell grep ^AC_INIT $(ROOT_PATH)/configure.ac | cpp -P -D'AC_INIT(_,v)=v')
# Specify pathmap for glib
pathmap_INCL += glib:external/bluetooth/glib
@@ -18,25 +19,25 @@ LOCAL_SRC_FILES := \
adapter.c adapter.h \
hid.c hid.h \
ipc.c ipc.h \
- $(LOCAL_PATH)/../src/sdp.h \
- $(LOCAL_PATH)/../src/shared/mgmt.c \
- $(LOCAL_PATH)/../src/shared/util.c \
- $(LOCAL_PATH)/../src/sdpd-database.c \
- $(LOCAL_PATH)/../src/sdpd-service.c \
- $(LOCAL_PATH)/../src/sdpd-request.c \
- $(LOCAL_PATH)/../src/sdpd-server.c \
- $(LOCAL_PATH)/../lib/sdp.c \
- $(LOCAL_PATH)/../lib/bluetooth.c \
- $(LOCAL_PATH)/../lib/hci.c \
+ $(ROOT_PATH)/src/sdp.h \
+ $(ROOT_PATH)/src/shared/mgmt.c \
+ $(ROOT_PATH)/src/shared/util.c \
+ $(ROOT_PATH)/src/sdpd-database.c \
+ $(ROOT_PATH)/src/sdpd-service.c \
+ $(ROOT_PATH)/src/sdpd-request.c \
+ $(ROOT_PATH)/src/sdpd-server.c \
+ $(ROOT_PATH)/lib/sdp.c \
+ $(ROOT_PATH)/lib/bluetooth.c \
+ $(ROOT_PATH)/lib/hci.c \
LOCAL_C_INCLUDES := \
$(call include-path-for, glib) \
$(call include-path-for, glib)/glib \
LOCAL_C_INCLUDES += \
- $(LOCAL_PATH)/../ \
- $(LOCAL_PATH)/../src \
- $(LOCAL_PATH)/../lib \
+ $(ROOT_PATH)/ \
+ $(ROOT_PATH)/src \
+ $(ROOT_PATH)/lib \
LOCAL_CFLAGS := -DVERSION=\"$(BLUEZ_VERSION)\"
@@ -51,9 +52,9 @@ lib_headers := \
sdp_lib.h \
sdp.h \
-$(shell mkdir -p $(LOCAL_PATH)/../lib/bluetooth)
+$(shell mkdir -p $(ROOT_PATH)/lib/bluetooth)
-$(foreach file,$(lib_headers), $(shell ln -sf ../$(file) $(LOCAL_PATH)/../lib/bluetooth/$(file)))
+$(foreach file,$(lib_headers), $(shell ln -sf ../$(file) $(ROOT_PATH)/lib/bluetooth/$(file)))
LOCAL_MODULE := bluetoothd
--
1.8.3.1
^ permalink raw reply related
* [PATCH v2 BlueZ 3/4] android: Fix build dependency of haltest on target
From: Luiz Augusto von Dentz @ 2013-10-23 8:08 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1382515699-30338-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds missing headers necessary to build haltest.
---
android/Android.mk | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/android/Android.mk b/android/Android.mk
index 01ef3e7..4c87a9b 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -92,11 +92,12 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
client/haltest.c \
- client/pollhandler.c \
- client/terminal.c \
- client/history.c \
- client/textconv.c \
+ client/pollhandler.c client/pollhandler.h \
+ client/terminal.c client/terminal.h \
+ client/history.c client/history.h \
+ client/textconv.c client/textconv.h \
client/tabcompletion.c \
+ client/if-main.h \
client/if-bt.c \
client/if-hh.c \
--
1.8.3.1
^ permalink raw reply related
* [PATCH v2 BlueZ 2/4] android: Fix build dependency of bluetooth.default.so HAL on target
From: Luiz Augusto von Dentz @ 2013-10-23 8:08 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1382515699-30338-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds missing headers necessary to build bluetooth.default.so
---
android/Android.mk | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/android/Android.mk b/android/Android.mk
index d276102..01ef3e7 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -66,7 +66,8 @@ include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- hal-ipc.c \
+ hal.h hal-msg.h hal-log.h \
+ hal-ipc.c hal-ipc.h \
hal-bluetooth.c \
hal-sock.c \
hal-hidhost.c \
--
1.8.3.1
^ permalink raw reply related
* [PATCH v2 BlueZ 1/4] android: Fix build dependency of bluetoothd on target
From: Luiz Augusto von Dentz @ 2013-10-23 8:08 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds missing headers necessary to build bluetoothd.
---
android/Android.mk | 23 ++++++++++++-----------
1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/android/Android.mk b/android/Android.mk
index 7132279..d276102 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -15,18 +15,19 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
main.c \
log.c \
- adapter.c \
- hid.c \
+ adapter.c adapter.h \
+ hid.c hid.h \
ipc.c ipc.h \
- ../src/shared/mgmt.c \
- ../src/shared/util.c \
- ../src/sdpd-database.c \
- ../src/sdpd-service.c \
- ../src/sdpd-request.c \
- ../src/sdpd-server.c \
- ../lib/sdp.c \
- ../lib/bluetooth.c \
- ../lib/hci.c \
+ $(LOCAL_PATH)/../src/sdp.h \
+ $(LOCAL_PATH)/../src/shared/mgmt.c \
+ $(LOCAL_PATH)/../src/shared/util.c \
+ $(LOCAL_PATH)/../src/sdpd-database.c \
+ $(LOCAL_PATH)/../src/sdpd-service.c \
+ $(LOCAL_PATH)/../src/sdpd-request.c \
+ $(LOCAL_PATH)/../src/sdpd-server.c \
+ $(LOCAL_PATH)/../lib/sdp.c \
+ $(LOCAL_PATH)/../lib/bluetooth.c \
+ $(LOCAL_PATH)/../lib/hci.c \
LOCAL_C_INCLUDES := \
$(call include-path-for, glib) \
--
1.8.3.1
^ permalink raw reply related
* Re: [PATCHv2] android: Create header links for lib
From: Johan Hedberg @ 2013-10-23 8:00 UTC (permalink / raw)
To: Andrei Emeltchenko; +Cc: linux-bluetooth
In-Reply-To: <1382514501-20335-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
Hi Andrei,
On Wed, Oct 23, 2013, Andrei Emeltchenko wrote:
> BlueZ headers are referring as bluetooth/* for headers which are
> located in lib/*. Create symlinks for now until we find better solution.
> ---
> android/Android.mk | 12 ++++++++++++
> 1 file changed, 12 insertions(+)
Applied. Thanks.
Johan
^ permalink raw reply
* Re: [PATCH_v2 0/7] Initial code for hal hid host
From: Johan Hedberg @ 2013-10-23 7:59 UTC (permalink / raw)
To: Ravi kumar Veeramally; +Cc: linux-bluetooth
In-Reply-To: <1382514120-13152-1-git-send-email-ravikumar.veeramally@linux.intel.com>
Hi Ravi,
On Wed, Oct 23, 2013, Ravi kumar Veeramally wrote:
> Patch set is all about initial code for hal hidhost interfaces which
> are .virtual_unplug, .set_info, .get_protocol, .set_protocol,
> .get_report, .set_report and .send_data. Also includes issue fixes
> for .connect and .disconnect interfaces.
> ---
> _v2 is about fixing issues as per Johan comments.
>
> Ravi kumar Veeramally (7):
> android: Return right from hal_ipc_cmd call in hal hid connect
> android: Return right from hal_ipc_cmd call in hal hid disconnect
> android: Add initial code for hidhost virtual unplug
> android: Add initial code for hidhost get and set protocol
> android: Add initial code for hidhost get and set report
> android: Add initial code for hidhost send data
> android: Add initial code for hidhost set hid information
>
> android/hal-hidhost.c | 126 ++++++++++++++++++++++++++++++++++++++++---------
> 1 file changed, 105 insertions(+), 21 deletions(-)
All patches have been applied (after some minor coding style fixes).
Thanks.
Johan
^ permalink raw reply
* [PATCH BlueZ 4/4] android: Add variable ROOT_PATH to Android.mk
From: Luiz Augusto von Dentz @ 2013-10-23 7:58 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1382515098-28782-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This makes it simpler to include files from other parts of the code.
---
android/Android.mk | 29 +++++++++++++++--------------
1 file changed, 15 insertions(+), 14 deletions(-)
diff --git a/android/Android.mk b/android/Android.mk
index 9becddc..baa0a49 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -1,7 +1,8 @@
LOCAL_PATH := $(call my-dir)
+ROOT_PATH := $(LOCAL_PATH)/..
# Retrieve BlueZ version from configure.ac file
-BLUEZ_VERSION := $(shell grep ^AC_INIT $(LOCAL_PATH)/../configure.ac | cpp -P -D'AC_INIT(_,v)=v')
+BLUEZ_VERSION := $(shell grep ^AC_INIT $(ROOT_PATH)/configure.ac | cpp -P -D'AC_INIT(_,v)=v')
# Specify pathmap for glib
pathmap_INCL += glib:external/bluetooth/glib
@@ -18,25 +19,25 @@ LOCAL_SRC_FILES := \
adapter.c adapter.h \
hid.c hid.h \
ipc.c ipc.h \
- $(LOCAL_PATH)/../src/sdp.h \
- $(LOCAL_PATH)/../src/shared/mgmt.c \
- $(LOCAL_PATH)/../src/shared/util.c \
- $(LOCAL_PATH)/../src/sdpd-database.c \
- $(LOCAL_PATH)/../src/sdpd-service.c \
- $(LOCAL_PATH)/../src/sdpd-request.c \
- $(LOCAL_PATH)/../src/sdpd-server.c \
- $(LOCAL_PATH)/../lib/sdp.c \
- $(LOCAL_PATH)/../lib/bluetooth.c \
- $(LOCAL_PATH)/../lib/hci.c \
+ $(ROOT_PATH)/src/sdp.h \
+ $(ROOT_PATH)/src/shared/mgmt.c \
+ $(ROOT_PATH)/src/shared/util.c \
+ $(ROOT_PATH)/src/sdpd-database.c \
+ $(ROOT_PATH)/src/sdpd-service.c \
+ $(ROOT_PATH)/src/sdpd-request.c \
+ $(ROOT_PATH)/src/sdpd-server.c \
+ $(ROOT_PATH)/lib/sdp.c \
+ $(ROOT_PATH)/lib/bluetooth.c \
+ $(ROOT_PATH)/lib/hci.c \
LOCAL_C_INCLUDES := \
$(call include-path-for, glib) \
$(call include-path-for, glib)/glib \
LOCAL_C_INCLUDES += \
- $(LOCAL_PATH)/../ \
- $(LOCAL_PATH)/../src \
- $(LOCAL_PATH)/../lib \
+ $(ROOT_PATH)/ \
+ $(ROOT_PATH)/src \
+ $(ROOT_PATH)/lib \
LOCAL_CFLAGS := -DVERSION=\"$(BLUEZ_VERSION)\"
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ 3/4] android: Fix build dependency of haltest on target
From: Luiz Augusto von Dentz @ 2013-10-23 7:58 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1382515098-28782-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds missing headers necessary to build haltest.
---
android/Android.mk | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/android/Android.mk b/android/Android.mk
index cdc99a8..9becddc 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -80,11 +80,12 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
client/haltest.c \
- client/pollhandler.c \
- client/terminal.c \
- client/history.c \
- client/textconv.c \
+ client/pollhandler.c client/pollhandler.h \
+ client/terminal.c client/terminal.h \
+ client/history.c client/history.h \
+ client/textconv.c client/textconv.h \
client/tabcompletion.c \
+ client/if-main.h \
client/if-bt.c \
client/if-hh.c \
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ 2/4] android: Fix build dependency of bluetooth.default.so HAL on target
From: Luiz Augusto von Dentz @ 2013-10-23 7:58 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1382515098-28782-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds missing headers necessary to build bluetooth.default.so
---
android/Android.mk | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/android/Android.mk b/android/Android.mk
index a00b658..cdc99a8 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -54,7 +54,8 @@ include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- hal-ipc.c \
+ hal.h hal-msg.h hal-log.h \
+ hal-ipc.c hal-ipc.h \
hal-bluetooth.c \
hal-sock.c \
hal-hidhost.c \
--
1.8.3.1
^ permalink raw reply related
* [PATCH BlueZ 1/4] android: Fix build dependency of bluetoothd on target
From: Luiz Augusto von Dentz @ 2013-10-23 7:58 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This adds missing headers necessary to build bluetoothd.
---
android/Android.mk | 23 ++++++++++++-----------
1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/android/Android.mk b/android/Android.mk
index eef809a..a00b658 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -15,18 +15,19 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
main.c \
log.c \
- adapter.c \
- hid.c \
+ adapter.c adapter.h \
+ hid.c hid.h \
ipc.c ipc.h \
- ../src/shared/mgmt.c \
- ../src/shared/util.c \
- ../src/sdpd-database.c \
- ../src/sdpd-service.c \
- ../src/sdpd-request.c \
- ../src/sdpd-server.c \
- ../lib/sdp.c \
- ../lib/bluetooth.c \
- ../lib/hci.c \
+ $(LOCAL_PATH)/../src/sdp.h \
+ $(LOCAL_PATH)/../src/shared/mgmt.c \
+ $(LOCAL_PATH)/../src/shared/util.c \
+ $(LOCAL_PATH)/../src/sdpd-database.c \
+ $(LOCAL_PATH)/../src/sdpd-service.c \
+ $(LOCAL_PATH)/../src/sdpd-request.c \
+ $(LOCAL_PATH)/../src/sdpd-server.c \
+ $(LOCAL_PATH)/../lib/sdp.c \
+ $(LOCAL_PATH)/../lib/bluetooth.c \
+ $(LOCAL_PATH)/../lib/hci.c \
LOCAL_C_INCLUDES := \
$(call include-path-for, glib) \
--
1.8.3.1
^ permalink raw reply related
* Re: [PATCH] android: Fix compilation error for Android 4.2.2
From: Johan Hedberg @ 2013-10-23 7:51 UTC (permalink / raw)
To: Andrei Emeltchenko; +Cc: linux-bluetooth
In-Reply-To: <1382438228-23422-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
Hi Andrei,
On Tue, Oct 22, 2013, Andrei Emeltchenko wrote:
> On our current target the tools cannot be compiled.
> ---
> android/Android.mk | 2 ++
> android/client/if-bt.c | 6 ++++++
> android/client/if-main.h | 3 +++
> android/client/textconv.c | 2 ++
> 4 files changed, 13 insertions(+)
Applied. Thanks.
Johan
^ permalink raw reply
* [PATCHv2] android: Create header links for lib
From: Andrei Emeltchenko @ 2013-10-23 7:48 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
BlueZ headers are referring as bluetooth/* for headers which are
located in lib/*. Create symlinks for now until we find better solution.
---
android/Android.mk | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/android/Android.mk b/android/Android.mk
index c4b0621..3163763 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -41,6 +41,18 @@ LOCAL_CFLAGS := -DVERSION=\"$(BLUEZ_VERSION)\"
LOCAL_SHARED_LIBRARIES := \
libglib \
+lib_headers := \
+ bluetooth.h \
+ hci.h \
+ hci_lib.h \
+ l2cap.h \
+ sdp_lib.h \
+ sdp.h \
+
+$(shell mkdir -p $(LOCAL_PATH)/../lib/bluetooth)
+
+$(foreach file,$(lib_headers), $(shell ln -sf ../$(file) $(LOCAL_PATH)/../lib/bluetooth/$(file)))
+
LOCAL_MODULE := bluetoothd
include $(BUILD_EXECUTABLE)
--
1.7.10.4
^ permalink raw reply related
* [PATCH_v2 7/7] android: Add initial code for hidhost set hid information
From: Ravi kumar Veeramally @ 2013-10-23 7:41 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1382514120-13152-1-git-send-email-ravikumar.veeramally@linux.intel.com>
This adds the initial code for hidhost .set_info interface
---
android/hal-hidhost.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/android/hal-hidhost.c b/android/hal-hidhost.c
index 02a3f7d..4842a01 100644
--- a/android/hal-hidhost.c
+++ b/android/hal-hidhost.c
@@ -87,6 +87,8 @@ static bt_status_t hh_virtual_unplug(bt_bdaddr_t *bd_addr)
static bt_status_t hh_set_info(bt_bdaddr_t *bd_addr, bthh_hid_info_t hid_info)
{
+ struct hal_msg_cmd_bt_hid_set_info cmd;
+
DBG("");
if (!interface_ready())
@@ -95,7 +97,18 @@ static bt_status_t hh_set_info(bt_bdaddr_t *bd_addr, bthh_hid_info_t hid_info)
if (!bd_addr)
return BT_STATUS_PARM_INVALID;
- return BT_STATUS_UNSUPPORTED;
+ memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+ cmd.attr = hid_info.attr_mask;
+ cmd.subclass = hid_info.sub_class;
+ cmd.app_id = hid_info.app_id;
+ cmd.vendor = hid_info.vendor_id;
+ cmd.product = hid_info.product_id;
+ cmd.country = hid_info.ctry_code;
+ cmd.descr_len = hid_info.dl_len;
+ memcpy(cmd.descr, hid_info.dsc_list, cmd.descr_len);
+
+ return hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST, HAL_MSG_OP_BT_HID_SET_INFO,
+ sizeof(cmd), &cmd, 0, NULL, NULL);
}
static bt_status_t hh_get_protocol(bt_bdaddr_t *bd_addr,
--
1.7.9.5
^ permalink raw reply related
* [PATCH_v2 6/7] android: Add initial code for hidhost send data
From: Ravi kumar Veeramally @ 2013-10-23 7:41 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1382514120-13152-1-git-send-email-ravikumar.veeramally@linux.intel.com>
This adds the initial code for hidhost .send_data interface
---
android/hal-hidhost.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/android/hal-hidhost.c b/android/hal-hidhost.c
index 22045f1..02a3f7d 100644
--- a/android/hal-hidhost.c
+++ b/android/hal-hidhost.c
@@ -230,6 +230,8 @@ static bt_status_t hh_set_report(bt_bdaddr_t *bd_addr,
static bt_status_t hh_send_data(bt_bdaddr_t *bd_addr, char *data)
{
+ struct hal_msg_cmd_bt_hid_send_data cmd;
+
DBG("");
if (!interface_ready())
@@ -238,7 +240,10 @@ static bt_status_t hh_send_data(bt_bdaddr_t *bd_addr, char *data)
if (!bd_addr || !data)
return BT_STATUS_PARM_INVALID;
- return BT_STATUS_UNSUPPORTED;
+ memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+
+ return hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST, HAL_MSG_OP_BT_HID_SEND_DATA,
+ sizeof(cmd), &cmd, 0, NULL, NULL);
}
static bt_status_t hh_init(bthh_callbacks_t *callbacks)
--
1.7.9.5
^ permalink raw reply related
* [PATCH_v2 5/7] android: Add initial code for hidhost get and set report
From: Ravi kumar Veeramally @ 2013-10-23 7:41 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1382514120-13152-1-git-send-email-ravikumar.veeramally@linux.intel.com>
This adds the initial code for hidhost .get_report and .set_report
interfaces
---
android/hal-hidhost.c | 39 +++++++++++++++++++++++++++++++++++++--
1 file changed, 37 insertions(+), 2 deletions(-)
diff --git a/android/hal-hidhost.c b/android/hal-hidhost.c
index f289f7f..22045f1 100644
--- a/android/hal-hidhost.c
+++ b/android/hal-hidhost.c
@@ -167,6 +167,8 @@ static bt_status_t hh_get_report(bt_bdaddr_t *bd_addr,
uint8_t reportId,
int bufferSize)
{
+ struct hal_msg_cmd_bt_hid_get_report cmd;
+
DBG("");
if (!interface_ready())
@@ -175,13 +177,31 @@ static bt_status_t hh_get_report(bt_bdaddr_t *bd_addr,
if (!bd_addr)
return BT_STATUS_PARM_INVALID;
- return BT_STATUS_UNSUPPORTED;
+ memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+ cmd.id = reportId;
+
+ switch (reportType) {
+ case BTHH_INPUT_REPORT:
+ cmd.type = HAL_MSG_BT_HID_INPUT_REPORT;
+ break;
+ case BTHH_OUTPUT_REPORT:
+ cmd.type = HAL_MSG_BT_HID_OUTPUT_REPORT;
+ break;
+ case BTHH_FEATURE_REPORT:
+ cmd.type = HAL_MSG_BT_HID_FEATURE_REPORT;
+ break;
+ }
+
+ return hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST, HAL_MSG_OP_BT_HID_GET_REPORT,
+ sizeof(cmd), &cmd, 0, NULL, NULL);
}
static bt_status_t hh_set_report(bt_bdaddr_t *bd_addr,
bthh_report_type_t reportType,
char *report)
{
+ struct hal_msg_cmd_bt_hid_set_report cmd;
+
DBG("");
if (!interface_ready())
@@ -190,7 +210,22 @@ static bt_status_t hh_set_report(bt_bdaddr_t *bd_addr,
if (!bd_addr || !report)
return BT_STATUS_PARM_INVALID;
- return BT_STATUS_UNSUPPORTED;
+ memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+
+ switch (reportType) {
+ case BTHH_INPUT_REPORT:
+ cmd.type = HAL_MSG_BT_HID_INPUT_REPORT;
+ break;
+ case BTHH_OUTPUT_REPORT:
+ cmd.type = HAL_MSG_BT_HID_OUTPUT_REPORT;
+ break;
+ case BTHH_FEATURE_REPORT:
+ cmd.type = HAL_MSG_BT_HID_FEATURE_REPORT;
+ break;
+ }
+
+ return hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST, HAL_MSG_OP_BT_HID_SET_REPORT,
+ sizeof(cmd), &cmd, 0, NULL, NULL);
}
static bt_status_t hh_send_data(bt_bdaddr_t *bd_addr, char *data)
--
1.7.9.5
^ permalink raw reply related
* [PATCH_v2 4/7] android: Add initial code for hidhost get and set protocol
From: Ravi kumar Veeramally @ 2013-10-23 7:41 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1382514120-13152-1-git-send-email-ravikumar.veeramally@linux.intel.com>
This adds the initial code for hidhost .get_protocol and .set_protocol
interfaces
---
android/hal-hidhost.c | 40 ++++++++++++++++++++++++++++++++++++++--
1 file changed, 38 insertions(+), 2 deletions(-)
diff --git a/android/hal-hidhost.c b/android/hal-hidhost.c
index c6ac42f..f289f7f 100644
--- a/android/hal-hidhost.c
+++ b/android/hal-hidhost.c
@@ -101,6 +101,8 @@ static bt_status_t hh_set_info(bt_bdaddr_t *bd_addr, bthh_hid_info_t hid_info)
static bt_status_t hh_get_protocol(bt_bdaddr_t *bd_addr,
bthh_protocol_mode_t protocolMode)
{
+ struct hal_msg_cmd_bt_hid_get_protocol cmd;
+
DBG("");
if (!interface_ready())
@@ -109,12 +111,30 @@ static bt_status_t hh_get_protocol(bt_bdaddr_t *bd_addr,
if (!bd_addr)
return BT_STATUS_PARM_INVALID;
- return BT_STATUS_UNSUPPORTED;
+ memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+
+ switch (protocolMode) {
+ case BTHH_REPORT_MODE:
+ cmd.mode = HAL_MSG_BT_HID_REPORT_PROTOCOL;
+ break;
+ case BTHH_BOOT_MODE:
+ cmd.mode = HAL_MSG_BT_HID_BOOT_PROTOCOL;
+ break;
+ case BTHH_UNSUPPORTED_MODE:
+ cmd.mode = HAL_MSG_BT_HID_UNSUPPORTED_PROTOCOL;
+ break;
+ }
+
+ return hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST,
+ HAL_MSG_OP_BT_HID_GET_PROTOCOL,
+ sizeof(cmd), &cmd, 0, NULL, NULL);
}
static bt_status_t hh_set_protocol(bt_bdaddr_t *bd_addr,
bthh_protocol_mode_t protocolMode)
{
+ struct hal_msg_cmd_bt_hid_set_protocol cmd;
+
DBG("");
if (!interface_ready())
@@ -123,7 +143,23 @@ static bt_status_t hh_set_protocol(bt_bdaddr_t *bd_addr,
if (!bd_addr)
return BT_STATUS_PARM_INVALID;
- return BT_STATUS_UNSUPPORTED;
+ memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+
+ switch (protocolMode) {
+ case BTHH_REPORT_MODE:
+ cmd.mode = HAL_MSG_BT_HID_REPORT_PROTOCOL;
+ break;
+ case BTHH_BOOT_MODE:
+ cmd.mode = HAL_MSG_BT_HID_BOOT_PROTOCOL;
+ break;
+ case BTHH_UNSUPPORTED_MODE:
+ cmd.mode = HAL_MSG_BT_HID_UNSUPPORTED_PROTOCOL;
+ break;
+ }
+
+ return hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST,
+ HAL_MSG_OP_BT_HID_SET_PROTOCOL,
+ sizeof(cmd), &cmd, 0, NULL, NULL);
}
static bt_status_t hh_get_report(bt_bdaddr_t *bd_addr,
--
1.7.9.5
^ permalink raw reply related
* [PATCH_v2 3/7] android: Add initial code for hidhost virtual unplug
From: Ravi kumar Veeramally @ 2013-10-23 7:41 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1382514120-13152-1-git-send-email-ravikumar.veeramally@linux.intel.com>
This adds initial code for hidhost .virtual_unplug interface
---
android/hal-hidhost.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/android/hal-hidhost.c b/android/hal-hidhost.c
index 1f54bc4..c6ac42f 100644
--- a/android/hal-hidhost.c
+++ b/android/hal-hidhost.c
@@ -69,6 +69,8 @@ static bt_status_t hh_disconnect(bt_bdaddr_t *bd_addr)
static bt_status_t hh_virtual_unplug(bt_bdaddr_t *bd_addr)
{
+ struct hal_msg_cmd_bt_hid_vp cmd;
+
DBG("");
if (!interface_ready())
@@ -77,7 +79,10 @@ static bt_status_t hh_virtual_unplug(bt_bdaddr_t *bd_addr)
if (!bd_addr)
return BT_STATUS_PARM_INVALID;
- return BT_STATUS_UNSUPPORTED;
+ memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
+
+ return hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST, HAL_MSG_OP_BT_HID_VP,
+ sizeof(cmd), &cmd, 0, NULL, NULL);
}
static bt_status_t hh_set_info(bt_bdaddr_t *bd_addr, bthh_hid_info_t hid_info)
--
1.7.9.5
^ permalink raw reply related
* [PATCH_v2 2/7] android: Return right from hal_ipc_cmd call in hal hid disconnect
From: Ravi kumar Veeramally @ 2013-10-23 7:41 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1382514120-13152-1-git-send-email-ravikumar.veeramally@linux.intel.com>
Do not print any error message and return from hal_ipc_cmd call in hal
hid disconnect
---
android/hal-hidhost.c | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/android/hal-hidhost.c b/android/hal-hidhost.c
index f7d8cbf..1f54bc4 100644
--- a/android/hal-hidhost.c
+++ b/android/hal-hidhost.c
@@ -63,13 +63,8 @@ static bt_status_t hh_disconnect(bt_bdaddr_t *bd_addr)
memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
- if (hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST, HAL_MSG_OP_BT_HID_DISCONNECT,
- sizeof(cmd), &cmd, 0, NULL, NULL) < 0) {
- error("Failed to disconnect hid device");
- return BT_STATUS_FAIL;
- }
-
- return BT_STATUS_SUCCESS;
+ return hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST, HAL_MSG_OP_BT_HID_DISCONNECT,
+ sizeof(cmd), &cmd, 0, NULL, NULL);
}
static bt_status_t hh_virtual_unplug(bt_bdaddr_t *bd_addr)
--
1.7.9.5
^ permalink raw reply related
* [PATCH_v2 1/7] android: Return right from hal_ipc_cmd call in hal hid connect
From: Ravi kumar Veeramally @ 2013-10-23 7:41 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
In-Reply-To: <1382514120-13152-1-git-send-email-ravikumar.veeramally@linux.intel.com>
Do not print any error message and return from hal_ipc_cmd call in hal
hid connect
---
android/hal-hidhost.c | 9 ++-------
1 file changed, 2 insertions(+), 7 deletions(-)
diff --git a/android/hal-hidhost.c b/android/hal-hidhost.c
index f941f2f..f7d8cbf 100644
--- a/android/hal-hidhost.c
+++ b/android/hal-hidhost.c
@@ -45,13 +45,8 @@ static bt_status_t hh_connect(bt_bdaddr_t *bd_addr)
memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
- if (hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST, HAL_MSG_OP_BT_HID_CONNECT,
- sizeof(cmd), &cmd, 0, NULL, NULL) < 0) {
- error("Failed to connect hid device");
- return BT_STATUS_FAIL;
- }
-
- return BT_STATUS_SUCCESS;
+ return hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST, HAL_MSG_OP_BT_HID_CONNECT,
+ sizeof(cmd), &cmd, 0, NULL, NULL);
}
static bt_status_t hh_disconnect(bt_bdaddr_t *bd_addr)
--
1.7.9.5
^ permalink raw reply related
* [PATCH_v2 0/7] Initial code for hal hid host
From: Ravi kumar Veeramally @ 2013-10-23 7:41 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Ravi kumar Veeramally
Patch set is all about initial code for hal hidhost interfaces which
are .virtual_unplug, .set_info, .get_protocol, .set_protocol,
.get_report, .set_report and .send_data. Also includes issue fixes
for .connect and .disconnect interfaces.
---
_v2 is about fixing issues as per Johan comments.
Ravi kumar Veeramally (7):
android: Return right from hal_ipc_cmd call in hal hid connect
android: Return right from hal_ipc_cmd call in hal hid disconnect
android: Add initial code for hidhost virtual unplug
android: Add initial code for hidhost get and set protocol
android: Add initial code for hidhost get and set report
android: Add initial code for hidhost send data
android: Add initial code for hidhost set hid information
android/hal-hidhost.c | 126 ++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 105 insertions(+), 21 deletions(-)
--
1.7.9.5
^ permalink raw reply
* [RFC 5/5] Bluetooth: Manually enable or disable 6LoWPAN between devices
From: Jukka Rissanen @ 2013-10-23 6:52 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1382511164-1989-1-git-send-email-jukka.rissanen@linux.intel.com>
This is a temporary patch where user can manually enable or
disable BT LE 6LoWPAN functionality between devices.
Eventually the connection is established automatically if
the devices are advertising suitable capability and this patch
can be removed.
If you have two devices with these BT addresses
device1 00:11:22:33:44:55
device2 66:77:88:99:00:11
First add the desired devices manually into kernel
root@dev1# echo 66:77:88:99:00:11 > /sys/kernel/debug/bluetooth/hci0/ble6lowpan
root@dev2# echo 00:11:22:33:44:55 > /sys/kernel/debug/bluetooth/hci0/ble6lowpan
then connect the devices
root@dev1# hciconfig hci0 leadv
root@dev2# hcitool lecc 00:11:22:33:44:55
if the connection is established, then you can send IPv6 packets
between these two systems using the link local addresses
root@dev1# ping6 fe80::6477:88ff:fe99:0011
root@dev2# ping6 fe80::211:22ff:fe33:4455
By default 6LoWPAN connection is not established between devices,
so you need to add the MAC addresses manually into the
/sys/kernel/debug/bluetooth/hci0/ble6lowpan file.
If you want to prevent further connections you can remove
MAC address from the debugfs file like this
echo "00:11:22:33:44:55 d" > /sys/kernel/debug/bluetooth/hci0/ble6lowpan
Rebooting or unloading the bluetooth kernel module will also clear the
settings from the kernel.
---
net/bluetooth/ble_6lowpan.c | 164 ++++++++++++++++++++++++++++++++++++++++++++
net/bluetooth/ble_6lowpan.h | 1 +
net/bluetooth/hci_core.c | 4 ++
net/bluetooth/l2cap_core.c | 12 ++--
4 files changed, 174 insertions(+), 7 deletions(-)
diff --git a/net/bluetooth/ble_6lowpan.c b/net/bluetooth/ble_6lowpan.c
index 44d65b3..0baf211 100644
--- a/net/bluetooth/ble_6lowpan.c
+++ b/net/bluetooth/ble_6lowpan.c
@@ -12,6 +12,7 @@
*/
#include <linux/version.h>
+#include <linux/debugfs.h>
#include <linux/bitops.h>
#include <linux/if_arp.h>
#include <linux/netdevice.h>
@@ -1535,6 +1536,169 @@ static struct notifier_block ble_6lowpan_dev_notifier = {
.notifier_call = ble_6lowpan_device_event,
};
+static LIST_HEAD(user_enabled);
+DEFINE_RWLOCK(user_enabled_list_lock);
+
+struct ble_6lowpan_enabled {
+ __u8 dev_name[HCI_MAX_NAME_LENGTH];
+ bdaddr_t addr;
+ struct list_head list;
+};
+
+bool ble_6lowpan_is_enabled(struct hci_dev *hdev, bdaddr_t *dst)
+{
+ struct ble_6lowpan_enabled *entry, *tmp;
+ bool found = false;
+
+ write_lock(&user_enabled_list_lock);
+ list_for_each_entry_safe(entry, tmp, &user_enabled, list) {
+ if (!strncmp(entry->dev_name, hdev->dev_name,
+ HCI_MAX_NAME_LENGTH) &&
+ !bacmp(dst, &entry->addr)) {
+ found = true;
+ break;
+ }
+ }
+ write_unlock(&user_enabled_list_lock);
+
+ /* Check also the device list just in case we removed the
+ * device from debugfs before disconnecting.
+ */
+ if (!found) {
+ struct ble_6lowpan_dev_record *entry, *tmp;
+ struct ble_6lowpan_dev_info *info;
+
+ write_lock(&net_dev_list_lock);
+ list_for_each_entry_safe(entry, tmp,
+ &ble_6lowpan_devices,
+ list) {
+ info = ble_6lowpan_dev_info(entry->dev);
+ if (info->conn->hcon->hdev == hdev &&
+ !bacmp(&info->addr, dst)) {
+ found = true;
+ break;
+ }
+ }
+ write_unlock(&net_dev_list_lock);
+ }
+
+ return found;
+}
+
+static int ble_6lowpan_debugfs_show(struct seq_file *f, void *p)
+{
+ struct ble_6lowpan_enabled *entry, *tmp;
+
+ write_lock(&user_enabled_list_lock);
+ list_for_each_entry_safe(entry, tmp, &user_enabled, list)
+ seq_printf(f, "%pMR\n", &entry->addr);
+
+ write_unlock(&user_enabled_list_lock);
+
+ return 0;
+}
+
+static int ble_6lowpan_debugfs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ble_6lowpan_debugfs_show, inode->i_private);
+}
+
+static ssize_t ble_6lowpan_writer(struct file *fp,
+ const char __user *user_buffer,
+ size_t count, loff_t *position)
+{
+#define MAC_STR_LEN 17
+ char mac_buf[MAC_STR_LEN + 1];
+ ssize_t ret;
+ bool delete_mode = false;
+
+ if(count > (MAC_STR_LEN + 1))
+ delete_mode = true;
+ else if (count < MAC_STR_LEN)
+ return count;
+
+ BT_DBG("count %zd mode %d", count, delete_mode);
+
+ memset(mac_buf, 0, MAC_STR_LEN + 1);
+ ret = simple_write_to_buffer(mac_buf, MAC_STR_LEN, position,
+ user_buffer, count);
+ if (ret > 0) {
+ struct ble_6lowpan_enabled *entry = NULL, *tmp;
+ bdaddr_t bdaddr;
+
+ if (sscanf(mac_buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
+ &bdaddr.b[5], &bdaddr.b[4],
+ &bdaddr.b[3], &bdaddr.b[2],
+ &bdaddr.b[1], &bdaddr.b[0]) != 6)
+ return -EINVAL;
+
+ BT_DBG("user %pMR", &bdaddr);
+
+ write_lock(&user_enabled_list_lock);
+ list_for_each_entry_safe(entry, tmp, &user_enabled, list) {
+ if (!bacmp(&entry->addr, &bdaddr)) {
+ struct hci_dev *hdev = fp->f_inode->i_private;
+
+ if (!strncmp(entry->dev_name, hdev->dev_name,
+ HCI_MAX_NAME_LENGTH) &&
+ delete_mode) {
+ break;
+ } else {
+ ret = -EEXIST;
+ break;
+ }
+ }
+ }
+ write_unlock(&user_enabled_list_lock);
+
+ if (ret > 0) {
+ struct hci_dev *hdev = fp->f_inode->i_private;
+
+ if (delete_mode) {
+ write_lock(&user_enabled_list_lock);
+ list_del(&entry->list);
+ kfree(entry);
+ write_unlock(&user_enabled_list_lock);
+ } else {
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
+ strncpy(entry->dev_name, hdev->dev_name,
+ HCI_MAX_NAME_LENGTH);
+ entry->addr = bdaddr;
+
+ write_lock(&user_enabled_list_lock);
+ INIT_LIST_HEAD(&entry->list);
+ list_add(&entry->list, &user_enabled);
+ write_unlock(&user_enabled_list_lock);
+ }
+ }
+ }
+
+ return ret;
+}
+
+static const struct file_operations ble_6lowpan_debugfs_fops = {
+ .open = ble_6lowpan_debugfs_open,
+ .read = seq_read,
+ .write = ble_6lowpan_writer,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static struct dentry *ble_6lowpan_debugfs;
+
+void ble_6lowpan_add_debugfs(struct hci_dev *hdev)
+{
+ if (hdev->debugfs) {
+ ble_6lowpan_debugfs = debugfs_create_file("ble6lowpan", 0644,
+ hdev->debugfs, hdev, &ble_6lowpan_debugfs_fops);
+ if (!ble_6lowpan_debugfs)
+ BT_ERR("Failed to create 6LoWPAN debug file");
+ }
+}
+
int ble_6lowpan_init(void)
{
int err;
diff --git a/net/bluetooth/ble_6lowpan.h b/net/bluetooth/ble_6lowpan.h
index 7975a55..047b8b7 100644
--- a/net/bluetooth/ble_6lowpan.h
+++ b/net/bluetooth/ble_6lowpan.h
@@ -23,5 +23,6 @@ int ble_6lowpan_del_conn(struct l2cap_conn *conn);
int ble_6lowpan_init(void);
void ble_6lowpan_cleanup(void);
bool ble_6lowpan_is_enabled(struct hci_dev *hdev, bdaddr_t *dst);
+void ble_6lowpan_add_debugfs(struct hci_dev *hdev);
#endif /* __BLE_LOWPAN_H */
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 6ccc4eb..d0db818 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -34,6 +34,8 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
+#include "ble_6lowpan.h"
+
static void hci_rx_work(struct work_struct *work);
static void hci_cmd_work(struct work_struct *work);
static void hci_tx_work(struct work_struct *work);
@@ -1406,6 +1408,8 @@ static int __hci_init(struct hci_dev *hdev)
hdev, &conn_max_interval_fops);
}
+ ble_6lowpan_add_debugfs(hdev);
+
return 0;
}
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index fb1a49c..e3b30dd 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -6542,11 +6542,6 @@ int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
return exact ? lm1 : lm2;
}
-static bool is_ble_6lowpan(void)
-{
- return false;
-}
-
void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
{
struct l2cap_conn *conn;
@@ -6558,7 +6553,9 @@ void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
if (conn) {
l2cap_conn_ready(conn);
- if (hcon->type == LE_LINK && is_ble_6lowpan())
+ if (hcon->type == LE_LINK &&
+ ble_6lowpan_is_enabled(hcon->hdev,
+ &hcon->dst))
ble_6lowpan_add_conn(conn);
}
} else {
@@ -6581,7 +6578,8 @@ void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
{
BT_DBG("hcon %p reason %d", hcon, reason);
- if (hcon->type == LE_LINK && is_ble_6lowpan())
+ if (hcon->type == LE_LINK && ble_6lowpan_is_enabled(hcon->hdev,
+ &hcon->dst))
ble_6lowpan_del_conn(hcon->l2cap_data);
l2cap_conn_del(hcon, bt_to_errno(reason));
--
1.7.11.7
^ permalink raw reply related
* [RFC 4/5] Bluetooth: Set route to peer for 6LoWPAN
From: Jukka Rissanen @ 2013-10-23 6:52 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1382511164-1989-1-git-send-email-jukka.rissanen@linux.intel.com>
---
net/bluetooth/ble_6lowpan.c | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/net/bluetooth/ble_6lowpan.c b/net/bluetooth/ble_6lowpan.c
index 5b3ebe1..44d65b3 100644
--- a/net/bluetooth/ble_6lowpan.c
+++ b/net/bluetooth/ble_6lowpan.c
@@ -1344,6 +1344,39 @@ static void set_addr(u8 *eui, u8 *addr)
eui[0] ^= 2;
}
+static int add_peer_route(struct ble_6lowpan_dev_info *dev,
+ struct net_device *net, bdaddr_t *addr)
+{
+ struct in6_addr peer;
+ struct fib6_config cfg = {
+ .fc_table = RT6_TABLE_MAIN,
+ .fc_metric = IP6_RT_PRIO_ADDRCONF,
+ .fc_ifindex = net->ifindex,
+ .fc_dst_len = 128,
+ .fc_flags = RTF_ADDRCONF | RTF_UP |
+ RTF_PREF(ICMPV6_ROUTER_PREF_MEDIUM),
+ .fc_nlinfo.portid = 0,
+ .fc_nlinfo.nlh = NULL,
+ .fc_nlinfo.nl_net = dev_net(net),
+ };
+
+ memset(&peer, 0, sizeof(struct in6_addr));
+
+ /* RFC 2464 ch. 5 */
+ peer.s6_addr[0] = 0xFE;
+ peer.s6_addr[1] = 0x80;
+ set_addr((u8 *)&peer.s6_addr + 8, addr->b);
+
+ memcpy(&dev->ieee802154_addr, (u8 *)&peer.s6_addr + 8,
+ IEEE802154_ADDR_LEN);
+
+ BT_DBG("peer address %pI6c", (u8 *)&peer.s6_addr);
+
+ cfg.fc_dst = dev->peer = peer;
+
+ return ip6_route_add(&cfg);
+}
+
static void set_dev_addr(struct net_device *net, bdaddr_t *addr)
{
net->addr_assign_type = NET_ADDR_PERM;
@@ -1428,6 +1461,9 @@ int ble_6lowpan_add_conn(struct l2cap_conn *conn)
write_unlock(&net_dev_list_lock);
ifup(net);
+
+ if ((status = add_peer_route(dev, net, &dev->addr)) < 0)
+ BT_INFO("Setting route failed %d", status);
}
return 0;
--
1.7.11.7
^ permalink raw reply related
* [RFC 3/5] route: Exporting ip6_route_add() so that BLE 6LoWPAN can use it
From: Jukka Rissanen @ 2013-10-23 6:52 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1382511164-1989-1-git-send-email-jukka.rissanen@linux.intel.com>
---
net/ipv6/route.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index c979dd9..d7c200f 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1662,6 +1662,7 @@ out:
dst_free(&rt->dst);
return err;
}
+EXPORT_SYMBOL_GPL(ip6_route_add);
static int __ip6_del_rt(struct rt6_info *rt, struct nl_info *info)
{
--
1.7.11.7
^ permalink raw reply related
* [RFC 2/5] Bluetooth: Enable 6LoWPAN support for BT LE devices
From: Jukka Rissanen @ 2013-10-23 6:52 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1382511164-1989-1-git-send-email-jukka.rissanen@linux.intel.com>
---
net/bluetooth/ble_6lowpan.c | 1114 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 1112 insertions(+), 2 deletions(-)
diff --git a/net/bluetooth/ble_6lowpan.c b/net/bluetooth/ble_6lowpan.c
index 0fd3302..5b3ebe1 100644
--- a/net/bluetooth/ble_6lowpan.c
+++ b/net/bluetooth/ble_6lowpan.c
@@ -69,6 +69,9 @@ struct lowpan_fragment {
struct list_head list; /* fragments list */
};
+static LIST_HEAD(lowpan_fragments);
+static DEFINE_SPINLOCK(flist_lock);
+
#define DELETE_TIMEOUT msecs_to_jiffies(1)
/* TTL uncompression values */
@@ -110,8 +113,723 @@ static inline void ble_6lowpan_raw_dump_table(const char *caller, char *msg,
#endif /* DEBUG */
}
+static inline bool ble_6lowpan_fetch_skb(struct sk_buff *skb,
+ void *data, const unsigned int len)
+{
+ if (unlikely(!pskb_may_pull(skb, len)))
+ return true;
+
+ skb_copy_from_linear_data(skb, data, len);
+ skb_pull(skb, len);
+
+ return false;
+}
+
+/*
+ * Uncompress address function for source and
+ * destination address(non-multicast).
+ *
+ * address_mode is sam value or dam value.
+ */
+static int ble_6lowpan_uncompress_addr(struct sk_buff *skb,
+ struct in6_addr *ipaddr,
+ const u8 address_mode,
+ const u8 *lladdr)
+{
+ bool fail;
+
+ switch (address_mode) {
+ case LOWPAN_IPHC_ADDR_00:
+ /* for global link addresses */
+ fail = ble_6lowpan_fetch_skb(skb, ipaddr->s6_addr, 16);
+ break;
+ case LOWPAN_IPHC_ADDR_01:
+ /* fe:80::XXXX:XXXX:XXXX:XXXX */
+ ipaddr->s6_addr[0] = 0xFE;
+ ipaddr->s6_addr[1] = 0x80;
+ fail = ble_6lowpan_fetch_skb(skb, &ipaddr->s6_addr[8], 8);
+ break;
+ case LOWPAN_IPHC_ADDR_02:
+ /* fe:80::ff:fe00:XXXX */
+ ipaddr->s6_addr[0] = 0xFE;
+ ipaddr->s6_addr[1] = 0x80;
+ ipaddr->s6_addr[11] = 0xFF;
+ ipaddr->s6_addr[12] = 0xFE;
+ fail = ble_6lowpan_fetch_skb(skb, &ipaddr->s6_addr[14], 2);
+ break;
+ case LOWPAN_IPHC_ADDR_03:
+ fail = false;
+ /* XXX: support only normal addr (IEEE802154_ADDR_LONG) atm */
+
+ /* fe:80::XXXX:XXXX:XXXX:XXXX
+ * \_________________/
+ * hwaddr
+ */
+ ipaddr->s6_addr[0] = 0xFE;
+ ipaddr->s6_addr[1] = 0x80;
+ memcpy(&ipaddr->s6_addr[8], lladdr, IEEE802154_ADDR_LEN);
+ break;
+ default:
+ pr_debug("Invalid address mode value: 0x%x\n", address_mode);
+ return -EINVAL;
+ }
+
+ if (fail) {
+ pr_debug("Failed to fetch skb data\n");
+ return -EIO;
+ }
+
+ ble_6lowpan_raw_dump_inline(NULL, "Reconstructed ipv6 addr is",
+ ipaddr->s6_addr, 16);
+
+ return 0;
+}
+
+/*
+ * Uncompress address function for source context
+ * based address(non-multicast).
+ */
+static int ble_6lowpan_uncompress_context_based_src_addr(struct sk_buff *skb,
+ struct in6_addr *ipaddr,
+ const u8 sam)
+{
+ switch (sam) {
+ case LOWPAN_IPHC_ADDR_00:
+ /* unspec address ::
+ * Do nothing, address is already ::
+ */
+ break;
+ case LOWPAN_IPHC_ADDR_01:
+ /* TODO */
+ case LOWPAN_IPHC_ADDR_02:
+ /* TODO */
+ case LOWPAN_IPHC_ADDR_03:
+ /* TODO */
+ netdev_warn(skb->dev, "SAM value 0x%x not supported\n", sam);
+ return -EINVAL;
+ default:
+ pr_debug("Invalid sam value: 0x%x\n", sam);
+ return -EINVAL;
+ }
+
+ ble_6lowpan_raw_dump_inline(NULL,
+ "Reconstructed context based ipv6 src addr is",
+ ipaddr->s6_addr, 16);
+
+ return 0;
+}
+
+/*
+ * This func is called when the packet from BT LE device
+ * needs to be sent upper layers.
+ */
+static int ble_6lowpan_give_skb_to_upper(struct sk_buff *skb,
+ struct net_device *dev)
+{
+ struct sk_buff *skb_cp;
+ int ret = NET_RX_SUCCESS;
+
+ skb_cp = skb_copy(skb, GFP_ATOMIC);
+ if (!skb_cp) {
+ ret = -ENOMEM;
+ } else {
+ ret = netif_rx(skb_cp);
+
+ BT_DBG("receive skb %d", ret);
+ if (ret < 0)
+ ret = NET_RX_DROP;
+ }
+
+ return ret;
+}
+
+static inline int ble_6lowpan_fetch_skb_u8(struct sk_buff *skb, u8 *val)
+{
+ if (unlikely(!pskb_may_pull(skb, 1)))
+ return -EINVAL;
+
+ *val = skb->data[0];
+ skb_pull(skb, 1);
+
+ return 0;
+}
+
+static inline int ble_6lowpan_fetch_skb_u16(struct sk_buff *skb, u16 *val)
+{
+ if (unlikely(!pskb_may_pull(skb, 2)))
+ return -EINVAL;
+
+ *val = (skb->data[0] << 8) | skb->data[1];
+ skb_pull(skb, 2);
+
+ return 0;
+}
+
+static int ble_6lowpan_skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr,
+ struct net_device *dev)
+{
+ struct sk_buff *new;
+ int stat;
+
+ new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb),
+ GFP_ATOMIC);
+ kfree_skb(skb);
+
+ if (!new)
+ return -ENOMEM;
+
+ skb_push(new, sizeof(struct ipv6hdr));
+ skb_reset_network_header(new);
+ skb_copy_to_linear_data(new, hdr, sizeof(struct ipv6hdr));
+
+ new->protocol = htons(ETH_P_IPV6);
+ new->pkt_type = PACKET_HOST;
+ new->dev = dev;
+
+ ble_6lowpan_raw_dump_table(__func__,
+ "raw skb data dump before receiving",
+ new->data, new->len);
+
+ stat = ble_6lowpan_give_skb_to_upper(new, dev);
+
+ kfree_skb(new);
+
+ return stat;
+}
+
+static void lowpan_fragment_timer_expired(unsigned long entry_addr)
+{
+ struct lowpan_fragment *entry = (struct lowpan_fragment *)entry_addr;
+
+ pr_debug("timer expired for frame with tag %d\n", entry->tag);
+
+ list_del(&entry->list);
+ dev_kfree_skb(entry->skb);
+ kfree(entry);
+}
+
+static struct lowpan_fragment *ble_6lowpan_alloc_new_frame(struct sk_buff *skb,
+ u16 len, u16 tag)
+{
+ struct lowpan_fragment *frame;
+
+ frame = kzalloc(sizeof(struct lowpan_fragment),
+ GFP_ATOMIC);
+ if (!frame)
+ goto frame_err;
+
+ INIT_LIST_HEAD(&frame->list);
+
+ frame->length = len;
+ frame->tag = tag;
+
+ /* allocate buffer for frame assembling */
+ frame->skb = netdev_alloc_skb_ip_align(skb->dev, frame->length +
+ sizeof(struct ipv6hdr));
+
+ if (!frame->skb)
+ goto skb_err;
+
+ frame->skb->priority = skb->priority;
+ frame->skb->dev = skb->dev;
+
+ /* reserve headroom for uncompressed ipv6 header */
+ skb_reserve(frame->skb, sizeof(struct ipv6hdr));
+ skb_put(frame->skb, frame->length);
+
+ /* copy the first control block to keep a
+ * trace of the link-layer addresses in case
+ * of a link-local compressed address
+ */
+ memcpy(frame->skb->cb, skb->cb, sizeof(skb->cb));
+
+ init_timer(&frame->timer);
+ /* time out is the same as for ipv6 - 60 sec */
+ frame->timer.expires = jiffies + LOWPAN_FRAG_TIMEOUT;
+ frame->timer.data = (unsigned long)frame;
+ frame->timer.function = lowpan_fragment_timer_expired;
+
+ add_timer(&frame->timer);
+
+ list_add_tail(&frame->list, &lowpan_fragments);
+
+ return frame;
+
+skb_err:
+ kfree(frame);
+frame_err:
+ return NULL;
+}
+
+/* Uncompress function for multicast destination address,
+ * when M bit is set.
+ */
+static int
+lowpan_uncompress_multicast_daddr(struct sk_buff *skb,
+ struct in6_addr *ipaddr,
+ const u8 dam)
+{
+ bool fail;
+
+ switch (dam) {
+ case LOWPAN_IPHC_DAM_00:
+ /* 00: 128 bits. The full address
+ * is carried in-line.
+ */
+ fail = ble_6lowpan_fetch_skb(skb, ipaddr->s6_addr, 16);
+ break;
+ case LOWPAN_IPHC_DAM_01:
+ /* 01: 48 bits. The address takes
+ * the form ffXX::00XX:XXXX:XXXX.
+ */
+ ipaddr->s6_addr[0] = 0xFF;
+ fail = ble_6lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1);
+ fail |= ble_6lowpan_fetch_skb(skb, &ipaddr->s6_addr[11], 5);
+ break;
+ case LOWPAN_IPHC_DAM_10:
+ /* 10: 32 bits. The address takes
+ * the form ffXX::00XX:XXXX.
+ */
+ ipaddr->s6_addr[0] = 0xFF;
+ fail = ble_6lowpan_fetch_skb(skb, &ipaddr->s6_addr[1], 1);
+ fail |= ble_6lowpan_fetch_skb(skb, &ipaddr->s6_addr[13], 3);
+ break;
+ case LOWPAN_IPHC_DAM_11:
+ /* 11: 8 bits. The address takes
+ * the form ff02::00XX.
+ */
+ ipaddr->s6_addr[0] = 0xFF;
+ ipaddr->s6_addr[1] = 0x02;
+ fail = ble_6lowpan_fetch_skb(skb, &ipaddr->s6_addr[15], 1);
+ break;
+ default:
+ pr_debug("DAM value has a wrong value: 0x%x\n", dam);
+ return -EINVAL;
+ }
+
+ if (fail) {
+ pr_debug("Failed to fetch skb data\n");
+ return -EIO;
+ }
+
+ ble_6lowpan_raw_dump_inline(NULL,
+ "Reconstructed ipv6 multicast addr is",
+ ipaddr->s6_addr, 16);
+
+ return 0;
+}
+
+static int
+ble_6lowpan_uncompress_udp_header(struct sk_buff *skb, struct udphdr *uh)
+{
+ u8 tmp;
+
+ if (!uh)
+ goto err;
+
+ if (ble_6lowpan_fetch_skb_u8(skb, &tmp))
+ goto err;
+
+ if ((tmp & LOWPAN_NHC_UDP_MASK) == LOWPAN_NHC_UDP_ID) {
+ pr_debug("UDP header uncompression\n");
+ switch (tmp & LOWPAN_NHC_UDP_CS_P_11) {
+ case LOWPAN_NHC_UDP_CS_P_00:
+ memcpy(&uh->source, &skb->data[0], 2);
+ memcpy(&uh->dest, &skb->data[2], 2);
+ skb_pull(skb, 4);
+ break;
+ case LOWPAN_NHC_UDP_CS_P_01:
+ memcpy(&uh->source, &skb->data[0], 2);
+ uh->dest =
+ skb->data[2] + LOWPAN_NHC_UDP_8BIT_PORT;
+ skb_pull(skb, 3);
+ break;
+ case LOWPAN_NHC_UDP_CS_P_10:
+ uh->source = skb->data[0] + LOWPAN_NHC_UDP_8BIT_PORT;
+ memcpy(&uh->dest, &skb->data[1], 2);
+ skb_pull(skb, 3);
+ break;
+ case LOWPAN_NHC_UDP_CS_P_11:
+ uh->source =
+ LOWPAN_NHC_UDP_4BIT_PORT + (skb->data[0] >> 4);
+ uh->dest =
+ LOWPAN_NHC_UDP_4BIT_PORT + (skb->data[0] & 0x0f);
+ skb_pull(skb, 1);
+ break;
+ default:
+ pr_debug("ERROR: unknown UDP format\n");
+ goto err;
+ break;
+ }
+
+ pr_debug("uncompressed UDP ports: src = %d, dst = %d\n",
+ uh->source, uh->dest);
+
+ /* copy checksum */
+ memcpy(&uh->check, &skb->data[0], 2);
+ skb_pull(skb, 2);
+
+ /*
+ * UDP lenght needs to be infered from the lower layers
+ * here, we obtain the hint from the remaining size of the
+ * frame
+ */
+ uh->len = htons(skb->len + sizeof(struct udphdr));
+ pr_debug("uncompressed UDP length: src = %d", uh->len);
+ } else {
+ pr_debug("ERROR: unsupported NH format\n");
+ goto err;
+ }
+
+ return 0;
+err:
+ return -EINVAL;
+}
+
+static int ble_6lowpan_process_data(struct sk_buff *skb, struct net_device *dev)
+{
+ struct ipv6hdr hdr = {};
+ u8 tmp, iphc0, iphc1, num_context = 0;
+ const u8 *_saddr = NULL, *_daddr = NULL;
+ struct ble_6lowpan_dev_info *info;
+ int err;
+
+ ble_6lowpan_raw_dump_table(__func__, "raw skb data dump uncompressed",
+ skb->data, skb->len);
+
+ /* at least two bytes will be used for the encoding */
+ if (skb->len < 2)
+ goto drop;
+
+ if (ble_6lowpan_fetch_skb_u8(skb, &iphc0))
+ goto drop;
+
+ info = ble_6lowpan_dev_info(dev);
+
+ /* fragments assembling */
+ switch (iphc0 & LOWPAN_DISPATCH_MASK) {
+ case LOWPAN_DISPATCH_FRAG1:
+ case LOWPAN_DISPATCH_FRAGN:
+ {
+ struct lowpan_fragment *frame;
+ /* slen stores the rightmost 8 bits of the 11 bits length */
+ u8 slen, offset = 0;
+ u16 len, tag;
+ bool found = false;
+
+ if (ble_6lowpan_fetch_skb_u8(skb, &slen) || /* frame length */
+ ble_6lowpan_fetch_skb_u16(skb, &tag)) /* fragment tag */
+ goto drop;
+
+ /* adds the 3 MSB to the 8 LSB to retrieve the 11 bits length */
+ len = ((iphc0 & 7) << 8) | slen;
+
+ if ((iphc0 & LOWPAN_DISPATCH_MASK) == LOWPAN_DISPATCH_FRAG1) {
+ pr_debug("%s received a FRAG1 packet (tag: %d, "
+ "size of the entire IP packet: %d)\n",
+ __func__, tag, len);
+ } else { /* FRAGN */
+ if (ble_6lowpan_fetch_skb_u8(skb, &offset))
+ goto unlock_and_drop;
+ pr_debug("%s received a FRAGN packet (tag: %d, "
+ "size of the entire IP packet: %d, "
+ "offset: %d)\n", __func__, tag, len,
+ offset * 8);
+ }
+
+ /*
+ * check if frame assembling with the same tag is
+ * already in progress
+ */
+ spin_lock_bh(&flist_lock);
+
+ list_for_each_entry(frame, &lowpan_fragments, list)
+ if (frame->tag == tag) {
+ found = true;
+ break;
+ }
+
+ /* alloc new frame structure */
+ if (!found) {
+ pr_debug("%s first fragment received for tag %d, "
+ "begin packet reassembly\n", __func__, tag);
+ frame = ble_6lowpan_alloc_new_frame(skb, len, tag);
+ if (!frame)
+ goto unlock_and_drop;
+ }
+
+ /* if payload fits buffer, copy it */
+ if (likely((offset * 8 + skb->len) <= frame->length))
+ skb_copy_to_linear_data_offset(frame->skb, offset * 8,
+ skb->data, skb->len);
+ else
+ goto unlock_and_drop;
+
+ frame->bytes_rcv += skb->len;
+
+ /* frame assembling complete */
+ if ((frame->bytes_rcv == frame->length) &&
+ frame->timer.expires > jiffies) {
+ /* if timer haven't expired - first of all delete it */
+ del_timer_sync(&frame->timer);
+ list_del(&frame->list);
+ spin_unlock_bh(&flist_lock);
+
+ pr_debug("%s successfully reassembled fragment "
+ "(tag %d)\n", __func__, tag);
+
+ dev_kfree_skb(skb);
+ skb = frame->skb;
+ kfree(frame);
+
+ if (ble_6lowpan_fetch_skb_u8(skb, &iphc0))
+ goto drop;
+
+ break;
+ }
+ spin_unlock_bh(&flist_lock);
+
+ return kfree_skb(skb), 0;
+ }
+ default:
+ break;
+ }
+
+ if (ble_6lowpan_fetch_skb_u8(skb, &iphc1))
+ goto drop;
+
+ _saddr = info->ieee802154_addr;
+ _daddr = info->net->dev_addr;
+
+ /* another if the CID flag is set */
+ if (iphc1 & LOWPAN_IPHC_CID) {
+ pr_debug("CID flag is set, increase header with one\n");
+ if (ble_6lowpan_fetch_skb_u8(skb, &num_context))
+ goto drop;
+ }
+
+ hdr.version = 6;
+
+ /* Traffic Class and Flow Label */
+ switch ((iphc0 & LOWPAN_IPHC_TF) >> 3) {
+ /*
+ * Traffic Class and FLow Label carried in-line
+ * ECN + DSCP + 4-bit Pad + Flow Label (4 bytes)
+ */
+ case 0: /* 00b */
+ if (ble_6lowpan_fetch_skb_u8(skb, &tmp))
+ goto drop;
+
+ memcpy(&hdr.flow_lbl, &skb->data[0], 3);
+ skb_pull(skb, 3);
+ hdr.priority = ((tmp >> 2) & 0x0f);
+ hdr.flow_lbl[0] = ((tmp >> 2) & 0x30) | (tmp << 6) |
+ (hdr.flow_lbl[0] & 0x0f);
+ break;
+ /*
+ * Traffic class carried in-line
+ * ECN + DSCP (1 byte), Flow Label is elided
+ */
+ case 1: /* 10b */
+ if (ble_6lowpan_fetch_skb_u8(skb, &tmp))
+ goto drop;
+
+ hdr.priority = ((tmp >> 2) & 0x0f);
+ hdr.flow_lbl[0] = ((tmp << 6) & 0xC0) | ((tmp >> 2) & 0x30);
+ break;
+ /*
+ * Flow Label carried in-line
+ * ECN + 2-bit Pad + Flow Label (3 bytes), DSCP is elided
+ */
+ case 2: /* 01b */
+ if (ble_6lowpan_fetch_skb_u8(skb, &tmp))
+ goto drop;
+
+ hdr.flow_lbl[0] = (skb->data[0] & 0x0F) | ((tmp >> 2) & 0x30);
+ memcpy(&hdr.flow_lbl[1], &skb->data[0], 2);
+ skb_pull(skb, 2);
+ break;
+ /* Traffic Class and Flow Label are elided */
+ case 3: /* 11b */
+ break;
+ default:
+ break;
+ }
+
+ /* Next Header */
+ if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
+ /* Next header is carried inline */
+ if (ble_6lowpan_fetch_skb_u8(skb, &(hdr.nexthdr)))
+ goto drop;
+
+ pr_debug("NH flag is set, next header carried inline: %02x\n",
+ hdr.nexthdr);
+ }
+
+ /* Hop Limit */
+ if ((iphc0 & 0x03) != LOWPAN_IPHC_TTL_I)
+ hdr.hop_limit = lowpan_ttl_values[iphc0 & 0x03];
+ else {
+ if (ble_6lowpan_fetch_skb_u8(skb, &(hdr.hop_limit)))
+ goto drop;
+ }
+
+ /* Extract SAM to the tmp variable */
+ tmp = ((iphc1 & LOWPAN_IPHC_SAM) >> LOWPAN_IPHC_SAM_BIT) & 0x03;
+
+ if (iphc1 & LOWPAN_IPHC_SAC) {
+ /* Source address context based uncompression */
+ pr_debug("SAC bit is set. Handle context based source address.\n");
+ err = ble_6lowpan_uncompress_context_based_src_addr(
+ skb, &hdr.saddr, tmp);
+ } else {
+ /* Source address uncompression */
+ pr_debug("source address stateless compression\n");
+ err = ble_6lowpan_uncompress_addr(skb, &hdr.saddr, tmp, _saddr);
+ }
+
+ /* Check on error of previous branch */
+ if (err)
+ goto drop;
+
+ /* Extract DAM to the tmp variable */
+ tmp = ((iphc1 & LOWPAN_IPHC_DAM_11) >> LOWPAN_IPHC_DAM_BIT) & 0x03;
+
+ /* check for Multicast Compression */
+ if (iphc1 & LOWPAN_IPHC_M) {
+ if (iphc1 & LOWPAN_IPHC_DAC) {
+ pr_debug("dest: context-based mcast compression\n");
+ /* TODO: implement this */
+ } else {
+ err = lowpan_uncompress_multicast_daddr(
+ skb, &hdr.daddr, tmp);
+ if (err)
+ goto drop;
+ }
+ } else {
+ pr_debug("dest: stateless compression\n");
+ err = ble_6lowpan_uncompress_addr(skb, &hdr.daddr, tmp, _daddr);
+ if (err)
+ goto drop;
+ }
+
+ /* UDP data uncompression */
+ if (iphc0 & LOWPAN_IPHC_NH_C) {
+ struct udphdr uh;
+ struct sk_buff *new;
+ if (ble_6lowpan_uncompress_udp_header(skb, &uh))
+ goto drop;
+
+ /*
+ * replace the compressed UDP head by the uncompressed UDP
+ * header
+ */
+ new = skb_copy_expand(skb, sizeof(struct udphdr),
+ skb_tailroom(skb), GFP_ATOMIC);
+ kfree_skb(skb);
+
+ if (!new)
+ return -ENOMEM;
+
+ skb = new;
+
+ skb_push(skb, sizeof(struct udphdr));
+ skb_reset_transport_header(skb);
+ skb_copy_to_linear_data(skb, &uh, sizeof(struct udphdr));
+
+ ble_6lowpan_raw_dump_table(__func__, "raw UDP header dump",
+ (u8 *)&uh, sizeof(uh));
+
+ hdr.nexthdr = UIP_PROTO_UDP;
+ }
+
+ /* Not fragmented package */
+ hdr.payload_len = htons(skb->len);
+
+ pr_debug("skb headroom size = %d, data length = %d\n",
+ skb_headroom(skb), skb->len);
+
+ pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n\t"
+ "nexthdr = 0x%02x\n\thop_lim = %d\n", hdr.version,
+ ntohs(hdr.payload_len), hdr.nexthdr, hdr.hop_limit);
+
+ ble_6lowpan_raw_dump_table(__func__, "raw header dump", (u8 *)&hdr,
+ sizeof(hdr));
+
+ return ble_6lowpan_skb_deliver(skb, &hdr, dev);
+
+unlock_and_drop:
+ spin_unlock_bh(&flist_lock);
+drop:
+ kfree_skb(skb);
+ return -EINVAL;
+}
+
static int ble_6lowpan_recv_pkt(struct sk_buff *skb, struct net_device *dev)
{
+ struct sk_buff *local_skb;
+
+ if (!netif_running(dev))
+ goto drop;
+
+ if (dev->type != ARPHRD_IEEE802154)
+ goto drop;
+
+ ble_6lowpan_raw_dump_table(__func__, "raw recv dump", skb->head,
+ skb->len);
+
+ /* check that it's our buffer */
+ if (skb->data[0] == LOWPAN_DISPATCH_IPV6) {
+ /* Copy the packet so that the IPv6 header is
+ * properly aligned.
+ */
+ local_skb = skb_copy_expand(skb, NET_SKB_PAD - 1,
+ skb_tailroom(skb), GFP_ATOMIC);
+ if (!local_skb)
+ goto drop;
+
+ local_skb->protocol = htons(ETH_P_IPV6);
+ local_skb->pkt_type = PACKET_HOST;
+
+ skb_reset_network_header(local_skb);
+ skb_set_transport_header(local_skb, sizeof(struct ipv6hdr));
+
+ if (ble_6lowpan_give_skb_to_upper(local_skb,
+ dev) != NET_RX_SUCCESS) {
+ kfree_skb(local_skb);
+ goto drop;
+ }
+
+ dev->stats.rx_bytes += skb->len;
+ dev->stats.rx_packets++;
+
+ kfree_skb(local_skb);
+ kfree_skb(skb);
+ } else {
+ switch (skb->data[0] & 0xe0) {
+ case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */
+ case LOWPAN_DISPATCH_FRAG1: /* first fragment header */
+ case LOWPAN_DISPATCH_FRAGN: /* next fragments headers */
+ local_skb = skb_clone(skb, GFP_ATOMIC);
+ if (!local_skb)
+ goto drop;
+ if (ble_6lowpan_process_data(local_skb,
+ dev) != NET_RX_SUCCESS)
+ goto drop;
+
+ dev->stats.rx_bytes += skb->len;
+ dev->stats.rx_packets++;
+
+ kfree_skb(skb);
+ break;
+ default:
+ break;
+ }
+ }
+
+ return NET_RX_SUCCESS;
+
+drop:
kfree_skb(skb);
return NET_RX_DROP;
}
@@ -147,19 +865,406 @@ static void ble_6lowpan_do_send(struct l2cap_conn *conn, struct sk_buff *skb)
BT_DBG("conn %p, skb %p len %d priority %u", conn, skb, skb->len,
skb->priority);
- return;
+ hci_send_acl(conn->hchan, skb, ACL_START);
+}
+
+static inline int ble_6lowpan_skbuff_copy(void *msg, int len,
+ int count, int mtu,
+ struct sk_buff *skb,
+ struct net_device *dev)
+{
+ struct sk_buff **frag;
+ int sent = 0;
+
+ memcpy(skb_put(skb, count), msg, count);
+
+ sent += count;
+ msg += count;
+ len -= count;
+
+ dev->stats.tx_bytes += count;
+ dev->stats.tx_packets++;
+
+ ble_6lowpan_raw_dump_table(__func__, "Sending", skb->data, skb->len);
+
+ /* Continuation fragments (no L2CAP header) */
+ frag = &skb_shinfo(skb)->frag_list;
+ while (len > 0) {
+ struct sk_buff *tmp;
+
+ count = min_t(unsigned int, mtu, len);
+
+ tmp = bt_skb_alloc(count, GFP_KERNEL);
+ if (IS_ERR(tmp))
+ return PTR_ERR(tmp);
+
+ *frag = tmp;
+
+ memcpy(skb_put(*frag, count), msg, count);
+
+ ble_6lowpan_raw_dump_table(__func__, "Sending fragment",
+ (*frag)->data, count);
+
+ (*frag)->priority = skb->priority;
+
+ sent += count;
+ msg += count;
+ len -= count;
+
+ skb->len += (*frag)->len;
+ skb->data_len += (*frag)->len;
+
+ frag = &(*frag)->next;
+
+ dev->stats.tx_bytes += count;
+ dev->stats.tx_packets++;
+ }
+
+ return sent;
+}
+
+static struct sk_buff *ble_6lowpan_create_pdu(struct l2cap_conn *conn,
+ void *msg, size_t len,
+ u32 priority,
+ struct net_device *dev)
+{
+ struct sk_buff *skb;
+ int err, count;
+ struct l2cap_hdr *lh;
+
+ if (conn->mtu > (L2CAP_LE_MIN_MTU + L2CAP_HDR_SIZE))
+ /* XXX: This should be not needed and atm is only used for
+ * testing purposes */
+ conn->mtu = L2CAP_LE_MIN_MTU + L2CAP_HDR_SIZE;
+
+ count = min_t(unsigned int, (conn->mtu - L2CAP_HDR_SIZE), len);
+
+ BT_DBG("conn %p len %zu mtu %d count %d", conn, len, conn->mtu, count);
+
+ skb = bt_skb_alloc(count + L2CAP_HDR_SIZE, GFP_KERNEL);
+ if (IS_ERR(skb))
+ return skb;
+
+ skb->priority = priority;
+
+ lh = (struct l2cap_hdr *)skb_put(skb, L2CAP_HDR_SIZE);
+ lh->cid = cpu_to_le16(L2CAP_FC_6LOWPAN);
+ lh->len = cpu_to_le16(len);
+
+ err = ble_6lowpan_skbuff_copy(msg, len, count, conn->mtu, skb, dev);
+ if (unlikely(err < 0)) {
+ kfree_skb(skb);
+ BT_DBG("skbuff copy %d failed", err);
+ return ERR_PTR(err);
+ }
+
+ return skb;
}
static int lowpan_conn_send(struct l2cap_conn *conn,
void *msg, size_t len, u32 priority,
struct net_device *dev)
{
- struct sk_buff *skb = {0};
+ struct sk_buff *skb;
+
+ skb = ble_6lowpan_create_pdu(conn, msg, len, priority, dev);
+ if (IS_ERR(skb))
+ return -EINVAL;
ble_6lowpan_do_send(conn, skb);
return 0;
}
+static u8 lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift,
+ const struct in6_addr *ipaddr,
+ const unsigned char *lladdr)
+{
+ u8 val = 0;
+
+ if (is_addr_mac_addr_based(ipaddr, lladdr))
+ val = 3; /* 0-bits */
+ else if (lowpan_is_iid_16_bit_compressable(ipaddr)) {
+ /* compress IID to 16 bits xxxx::XXXX */
+ memcpy(*hc06_ptr, &ipaddr->s6_addr16[7], 2);
+ *hc06_ptr += 2;
+ val = 2; /* 16-bits */
+ } else {
+ /* do not compress IID => xxxx::IID */
+ memcpy(*hc06_ptr, &ipaddr->s6_addr16[4], 8);
+ *hc06_ptr += 8;
+ val = 1; /* 64-bits */
+ }
+
+ return rol8(val, shift);
+}
+
+static void ble_6lowpan_compress_udp_header(u8 **hc06_ptr, struct sk_buff *skb)
+{
+ struct udphdr *uh = udp_hdr(skb);
+
+ if (((uh->source & LOWPAN_NHC_UDP_4BIT_MASK) ==
+ LOWPAN_NHC_UDP_4BIT_PORT) &&
+ ((uh->dest & LOWPAN_NHC_UDP_4BIT_MASK) ==
+ LOWPAN_NHC_UDP_4BIT_PORT)) {
+ pr_debug("UDP header: both ports compression to 4 bits\n");
+ **hc06_ptr = LOWPAN_NHC_UDP_CS_P_11;
+ **(hc06_ptr + 1) = /* subtraction is faster */
+ (u8)((uh->dest - LOWPAN_NHC_UDP_4BIT_PORT) +
+ ((uh->source & LOWPAN_NHC_UDP_4BIT_PORT) << 4));
+ *hc06_ptr += 2;
+ } else if ((uh->dest & LOWPAN_NHC_UDP_8BIT_MASK) ==
+ LOWPAN_NHC_UDP_8BIT_PORT) {
+ pr_debug("UDP header: remove 8 bits of dest\n");
+ **hc06_ptr = LOWPAN_NHC_UDP_CS_P_01;
+ memcpy(*hc06_ptr + 1, &uh->source, 2);
+ **(hc06_ptr + 3) = (u8)(uh->dest - LOWPAN_NHC_UDP_8BIT_PORT);
+ *hc06_ptr += 4;
+ } else if ((uh->source & LOWPAN_NHC_UDP_8BIT_MASK) ==
+ LOWPAN_NHC_UDP_8BIT_PORT) {
+ pr_debug("UDP header: remove 8 bits of source\n");
+ **hc06_ptr = LOWPAN_NHC_UDP_CS_P_10;
+ memcpy(*hc06_ptr + 1, &uh->dest, 2);
+ **(hc06_ptr + 3) = (u8)(uh->source - LOWPAN_NHC_UDP_8BIT_PORT);
+ *hc06_ptr += 4;
+ } else {
+ pr_debug("UDP header: can't compress\n");
+ **hc06_ptr = LOWPAN_NHC_UDP_CS_P_00;
+ memcpy(*hc06_ptr + 1, &uh->source, 2);
+ memcpy(*hc06_ptr + 3, &uh->dest, 2);
+ *hc06_ptr += 5;
+ }
+
+ /* checksum is always inline */
+ memcpy(*hc06_ptr, &uh->check, 2);
+ *hc06_ptr += 2;
+
+ /* skip the UDP header */
+ skb_pull(skb, sizeof(struct udphdr));
+}
+
+static inline int lowpan_fetch_skb_u8(struct sk_buff *skb, u8 *val)
+{
+ if (unlikely(!pskb_may_pull(skb, 1)))
+ return -EINVAL;
+
+ *val = skb->data[0];
+ skb_pull(skb, 1);
+
+ return 0;
+}
+
+static inline int lowpan_fetch_skb_u16(struct sk_buff *skb, u16 *val)
+{
+ if (unlikely(!pskb_may_pull(skb, 2)))
+ return -EINVAL;
+
+ *val = (skb->data[0] << 8) | skb->data[1];
+ skb_pull(skb, 2);
+
+ return 0;
+}
+
+static int ble_6lowpan_header_create(struct sk_buff *skb,
+ struct net_device *dev,
+ unsigned short type, const void *_daddr,
+ const void *_saddr, unsigned int len)
+{
+ u8 tmp, iphc0, iphc1, *hc06_ptr;
+ struct ipv6hdr *hdr;
+ u8 *saddr, *daddr;
+ u8 head[100];
+ struct ble_6lowpan_dev_info *info;
+
+ if (type != ETH_P_IPV6)
+ return -EINVAL;
+
+ info = ble_6lowpan_dev_info(dev);
+ daddr = info->ieee802154_addr;
+ saddr = info->net->dev_addr;
+
+ hdr = ipv6_hdr(skb);
+ hc06_ptr = head + 2;
+
+ pr_debug("IPv6 header dump:\n\tversion = %d\n\tlength = %d\n"
+ "\tnexthdr = 0x%02x\n\thop_lim = %d\n", hdr->version,
+ ntohs(hdr->payload_len), hdr->nexthdr, hdr->hop_limit);
+
+ ble_6lowpan_raw_dump_table(__func__, "raw skb network header dump",
+ skb_network_header(skb), sizeof(struct ipv6hdr));
+
+ ble_6lowpan_raw_dump_inline(__func__, "saddr",
+ (unsigned char *)saddr, 8);
+
+ /*
+ * As we copy some bit-length fields, in the IPHC encoding bytes,
+ * we sometimes use |=
+ * If the field is 0, and the current bit value in memory is 1,
+ * this does not work. We therefore reset the IPHC encoding here
+ */
+ iphc0 = LOWPAN_DISPATCH_IPHC;
+ iphc1 = 0;
+
+ /* TODO: context lookup */
+
+ ble_6lowpan_raw_dump_inline(__func__, "daddr",
+ (unsigned char *)daddr, 8);
+
+ ble_6lowpan_raw_dump_table(__func__,
+ "sending raw skb network uncompressed packet",
+ skb->data, skb->len);
+
+ /*
+ * Traffic class, flow label
+ * If flow label is 0, compress it. If traffic class is 0, compress it
+ * We have to process both in the same time as the offset of traffic
+ * class depends on the presence of version and flow label
+ */
+
+ /* hc06 format of TC is ECN | DSCP , original one is DSCP | ECN */
+ tmp = (hdr->priority << 4) | (hdr->flow_lbl[0] >> 4);
+ tmp = ((tmp & 0x03) << 6) | (tmp >> 2);
+
+ if (((hdr->flow_lbl[0] & 0x0F) == 0) &&
+ (hdr->flow_lbl[1] == 0) && (hdr->flow_lbl[2] == 0)) {
+ /* flow label can be compressed */
+ iphc0 |= LOWPAN_IPHC_FL_C;
+ if ((hdr->priority == 0) &&
+ ((hdr->flow_lbl[0] & 0xF0) == 0)) {
+ /* compress (elide) all */
+ iphc0 |= LOWPAN_IPHC_TC_C;
+ } else {
+ /* compress only the flow label */
+ *hc06_ptr = tmp;
+ hc06_ptr += 1;
+ }
+ } else {
+ /* Flow label cannot be compressed */
+ if ((hdr->priority == 0) &&
+ ((hdr->flow_lbl[0] & 0xF0) == 0)) {
+ /* compress only traffic class */
+ iphc0 |= LOWPAN_IPHC_TC_C;
+ *hc06_ptr = (tmp & 0xc0) | (hdr->flow_lbl[0] & 0x0F);
+ memcpy(hc06_ptr + 1, &hdr->flow_lbl[1], 2);
+ hc06_ptr += 3;
+ } else {
+ /* compress nothing */
+ memcpy(hc06_ptr, &hdr, 4);
+ /* replace the top byte with new ECN | DSCP format */
+ *hc06_ptr = tmp;
+ hc06_ptr += 4;
+ }
+ }
+
+ /* NOTE: payload length is always compressed */
+
+ /* Next Header is compress if UDP */
+ if (hdr->nexthdr == UIP_PROTO_UDP)
+ iphc0 |= LOWPAN_IPHC_NH_C;
+
+ if ((iphc0 & LOWPAN_IPHC_NH_C) == 0) {
+ *hc06_ptr = hdr->nexthdr;
+ hc06_ptr += 1;
+ }
+
+ /*
+ * Hop limit
+ * if 1: compress, encoding is 01
+ * if 64: compress, encoding is 10
+ * if 255: compress, encoding is 11
+ * else do not compress
+ */
+ switch (hdr->hop_limit) {
+ case 1:
+ iphc0 |= LOWPAN_IPHC_TTL_1;
+ break;
+ case 64:
+ iphc0 |= LOWPAN_IPHC_TTL_64;
+ break;
+ case 255:
+ iphc0 |= LOWPAN_IPHC_TTL_255;
+ break;
+ default:
+ *hc06_ptr = hdr->hop_limit;
+ hc06_ptr += 1;
+ break;
+ }
+
+ /* source address compression */
+ if (is_addr_unspecified(&hdr->saddr)) {
+ pr_debug("source address is unspecified, setting SAC\n");
+ iphc1 |= LOWPAN_IPHC_SAC;
+ /* TODO: context lookup */
+ } else if (is_addr_link_local(&hdr->saddr)) {
+ pr_debug("source address is link-local\n");
+ iphc1 |= lowpan_compress_addr_64(&hc06_ptr,
+ LOWPAN_IPHC_SAM_BIT, &hdr->saddr, saddr);
+ } else {
+ pr_debug("send the full source address\n");
+ memcpy(hc06_ptr, &hdr->saddr.s6_addr16[0], 16);
+ hc06_ptr += 16;
+ }
+
+ /* destination address compression */
+ if (is_addr_mcast(&hdr->daddr)) {
+ pr_debug("destination address is multicast: ");
+ iphc1 |= LOWPAN_IPHC_M;
+ if (lowpan_is_mcast_addr_compressable8(&hdr->daddr)) {
+ pr_debug("compressed to 1 octet\n");
+ iphc1 |= LOWPAN_IPHC_DAM_11;
+ /* use last byte */
+ *hc06_ptr = hdr->daddr.s6_addr[15];
+ hc06_ptr += 1;
+ } else if (lowpan_is_mcast_addr_compressable32(&hdr->daddr)) {
+ pr_debug("compressed to 4 octets\n");
+ iphc1 |= LOWPAN_IPHC_DAM_10;
+ /* second byte + the last three */
+ *hc06_ptr = hdr->daddr.s6_addr[1];
+ memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[13], 3);
+ hc06_ptr += 4;
+ } else if (lowpan_is_mcast_addr_compressable48(&hdr->daddr)) {
+ pr_debug("compressed to 6 octets\n");
+ iphc1 |= LOWPAN_IPHC_DAM_01;
+ /* second byte + the last five */
+ *hc06_ptr = hdr->daddr.s6_addr[1];
+ memcpy(hc06_ptr + 1, &hdr->daddr.s6_addr[11], 5);
+ hc06_ptr += 6;
+ } else {
+ pr_debug("using full address\n");
+ iphc1 |= LOWPAN_IPHC_DAM_00;
+ memcpy(hc06_ptr, &hdr->daddr.s6_addr[0], 16);
+ hc06_ptr += 16;
+ }
+ } else {
+ /* TODO: context lookup */
+ if (is_addr_link_local(&hdr->daddr)) {
+ pr_debug("dest address is unicast and link-local\n");
+ iphc1 |= lowpan_compress_addr_64(&hc06_ptr,
+ LOWPAN_IPHC_DAM_BIT, &hdr->daddr, daddr);
+ } else {
+ pr_debug("dest address is unicast: using full one\n");
+ memcpy(hc06_ptr, &hdr->daddr.s6_addr16[0], 16);
+ hc06_ptr += 16;
+ }
+ }
+
+ /* UDP header compression */
+ if (hdr->nexthdr == UIP_PROTO_UDP)
+ ble_6lowpan_compress_udp_header(&hc06_ptr, skb);
+
+ head[0] = iphc0;
+ head[1] = iphc1;
+
+ skb_pull(skb, sizeof(struct ipv6hdr));
+ memcpy(skb_push(skb, hc06_ptr - head), head, hc06_ptr - head);
+
+ BT_DBG("header len %d skb %u", (int)(hc06_ptr - head), skb->len);
+
+ ble_6lowpan_raw_dump_table(__func__, "raw skb data dump compressed",
+ skb->data, skb->len);
+
+ return 0;
+}
+
/* Packet to BT LE device */
static int ble_6lowpan_send(struct l2cap_conn *conn, const void *saddr,
const void *daddr, struct sk_buff *skb,
@@ -199,6 +1304,10 @@ static const struct net_device_ops ble_6lowpan_netdev_ops = {
.ndo_start_xmit = ble_6lowpan_xmit,
};
+static struct header_ops ble_6lowpan_header_ops = {
+ .create = ble_6lowpan_header_create,
+};
+
static void ble_6lowpan_setup(struct net_device *dev)
{
dev->addr_len = IEEE802154_ADDR_LEN;
@@ -212,6 +1321,7 @@ static void ble_6lowpan_setup(struct net_device *dev)
dev->watchdog_timeo = 0;
dev->netdev_ops = &ble_6lowpan_netdev_ops;
+ dev->header_ops = &ble_6lowpan_header_ops;
dev->destructor = free_netdev;
}
--
1.7.11.7
^ 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