* [PATCH 7/8] android/bluetooth: Add send_device_property helper function
From: Szymon Janc @ 2013-12-09 15:14 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1386602049-5533-1-git-send-email-szymon.janc@tieto.com>
Remote device property notification will be send from multiple places
so it make sense to have helper for that. This will be especially
usefull for 'simple' properties.
---
android/bluetooth.c | 27 ++++++++++++++-------------
1 file changed, 14 insertions(+), 13 deletions(-)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index 7528921..fd69c86 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -557,26 +557,27 @@ static void new_link_key_callback(uint16_t index, uint16_t length,
browse_remote_sdp(&addr->bdaddr);
}
-
-static uint8_t get_device_name(struct device *dev)
+static void send_device_property(const bdaddr_t *bdaddr, uint8_t type,
+ uint16_t len, const void *val)
{
- struct hal_ev_remote_device_props *ev;
- size_t ev_len;
-
- ev_len = BASELEN_REMOTE_DEV_PROP + strlen(dev->name);
- ev = g_malloc0(ev_len);
+ uint8_t buf[BASELEN_REMOTE_DEV_PROP + len];
+ struct hal_ev_remote_device_props *ev = (void *) buf;
ev->status = HAL_STATUS_SUCCESS;
- bdaddr2android(&dev->bdaddr, ev->bdaddr);
+ bdaddr2android(bdaddr, ev->bdaddr);
ev->num_props = 1;
- ev->props[0].type = HAL_PROP_DEVICE_NAME;
- ev->props[0].len = strlen(dev->name);
- memcpy(&ev->props[0].val, dev->name, strlen(dev->name));
+ ev->props[0].type = type;
+ ev->props[0].len = len;
+ memcpy(ev->props[0].val, val, len);
ipc_send_notif(HAL_SERVICE_ID_BLUETOOTH, HAL_EV_REMOTE_DEVICE_PROPS,
- ev_len, ev);
+ sizeof(buf), buf);
+}
- g_free(ev);
+static uint8_t get_device_name(struct device *dev)
+{
+ send_device_property(&dev->bdaddr, HAL_PROP_DEVICE_NAME,
+ strlen(dev->name), dev->name);
return HAL_STATUS_SUCCESS;
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH 6/8] android/bluetooth: Add stubs for set device property command
From: Szymon Janc @ 2013-12-09 15:14 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1386602049-5533-1-git-send-email-szymon.janc@tieto.com>
This adds per property stubs.
---
android/bluetooth.c | 36 ++++++++++++++++++++++++++++++++++--
1 file changed, 34 insertions(+), 2 deletions(-)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index 4b17f60..7528921 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -2362,10 +2362,30 @@ failed:
status);
}
+static uint8_t set_device_friendly_name(struct device *dev)
+{
+ DBG("Not implemented");
+
+ /* TODO */
+
+ return HAL_STATUS_FAILED;
+}
+
+static uint8_t set_device_version_info(struct device *dev)
+{
+ DBG("Not implemented");
+
+ /* TODO */
+
+ return HAL_STATUS_FAILED;
+}
+
static void handle_set_remote_device_prop_cmd(const void *buf, uint16_t len)
{
const struct hal_cmd_set_remote_device_prop *cmd = buf;
uint8_t status;
+ bdaddr_t addr;
+ GSList *l;
if (len != sizeof(*cmd) + cmd->len) {
error("Invalid set remote device prop cmd (0x%x), terminating",
@@ -2374,15 +2394,27 @@ static void handle_set_remote_device_prop_cmd(const void *buf, uint16_t len)
return;
}
- /* TODO */
+ android2bdaddr(cmd->bdaddr, &addr);
+
+ l = g_slist_find_custom(devices, &addr, bdaddr_cmp);
+ if (!l) {
+ status = HAL_STATUS_INVALID;
+ goto failed;
+ }
switch (cmd->type) {
+ case HAL_PROP_DEVICE_FRIENDLY_NAME:
+ status = set_device_friendly_name(l->data);
+ break;
+ case HAL_PROP_DEVICE_VERSION_INFO:
+ status = set_device_version_info(l->data);
+ break;
default:
- DBG("Unhandled property type 0x%x", cmd->type);
status = HAL_STATUS_FAILED;
break;
}
+failed:
ipc_send_rsp(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_SET_REMOTE_DEVICE_PROP,
status);
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH 5/8] android/bluetooth: Add stubs for get device properties command
From: Szymon Janc @ 2013-12-09 15:14 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1386602049-5533-1-git-send-email-szymon.janc@tieto.com>
This adds per property stubs.
---
android/bluetooth.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 119 insertions(+), 2 deletions(-)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index 879cf8d..4b17f60 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -2229,6 +2229,78 @@ static void handle_get_adapter_props_cmd(const void *buf, uint16_t len)
HAL_STATUS_SUCCESS);
}
+static uint8_t get_device_uuids(struct device *dev)
+{
+ DBG("Not implemented");
+
+ /* TODO */
+
+ return HAL_STATUS_FAILED;
+}
+
+static uint8_t get_device_class(struct device *dev)
+{
+ DBG("Not implemented");
+
+ /* TODO */
+
+ return HAL_STATUS_FAILED;
+}
+
+static uint8_t get_device_type(struct device *dev)
+{
+ DBG("Not implemented");
+
+ /* TODO */
+
+ return HAL_STATUS_FAILED;
+}
+
+static uint8_t get_device_service_rec(struct device *dev)
+{
+ DBG("Not implemented");
+
+ /* TODO */
+
+ return HAL_STATUS_FAILED;
+}
+
+static uint8_t get_device_friendly_name(struct device *dev)
+{
+ DBG("Not implemented");
+
+ /* TODO */
+
+ return HAL_STATUS_FAILED;
+}
+
+static uint8_t get_device_rssi(struct device *dev)
+{
+ DBG("Not implemented");
+
+ /* TODO */
+
+ return HAL_STATUS_FAILED;
+}
+
+static uint8_t get_device_version_info(struct device *dev)
+{
+ DBG("Not implemented");
+
+ /* TODO */
+
+ return HAL_STATUS_FAILED;
+}
+
+static uint8_t get_device_timestamp(struct device *dev)
+{
+ DBG("Not implemented");
+
+ /* TODO */
+
+ return HAL_STATUS_FAILED;
+}
+
static void handle_get_remote_device_props_cmd(const void *buf, uint16_t len)
{
/* TODO */
@@ -2239,10 +2311,55 @@ static void handle_get_remote_device_props_cmd(const void *buf, uint16_t len)
static void handle_get_remote_device_prop_cmd(const void *buf, uint16_t len)
{
- /* TODO */
+ const struct hal_cmd_get_remote_device_prop *cmd = buf;
+ uint8_t status;
+ bdaddr_t addr;
+ GSList *l;
+ android2bdaddr(cmd->bdaddr, &addr);
+
+ l = g_slist_find_custom(devices, &addr, bdaddr_cmp);
+ if (!l) {
+ status = HAL_STATUS_INVALID;
+ goto failed;
+ }
+
+ switch (cmd->type) {
+ case HAL_PROP_DEVICE_NAME:
+ status = get_device_name(l->data);
+ break;
+ case HAL_PROP_DEVICE_UUIDS:
+ status = get_device_uuids(l->data);
+ break;
+ case HAL_PROP_DEVICE_CLASS:
+ status = get_device_class(l->data);
+ break;
+ case HAL_PROP_DEVICE_TYPE:
+ status = get_device_type(l->data);
+ break;
+ case HAL_PROP_DEVICE_SERVICE_REC:
+ status = get_device_service_rec(l->data);
+ break;
+ case HAL_PROP_DEVICE_FRIENDLY_NAME:
+ status = get_device_friendly_name(l->data);
+ break;
+ case HAL_PROP_DEVICE_RSSI:
+ status = get_device_rssi(l->data);
+ break;
+ case HAL_PROP_DEVICE_VERSION_INFO:
+ status = get_device_version_info(l->data);
+ break;
+ case HAL_PROP_DEVICE_TIMESTAMP:
+ status = get_device_timestamp(l->data);
+ break;
+ default:
+ status = HAL_STATUS_FAILED;
+ break;
+ }
+
+failed:
ipc_send_rsp(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_GET_REMOTE_DEVICE_PROP,
- HAL_STATUS_FAILED);
+ status);
}
static void handle_set_remote_device_prop_cmd(const void *buf, uint16_t len)
--
1.8.3.2
^ permalink raw reply related
* [PATCH 4/8] android/bluetooth: Refactor send_remote_device_name_prop
From: Szymon Janc @ 2013-12-09 15:14 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1386602049-5533-1-git-send-email-szymon.janc@tieto.com>
Rename send_remote_device_name_prop to get_device_name and make it
accept struct device as parameter. Also return HAL status code.
This will allow to use this function also in get device property
command handler.
---
android/bluetooth.c | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index 4ceb40f..879cf8d 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -558,19 +558,16 @@ static void new_link_key_callback(uint16_t index, uint16_t length,
browse_remote_sdp(&addr->bdaddr);
}
-static void send_remote_device_name_prop(const bdaddr_t *bdaddr)
+static uint8_t get_device_name(struct device *dev)
{
struct hal_ev_remote_device_props *ev;
- struct device *dev;
size_t ev_len;
- dev = get_device(bdaddr);
-
ev_len = BASELEN_REMOTE_DEV_PROP + strlen(dev->name);
ev = g_malloc0(ev_len);
ev->status = HAL_STATUS_SUCCESS;
- bdaddr2android(bdaddr, ev->bdaddr);
+ bdaddr2android(&dev->bdaddr, ev->bdaddr);
ev->num_props = 1;
ev->props[0].type = HAL_PROP_DEVICE_NAME;
ev->props[0].len = strlen(dev->name);
@@ -580,6 +577,8 @@ static void send_remote_device_name_prop(const bdaddr_t *bdaddr)
ev_len, ev);
g_free(ev);
+
+ return HAL_STATUS_SUCCESS;
}
static void pin_code_request_callback(uint16_t index, uint16_t length,
@@ -598,7 +597,7 @@ static void pin_code_request_callback(uint16_t index, uint16_t length,
/* Workaround for Android Bluetooth.apk issue: send remote
* device property */
- send_remote_device_name_prop(&ev->addr.bdaddr);
+ get_device_name(get_device(&ev->addr.bdaddr));
set_device_bond_state(&ev->addr.bdaddr, HAL_STATUS_SUCCESS,
HAL_BOND_STATE_BONDING);
--
1.8.3.2
^ permalink raw reply related
* [PATCH 3/8] android/bluetooth: Fix coding style issue in set_device_bond_state
From: Szymon Janc @ 2013-12-09 15:14 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1386602049-5533-1-git-send-email-szymon.janc@tieto.com>
---
android/bluetooth.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index 3c27b74..4ceb40f 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -355,7 +355,8 @@ static void send_bond_state_change(const bdaddr_t *addr, uint8_t status,
}
static void set_device_bond_state(const bdaddr_t *addr, uint8_t status,
- int state) {
+ int state)
+{
struct device *dev;
--
1.8.3.2
^ permalink raw reply related
* [PATCH 2/8] android/bluetooth: Use single list for device caching
From: Szymon Janc @ 2013-12-09 15:14 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
In-Reply-To: <1386602049-5533-1-git-send-email-szymon.janc@tieto.com>
This makes code much simpler and easier to follow. It is also
a preparation for supporting remote device properties getting, setting
and storing.
---
android/bluetooth.c | 140 ++++++++++++++++++----------------------------------
1 file changed, 49 insertions(+), 91 deletions(-)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index e2fa211..3c27b74 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -111,9 +111,42 @@ static const uint16_t uuid_list[] = {
0
};
-static GSList *found_devices = NULL;
static GSList *devices = NULL;
+static int bdaddr_cmp(gconstpointer a, gconstpointer b)
+{
+ const bdaddr_t *bda = a;
+ const bdaddr_t *bdb = b;
+
+ return bacmp(bdb, bda);
+}
+
+static struct device *get_device(const bdaddr_t *bdaddr)
+{
+ struct device *dev;
+ char addr[18];
+ GSList *l;
+
+ l = g_slist_find_custom(devices, bdaddr, bdaddr_cmp);
+ if (l)
+ return dev = l->data;
+
+ ba2str(bdaddr, addr);
+ DBG("new device: %s", addr);
+
+ dev = g_new0(struct device, 1);
+
+ bacpy(&dev->bdaddr, bdaddr);
+ dev->bond_state = HAL_BOND_STATE_NONE;
+
+ /* use address for name, will be change if one is present
+ * eg. in EIR or set by set_property. */
+ dev->name = g_strdup(addr);
+ devices = g_slist_prepend(devices, dev);
+
+ return dev;
+}
+
static void adapter_name_changed(const uint8_t *name)
{
struct hal_ev_adapter_props_changed *ev;
@@ -308,14 +341,6 @@ static void store_link_key(const bdaddr_t *dst, const uint8_t *key,
}
-static int bdaddr_cmp(gconstpointer a, gconstpointer b)
-{
- const bdaddr_t *bda = a;
- const bdaddr_t *bdb = b;
-
- return bacmp(bdb, bda);
-}
-
static void send_bond_state_change(const bdaddr_t *addr, uint8_t status,
uint8_t state)
{
@@ -329,46 +354,12 @@ static void send_bond_state_change(const bdaddr_t *addr, uint8_t status,
sizeof(ev), &ev);
}
-static void cache_device_name(const bdaddr_t *addr, const char *name)
-{
- struct device *dev = NULL;
- GSList *l;
-
- l = g_slist_find_custom(devices, addr, bdaddr_cmp);
- if (l)
- dev = l->data;
-
- if (!dev) {
- dev = g_new0(struct device, 1);
- bacpy(&dev->bdaddr, addr);
- dev->bond_state = HAL_BOND_STATE_NONE;
- devices = g_slist_prepend(devices, dev);
- }
-
- if (!g_strcmp0(dev->name, name))
- return;
-
- g_free(dev->name);
- dev->name = g_strdup(name);
- /*TODO: Do some real caching here */
-}
-
static void set_device_bond_state(const bdaddr_t *addr, uint8_t status,
int state) {
- struct device *dev = NULL;
- GSList *l;
-
- l = g_slist_find_custom(devices, addr, bdaddr_cmp);
- if (l)
- dev = l->data;
+ struct device *dev;
- if (!dev) {
- dev = g_new0(struct device, 1);
- bacpy(&dev->bdaddr, addr);
- dev->bond_state = HAL_BOND_STATE_NONE;
- devices = g_slist_prepend(devices, dev);
- }
+ dev = get_device(addr);
if (dev->bond_state != state) {
dev->bond_state = state;
@@ -566,42 +557,23 @@ static void new_link_key_callback(uint16_t index, uint16_t length,
browse_remote_sdp(&addr->bdaddr);
}
-static const char *get_device_name(const bdaddr_t *addr)
-{
- GSList *l;
-
- l = g_slist_find_custom(devices, addr, bdaddr_cmp);
- if (l) {
- struct device *dev = l->data;
- return dev->name;
- }
-
- return NULL;
-}
-
static void send_remote_device_name_prop(const bdaddr_t *bdaddr)
{
struct hal_ev_remote_device_props *ev;
- const char *name;
+ struct device *dev;
size_t ev_len;
- char dst[18];
- /* Use cached name or bdaddr string */
- name = get_device_name(bdaddr);
- if (!name) {
- ba2str(bdaddr, dst);
- name = dst;
- }
+ dev = get_device(bdaddr);
- ev_len = BASELEN_REMOTE_DEV_PROP + strlen(name);
+ ev_len = BASELEN_REMOTE_DEV_PROP + strlen(dev->name);
ev = g_malloc0(ev_len);
ev->status = HAL_STATUS_SUCCESS;
bdaddr2android(bdaddr, ev->bdaddr);
ev->num_props = 1;
ev->props[0].type = HAL_PROP_DEVICE_NAME;
- ev->props[0].len = strlen(name);
- memcpy(&ev->props[0].val, name, strlen(name));
+ ev->props[0].len = strlen(dev->name);
+ memcpy(&ev->props[0].val, dev->name, strlen(dev->name));
ipc_send_notif(HAL_SERVICE_ID_BLUETOOTH, HAL_EV_REMOTE_DEVICE_PROPS,
ev_len, ev);
@@ -749,14 +721,10 @@ static void mgmt_discovering_event(uint16_t index, uint16_t length,
DBG("new discovering state %u", ev->discovering);
- if (adapter.discovering) {
+ if (adapter.discovering)
cp.state = HAL_DISCOVERY_STATE_STARTED;
- } else {
- g_slist_free_full(found_devices, g_free);
- found_devices = NULL;
-
+ else
cp.state = HAL_DISCOVERY_STATE_STOPPED;
- }
ipc_send_notif(HAL_SERVICE_ID_BLUETOOTH,
HAL_EV_DISCOVERY_STATE_CHANGED, sizeof(cp), &cp);
@@ -793,10 +761,11 @@ static void update_found_device(const bdaddr_t *bdaddr, uint8_t bdaddr_type,
const uint8_t *data, uint8_t data_len)
{
uint8_t buf[BLUEZ_HAL_MTU];
- bool new_dev = false;
struct eir_data eir;
+ struct device *dev;
uint8_t *num_prop;
uint8_t opcode;
+ bool new_dev;
int size = 0;
int err;
@@ -809,20 +778,8 @@ static void update_found_device(const bdaddr_t *bdaddr, uint8_t bdaddr_type,
return;
}
- if (!g_slist_find_custom(found_devices, bdaddr, bdaddr_cmp)) {
- bdaddr_t *new_bdaddr;
- char addr[18];
-
- new_bdaddr = g_new0(bdaddr_t, 1);
- bacpy(new_bdaddr, bdaddr);
-
- found_devices = g_slist_prepend(found_devices, new_bdaddr);
-
- ba2str(new_bdaddr, addr);
- DBG("New device found: %s", addr);
-
- new_dev = true;
- }
+ new_dev = !g_slist_find_custom(devices, bdaddr, bdaddr_cmp);
+ dev = get_device(bdaddr);
if (new_dev) {
struct hal_ev_device_found *ev = (void *) buf;
@@ -863,7 +820,8 @@ static void update_found_device(const bdaddr_t *bdaddr, uint8_t bdaddr_type,
}
if (eir.name) {
- cache_device_name(bdaddr, eir.name);
+ g_free(dev->name);
+ dev->name = g_strdup(eir.name);
size += fill_hal_prop(buf + size, HAL_PROP_DEVICE_NAME,
strlen(eir.name), eir.name);
--
1.8.3.2
^ permalink raw reply related
* [PATCH 1/8] android/bluetooth: Rename functions to match adapter properties names
From: Szymon Janc @ 2013-12-09 15:14 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
This match adapter properties handling functions with properties names.
Will make code easier to understand and avoid clashes with remote
device properties functions.
---
android/bluetooth.c | 72 ++++++++++++++++++++++++++---------------------------
1 file changed, 36 insertions(+), 36 deletions(-)
diff --git a/android/bluetooth.c b/android/bluetooth.c
index 6174b1f..e2fa211 100644
--- a/android/bluetooth.c
+++ b/android/bluetooth.c
@@ -1133,7 +1133,7 @@ static void uuid16_to_uint128(uint16_t uuid, uint128_t *u128)
ntoh128(&uuid128.value.uuid128, u128);
}
-static uint8_t get_uuids(void)
+static uint8_t get_adapter_uuids(void)
{
struct hal_ev_adapter_props_changed *ev;
GSList *list = adapter.uuids;
@@ -1183,7 +1183,7 @@ static void remove_uuid_complete(uint8_t status, uint16_t length,
mgmt_dev_class_changed_event(adapter.index, length, param, NULL);
- get_uuids();
+ get_adapter_uuids();
}
static void remove_uuid(uint16_t uuid)
@@ -1209,7 +1209,7 @@ static void add_uuid_complete(uint8_t status, uint16_t length,
mgmt_dev_class_changed_event(adapter.index, length, param, NULL);
- get_uuids();
+ get_adapter_uuids();
}
static void add_uuid(uint8_t svc_hint, uint16_t uuid)
@@ -1378,7 +1378,7 @@ static uint8_t set_adapter_name(const uint8_t *name, uint16_t len)
return HAL_STATUS_FAILED;
}
-static uint8_t set_discoverable_timeout(const void *buf, uint16_t len)
+static uint8_t set_adapter_discoverable_timeout(const void *buf, uint16_t len)
{
const uint32_t *timeout = buf;
@@ -1691,7 +1691,7 @@ static bool set_discoverable(uint8_t mode, uint16_t timeout)
return false;
}
-static uint8_t get_address(void)
+static uint8_t get_adapter_address(void)
{
uint8_t buf[BASELEN_PROP_CHANGED + sizeof(bdaddr_t)];
struct hal_ev_adapter_props_changed *ev = (void *) buf;
@@ -1709,7 +1709,7 @@ static uint8_t get_address(void)
return HAL_STATUS_SUCCESS;
}
-static uint8_t get_name(void)
+static uint8_t get_adapter_name(void)
{
if (!adapter.name)
return HAL_STATUS_FAILED;
@@ -1720,7 +1720,7 @@ static uint8_t get_name(void)
}
-static uint8_t get_class(void)
+static uint8_t get_adapter_class(void)
{
DBG("");
@@ -1729,7 +1729,7 @@ static uint8_t get_class(void)
return HAL_STATUS_SUCCESS;
}
-static uint8_t get_type(void)
+static uint8_t get_adapter_type(void)
{
DBG("Not implemented");
@@ -1738,7 +1738,7 @@ static uint8_t get_type(void)
return HAL_STATUS_FAILED;
}
-static uint8_t get_service(void)
+static uint8_t get_adapter_service_rec(void)
{
DBG("Not implemented");
@@ -1747,7 +1747,7 @@ static uint8_t get_service(void)
return HAL_STATUS_FAILED;
}
-static uint8_t get_scan_mode(void)
+static uint8_t get_adapter_scan_mode(void)
{
DBG("");
@@ -1756,7 +1756,7 @@ static uint8_t get_scan_mode(void)
return HAL_STATUS_SUCCESS;
}
-static uint8_t get_devices(void)
+static uint8_t get_adapter_bonded_devices(void)
{
DBG("Not implemented");
@@ -1765,7 +1765,7 @@ static uint8_t get_devices(void)
return HAL_STATUS_FAILED;
}
-static uint8_t get_discoverable_timeout(void)
+static uint8_t get_adapter_discoverable_timeout(void)
{
struct hal_ev_adapter_props_changed *ev;
uint8_t buf[BASELEN_PROP_CHANGED + sizeof(uint32_t)];
@@ -1794,31 +1794,31 @@ static void handle_get_adapter_prop_cmd(const void *buf, uint16_t len)
switch (cmd->type) {
case HAL_PROP_ADAPTER_ADDR:
- status = get_address();
+ status = get_adapter_address();
break;
case HAL_PROP_ADAPTER_NAME:
- status = get_name();
+ status = get_adapter_name();
break;
case HAL_PROP_ADAPTER_UUIDS:
- status = get_uuids();
+ status = get_adapter_uuids();
break;
case HAL_PROP_ADAPTER_CLASS:
- status = get_class();
+ status = get_adapter_class();
break;
case HAL_PROP_ADAPTER_TYPE:
- status = get_type();
+ status = get_adapter_type();
break;
case HAL_PROP_ADAPTER_SERVICE_REC:
- status = get_service();
+ status = get_adapter_service_rec();
break;
case HAL_PROP_ADAPTER_SCAN_MODE:
- status = get_scan_mode();
+ status = get_adapter_scan_mode();
break;
case HAL_PROP_ADAPTER_BONDED_DEVICES:
- status = get_devices();
+ status = get_adapter_bonded_devices();
break;
case HAL_PROP_ADAPTER_DISC_TIMEOUT:
- status = get_discoverable_timeout();
+ status = get_adapter_discoverable_timeout();
break;
default:
status = HAL_STATUS_FAILED;
@@ -1828,17 +1828,17 @@ static void handle_get_adapter_prop_cmd(const void *buf, uint16_t len)
ipc_send_rsp(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_GET_ADAPTER_PROP, status);
}
-static void get_properties(void)
+static void get_adapter_properties(void)
{
- get_address();
- get_name();
- get_uuids();
- get_class();
- get_type();
- get_service();
- get_scan_mode();
- get_devices();
- get_discoverable_timeout();
+ get_adapter_address();
+ get_adapter_name();
+ get_adapter_uuids();
+ get_adapter_class();
+ get_adapter_type();
+ get_adapter_service_rec();
+ get_adapter_scan_mode();
+ get_adapter_bonded_devices();
+ get_adapter_discoverable_timeout();
}
static bool start_discovery(void)
@@ -1881,7 +1881,7 @@ static bool stop_discovery(void)
return false;
}
-static uint8_t set_scan_mode(const void *buf, uint16_t len)
+static uint8_t set_adapter_scan_mode(const void *buf, uint16_t len)
{
const uint8_t *mode = buf;
bool conn, disc, cur_conn, cur_disc;
@@ -1958,13 +1958,13 @@ static void handle_set_adapter_prop_cmd(const void *buf, uint16_t len)
switch (cmd->type) {
case HAL_PROP_ADAPTER_SCAN_MODE:
- status = set_scan_mode(cmd->val, cmd->len);
+ status = set_adapter_scan_mode(cmd->val, cmd->len);
break;
case HAL_PROP_ADAPTER_NAME:
status = set_adapter_name(cmd->val, cmd->len);
break;
case HAL_PROP_ADAPTER_DISC_TIMEOUT:
- status = set_discoverable_timeout(cmd->val, cmd->len);
+ status = set_adapter_discoverable_timeout(cmd->val, cmd->len);
break;
default:
DBG("Unhandled property type 0x%x", cmd->type);
@@ -2227,7 +2227,7 @@ static void handle_enable_cmd(const void *buf, uint16_t len)
/* Framework expects all properties to be emitted while
* enabling adapter */
- get_properties();
+ get_adapter_properties();
if (adapter.current_settings & MGMT_SETTING_POWERED) {
status = HAL_STATUS_DONE;
@@ -2265,7 +2265,7 @@ failed:
static void handle_get_adapter_props_cmd(const void *buf, uint16_t len)
{
- get_properties();
+ get_adapter_properties();
ipc_send_rsp(HAL_SERVICE_ID_BLUETOOTH, HAL_OP_GET_ADAPTER_PROPS,
HAL_STATUS_SUCCESS);
--
1.8.3.2
^ permalink raw reply related
* [PATCH] bnep: Remove unneeded assignment
From: Andrei Emeltchenko @ 2013-12-09 14:17 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
profiles/network/bnep.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/profiles/network/bnep.c b/profiles/network/bnep.c
index 0a719a2..912c0c2 100644
--- a/profiles/network/bnep.c
+++ b/profiles/network/bnep.c
@@ -88,7 +88,6 @@ static void free_bnep_connect(struct bnep_conn *bc)
}
g_free(bc);
- bc = NULL;
}
uint16_t bnep_service_id(const char *svc)
--
1.8.3.2
^ permalink raw reply related
* [PATCH] btmgmt: Remove unneeded code
From: Andrei Emeltchenko @ 2013-12-09 14:13 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
---
tools/btmgmt.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/tools/btmgmt.c b/tools/btmgmt.c
index 1d71d74..f31d8b1 100644
--- a/tools/btmgmt.c
+++ b/tools/btmgmt.c
@@ -555,7 +555,6 @@ static void user_confirm(uint16_t index, uint16_t len, const void *param,
rsp_len = strlen(rsp);
if (rsp[rsp_len - 1] == '\n') {
rsp[rsp_len - 1] = '\0';
- rsp_len--;
}
if (rsp[0] == 'y' || rsp[0] == 'Y')
--
1.8.3.2
^ permalink raw reply related
* [PATCH] android/socket: Use getsockopt to set buffer
From: Andrei Emeltchenko @ 2013-12-09 14:11 UTC (permalink / raw)
To: linux-bluetooth
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
Use buffer size similar to one returned by getsockopt for RFCOMM socket.
If getsockopt fails use default value 25400 which is half of the default
RFCOMM kernel buffer (50800) calculated in kernel as:
RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10
---
android/socket.c | 43 +++++++++++++++++++++++++++++++++++++------
1 file changed, 37 insertions(+), 6 deletions(-)
diff --git a/android/socket.c b/android/socket.c
index 9020874..b5f7b1d 100644
--- a/android/socket.c
+++ b/android/socket.c
@@ -52,6 +52,8 @@
#define SVC_HINT_OBEX 0x10
+#define SOCKET_BUFFER 25400 /* Half of the kernel buffer */
+
static bdaddr_t adapter_addr;
/* Simple list of RFCOMM server sockets */
@@ -71,9 +73,33 @@ struct rfcomm_sock {
bdaddr_t dst;
uint32_t service_handle;
+ unsigned char *buf;
+ int buf_size;
+
const struct profile_info *profile;
};
+static void rfsock_set_buffer(struct rfcomm_sock *rfsock)
+{
+ socklen_t len = sizeof(int);
+ int size;
+
+ if (getsockopt(rfsock->real_sock, SOL_SOCKET, SO_RCVBUF, &size, &len)
+ < 0) {
+ warn("getsockopt(SO_RCVBUF) failed: %s", strerror(errno));
+ /* Use default buffer */
+ size = SOCKET_BUFFER;
+ } else {
+ /* Kernel doubles this */
+ size /= 2;
+ }
+
+ DBG("Set buffer size %d", size);
+
+ rfsock->buf = g_malloc(size);
+ rfsock->buf_size = size;
+}
+
static struct rfcomm_sock *create_rfsock(int sock, int *hal_fd)
{
int fds[2] = {-1, -1};
@@ -90,6 +116,9 @@ static struct rfcomm_sock *create_rfsock(int sock, int *hal_fd)
*hal_fd = fds[1];
rfsock->real_sock = sock;
+ if (sock >= 0)
+ rfsock_set_buffer(rfsock);
+
return rfsock;
}
@@ -121,6 +150,9 @@ static void cleanup_rfsock(gpointer data)
if (rfsock->service_handle)
bt_adapter_remove_record(rfsock->service_handle);
+ if (rfsock->buf)
+ g_free(rfsock->buf);
+
g_free(rfsock);
}
@@ -487,7 +519,6 @@ static gboolean sock_stack_event_cb(GIOChannel *io, GIOCondition cond,
gpointer data)
{
struct rfcomm_sock *rfsock = data;
- unsigned char buf[1024];
int len, sent;
if (cond & G_IO_HUP) {
@@ -501,14 +532,14 @@ static gboolean sock_stack_event_cb(GIOChannel *io, GIOCondition cond,
goto fail;
}
- len = read(rfsock->fd, buf, sizeof(buf));
+ len = read(rfsock->fd, rfsock->buf, rfsock->buf_size);
if (len <= 0) {
error("read(): %s", strerror(errno));
/* Read again */
return TRUE;
}
- sent = try_write_all(rfsock->real_sock, buf, len);
+ sent = try_write_all(rfsock->real_sock, rfsock->buf, len);
if (sent < 0) {
error("write(): %s", strerror(errno));
goto fail;
@@ -526,7 +557,6 @@ static gboolean sock_rfcomm_event_cb(GIOChannel *io, GIOCondition cond,
gpointer data)
{
struct rfcomm_sock *rfsock = data;
- unsigned char buf[1024];
int len, sent;
if (cond & G_IO_HUP) {
@@ -540,14 +570,14 @@ static gboolean sock_rfcomm_event_cb(GIOChannel *io, GIOCondition cond,
goto fail;
}
- len = read(rfsock->real_sock, buf, sizeof(buf));
+ len = read(rfsock->real_sock, rfsock->buf, rfsock->buf_size);
if (len <= 0) {
error("read(): %s", strerror(errno));
/* Read again */
return TRUE;
}
- sent = try_write_all(rfsock->fd, buf, len);
+ sent = try_write_all(rfsock->fd, rfsock->buf, len);
if (sent < 0) {
error("write(): %s", strerror(errno));
goto fail;
@@ -866,6 +896,7 @@ static void sdp_search_cb(sdp_list_t *recs, int err, gpointer data)
}
rfsock->real_sock = g_io_channel_unix_get_fd(io);
+ rfsock_set_buffer(rfsock);
rfsock->channel = chan;
connections = g_list_append(connections, rfsock);
--
1.8.3.2
^ permalink raw reply related
* Crasher when cancelling pairing
From: Bastien Nocera @ 2013-12-09 13:16 UTC (permalink / raw)
To: linux-bluetooth
Heya,
When a remote pairing is cancelled, bluetoothd will go in a loop, or
crash.
1. Start pairing from a non-SSP remote device (such as my old phone)
2. Enter the PIN on the phone
3. When the RequestPinCode callback is called on the computer, kill the
agent (simple-agent for example).
4. bluetoothd goes in a loop or crashes as it does in:
https://bugzilla.redhat.com/show_bug.cgi?id=1027365
Applying this patch gives more reasonable backtraces:
diff --git a/src/agent.c b/src/agent.c
index bcba969..b292881 100644
--- a/src/agent.c
+++ b/src/agent.c
@@ -203,6 +203,8 @@ void agent_unref(struct agent *agent)
if (agent->ref > 0)
return;
+ g_assert (agent->ref == 0);
+
if (agent->request) {
DBusError err;
agent_pincode_cb pincode_cb;
And asserts nicely before looping forever:
bluetoothd[28090]: src/agent.c:agent_unref() 0x6c5f90: ref=-1
**
ERROR:src/agent.c:206:agent_unref: assertion failed: (agent->ref == 0)
The backtrace:
#0 0x00000033f2835c59 in raise () from /lib64/libc.so.6
#1 0x00000033f2837368 in abort () from /lib64/libc.so.6
#2 0x00007ffff7d000ed in _g_log_abort () from /lib64/libglib-2.0.so.0
#3 0x00007ffff7d1dc97 in g_assertion_message () from /lib64/libglib-2.0.so.0
#4 0x00007ffff7d1dcfa in g_assertion_message_expr () from /lib64/libglib-2.0.so.0
#5 0x00000000004529f4 in agent_unref (agent=0x6c5f90) at src/agent.c:206
#6 0x00000000004621d7 in pincode_cb (agent=<optimized out>, err=<optimized out>, pin=0x0, data=<optimized out>) at src/device.c:3979
#7 0x000000000045297d in agent_unref (agent=0x6c5f90) at src/agent.c:221
#8 0x00000000004621d7 in pincode_cb (agent=<optimized out>, err=<optimized out>, pin=0x0, data=<optimized out>) at src/device.c:3979
#9 0x0000000000452236 in pincode_reply (call=<optimized out>, user_data=0x6f2790) at src/agent.c:445
#10 0x00000033f780c782 in complete_pending_call_and_unlock (connection=connection@entry=0x6c6320, pending=0x6eb100, message=message@entry=0x6ce680) at dbus-connection.c:2314
#11 0x00000033f780f9b1 in dbus_connection_dispatch (connection=connection@entry=0x6c6320) at dbus-connection.c:4580
#12 0x0000000000474ea8 in message_dispatch (data=0x6c6320) at gdbus/mainloop.c:76
#13 0x00007ffff7cf9e43 in g_timeout_dispatch () from /lib64/libglib-2.0.so.0
#14 0x00007ffff7cf92a6 in g_main_context_dispatch () from /lib64/libglib-2.0.so.0
#15 0x00007ffff7cf9628 in g_main_context_iterate.isra.24 () from /lib64/libglib-2.0.so.0
#16 0x00007ffff7cf9a3a in g_main_loop_run () from /lib64/libglib-2.0.so.0
#17 0x000000000040a530 in main (argc=1, argv=0x7fffffffe518) at src/main.c:587
Cheers
^ permalink raw reply related
* [PATCH] adapter: Remove not needed struct adapter_keys
From: Szymon Janc @ 2013-12-09 10:11 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Szymon Janc
This is a leftover from using old storage format.
---
src/adapter.c | 21 ++++++++-------------
1 file changed, 8 insertions(+), 13 deletions(-)
diff --git a/src/adapter.c b/src/adapter.c
index 41f7bd6..8ec9e92 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -2196,11 +2196,6 @@ static const GDBusPropertyTable adapter_properties[] = {
{ }
};
-struct adapter_keys {
- struct btd_adapter *adapter;
- GSList *keys;
-};
-
static int str2buf(const char *str, uint8_t *buf, size_t blen)
{
int i, dlen;
@@ -2479,8 +2474,8 @@ static void load_devices(struct btd_adapter *adapter)
{
char filename[PATH_MAX + 1];
char srcaddr[18];
- struct adapter_keys keys = { adapter, NULL };
- struct adapter_keys ltks = { adapter, NULL };
+ GSList *keys = NULL;
+ GSList *ltks = NULL;
DIR *dir;
struct dirent *entry;
@@ -2514,11 +2509,11 @@ static void load_devices(struct btd_adapter *adapter)
key_info = get_key_info(key_file, entry->d_name);
if (key_info)
- keys.keys = g_slist_append(keys.keys, key_info);
+ keys = g_slist_append(keys, key_info);
ltk_info = get_ltk_info(key_file, entry->d_name);
if (ltk_info)
- ltks.keys = g_slist_append(ltks.keys, ltk_info);
+ ltks = g_slist_append(ltks, ltk_info);
list = g_slist_find_custom(adapter->devices, entry->d_name,
device_address_cmp);
@@ -2553,11 +2548,11 @@ free:
closedir(dir);
- load_link_keys(adapter, keys.keys, main_opts.debug_keys);
- g_slist_free_full(keys.keys, g_free);
+ load_link_keys(adapter, keys, main_opts.debug_keys);
+ g_slist_free_full(keys, g_free);
- load_ltks(adapter, ltks.keys);
- g_slist_free_full(ltks.keys, g_free);
+ load_ltks(adapter, ltks);
+ g_slist_free_full(ltks, g_free);
}
int btd_adapter_block_address(struct btd_adapter *adapter,
--
1.8.3.2
^ permalink raw reply related
* Re: [PATCH] obex: Fix checking incorrect error code
From: Luiz Augusto von Dentz @ 2013-12-09 9:56 UTC (permalink / raw)
To: Andrei Emeltchenko, linux-bluetooth@vger.kernel.org
In-Reply-To: <20131209080310.GC6506@aemeltch-MOBL1>
Hi Andrei,
On Mon, Dec 9, 2013 at 10:03 AM, Andrei Emeltchenko
<Andrei.Emeltchenko.news@gmail.com> wrote:
> ping
>
> On Tue, Dec 03, 2013 at 06:04:54PM +0200, Andrei Emeltchenko wrote:
>> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>>
>> chdir return -1 if error and 0 in success. Checking for > 0 is pointless.
>> ---
>> tools/obex-server-tool.c | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/tools/obex-server-tool.c b/tools/obex-server-tool.c
>> index e37c56f..86c2271 100644
>> --- a/tools/obex-server-tool.c
>> +++ b/tools/obex-server-tool.c
>> @@ -427,7 +427,7 @@ int main(int argc, char *argv[])
>> exit(EXIT_FAILURE);
>> }
>>
>> - if (option_root && chdir(option_root) > 0) {
>> + if (option_root && chdir(option_root) < 0) {
>> perror("chdir:");
>> exit(EXIT_FAILURE);
>> }
>> --
>> 1.8.3.2
Pushed, thanks.
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH] android: Fix missing failure check in ipc_init
From: Luiz Augusto von Dentz @ 2013-12-09 9:34 UTC (permalink / raw)
To: Szymon Janc; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <3479757.7T9GkbTkhq@uw000953>
Hi Szymon,
On Mon, Dec 9, 2013 at 10:55 AM, Szymon Janc <szymon.janc@tieto.com> wrote:
>
>> If connecting command socket failed daemon should be terminated.
>> ---
>> android/ipc.c | 2 ++
>> 1 file changed, 2 insertions(+)
>>
>> diff --git a/android/ipc.c b/android/ipc.c
>> index 1d369a8..6f940cd 100644
>> --- a/android/ipc.c
>> +++ b/android/ipc.c
>> @@ -229,6 +229,8 @@ static gboolean cmd_connect_cb(GIOChannel *io, GIOCondition cond,
>> void ipc_init(void)
>> {
>> cmd_io = connect_hal(cmd_connect_cb);
>> + if (!cmd_io)
>> + raise(SIGTERM);
>> }
>>
>> void ipc_cleanup(void)
>>
Applied, thanks.
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH] android: Fix missing failure check in ipc_init
From: Szymon Janc @ 2013-12-09 8:55 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386074528-8020-1-git-send-email-szymon.janc@tieto.com>
> If connecting command socket failed daemon should be terminated.
> ---
> android/ipc.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/android/ipc.c b/android/ipc.c
> index 1d369a8..6f940cd 100644
> --- a/android/ipc.c
> +++ b/android/ipc.c
> @@ -229,6 +229,8 @@ static gboolean cmd_connect_cb(GIOChannel *io, GIOCondition cond,
> void ipc_init(void)
> {
> cmd_io = connect_hal(cmd_connect_cb);
> + if (!cmd_io)
> + raise(SIGTERM);
> }
>
> void ipc_cleanup(void)
>
ping
^ permalink raw reply
* Re: [PATCH] obex: Fix checking incorrect error code
From: Andrei Emeltchenko @ 2013-12-09 8:03 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386086694-22682-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
ping
On Tue, Dec 03, 2013 at 06:04:54PM +0200, Andrei Emeltchenko wrote:
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> chdir return -1 if error and 0 in success. Checking for > 0 is pointless.
> ---
> tools/obex-server-tool.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/tools/obex-server-tool.c b/tools/obex-server-tool.c
> index e37c56f..86c2271 100644
> --- a/tools/obex-server-tool.c
> +++ b/tools/obex-server-tool.c
> @@ -427,7 +427,7 @@ int main(int argc, char *argv[])
> exit(EXIT_FAILURE);
> }
>
> - if (option_root && chdir(option_root) > 0) {
> + if (option_root && chdir(option_root) < 0) {
> perror("chdir:");
> exit(EXIT_FAILURE);
> }
> --
> 1.8.3.2
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 1/6] android/a2dp: Fix possible NULL dereference
From: Andrei Emeltchenko @ 2013-12-09 8:01 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <CABBYNZ+pmDkN0EHuycjtSxaAfW0ZT94OtN7TRK1+pBo99ydM+g@mail.gmail.com>
Hi Luiz,
On Sun, Dec 08, 2013 at 05:39:37PM +0200, Luiz Augusto von Dentz wrote:
> I fixed this myself and applied 1-4, patch 5 is actually wrong since
> sdp_next_handle may return values bellow 0x10000 if we run out of
OK
> handles and patch 6 is not necessary since what is in android/avdtp.c
> is what we will be using in the future.
How are we going to use those local vars? If they would be global it probably
make some (little) sense ...
@@ -773,10 +773,9 @@ static int get_send_buffer_size(int sk)
socklen_t optlen = sizeof(size);
if (getsockopt(sk, SOL_SOCKET, SO_SNDBUF, &size, &optlen) < 0) {
- int err = -errno;
- error("getsockopt(SO_SNDBUF) failed: %s (%d)", strerror(-err),
- -err);
- return err;
+ error("getsockopt(SO_SNDBUF) failed: %s (%d)", strerror(errno),
+ errno);
+ return -errno;
}
/*
Regards,
Andrei
^ permalink raw reply
* Re: [PATCH] Bluetooth: Use macros for connectionless slave broadcast features
From: Johan Hedberg @ 2013-12-08 20:03 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: linux-bluetooth
In-Reply-To: <1386532533-48770-1-git-send-email-marcel@holtmann.org>
Hi Marcel,
On Sun, Dec 08, 2013, Marcel Holtmann wrote:
> Add the LMP feature constants for connectionless slave broadcast
> and use them for capability testing.
>
> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
> ---
> include/net/bluetooth/hci.h | 6 ++++++
> include/net/bluetooth/hci_core.h | 6 ++++++
> net/bluetooth/hci_core.c | 6 +++---
> 3 files changed, 15 insertions(+), 3 deletions(-)
Applied to bluetooth-next. Thanks.
Johan
^ permalink raw reply
* [PATCH] Bluetooth: Use macros for connectionless slave broadcast features
From: Marcel Holtmann @ 2013-12-08 19:55 UTC (permalink / raw)
To: linux-bluetooth
Add the LMP feature constants for connectionless slave broadcast
and use them for capability testing.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
include/net/bluetooth/hci.h | 6 ++++++
include/net/bluetooth/hci_core.h | 6 ++++++
net/bluetooth/hci_core.c | 6 +++---
3 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 1784c48699f0..cc2da73055fa 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -275,6 +275,12 @@ enum {
#define LMP_EXTFEATURES 0x80
/* Extended LMP features */
+#define LMP_CSB_MASTER 0x01
+#define LMP_CSB_SLAVE 0x02
+#define LMP_SYNC_TRAIN 0x04
+#define LMP_SYNC_SCAN 0x08
+
+/* Host features */
#define LMP_HOST_SSP 0x01
#define LMP_HOST_LE 0x02
#define LMP_HOST_LE_BREDR 0x04
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index f8555ad7b104..b796161fb04e 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -798,6 +798,12 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
#define lmp_transp_capable(dev) ((dev)->features[0][2] & LMP_TRANSPARENT)
/* ----- Extended LMP capabilities ----- */
+#define lmp_csb_master_capable(dev) ((dev)->features[2][0] & LMP_CSB_MASTER)
+#define lmp_csb_slave_capable(dev) ((dev)->features[2][0] & LMP_CSB_SLAVE)
+#define lmp_sync_train_capable(dev) ((dev)->features[2][0] & LMP_SYNC_TRAIN)
+#define lmp_sync_scan_capable(dev) ((dev)->features[2][0] & LMP_SYNC_SCAN)
+
+/* ----- Host capabilities ----- */
#define lmp_host_ssp_capable(dev) ((dev)->features[1][0] & LMP_HOST_SSP)
#define lmp_host_le_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE))
#define lmp_host_le_br_capable(dev) (!!((dev)->features[1][0] & LMP_HOST_LE_BREDR))
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 03e83558a411..8b8b5f80dd89 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1228,7 +1228,7 @@ static void hci_set_event_mask_page_2(struct hci_request *req)
/* If Connectionless Slave Broadcast master role is supported
* enable all necessary events for it.
*/
- if (hdev->features[2][0] & 0x01) {
+ if (lmp_csb_master_capable(hdev)) {
events[1] |= 0x40; /* Triggered Clock Capture */
events[1] |= 0x80; /* Synchronization Train Complete */
events[2] |= 0x10; /* Slave Page Response Timeout */
@@ -1238,7 +1238,7 @@ static void hci_set_event_mask_page_2(struct hci_request *req)
/* If Connectionless Slave Broadcast slave role is supported
* enable all necessary events for it.
*/
- if (hdev->features[2][0] & 0x02) {
+ if (lmp_csb_slave_capable(hdev)) {
events[2] |= 0x01; /* Synchronization Train Received */
events[2] |= 0x02; /* CSB Receive */
events[2] |= 0x04; /* CSB Timeout */
@@ -1309,7 +1309,7 @@ static void hci_init4_req(struct hci_request *req, unsigned long opt)
hci_set_event_mask_page_2(req);
/* Check for Synchronization Train support */
- if (hdev->features[2][0] & 0x04)
+ if (lmp_sync_train_capable(hdev))
hci_req_add(req, HCI_OP_READ_SYNC_TRAIN_PARAMS, 0, NULL);
}
--
1.8.3.1
^ permalink raw reply related
* Re: [PATCHv2] android: Fix delayed adapter turn off
From: Luiz Augusto von Dentz @ 2013-12-08 16:07 UTC (permalink / raw)
To: Jakub Tyszkowski; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <1386343854-1529-1-git-send-email-jakub.tyszkowski@tieto.com>
Hi Jakub,
On Fri, Dec 6, 2013 at 5:30 PM, Jakub Tyszkowski
<jakub.tyszkowski@tieto.com> wrote:
> We shouldn't care about pending actions being completed as we want to
> turn BT off. This fixes Android UI controlls being locked when BT off
> action waits in queue for to long.
>
> ---
> android/bluetooth.c | 28 ++++++++++++++++++++--------
> 1 file changed, 20 insertions(+), 8 deletions(-)
>
> diff --git a/android/bluetooth.c b/android/bluetooth.c
> index 6174b1f..e5d8b7a 100644
> --- a/android/bluetooth.c
> +++ b/android/bluetooth.c
> @@ -1290,17 +1290,24 @@ static void set_mode_complete(uint8_t status, uint16_t length,
> new_settings_callback(adapter.index, length, param, NULL);
> }
>
> -static bool set_mode(uint16_t opcode, uint8_t mode)
> +static bool set_mode(uint16_t opcode, uint8_t mode, bool unqueued)
> {
> struct mgmt_mode cp;
> + unsigned int mgmt_result;
>
> memset(&cp, 0, sizeof(cp));
> cp.val = mode;
>
> DBG("opcode=0x%x mode=0x%x", opcode, mode);
>
> - if (mgmt_send(mgmt_if, opcode, adapter.index, sizeof(cp), &cp,
> - set_mode_complete, NULL, NULL) > 0)
> + if (unqueued)
> + mgmt_result = mgmt_reply(mgmt_if, opcode, adapter.index,
> + sizeof(cp), &cp, set_mode_complete, NULL, NULL);
> + else
> + mgmt_result = mgmt_send(mgmt_if, opcode, adapter.index,
> + sizeof(cp), &cp, set_mode_complete, NULL, NULL);
> +
> + if (mgmt_result > 0)
> return true;
>
> error("Failed to set mode");
> @@ -1462,10 +1469,10 @@ static void read_info_complete(uint8_t status, uint16_t length,
> missing_settings = adapter.current_settings ^ supported_settings;
>
> if (missing_settings & MGMT_SETTING_SSP)
> - set_mode(MGMT_OP_SET_SSP, 0x01);
> + set_mode(MGMT_OP_SET_SSP, 0x01, false);
>
> if (missing_settings & MGMT_SETTING_PAIRABLE)
> - set_mode(MGMT_OP_SET_PAIRABLE, 0x01);
> + set_mode(MGMT_OP_SET_PAIRABLE, 0x01, false);
>
> return;
>
> @@ -1926,7 +1933,8 @@ static uint8_t set_scan_mode(const void *buf, uint16_t len)
> }
>
> if (cur_conn != conn) {
> - if (!set_mode(MGMT_OP_SET_CONNECTABLE, conn ? 0x01 : 0x00))
> + if (!set_mode(MGMT_OP_SET_CONNECTABLE, conn ? 0x01 : 0x00,
> + false))
> return HAL_STATUS_FAILED;
> }
>
> @@ -2234,7 +2242,7 @@ static void handle_enable_cmd(const void *buf, uint16_t len)
> goto failed;
> }
>
> - if (!set_mode(MGMT_OP_SET_POWERED, 0x01)) {
> + if (!set_mode(MGMT_OP_SET_POWERED, 0x01, false)) {
> status = HAL_STATUS_FAILED;
> goto failed;
> }
> @@ -2253,7 +2261,11 @@ static void handle_disable_cmd(const void *buf, uint16_t len)
> goto failed;
> }
>
> - if (!set_mode(MGMT_OP_SET_POWERED, 0x00)) {
> + /*
> + * Prioritize BT turn off as not doing it in time makes Android
> + * unstable and locks Bluetooth UI controlls.
> + */
> + if (!set_mode(MGMT_OP_SET_POWERED, 0x00, true)) {
> status = HAL_STATUS_FAILED;
> goto failed;
> }
> --
> 1.8.5
Ive applied all the patches from this set except this one, it seems
you are misusing mgmt_reply is for actual replies and this one seems
to be a request. We should probably store pending handles and cancel
them properly if is the case here.
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH 1/6] android/a2dp: Fix possible NULL dereference
From: Luiz Augusto von Dentz @ 2013-12-08 15:39 UTC (permalink / raw)
To: Andrei Emeltchenko, Luiz Augusto von Dentz,
linux-bluetooth@vger.kernel.org
In-Reply-To: <20131204083622.GA18198@aemeltch-MOBL1>
Hi Andrei,
On Wed, Dec 4, 2013 at 10:36 AM, Andrei Emeltchenko
<Andrei.Emeltchenko.news@gmail.com> wrote:
> Hi Luiz,
>
> On Tue, Dec 03, 2013 at 09:53:43PM +0200, Luiz Augusto von Dentz wrote:
>> Hi Andrei,
>>
>> On Tue, Dec 3, 2013 at 5:53 PM, Andrei Emeltchenko
>> <Andrei.Emeltchenko.news@gmail.com> wrote:
>> > From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>> >
>> > Since a2dp_record may return NULL, check return value. This
>> > silences static analysers tools.
>> > ---
>> > android/a2dp.c | 5 +++--
>> > 1 file changed, 3 insertions(+), 2 deletions(-)
>> >
>> > diff --git a/android/a2dp.c b/android/a2dp.c
>> > index cee4bfa..36a0714 100644
>> > --- a/android/a2dp.c
>> > +++ b/android/a2dp.c
>> > @@ -366,9 +366,10 @@ bool bt_a2dp_register(const bdaddr_t *addr)
>> > }
>> >
>> > rec = a2dp_record();
>> > - if (bt_adapter_add_record(rec, SVC_HINT_CAPTURING) < 0) {
>> > + if (!rec || bt_adapter_add_record(rec, SVC_HINT_CAPTURING) < 0) {
>>
>> Usually we check the return individually, that means you do if (rec)
>> and perhaps handle the error path with goto, but first make sure that
>> a2dp_record can actually fail otherwise this is pointless.
>
> It might return NULL if malloc fails, do you think that we need to change
> malloc to g_malloc in sdp code. Otherwise every tools warns about NULL
> dereference.
>
> Best regards
> Andrei Emeltchenko
>
>>
>> > error("Failed to register on A2DP record");
>> > - sdp_record_free(rec);
>> > + if (rec)
>> > + sdp_record_free(rec);
>> > g_io_channel_shutdown(server, TRUE, NULL);
>> > g_io_channel_unref(server);
>> > server = NULL;
>> > --
>> > 1.8.3.2
>> >
>> > --
>> > To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
>> > the body of a message to majordomo@vger.kernel.org
>> > More majordomo info at http://vger.kernel.org/majordomo-info.html
I fixed this myself and applied 1-4, patch 5 is actually wrong since
sdp_next_handle may return values bellow 0x10000 if we run out of
handles and patch 6 is not necessary since what is in android/avdtp.c
is what we will be using in the future.
--
Luiz Augusto von Dentz
^ permalink raw reply
* [PATCH v6 5/5] Bluetooth: Manually enable or disable 6LoWPAN between devices
From: Jukka Rissanen @ 2013-12-08 11:10 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386501056-2555-1-git-send-email-jukka.rissanen@linux.intel.com>
This is a temporary patch where user can manually enable or
disable BT 6LoWPAN functionality between devices.
Eventually the connection is established automatically if
the devices are advertising suitable capability and this patch
can be removed.
Before connecting the devices do this
echo 1 > /sys/kernel/debug/bluetooth/hci0/6lowpan
This enables 6LoWPAN support and creates the bt0 interface
automatically when devices are finally connected.
Rebooting or unloading the bluetooth kernel module will also clear the
settings from the kernel.
Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
---
net/bluetooth/hci_core.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 93 insertions(+)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 03e8355..0a2ec42 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -636,6 +636,97 @@ static int conn_max_interval_get(void *data, u64 *val)
DEFINE_SIMPLE_ATTRIBUTE(conn_max_interval_fops, conn_max_interval_get,
conn_max_interval_set, "%llu\n");
+static LIST_HEAD(lowpan_user_enabled);
+static DEFINE_RWLOCK(lowpan_enabled_lock);
+
+struct lowpan_enabled {
+ __u8 dev_name[HCI_MAX_NAME_LENGTH];
+ bool enabled;
+ struct list_head list;
+};
+
+static int lowpan_debugfs_show(struct seq_file *f, void *p)
+{
+ struct hci_dev *hdev = f->private;
+
+ if (test_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags))
+ seq_printf(f, "1\n");
+ else
+ seq_printf(f, "0\n");
+
+ return 0;
+}
+
+static int lowpan_debugfs_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, lowpan_debugfs_show, inode->i_private);
+}
+
+static ssize_t lowpan_writer(struct file *fp, const char __user *user_buffer,
+ size_t count, loff_t *position)
+{
+ struct hci_dev *hdev = fp->f_inode->i_private;
+ struct lowpan_enabled *entry = NULL, *tmp;
+ bool new_value, old_value;
+ char buf[3] = { 0 };
+ ssize_t ret;
+
+ BT_DBG("dev %s count %zd", hdev->dev_name, count);
+
+ ret = simple_write_to_buffer(buf, 2, position, user_buffer, count);
+ if (ret <= 0)
+ return ret;
+
+ if (strtobool(buf, &new_value) < 0)
+ return -EINVAL;
+
+ ret = -ENOENT;
+
+ write_lock(&lowpan_enabled_lock);
+ list_for_each_entry_safe(entry, tmp, &lowpan_user_enabled, list) {
+ if (!strncmp(entry->dev_name, hdev->dev_name,
+ HCI_MAX_NAME_LENGTH)) {
+ old_value = entry->enabled;
+ entry->enabled = new_value;
+ ret = 0;
+ break;
+ }
+ }
+ write_unlock(&lowpan_enabled_lock);
+
+ if (ret == 0 && old_value == new_value)
+ return count;
+
+ if (ret < 0) {
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
+ strncpy(entry->dev_name, hdev->dev_name, HCI_MAX_NAME_LENGTH);
+ entry->enabled = new_value;
+
+ write_lock(&lowpan_enabled_lock);
+ INIT_LIST_HEAD(&entry->list);
+ list_add(&entry->list, &lowpan_user_enabled);
+ write_unlock(&lowpan_enabled_lock);
+ }
+
+ if (new_value == true)
+ set_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags);
+ else
+ clear_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags);
+
+ return count;
+}
+
+static const struct file_operations lowpan_debugfs_fops = {
+ .open = lowpan_debugfs_open,
+ .read = seq_read,
+ .write = lowpan_writer,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
/* ---- HCI requests ---- */
static void hci_req_sync_complete(struct hci_dev *hdev, u8 result)
@@ -1406,6 +1497,8 @@ static int __hci_init(struct hci_dev *hdev)
hdev, &conn_min_interval_fops);
debugfs_create_file("conn_max_interval", 0644, hdev->debugfs,
hdev, &conn_max_interval_fops);
+ debugfs_create_file("6lowpan", 0644, hdev->debugfs, hdev,
+ &lowpan_debugfs_fops);
}
return 0;
--
1.8.3.1
^ permalink raw reply related
* [PATCH v6 4/5] Bluetooth: Enable 6LoWPAN support for BT LE devices
From: Jukka Rissanen @ 2013-12-08 11:10 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386501056-2555-1-git-send-email-jukka.rissanen@linux.intel.com>
Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
---
include/net/bluetooth/hci.h | 1 +
include/net/bluetooth/hci_core.h | 1 +
include/net/bluetooth/l2cap.h | 1 +
net/bluetooth/6lowpan.c | 881 +++++++++++++++++++++++++++++++++++++++
net/bluetooth/6lowpan.h | 26 ++
net/bluetooth/Makefile | 6 +-
net/bluetooth/hci_event.c | 3 +
net/bluetooth/l2cap_core.c | 14 +-
8 files changed, 931 insertions(+), 2 deletions(-)
create mode 100644 net/bluetooth/6lowpan.c
create mode 100644 net/bluetooth/6lowpan.h
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 1784c48..f8f8447 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -131,6 +131,7 @@ enum {
HCI_PERIODIC_INQ,
HCI_FAST_CONNECTABLE,
HCI_BREDR_ENABLED,
+ HCI_6LOWPAN_ENABLED,
};
/* A mask for the flags that are supposed to remain when a reset happens
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index f8555ad7..feae070 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -448,6 +448,7 @@ enum {
HCI_CONN_SSP_ENABLED,
HCI_CONN_POWER_SAVE,
HCI_CONN_REMOTE_OOB,
+ HCI_CONN_6LOWPAN,
};
static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index e149e99..dbc4a89 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -136,6 +136,7 @@ struct l2cap_conninfo {
#define L2CAP_FC_L2CAP 0x02
#define L2CAP_FC_CONNLESS 0x04
#define L2CAP_FC_A2MP 0x08
+#define L2CAP_FC_6LOWPAN 0x3e /* reserved and temporary value */
/* L2CAP Control Field bit masks */
#define L2CAP_CTRL_SAR 0xC000
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
new file mode 100644
index 0000000..5b6966a
--- /dev/null
+++ b/net/bluetooth/6lowpan.c
@@ -0,0 +1,881 @@
+/*
+ Copyright (c) 2013 Intel Corp.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 and
+ only version 2 as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+*/
+
+#include <linux/version.h>
+#include <linux/if_arp.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+#include <net/addrconf.h>
+
+#include <net/af_ieee802154.h> /* to get the address type */
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/l2cap.h>
+
+#include "../ieee802154/6lowpan.h" /* for the compression support */
+
+#define IFACE_NAME_TEMPLATE "bt%d"
+#define EUI64_ADDR_LEN 8
+
+struct skb_cb {
+ struct in6_addr addr;
+ struct l2cap_conn *conn;
+};
+#define lowpan_cb(skb) ((struct skb_cb *)((skb)->cb))
+
+/*
+ * The devices list contains those devices that we are acting
+ * as a proxy. The BT 6LoWPAN device is a virtual device that
+ * connects to the Bluetooth LE device. The real connection to
+ * BT device is done via l2cap layer. There exists one
+ * virtual device / one BT 6LoWPAN network (=hciX device).
+ * The list contains struct lowpan_dev elements.
+ */
+static LIST_HEAD(bt_6lowpan_devices);
+static DEFINE_RWLOCK(devices_lock);
+
+struct lowpan_dev {
+ struct net_device *dev;
+ struct work_struct delete_netdev;
+ struct list_head list;
+};
+
+struct lowpan_peer {
+ struct list_head list;
+ struct l2cap_conn *conn;
+
+ /* peer addresses in various formats */
+ unsigned char eui64_addr[EUI64_ADDR_LEN];
+ struct in6_addr peer_addr;
+};
+
+struct lowpan_info {
+ struct net_device *net;
+ struct list_head peers;
+ atomic_t peer_count; /* number of items in peers list */
+
+ struct delayed_work notify_peers;
+};
+
+static inline struct lowpan_info *lowpan_info(const struct net_device *dev)
+{
+ return netdev_priv(dev);
+}
+
+static inline void peer_add(struct lowpan_info *info, struct lowpan_peer *peer)
+{
+ list_add(&peer->list, &info->peers);
+ atomic_inc(&info->peer_count);
+}
+
+static inline bool peer_del(struct lowpan_info *info, struct lowpan_peer *peer)
+{
+ list_del(&peer->list);
+ if (atomic_dec_and_test(&info->peer_count)) {
+ BT_DBG("last peer");
+ return true;
+ }
+
+ return false;
+}
+
+static inline struct lowpan_peer *peer_lookup_ba(struct lowpan_info *info,
+ bdaddr_t *ba, __u8 type)
+{
+ struct lowpan_peer *peer, *tmp;
+
+ BT_DBG("peers %d addr %pMR type %d", atomic_read(&info->peer_count),
+ ba, type);
+
+ list_for_each_entry_safe(peer, tmp, &info->peers, list) {
+ BT_DBG("addr %pMR type %d",
+ &peer->conn->hcon->dst, peer->conn->hcon->dst_type);
+
+ if (!bacmp(&peer->conn->hcon->dst, ba))
+ return peer;
+ }
+
+ return NULL;
+}
+
+static inline struct lowpan_peer *peer_lookup_conn(struct lowpan_info *info,
+ struct l2cap_conn *conn)
+{
+ struct lowpan_peer *peer, *tmp;
+
+ list_for_each_entry_safe(peer, tmp, &info->peers, list) {
+ if (peer->conn == conn)
+ return peer;
+ }
+
+ return NULL;
+}
+
+static struct lowpan_peer *lookup_peer(struct l2cap_conn *conn,
+ struct lowpan_info **dev)
+{
+ struct lowpan_dev *entry, *tmp;
+ struct lowpan_peer *peer = NULL;
+ unsigned long flags;
+
+ read_lock_irqsave(&devices_lock, flags);
+
+ list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
+ struct lowpan_info *info = lowpan_info(entry->dev);
+
+ peer = peer_lookup_conn(info, conn);
+ if (peer) {
+ if (dev)
+ *dev = info;
+ break;
+ }
+ }
+
+ read_unlock_irqrestore(&devices_lock, flags);
+
+ return peer;
+}
+
+/* print data in line */
+static inline void raw_dump_inline(const char *caller, char *msg,
+ unsigned char *buf, int len)
+{
+ if (msg)
+ pr_debug("%s():%s: ", caller, msg);
+ print_hex_dump_debug("", DUMP_PREFIX_NONE,
+ 16, 1, buf, len, false);
+}
+
+/*
+ * print data in a table format:
+ *
+ * addr: xx xx xx xx xx xx
+ * addr: xx xx xx xx xx xx
+ * ...
+ */
+static inline void raw_dump_table(const char *caller, char *msg,
+ unsigned char *buf, int len)
+{
+ if (msg)
+ pr_debug("%s():%s:\n", caller, msg);
+ print_hex_dump_debug("\t", DUMP_PREFIX_OFFSET,
+ 16, 1, buf, len, false);
+}
+
+static int 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 int process_data(struct sk_buff *skb, struct net_device *dev,
+ struct l2cap_conn *conn)
+{
+ const u8 *saddr, *daddr;
+ u8 iphc0, iphc1;
+ struct lowpan_info *info;
+ struct lowpan_peer *peer;
+ unsigned long flags;
+
+ info = lowpan_info(dev);
+
+ read_lock_irqsave(&devices_lock, flags);
+ peer = peer_lookup_conn(info, conn);
+ read_unlock_irqrestore(&devices_lock, flags);
+ if (!peer)
+ return -EINVAL;
+
+ saddr = peer->eui64_addr;
+ daddr = info->net->dev_addr;
+
+ /* at least two bytes will be used for the encoding */
+ if (skb->len < 2)
+ goto drop;
+
+ if (lowpan_fetch_skb_u8(skb, &iphc0))
+ goto drop;
+
+ if (lowpan_fetch_skb_u8(skb, &iphc1))
+ goto drop;
+
+ return lowpan_process_data(skb, dev,
+ saddr, IEEE802154_ADDR_LONG, EUI64_ADDR_LEN,
+ daddr, IEEE802154_ADDR_LONG, EUI64_ADDR_LEN,
+ iphc0, iphc1, give_skb_to_upper);
+
+drop:
+ kfree_skb(skb);
+ return -EINVAL;
+}
+
+static int recv_pkt(struct sk_buff *skb, struct net_device *dev,
+ struct l2cap_conn *conn)
+{
+ struct sk_buff *local_skb;
+
+ if (!netif_running(dev))
+ goto drop;
+
+ if (dev->type != ARPHRD_6LOWPAN)
+ goto drop;
+
+ /* 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 (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 */
+ local_skb = skb_clone(skb, GFP_ATOMIC);
+ if (!local_skb)
+ goto drop;
+ if (process_data(local_skb, dev, conn)
+ != 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;
+}
+
+/* Packet from BT LE device */
+int bt_6lowpan_recv(struct l2cap_conn *conn, struct sk_buff *skb)
+{
+ struct lowpan_info *info = NULL;
+ struct lowpan_peer *peer;
+ int err;
+
+ peer = lookup_peer(conn, &info);
+ if (!peer)
+ return -ENOENT;
+
+ if (info->net) {
+ err = recv_pkt(skb, info->net, conn);
+ BT_DBG("recv pkt %d", err);
+ } else {
+ err = -ENOENT;
+ }
+
+ return err;
+}
+
+static void 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);
+
+ hci_send_acl(conn->hchan, skb, ACL_START);
+}
+
+static inline int 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++;
+
+ 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_ATOMIC);
+ if (IS_ERR(tmp))
+ return PTR_ERR(tmp);
+
+ *frag = tmp;
+
+ memcpy(skb_put(*frag, count), msg, count);
+
+ 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 *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_ATOMIC);
+ 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 = 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 conn_send(struct l2cap_conn *conn,
+ void *msg, size_t len, u32 priority,
+ struct net_device *dev)
+{
+ struct sk_buff *skb;
+
+ skb = create_pdu(conn, msg, len, priority, dev);
+ if (IS_ERR(skb))
+ return -EINVAL;
+
+ do_send(conn, skb);
+ return 0;
+}
+
+static void get_dest_bdaddr(struct in6_addr *ip6_daddr,
+ bdaddr_t *addr, u8 *addr_type)
+{
+ u8 *eui64;
+
+ eui64 = ip6_daddr->s6_addr + 8;
+
+ addr->b[0] = eui64[7];
+ addr->b[1] = eui64[6];
+ addr->b[2] = eui64[5];
+ addr->b[3] = eui64[2];
+ addr->b[4] = eui64[1];
+ addr->b[5] = eui64[0];
+
+ addr->b[5] ^= 2;
+
+ /* Set universal/local bit to 0 */
+ if (addr->b[5] & 1) {
+ addr->b[5] &= ~1;
+ *addr_type = BDADDR_LE_PUBLIC;
+ } else
+ *addr_type = BDADDR_LE_RANDOM;
+}
+
+static int header_create(struct sk_buff *skb, struct net_device *dev,
+ unsigned short type, const void *_daddr,
+ const void *_saddr, unsigned int len)
+{
+ struct ipv6hdr *hdr;
+ struct lowpan_info *info;
+ struct lowpan_peer *peer;
+ bdaddr_t addr, *any = BDADDR_ANY;
+ u8 *saddr, *daddr = any->b;
+ u8 addr_type;
+
+ if (type != ETH_P_IPV6)
+ return -EINVAL;
+
+ hdr = ipv6_hdr(skb);
+
+ info = lowpan_info(dev);
+
+ if (ipv6_addr_is_multicast(&hdr->daddr)) {
+ memcpy(&lowpan_cb(skb)->addr, &hdr->daddr,
+ sizeof(struct in6_addr));
+ lowpan_cb(skb)->conn = NULL;
+ } else {
+ unsigned long flags;
+
+ /*
+ * Get destination BT device from skb.
+ * If there is no such peer then discard the packet.
+ */
+ get_dest_bdaddr(&hdr->daddr, &addr, &addr_type);
+
+ BT_DBG("dest addr %pMR type %d", &addr, addr_type);
+
+ read_lock_irqsave(&devices_lock, flags);
+ peer = peer_lookup_ba(info, &addr, addr_type);
+ read_unlock_irqrestore(&devices_lock, flags);
+
+ if (!peer) {
+ BT_DBG("no such peer %pMR found", &addr);
+ return -ENOENT;
+ }
+
+ daddr = peer->eui64_addr;
+
+ memcpy(&lowpan_cb(skb)->addr, &hdr->daddr,
+ sizeof(struct in6_addr));
+ lowpan_cb(skb)->conn = peer->conn;
+ }
+
+ saddr = info->net->dev_addr;
+
+ return lowpan_header_compress(skb, dev, type, daddr, saddr, len);
+}
+
+/* Packet to BT LE device */
+static int send_pkt(struct l2cap_conn *conn, const void *saddr,
+ const void *daddr, struct sk_buff *skb,
+ struct net_device *dev)
+{
+ raw_dump_table(__func__, "raw skb data dump before fragmentation",
+ skb->data, skb->len);
+
+ return conn_send(conn, skb->data, skb->len, 0, dev);
+}
+
+static int send_mcast_pkt(struct sk_buff *skb, struct net_device *dev)
+{
+ struct sk_buff *local_skb;
+ struct lowpan_dev *entry, *tmp;
+ int err = 0;
+ unsigned long flags;
+
+ read_lock_irqsave(&devices_lock, flags);
+
+ list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
+ struct lowpan_peer *pentry, *ptmp;
+ struct lowpan_info *info;
+
+ if (entry->dev != dev)
+ continue;
+
+ info = lowpan_info(entry->dev);
+
+ list_for_each_entry_safe(pentry, ptmp, &info->peers, list) {
+ local_skb = skb_clone(skb, GFP_ATOMIC);
+
+ err = send_pkt(pentry->conn, dev->dev_addr,
+ pentry->eui64_addr,
+ local_skb, dev);
+
+ kfree_skb(local_skb);
+ }
+ }
+
+ read_unlock_irqrestore(&devices_lock, flags);
+
+ return err;
+}
+
+static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ int err = -ENOENT;
+ unsigned char *eui64_addr;
+ struct lowpan_info *info;
+ struct lowpan_peer *peer;
+ bdaddr_t addr;
+ u8 addr_type;
+
+ if (ipv6_addr_is_multicast(&lowpan_cb(skb)->addr)) {
+ /*
+ * We need to send the packet to every device
+ * behind this interface.
+ */
+ err = send_mcast_pkt(skb, dev);
+ } else {
+ unsigned long flags;
+
+ get_dest_bdaddr(&lowpan_cb(skb)->addr, &addr, &addr_type);
+ eui64_addr = lowpan_cb(skb)->addr.s6_addr + 8;
+ info = lowpan_info(dev);
+
+ read_lock_irqsave(&devices_lock, flags);
+ peer = peer_lookup_ba(info, &addr, addr_type);
+ read_unlock_irqrestore(&devices_lock, flags);
+
+ BT_DBG("xmit from %s to %pMR (%pI6c), peer %p", dev->name,
+ &addr, &lowpan_cb(skb)->addr, peer);
+
+ if (peer && peer->conn)
+ err = send_pkt(peer->conn, dev->dev_addr, eui64_addr,
+ skb, dev);
+ }
+ dev_kfree_skb(skb);
+
+ if (err)
+ BT_DBG("ERROR: xmit failed (%d)", err);
+
+ return (err < 0) ? NET_XMIT_DROP : err;
+}
+
+static const struct net_device_ops netdev_ops = {
+ .ndo_start_xmit = bt_xmit,
+};
+
+static struct header_ops header_ops = {
+ .create = header_create,
+};
+
+static void netdev_setup(struct net_device *dev)
+{
+ dev->addr_len = EUI64_ADDR_LEN;
+ dev->type = ARPHRD_6LOWPAN;
+
+ dev->hard_header_len = 0;
+ dev->needed_tailroom = 0;
+ dev->mtu = IPV6_MIN_MTU;
+ dev->tx_queue_len = 0;
+ dev->flags = IFF_RUNNING | IFF_POINTOPOINT;
+ dev->watchdog_timeo = 0;
+
+ dev->netdev_ops = &netdev_ops;
+ dev->header_ops = &header_ops;
+ dev->destructor = free_netdev;
+}
+
+static struct device_type bt_type = {
+ .name = "bluetooth",
+};
+
+static void set_addr(u8 *eui, u8 *addr, u8 addr_type)
+{
+ /* addr is the BT address in little-endian format */
+ eui[0] = addr[5];
+ eui[1] = addr[4];
+ eui[2] = addr[3];
+ eui[3] = 0xFF;
+ eui[4] = 0xFE;
+ eui[5] = addr[2];
+ eui[6] = addr[1];
+ eui[7] = addr[0];
+
+ eui[0] ^= 2;
+
+ /*
+ * Universal/local bit set, RFC 4291
+ */
+ if (addr_type == BDADDR_LE_PUBLIC)
+ eui[0] |= 1;
+ else
+ eui[0] &= ~1;
+}
+
+static void set_dev_addr(struct net_device *net, bdaddr_t *addr,
+ u8 addr_type)
+{
+ net->addr_assign_type = NET_ADDR_PERM;
+ set_addr(net->dev_addr, addr->b, addr_type);
+ net->dev_addr[0] ^= 2;
+}
+
+static void ifup(struct net_device *net)
+{
+ int err;
+
+ rtnl_lock();
+ err = dev_open(net);
+ if (err < 0)
+ BT_INFO("iface %s cannot be opened (%d)", net->name, err);
+ rtnl_unlock();
+}
+
+static void do_notify_peers(struct work_struct *work)
+{
+ struct lowpan_info *info = container_of(work, struct lowpan_info,
+ notify_peers.work);
+
+ netdev_notify_peers(info->net); /* send neighbour adv at startup */
+}
+
+static bool is_bt_6lowpan(struct hci_conn *hcon)
+{
+ if (hcon->type == LE_LINK && test_bit(HCI_CONN_6LOWPAN, &hcon->flags))
+ return true;
+
+ return false;
+}
+
+/*
+ * This gets called when BT LE 6LoWPAN device is connected. We then
+ * create network device that acts as a proxy between BT LE device
+ * and kernel network stack.
+ */
+int bt_6lowpan_add_conn(struct l2cap_conn *conn)
+{
+ struct lowpan_info *dev = NULL;
+ struct lowpan_peer *peer = NULL;
+ struct net_device *net;
+ struct lowpan_dev *entry;
+ int err = 0;
+ unsigned long flags;
+
+ if (!is_bt_6lowpan(conn->hcon))
+ return 0;
+
+ peer = lookup_peer(conn, &dev);
+ if (peer)
+ return -EEXIST;
+
+ if (dev && !peer)
+ goto add_peer;
+
+ net = alloc_netdev(sizeof(struct lowpan_info), IFACE_NAME_TEMPLATE,
+ netdev_setup);
+ if (!net)
+ return -ENOMEM;
+
+ dev = netdev_priv(net);
+ dev->net = net;
+ INIT_LIST_HEAD(&dev->peers);
+
+ set_dev_addr(net, &conn->hcon->src, conn->hcon->src_type);
+
+ net->netdev_ops = &netdev_ops;
+ SET_NETDEV_DEV(net, &conn->hcon->dev);
+ SET_NETDEV_DEVTYPE(net, &bt_type);
+
+ err = register_netdev(net);
+ if (err < 0) {
+ BT_INFO("register_netdev failed %d", err);
+ free_netdev(net);
+ goto out;
+ }
+
+ BT_DBG("ifindex %d peer bdaddr %pMR my addr %pMR",
+ net->ifindex, &conn->hcon->dst, &conn->hcon->src);
+ set_bit(__LINK_STATE_PRESENT, &net->state);
+
+ entry = kzalloc(sizeof(struct lowpan_dev), GFP_ATOMIC);
+ if (!entry) {
+ unregister_netdev(net);
+ return -ENOMEM;
+ }
+
+ entry->dev = net;
+
+ write_lock_irqsave(&devices_lock, flags);
+ INIT_LIST_HEAD(&entry->list);
+ list_add(&entry->list, &bt_6lowpan_devices);
+ write_unlock_irqrestore(&devices_lock, flags);
+
+ ifup(net);
+
+add_peer:
+ peer = kzalloc(sizeof(struct lowpan_peer), GFP_ATOMIC);
+ if (!peer)
+ return -ENOMEM;
+
+ peer->conn = conn;
+ memset(&peer->peer_addr, 0, sizeof(struct in6_addr));
+
+ /* RFC 2464 ch. 5 */
+ peer->peer_addr.s6_addr[0] = 0xFE;
+ peer->peer_addr.s6_addr[1] = 0x80;
+ set_addr((u8 *)&peer->peer_addr.s6_addr + 8, conn->hcon->dst.b,
+ conn->hcon->dst_type);
+
+ memcpy(&peer->eui64_addr, (u8 *)&peer->peer_addr.s6_addr + 8,
+ EUI64_ADDR_LEN);
+ peer->eui64_addr[0] ^= 2; /* second bit-flip (Universe/Local)
+ * is done according RFC2464
+ */
+
+ raw_dump_inline(__func__, "peer IPv6 address",
+ (unsigned char *)&peer->peer_addr, 16);
+ raw_dump_inline(__func__, "peer EUI64 address", peer->eui64_addr, 8);
+
+ write_lock_irqsave(&devices_lock, flags);
+ INIT_LIST_HEAD(&peer->list);
+ peer_add(dev, peer);
+ write_unlock_irqrestore(&devices_lock, flags);
+
+ /*
+ * Notifying peers about us needs to be done without locks held
+ */
+ INIT_DELAYED_WORK(&dev->notify_peers, do_notify_peers);
+ schedule_delayed_work(&dev->notify_peers, msecs_to_jiffies(100));
+
+out:
+ return err;
+}
+
+static void delete_netdev(struct work_struct *work)
+{
+ struct lowpan_dev *entry = container_of(work, struct lowpan_dev,
+ delete_netdev);
+
+ unregister_netdev(entry->dev);
+
+ /* The entry pointer is deleted in device_event() */
+}
+
+int bt_6lowpan_del_conn(struct l2cap_conn *conn)
+{
+ struct lowpan_dev *entry, *tmp;
+ struct lowpan_info *info = NULL;
+ struct lowpan_peer *peer;
+ int err = -ENOENT;
+ unsigned long flags;
+ bool last = false;
+
+ if (!is_bt_6lowpan(conn->hcon))
+ return 0;
+
+ write_lock_irqsave(&devices_lock, flags);
+
+ list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices, list) {
+ info = lowpan_info(entry->dev);
+ peer = peer_lookup_conn(info, conn);
+ if (peer) {
+ last = peer_del(info, peer);
+ err = 0;
+ break;
+ }
+ }
+
+ if (!err && last && info && !atomic_read(&info->peer_count)) {
+ write_unlock_irqrestore(&devices_lock, flags);
+
+ cancel_delayed_work_sync(&info->notify_peers);
+
+ /*
+ * bt_6lowpan_del_conn() is called with hci dev lock held which
+ * means that we must delete the netdevice in worker thread.
+ */
+ INIT_WORK(&entry->delete_netdev, delete_netdev);
+ schedule_work(&entry->delete_netdev);
+ } else
+ write_unlock_irqrestore(&devices_lock, flags);
+
+ return err;
+}
+
+static int device_event(struct notifier_block *unused,
+ unsigned long event, void *ptr)
+{
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+ struct lowpan_dev *entry, *tmp;
+ unsigned long flags;
+
+ if (dev->type != ARPHRD_6LOWPAN)
+ return NOTIFY_DONE;
+
+ switch (event) {
+ case NETDEV_UNREGISTER:
+ write_lock_irqsave(&devices_lock, flags);
+ list_for_each_entry_safe(entry, tmp, &bt_6lowpan_devices,
+ list) {
+ if (entry->dev == dev) {
+ list_del(&entry->list);
+ kfree(entry);
+ break;
+ }
+ }
+ write_unlock_irqrestore(&devices_lock, flags);
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block bt_6lowpan_dev_notifier = {
+ .notifier_call = device_event,
+};
+
+int bt_6lowpan_init(void)
+{
+ return register_netdevice_notifier(&bt_6lowpan_dev_notifier);
+}
+
+void bt_6lowpan_cleanup(void)
+{
+ unregister_netdevice_notifier(&bt_6lowpan_dev_notifier);
+}
diff --git a/net/bluetooth/6lowpan.h b/net/bluetooth/6lowpan.h
new file mode 100644
index 0000000..680eac8
--- /dev/null
+++ b/net/bluetooth/6lowpan.h
@@ -0,0 +1,26 @@
+/*
+ Copyright (c) 2013 Intel Corp.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 and
+ only version 2 as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+*/
+
+#ifndef __6LOWPAN_H
+#define __6LOWPAN_H
+
+#include <linux/skbuff.h>
+#include <net/bluetooth/l2cap.h>
+
+int bt_6lowpan_recv(struct l2cap_conn *conn, struct sk_buff *skb);
+int bt_6lowpan_add_conn(struct l2cap_conn *conn);
+int bt_6lowpan_del_conn(struct l2cap_conn *conn);
+int bt_6lowpan_init(void);
+void bt_6lowpan_cleanup(void);
+
+#endif /* __6LOWPAN_H */
diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
index 6a791e7..cc6827e 100644
--- a/net/bluetooth/Makefile
+++ b/net/bluetooth/Makefile
@@ -10,6 +10,10 @@ obj-$(CONFIG_BT_HIDP) += hidp/
bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
- a2mp.o amp.o
+ a2mp.o amp.o 6lowpan.o
+
+ifeq ($(CONFIG_IEEE802154_6LOWPAN),)
+ bluetooth-y += ../ieee802154/6lowpan_iphc.o
+endif
subdir-ccflags-y += -D__CHECK_ENDIAN__
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 5fb3df6..5f81245 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -3533,6 +3533,9 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
conn->handle = __le16_to_cpu(ev->handle);
conn->state = BT_CONNECTED;
+ if (test_bit(HCI_6LOWPAN_ENABLED, &hdev->dev_flags))
+ set_bit(HCI_CONN_6LOWPAN, &conn->flags);
+
hci_conn_add_sysfs(conn);
hci_proto_connect_cfm(conn, ev->status);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index ae0054c..9d6e952 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -40,6 +40,7 @@
#include "smp.h"
#include "a2mp.h"
#include "amp.h"
+#include "6lowpan.h"
bool disable_ertm;
@@ -7093,6 +7094,10 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb)
l2cap_conn_del(conn->hcon, EACCES);
break;
+ case L2CAP_FC_6LOWPAN:
+ bt_6lowpan_recv(conn, skb);
+ break;
+
default:
l2cap_data_channel(conn, cid, skb);
break;
@@ -7138,8 +7143,10 @@ void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
if (!status) {
conn = l2cap_conn_add(hcon);
- if (conn)
+ if (conn) {
l2cap_conn_ready(conn);
+ bt_6lowpan_add_conn(conn);
+ }
} else {
l2cap_conn_del(hcon, bt_to_errno(status));
}
@@ -7160,6 +7167,8 @@ void l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
{
BT_DBG("hcon %p reason %d", hcon, reason);
+ bt_6lowpan_del_conn(hcon->l2cap_data);
+
l2cap_conn_del(hcon, bt_to_errno(reason));
}
@@ -7441,11 +7450,14 @@ int __init l2cap_init(void)
debugfs_create_u16("l2cap_le_default_mps", 0466, bt_debugfs,
&le_default_mps);
+ bt_6lowpan_init();
+
return 0;
}
void l2cap_exit(void)
{
+ bt_6lowpan_cleanup();
debugfs_remove(l2cap_debugfs);
l2cap_cleanup_sockets();
}
--
1.8.3.1
^ permalink raw reply related
* [PATCH v6 3/5] ipv6: Add checks for 6LOWPAN ARP type
From: Jukka Rissanen @ 2013-12-08 11:10 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386501056-2555-1-git-send-email-jukka.rissanen@linux.intel.com>
Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
---
net/ipv6/addrconf.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 12c97d8..d125fcd 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -1816,6 +1816,7 @@ static int ipv6_generate_eui64(u8 *eui, struct net_device *dev)
return addrconf_ifid_sit(eui, dev);
case ARPHRD_IPGRE:
return addrconf_ifid_gre(eui, dev);
+ case ARPHRD_6LOWPAN:
case ARPHRD_IEEE802154:
return addrconf_ifid_eui64(eui, dev);
case ARPHRD_IEEE1394:
@@ -2658,7 +2659,8 @@ static void addrconf_dev_config(struct net_device *dev)
(dev->type != ARPHRD_INFINIBAND) &&
(dev->type != ARPHRD_IEEE802154) &&
(dev->type != ARPHRD_IEEE1394) &&
- (dev->type != ARPHRD_TUNNEL6)) {
+ (dev->type != ARPHRD_TUNNEL6) &&
+ (dev->type != ARPHRD_6LOWPAN)) {
/* Alas, we support only Ethernet autoconfiguration. */
return;
}
--
1.8.3.1
^ permalink raw reply related
* [PATCH v6 2/5] net: if_arp: add ARPHRD_6LOWPAN type
From: Jukka Rissanen @ 2013-12-08 11:10 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1386501056-2555-1-git-send-email-jukka.rissanen@linux.intel.com>
Used for IPv6 over LoWPAN networks. Example of this is
Bluetooth 6LoWPAN network.
Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
---
include/uapi/linux/if_arp.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/include/uapi/linux/if_arp.h b/include/uapi/linux/if_arp.h
index d7fea34..4d024d7 100644
--- a/include/uapi/linux/if_arp.h
+++ b/include/uapi/linux/if_arp.h
@@ -94,6 +94,7 @@
#define ARPHRD_CAIF 822 /* CAIF media type */
#define ARPHRD_IP6GRE 823 /* GRE over IPv6 */
#define ARPHRD_NETLINK 824 /* Netlink header */
+#define ARPHRD_6LOWPAN 825 /* IPv6 over LoWPAN */
#define ARPHRD_VOID 0xFFFF /* Void type, nothing is known */
#define ARPHRD_NONE 0xFFFE /* zero header length */
--
1.8.3.1
^ 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