All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation
@ 2016-08-07 14:30 Alexander Aring
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 01/19] ieee802154: 6lowpan: remove headroom check Alexander Aring
                   ` (19 more replies)
  0 siblings, 20 replies; 23+ messages in thread
From: Alexander Aring @ 2016-08-07 14:30 UTC (permalink / raw)
  To: linux-wpan; +Cc: kernel, linux-bluetooth, Alexander Aring

Hi,

This patch series is my second RFC for making btle 6lowpan into the right
direction.

I added hopefully all suggestions which I got from RFCv1. The interface address
will be assigned when the first l2cap chan connection gets in. This device
address will be get by "hci_copy_identity_address" bluetooth API function and
I hope this is the right function to get the "RPA device address".

Checkout commit message of Patch 19/19 to see how I used it.

Bad news are, I will start my master thesis shortly so I am not able to work
on this patch series anymore.

- Alex

changes since v2:
 - Add patch "bluetooth: introduce l2cap chan priv data" to deal with private
   l2cap chan data when doing the final put, instead handling own heap
   allocation to do that.
 - remove patch "6lowpan: ndisc: don't remove short address" which was for
   802.15.4 handling only. It's mainline now.
 - following changes was done for new btle 6lowpan implementation:
    - Changing debugfs UAPI:
      - 6LoWPAN interface will be add/del on power on/off per hci dev. Depends
        on 6lowpan_enable is "1".
      - "6lowpan_control" is moved now to the hci debugfs entry and available
         if 6lowpan interface is also available only.
    - Setting device address is done when the first l2cap_chan connection comes
      in (ready callback). This will be done by hci_copy_identity_address and
      I hope this will be the RPA address. After first connection comes in
      the 6LoWPAN interface will came up.
      If last connection is lost, the device address will be 0...0.
      In general a device address of 0...0 indicates no connection and the
      interface can be set "up" while this.
    - Adding module_get/put to don't remove module while interfaces are
      there and other bug fixes.
    - Added TODO comment for multicast listener support.

Alexander Aring (19):
  ieee802154: 6lowpan: remove headroom check
  ieee802154: 6lowpan: move skb cb BUILD_BUG_ON check
  6lowpan: remove LOWPAN_IPHC_MAX_HEADER_LEN
  6lowpan: hold netdev while unregister
  6lowpan: introduce generic default naming
  6lowpan: move rx defines to generic
  bluetooth: introduce l2cap_hdev_chan_connect
  bluetooth: add hci dev notifier
  bluetooth: introduce l2cap chan priv data
  bluetooth: export functions and variables
  6lowpan: bluetooth: remove implementation
  ieee802154: 6lowpan: move header create to 6lowpan
  6lowpan: move dev_init to generic
  6lowpan: iphc: override l2 packet information
  ipv6: addrconf: fix 48 bit 6lowpan autoconfiguration
  6lowpan: iphc: add handling for btle
  6lowpan: move multicast flags to generic
  6lowpan: move addr_len setting away from generic
  6lowpan: bluetooth: add new implementation

 include/net/6lowpan.h              |   30 +-
 include/net/bluetooth/hci_core.h   |    8 +
 include/net/bluetooth/l2cap.h      |    7 +
 net/6lowpan/core.c                 |   47 +-
 net/6lowpan/iphc.c                 |  111 +++
 net/bluetooth/6lowpan.c            | 1707 +++++++++++++-----------------------
 net/bluetooth/hci_core.c           |   24 +
 net/bluetooth/hci_sock.c           |    2 +
 net/bluetooth/l2cap_core.c         |   50 +-
 net/ieee802154/6lowpan/6lowpan_i.h |    9 -
 net/ieee802154/6lowpan/core.c      |   23 +-
 net/ieee802154/6lowpan/tx.c        |   94 +-
 net/ipv6/addrconf.c                |   19 +-
 13 files changed, 922 insertions(+), 1209 deletions(-)

-- 
2.9.2


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [RFCv2 bluetooth-next 01/19] ieee802154: 6lowpan: remove headroom check
  2016-08-07 14:30 [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation Alexander Aring
@ 2016-08-07 14:30 ` Alexander Aring
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 02/19] ieee802154: 6lowpan: move skb cb BUILD_BUG_ON check Alexander Aring
                   ` (18 subsequent siblings)
  19 siblings, 0 replies; 23+ messages in thread
From: Alexander Aring @ 2016-08-07 14:30 UTC (permalink / raw)
  To: linux-wpan; +Cc: kernel, linux-bluetooth, Alexander Aring

This patch removes unnessary headroom check. We will check that value
while register net device that we have such headroom for placing address
information at the headroom of skb.

Signed-off-by: Alexander Aring <aar@pengutronix.de>
---
 net/ieee802154/6lowpan/tx.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/net/ieee802154/6lowpan/tx.c b/net/ieee802154/6lowpan/tx.c
index dbb476d..a7a1b12 100644
--- a/net/ieee802154/6lowpan/tx.c
+++ b/net/ieee802154/6lowpan/tx.c
@@ -26,7 +26,6 @@ struct lowpan_addr_info {
 static inline struct
 lowpan_addr_info *lowpan_skb_priv(const struct sk_buff *skb)
 {
-	WARN_ON_ONCE(skb_headroom(skb) < sizeof(struct lowpan_addr_info));
 	return (struct lowpan_addr_info *)(skb->data -
 			sizeof(struct lowpan_addr_info));
 }
-- 
2.9.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFCv2 bluetooth-next 02/19] ieee802154: 6lowpan: move skb cb BUILD_BUG_ON check
  2016-08-07 14:30 [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation Alexander Aring
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 01/19] ieee802154: 6lowpan: remove headroom check Alexander Aring
@ 2016-08-07 14:30 ` Alexander Aring
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 03/19] 6lowpan: remove LOWPAN_IPHC_MAX_HEADER_LEN Alexander Aring
                   ` (17 subsequent siblings)
  19 siblings, 0 replies; 23+ messages in thread
From: Alexander Aring @ 2016-08-07 14:30 UTC (permalink / raw)
  To: linux-wpan; +Cc: kernel, linux-bluetooth, Alexander Aring

This patch moves the control block information BUILD_BUG_ON to the init
of module. All compile timed BUILD_BUG_ON macros should be placed there.

Signed-off-by: Alexander Aring <aar@pengutronix.de>
---
 include/net/6lowpan.h         | 1 -
 net/ieee802154/6lowpan/core.c | 3 +++
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h
index 5ab4c99..6d56be7 100644
--- a/include/net/6lowpan.h
+++ b/include/net/6lowpan.h
@@ -178,7 +178,6 @@ struct lowpan_802154_cb {
 static inline
 struct lowpan_802154_cb *lowpan_802154_cb(const struct sk_buff *skb)
 {
-	BUILD_BUG_ON(sizeof(struct lowpan_802154_cb) > sizeof(skb->cb));
 	return (struct lowpan_802154_cb *)skb->cb;
 }
 
diff --git a/net/ieee802154/6lowpan/core.c b/net/ieee802154/6lowpan/core.c
index d7efbf0..6afb8cd 100644
--- a/net/ieee802154/6lowpan/core.c
+++ b/net/ieee802154/6lowpan/core.c
@@ -233,6 +233,9 @@ static int __init lowpan_init_module(void)
 {
 	int err = 0;
 
+	BUILD_BUG_ON(sizeof(struct lowpan_802154_cb) >
+		     FIELD_SIZEOF(struct sk_buff, cb));
+
 	err = lowpan_net_frag_init();
 	if (err < 0)
 		goto out;
-- 
2.9.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFCv2 bluetooth-next 03/19] 6lowpan: remove LOWPAN_IPHC_MAX_HEADER_LEN
  2016-08-07 14:30 [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation Alexander Aring
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 01/19] ieee802154: 6lowpan: remove headroom check Alexander Aring
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 02/19] ieee802154: 6lowpan: move skb cb BUILD_BUG_ON check Alexander Aring
@ 2016-08-07 14:30 ` Alexander Aring
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 04/19] 6lowpan: hold netdev while unregister Alexander Aring
                   ` (16 subsequent siblings)
  19 siblings, 0 replies; 23+ messages in thread
From: Alexander Aring @ 2016-08-07 14:30 UTC (permalink / raw)
  To: linux-wpan; +Cc: kernel, linux-bluetooth, Alexander Aring

My observations with btle 6lowpan was that such parameter doesn't
exists. IPHC will not increase the packet size of IPv6 afterwards, but
decrease it.

I thought about that LOWPAN_IPHC are the 2 bytes headers, but we will
always save two bytes because the payload_length of ipv6 will be elided.

Then I thought the CID byte will increase the payload at one byte, this
is correct but when we add the CID byte, we need to compress at
worst-case 8 bytes.

After that I thought the nhc id will be at least increase currently the
payload to one byte. This is correct, but when we set the NHC bit, then
we save one byte because ipv6 next header byte will be elided. That's
why everything should be fine until we have NHC's which have two bytes
length until or NHC compression use more bytes than raw next header
format.

Signed-off-by: Alexander Aring <aar@pengutronix.de>
---
 include/net/6lowpan.h         | 7 -------
 net/ieee802154/6lowpan/core.c | 6 ++----
 2 files changed, 2 insertions(+), 11 deletions(-)

diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h
index 6d56be7..7f4b63c 100644
--- a/include/net/6lowpan.h
+++ b/include/net/6lowpan.h
@@ -68,15 +68,8 @@
  * possible inline data.
  */
 #define LOWPAN_NHC_MAX_HDR_LEN	(sizeof(struct udphdr))
-/* Max IPHC Header len without IPv6 hdr specific inline data.
- * Useful for getting the "extra" bytes we need at worst case compression.
- *
- * LOWPAN_IPHC + CID + LOWPAN_NHC_MAX_ID_LEN
- */
-#define LOWPAN_IPHC_MAX_HEADER_LEN	(2 + 1 + LOWPAN_NHC_MAX_ID_LEN)
 /* Maximum worst case IPHC header buffer size */
 #define LOWPAN_IPHC_MAX_HC_BUF_LEN	(sizeof(struct ipv6hdr) +	\
-					 LOWPAN_IPHC_MAX_HEADER_LEN +	\
 					 LOWPAN_NHC_MAX_HDR_LEN)
 /* SCI/DCI is 4 bit width, so we have maximum 16 entries */
 #define LOWPAN_IPHC_CTX_TABLE_SIZE	(1 << 4)
diff --git a/net/ieee802154/6lowpan/core.c b/net/ieee802154/6lowpan/core.c
index 6afb8cd..f70edcc 100644
--- a/net/ieee802154/6lowpan/core.c
+++ b/net/ieee802154/6lowpan/core.c
@@ -152,11 +152,9 @@ static int lowpan_newlink(struct net *src_net, struct net_device *ldev,
 	/* We need headroom for possible wpan_dev_hard_header call and tailroom
 	 * for encryption/fcs handling. The lowpan interface will replace
 	 * the IPv6 header with 6LoWPAN header. At worst case the 6LoWPAN
-	 * header has LOWPAN_IPHC_MAX_HEADER_LEN more bytes than the IPv6
-	 * header.
+	 * header has one byte more for possible raw IPv6 dispatch.
 	 */
-	ldev->needed_headroom = LOWPAN_IPHC_MAX_HEADER_LEN +
-				wdev->needed_headroom;
+	ldev->needed_headroom = 1 + wdev->needed_headroom;
 	ldev->needed_tailroom = wdev->needed_tailroom;
 
 	ldev->neigh_priv_len = sizeof(struct lowpan_802154_neigh);
-- 
2.9.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFCv2 bluetooth-next 04/19] 6lowpan: hold netdev while unregister
  2016-08-07 14:30 [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation Alexander Aring
                   ` (2 preceding siblings ...)
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 03/19] 6lowpan: remove LOWPAN_IPHC_MAX_HEADER_LEN Alexander Aring
@ 2016-08-07 14:30 ` Alexander Aring
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 05/19] 6lowpan: introduce generic default naming Alexander Aring
                   ` (15 subsequent siblings)
  19 siblings, 0 replies; 23+ messages in thread
From: Alexander Aring @ 2016-08-07 14:30 UTC (permalink / raw)
  To: linux-wpan; +Cc: kernel, linux-bluetooth, Alexander Aring

I saw that unregister_netdevice will also free the netdev by running
dev_put. This may clash run debugfs exist, because it use netdevice
private data room.

Signed-off-by: Alexander Aring <aar@pengutronix.de>
---
 net/6lowpan/core.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/net/6lowpan/core.c b/net/6lowpan/core.c
index 5945f7e..00ffab3 100644
--- a/net/6lowpan/core.c
+++ b/net/6lowpan/core.c
@@ -62,8 +62,10 @@ EXPORT_SYMBOL(lowpan_register_netdev);
 
 void lowpan_unregister_netdevice(struct net_device *dev)
 {
+	dev_hold(dev);
 	unregister_netdevice(dev);
 	lowpan_dev_debugfs_exit(dev);
+	dev_put(dev);
 }
 EXPORT_SYMBOL(lowpan_unregister_netdevice);
 
-- 
2.9.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFCv2 bluetooth-next 05/19] 6lowpan: introduce generic default naming
  2016-08-07 14:30 [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation Alexander Aring
                   ` (3 preceding siblings ...)
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 04/19] 6lowpan: hold netdev while unregister Alexander Aring
@ 2016-08-07 14:30 ` Alexander Aring
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 06/19] 6lowpan: move rx defines to generic Alexander Aring
                   ` (14 subsequent siblings)
  19 siblings, 0 replies; 23+ messages in thread
From: Alexander Aring @ 2016-08-07 14:30 UTC (permalink / raw)
  To: linux-wpan; +Cc: kernel, linux-bluetooth, Alexander Aring

This patch adds a default naming for all 6LoWPAN interfaces. All
userspace software should have them as example e.g. for configurations.

I see currently many examples which has different interface naming for
software which works for 6LoWPAN BTLE and 6LoWPAN 802.15.4.

We need to change also all examples outside to this naming stuff, so the
interface naming inside such examples doesn't depends on L2.

Signed-off-by: Alexander Aring <aar@pengutronix.de>
---
 include/net/6lowpan.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h
index 7f4b63c..2570237 100644
--- a/include/net/6lowpan.h
+++ b/include/net/6lowpan.h
@@ -78,6 +78,8 @@
 #define LOWPAN_DISPATCH_IPHC		0x60 /* 011xxxxx = ... */
 #define LOWPAN_DISPATCH_IPHC_MASK	0xe0
 
+#define LOWPAN_IFNAME_TEMPLATE "6lo%d"
+
 static inline bool lowpan_is_ipv6(u8 dispatch)
 {
 	return dispatch == LOWPAN_DISPATCH_IPV6;
-- 
2.9.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFCv2 bluetooth-next 06/19] 6lowpan: move rx defines to generic
  2016-08-07 14:30 [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation Alexander Aring
                   ` (4 preceding siblings ...)
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 05/19] 6lowpan: introduce generic default naming Alexander Aring
@ 2016-08-07 14:30 ` Alexander Aring
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 07/19] bluetooth: introduce l2cap_hdev_chan_connect Alexander Aring
                   ` (13 subsequent siblings)
  19 siblings, 0 replies; 23+ messages in thread
From: Alexander Aring @ 2016-08-07 14:30 UTC (permalink / raw)
  To: linux-wpan; +Cc: kernel, linux-bluetooth, Alexander Aring

This patch prepares to use 802.15.4 6LoWPAN receive handling also for
BTLE 6LoWPAN.

Signed-off-by: Alexander Aring <aar@pengutronix.de>
---
 include/net/6lowpan.h              | 6 ++++++
 net/ieee802154/6lowpan/6lowpan_i.h | 6 ------
 2 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h
index 2570237..90d9d08 100644
--- a/include/net/6lowpan.h
+++ b/include/net/6lowpan.h
@@ -80,6 +80,12 @@
 
 #define LOWPAN_IFNAME_TEMPLATE "6lo%d"
 
+typedef unsigned __bitwise__ lowpan_rx_result;
+#define RX_CONTINUE		((__force lowpan_rx_result) 0u)
+#define RX_DROP_UNUSABLE	((__force lowpan_rx_result) 1u)
+#define RX_DROP			((__force lowpan_rx_result) 2u)
+#define RX_QUEUED		((__force lowpan_rx_result) 3u)
+
 static inline bool lowpan_is_ipv6(u8 dispatch)
 {
 	return dispatch == LOWPAN_DISPATCH_IPV6;
diff --git a/net/ieee802154/6lowpan/6lowpan_i.h b/net/ieee802154/6lowpan/6lowpan_i.h
index 5ac7789..39b739f 100644
--- a/net/ieee802154/6lowpan/6lowpan_i.h
+++ b/net/ieee802154/6lowpan/6lowpan_i.h
@@ -7,12 +7,6 @@
 #include <net/inet_frag.h>
 #include <net/6lowpan.h>
 
-typedef unsigned __bitwise__ lowpan_rx_result;
-#define RX_CONTINUE		((__force lowpan_rx_result) 0u)
-#define RX_DROP_UNUSABLE	((__force lowpan_rx_result) 1u)
-#define RX_DROP			((__force lowpan_rx_result) 2u)
-#define RX_QUEUED		((__force lowpan_rx_result) 3u)
-
 #define LOWPAN_DISPATCH_FRAG1           0xc0
 #define LOWPAN_DISPATCH_FRAGN           0xe0
 
-- 
2.9.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFCv2 bluetooth-next 07/19] bluetooth: introduce l2cap_hdev_chan_connect
  2016-08-07 14:30 [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation Alexander Aring
                   ` (5 preceding siblings ...)
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 06/19] 6lowpan: move rx defines to generic Alexander Aring
@ 2016-08-07 14:30 ` Alexander Aring
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 08/19] bluetooth: add hci dev notifier Alexander Aring
                   ` (12 subsequent siblings)
  19 siblings, 0 replies; 23+ messages in thread
From: Alexander Aring @ 2016-08-07 14:30 UTC (permalink / raw)
  To: linux-wpan; +Cc: kernel, linux-bluetooth, Alexander Aring

A BTLE 6LoWPAN should be binded to one hci device and is not changeable
afterwards. This patch adds l2cap_hdev_chan_connect function without calling
hci_get_route which decides on bluetooth side which may be the best hci
device which should be use. The hci dev will be available by parameter.

Signed-off-by: Alexander Aring <aar@pengutronix.de>
---
 include/net/bluetooth/l2cap.h |  3 +++
 net/bluetooth/l2cap_core.c    | 28 +++++++++++++++++++++-------
 2 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 5ee3c68..8a4d26e 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -928,6 +928,9 @@ struct l2cap_chan *l2cap_chan_create(void);
 void l2cap_chan_close(struct l2cap_chan *chan, int reason);
 int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
 		       bdaddr_t *dst, u8 dst_type);
+int l2cap_hdev_chan_connect(struct hci_dev *hdev,
+			    struct l2cap_chan *chan, __le16 psm, u16 cid,
+			    bdaddr_t *dst, u8 dst_type);
 int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len);
 void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
 int l2cap_chan_check_security(struct l2cap_chan *chan, bool initiator);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 54ceb1f..2ab8814 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -7041,21 +7041,17 @@ static bool is_valid_psm(u16 psm, u8 dst_type) {
 	return ((psm & 0x0101) == 0x0001);
 }
 
-int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
-		       bdaddr_t *dst, u8 dst_type)
+int l2cap_hdev_chan_connect(struct hci_dev *hdev,
+			    struct l2cap_chan *chan, __le16 psm, u16 cid,
+			    bdaddr_t *dst, u8 dst_type)
 {
 	struct l2cap_conn *conn;
 	struct hci_conn *hcon;
-	struct hci_dev *hdev;
 	int err;
 
 	BT_DBG("%pMR -> %pMR (type %u) psm 0x%2.2x", &chan->src, dst,
 	       dst_type, __le16_to_cpu(psm));
 
-	hdev = hci_get_route(dst, &chan->src);
-	if (!hdev)
-		return -EHOSTUNREACH;
-
 	hci_dev_lock(hdev);
 
 	if (!is_valid_psm(__le16_to_cpu(psm), dst_type) && !cid &&
@@ -7199,7 +7195,25 @@ chan_unlock:
 	mutex_unlock(&conn->chan_lock);
 done:
 	hci_dev_unlock(hdev);
+	return err;
+}
+EXPORT_SYMBOL_GPL(l2cap_hdev_chan_connect);
+
+int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
+		       bdaddr_t *dst, u8 dst_type)
+{
+	struct hci_dev *hdev;
+	int err = -EHOSTUNREACH;
+
+	hdev = hci_get_route(dst, &chan->src);
+	if (!hdev)
+		goto done;
+
+	err = l2cap_hdev_chan_connect(hdev, chan, psm, cid, dst, dst_type);
+
 	hci_dev_put(hdev);
+
+done:
 	return err;
 }
 EXPORT_SYMBOL_GPL(l2cap_chan_connect);
-- 
2.9.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFCv2 bluetooth-next 08/19] bluetooth: add hci dev notifier
  2016-08-07 14:30 [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation Alexander Aring
                   ` (6 preceding siblings ...)
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 07/19] bluetooth: introduce l2cap_hdev_chan_connect Alexander Aring
@ 2016-08-07 14:30 ` Alexander Aring
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 09/19] bluetooth: introduce l2cap chan priv data Alexander Aring
                   ` (11 subsequent siblings)
  19 siblings, 0 replies; 23+ messages in thread
From: Alexander Aring @ 2016-08-07 14:30 UTC (permalink / raw)
  To: linux-wpan; +Cc: kernel, linux-bluetooth, Alexander Aring

I need to react at least somehow on a hci dev unregister event to clean
all 6LoWPAN interfaces on it. This patch adds a notifier for non
socket stuff.

I also thought about to react somehow on "struct device" unregister but
I didn't found any functionality for that.

Signed-off-by: Alexander Aring <aar@pengutronix.de>
---
 include/net/bluetooth/hci_core.h |  4 ++++
 net/bluetooth/hci_core.c         | 22 ++++++++++++++++++++++
 net/bluetooth/hci_sock.c         |  2 ++
 3 files changed, 28 insertions(+)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index b8d43bd..f808aa0 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -907,6 +907,10 @@ void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active);
 
 void hci_le_conn_failed(struct hci_conn *conn, u8 status);
 
+int register_hci_dev_notifier(struct notifier_block *nb);
+void unregister_hci_dev_notifier(struct notifier_block *nb);
+int call_hci_dev_notifiers(unsigned long val, struct hci_dev *hdev);
+
 /*
  * hci_conn_get() and hci_conn_put() are used to control the life-time of an
  * "hci_conn" object. They do not guarantee that the hci_conn object is running,
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index ddf8432..999c83b 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -57,6 +57,28 @@ DEFINE_MUTEX(hci_cb_list_lock);
 /* HCI ID Numbering */
 static DEFINE_IDA(hci_index_ida);
 
+/* HCI device notifier list */
+static RAW_NOTIFIER_HEAD(hci_dev_chain);
+
+/* ---- HCI notifiers functions ---- */
+
+int register_hci_dev_notifier(struct notifier_block *nb)
+{
+	return raw_notifier_chain_register(&hci_dev_chain, nb);
+}
+EXPORT_SYMBOL(register_hci_dev_notifier);
+
+void unregister_hci_dev_notifier(struct notifier_block *nb)
+{
+	raw_notifier_chain_unregister(&hci_dev_chain, nb);
+}
+EXPORT_SYMBOL(unregister_hci_dev_notifier);
+
+int call_hci_dev_notifiers(unsigned long val, struct hci_dev *hdev)
+{
+	return raw_notifier_call_chain(&hci_dev_chain, val, hdev);
+}
+
 /* ---- HCI debugfs entries ---- */
 
 static ssize_t dut_mode_read(struct file *file, char __user *user_buf,
diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c
index 6ef8a01..290eb1e 100644
--- a/net/bluetooth/hci_sock.c
+++ b/net/bluetooth/hci_sock.c
@@ -529,6 +529,8 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event)
 		}
 		read_unlock(&hci_sk_list.lock);
 	}
+
+	call_hci_dev_notifiers(event, hdev);
 }
 
 static struct hci_mgmt_chan *__hci_mgmt_chan_find(unsigned short channel)
-- 
2.9.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFCv2 bluetooth-next 09/19] bluetooth: introduce l2cap chan priv data
  2016-08-07 14:30 [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation Alexander Aring
                   ` (7 preceding siblings ...)
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 08/19] bluetooth: add hci dev notifier Alexander Aring
@ 2016-08-07 14:30 ` Alexander Aring
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 10/19] bluetooth: export functions and variables Alexander Aring
                   ` (10 subsequent siblings)
  19 siblings, 0 replies; 23+ messages in thread
From: Alexander Aring @ 2016-08-07 14:30 UTC (permalink / raw)
  To: linux-wpan; +Cc: kernel, linux-bluetooth, Alexander Aring

This patch adds possibility to add a private data room to the l2cap_chan
structure. This private dataroom will be freed when the l2cap_chan
reference count reach zero. This avoids dealing with separate allocated
data pointer for l2cap_chan "data" attribute.

Signed-off-by: Alexander Aring <aar@pengutronix.de>
---
 include/net/bluetooth/l2cap.h |  4 ++++
 net/bluetooth/l2cap_core.c    | 21 +++++++++++++++++++--
 2 files changed, 23 insertions(+), 2 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 8a4d26e..925c78a 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -598,6 +598,9 @@ struct l2cap_chan {
 	void			*data;
 	const struct l2cap_ops	*ops;
 	struct mutex		lock;
+
+	/* must be last */
+	u8 priv[0] __aligned(sizeof(void *));
 };
 
 struct l2cap_ops {
@@ -925,6 +928,7 @@ int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm);
 int l2cap_add_scid(struct l2cap_chan *chan,  __u16 scid);
 
 struct l2cap_chan *l2cap_chan_create(void);
+struct l2cap_chan *l2cap_chan_create_priv(size_t priv_size);
 void l2cap_chan_close(struct l2cap_chan *chan, int reason);
 int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
 		       bdaddr_t *dst, u8 dst_type);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 2ab8814..cce5d21 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -433,11 +433,11 @@ static void l2cap_chan_timeout(struct work_struct *work)
 	l2cap_chan_put(chan);
 }
 
-struct l2cap_chan *l2cap_chan_create(void)
+static struct l2cap_chan *__l2cap_chan_create(size_t priv_size)
 {
 	struct l2cap_chan *chan;
 
-	chan = kzalloc(sizeof(*chan), GFP_ATOMIC);
+	chan = kzalloc(sizeof(*chan) + priv_size, GFP_ATOMIC);
 	if (!chan)
 		return NULL;
 
@@ -463,8 +463,25 @@ struct l2cap_chan *l2cap_chan_create(void)
 
 	return chan;
 }
+
+struct l2cap_chan *l2cap_chan_create(void)
+{
+	return __l2cap_chan_create(0);
+}
 EXPORT_SYMBOL_GPL(l2cap_chan_create);
 
+struct l2cap_chan *l2cap_chan_create_priv(size_t priv_size)
+{
+	struct l2cap_chan *chan = __l2cap_chan_create(priv_size);
+
+	/* let's point data pointer to private space */
+	if (chan)
+		chan->data = chan->priv;
+
+	return chan;
+}
+EXPORT_SYMBOL_GPL(l2cap_chan_create_priv);
+
 static void l2cap_chan_destroy(struct kref *kref)
 {
 	struct l2cap_chan *chan = container_of(kref, struct l2cap_chan, kref);
-- 
2.9.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFCv2 bluetooth-next 10/19] bluetooth: export functions and variables
  2016-08-07 14:30 [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation Alexander Aring
                   ` (8 preceding siblings ...)
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 09/19] bluetooth: introduce l2cap chan priv data Alexander Aring
@ 2016-08-07 14:30 ` Alexander Aring
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 11/19] 6lowpan: bluetooth: remove implementation Alexander Aring
                   ` (9 subsequent siblings)
  19 siblings, 0 replies; 23+ messages in thread
From: Alexander Aring @ 2016-08-07 14:30 UTC (permalink / raw)
  To: linux-wpan; +Cc: kernel, linux-bluetooth, Alexander Aring

This function exports some functions which are needed by the 6LoWPAN BTLE
module.

Signed-off-by: Alexander Aring <aar@pengutronix.de>
---
 net/bluetooth/hci_core.c   | 2 ++
 net/bluetooth/l2cap_core.c | 1 +
 2 files changed, 3 insertions(+)

diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 999c83b..4624165 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -955,6 +955,7 @@ struct hci_dev *hci_dev_get(int index)
 	read_unlock(&hci_dev_list_lock);
 	return hdev;
 }
+EXPORT_SYMBOL(hci_dev_get);
 
 /* ---- Inquiry support ---- */
 
@@ -2941,6 +2942,7 @@ void hci_copy_identity_address(struct hci_dev *hdev, bdaddr_t *bdaddr,
 		*bdaddr_type = ADDR_LE_DEV_PUBLIC;
 	}
 }
+EXPORT_SYMBOL(hci_copy_identity_address);
 
 /* Alloc HCI device */
 struct hci_dev *hci_alloc_dev(void)
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index cce5d21..128d5a4 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -501,6 +501,7 @@ void l2cap_chan_hold(struct l2cap_chan *c)
 
 	kref_get(&c->kref);
 }
+EXPORT_SYMBOL(l2cap_chan_hold);
 
 void l2cap_chan_put(struct l2cap_chan *c)
 {
-- 
2.9.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFCv2 bluetooth-next 11/19] 6lowpan: bluetooth: remove implementation
  2016-08-07 14:30 [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation Alexander Aring
                   ` (9 preceding siblings ...)
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 10/19] bluetooth: export functions and variables Alexander Aring
@ 2016-08-07 14:30 ` Alexander Aring
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 12/19] ieee802154: 6lowpan: move header create to 6lowpan Alexander Aring
                   ` (8 subsequent siblings)
  19 siblings, 0 replies; 23+ messages in thread
From: Alexander Aring @ 2016-08-07 14:30 UTC (permalink / raw)
  To: linux-wpan; +Cc: kernel, linux-bluetooth, Alexander Aring

This patch prepares for a new bluetooth implementation which supports
correct ndisc handling and solves some races. The get the correct ndisc
handling it's better to remove the whole implementation while
implementing this handling in different layers.

Signed-off-by: Alexander Aring <aar@pengutronix.de>
---
 net/bluetooth/6lowpan.c | 1413 -----------------------------------------------
 net/bluetooth/Makefile  |    3 -
 2 files changed, 1416 deletions(-)
 delete mode 100644 net/bluetooth/6lowpan.c

diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
deleted file mode 100644
index d020299..0000000
--- a/net/bluetooth/6lowpan.c
+++ /dev/null
@@ -1,1413 +0,0 @@
-/*
-   Copyright (c) 2013-2014 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/if_arp.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/module.h>
-#include <linux/debugfs.h>
-
-#include <net/ipv6.h>
-#include <net/ip6_route.h>
-#include <net/addrconf.h>
-
-#include <net/bluetooth/bluetooth.h>
-#include <net/bluetooth/hci_core.h>
-#include <net/bluetooth/l2cap.h>
-
-#include <net/6lowpan.h> /* for the compression support */
-
-#define VERSION "0.1"
-
-static struct dentry *lowpan_enable_debugfs;
-static struct dentry *lowpan_control_debugfs;
-
-#define IFACE_NAME_TEMPLATE "bt%d"
-
-struct skb_cb {
-	struct in6_addr addr;
-	struct in6_addr gw;
-	struct l2cap_chan *chan;
-	int status;
-};
-#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_SPINLOCK(devices_lock);
-
-static bool enable_6lowpan;
-
-/* We are listening incoming connections via this channel
- */
-static struct l2cap_chan *listen_chan;
-
-struct lowpan_peer {
-	struct list_head list;
-	struct rcu_head rcu;
-	struct l2cap_chan *chan;
-
-	/* peer addresses in various formats */
-	unsigned char eui64_addr[EUI64_ADDR_LEN];
-	struct in6_addr peer_addr;
-};
-
-struct lowpan_btle_dev {
-	struct list_head list;
-
-	struct hci_dev *hdev;
-	struct net_device *netdev;
-	struct list_head peers;
-	atomic_t peer_count; /* number of items in peers list */
-
-	struct work_struct delete_netdev;
-	struct delayed_work notify_peers;
-};
-
-static inline struct lowpan_btle_dev *
-lowpan_btle_dev(const struct net_device *netdev)
-{
-	return (struct lowpan_btle_dev *)lowpan_dev(netdev)->priv;
-}
-
-static inline void peer_add(struct lowpan_btle_dev *dev,
-			    struct lowpan_peer *peer)
-{
-	list_add_rcu(&peer->list, &dev->peers);
-	atomic_inc(&dev->peer_count);
-}
-
-static inline bool peer_del(struct lowpan_btle_dev *dev,
-			    struct lowpan_peer *peer)
-{
-	list_del_rcu(&peer->list);
-	kfree_rcu(peer, rcu);
-
-	module_put(THIS_MODULE);
-
-	if (atomic_dec_and_test(&dev->peer_count)) {
-		BT_DBG("last peer");
-		return true;
-	}
-
-	return false;
-}
-
-static inline struct lowpan_peer *peer_lookup_ba(struct lowpan_btle_dev *dev,
-						 bdaddr_t *ba, __u8 type)
-{
-	struct lowpan_peer *peer;
-
-	BT_DBG("peers %d addr %pMR type %d", atomic_read(&dev->peer_count),
-	       ba, type);
-
-	rcu_read_lock();
-
-	list_for_each_entry_rcu(peer, &dev->peers, list) {
-		BT_DBG("dst addr %pMR dst type %d",
-		       &peer->chan->dst, peer->chan->dst_type);
-
-		if (bacmp(&peer->chan->dst, ba))
-			continue;
-
-		if (type == peer->chan->dst_type) {
-			rcu_read_unlock();
-			return peer;
-		}
-	}
-
-	rcu_read_unlock();
-
-	return NULL;
-}
-
-static inline struct lowpan_peer *
-__peer_lookup_chan(struct lowpan_btle_dev *dev, struct l2cap_chan *chan)
-{
-	struct lowpan_peer *peer;
-
-	list_for_each_entry_rcu(peer, &dev->peers, list) {
-		if (peer->chan == chan)
-			return peer;
-	}
-
-	return NULL;
-}
-
-static inline struct lowpan_peer *
-__peer_lookup_conn(struct lowpan_btle_dev *dev, struct l2cap_conn *conn)
-{
-	struct lowpan_peer *peer;
-
-	list_for_each_entry_rcu(peer, &dev->peers, list) {
-		if (peer->chan->conn == conn)
-			return peer;
-	}
-
-	return NULL;
-}
-
-static inline struct lowpan_peer *peer_lookup_dst(struct lowpan_btle_dev *dev,
-						  struct in6_addr *daddr,
-						  struct sk_buff *skb)
-{
-	struct lowpan_peer *peer;
-	struct in6_addr *nexthop;
-	struct rt6_info *rt = (struct rt6_info *)skb_dst(skb);
-	int count = atomic_read(&dev->peer_count);
-
-	BT_DBG("peers %d addr %pI6c rt %p", count, daddr, rt);
-
-	/* If we have multiple 6lowpan peers, then check where we should
-	 * send the packet. If only one peer exists, then we can send the
-	 * packet right away.
-	 */
-	if (count == 1) {
-		rcu_read_lock();
-		peer = list_first_or_null_rcu(&dev->peers, struct lowpan_peer,
-					      list);
-		rcu_read_unlock();
-		return peer;
-	}
-
-	if (!rt) {
-		nexthop = &lowpan_cb(skb)->gw;
-
-		if (ipv6_addr_any(nexthop))
-			return NULL;
-	} else {
-		nexthop = rt6_nexthop(rt, daddr);
-
-		/* We need to remember the address because it is needed
-		 * by bt_xmit() when sending the packet. In bt_xmit(), the
-		 * destination routing info is not set.
-		 */
-		memcpy(&lowpan_cb(skb)->gw, nexthop, sizeof(struct in6_addr));
-	}
-
-	BT_DBG("gw %pI6c", nexthop);
-
-	rcu_read_lock();
-
-	list_for_each_entry_rcu(peer, &dev->peers, list) {
-		BT_DBG("dst addr %pMR dst type %d ip %pI6c",
-		       &peer->chan->dst, peer->chan->dst_type,
-		       &peer->peer_addr);
-
-		if (!ipv6_addr_cmp(&peer->peer_addr, nexthop)) {
-			rcu_read_unlock();
-			return peer;
-		}
-	}
-
-	rcu_read_unlock();
-
-	return NULL;
-}
-
-static struct lowpan_peer *lookup_peer(struct l2cap_conn *conn)
-{
-	struct lowpan_btle_dev *entry;
-	struct lowpan_peer *peer = NULL;
-
-	rcu_read_lock();
-
-	list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
-		peer = __peer_lookup_conn(entry, conn);
-		if (peer)
-			break;
-	}
-
-	rcu_read_unlock();
-
-	return peer;
-}
-
-static struct lowpan_btle_dev *lookup_dev(struct l2cap_conn *conn)
-{
-	struct lowpan_btle_dev *entry;
-	struct lowpan_btle_dev *dev = NULL;
-
-	rcu_read_lock();
-
-	list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
-		if (conn->hcon->hdev == entry->hdev) {
-			dev = entry;
-			break;
-		}
-	}
-
-	rcu_read_unlock();
-
-	return dev;
-}
-
-static int give_skb_to_upper(struct sk_buff *skb, struct net_device *dev)
-{
-	struct sk_buff *skb_cp;
-
-	skb_cp = skb_copy(skb, GFP_ATOMIC);
-	if (!skb_cp)
-		return NET_RX_DROP;
-
-	return netif_rx_ni(skb_cp);
-}
-
-static int iphc_decompress(struct sk_buff *skb, struct net_device *netdev,
-			   struct l2cap_chan *chan)
-{
-	const u8 *saddr, *daddr;
-	struct lowpan_btle_dev *dev;
-	struct lowpan_peer *peer;
-
-	dev = lowpan_btle_dev(netdev);
-
-	rcu_read_lock();
-	peer = __peer_lookup_chan(dev, chan);
-	rcu_read_unlock();
-	if (!peer)
-		return -EINVAL;
-
-	saddr = peer->eui64_addr;
-	daddr = dev->netdev->dev_addr;
-
-	return lowpan_header_decompress(skb, netdev, daddr, saddr);
-}
-
-static int recv_pkt(struct sk_buff *skb, struct net_device *dev,
-		    struct l2cap_chan *chan)
-{
-	struct sk_buff *local_skb;
-	int ret;
-
-	if (!netif_running(dev))
-		goto drop;
-
-	if (dev->type != ARPHRD_6LOWPAN || !skb->len)
-		goto drop;
-
-	skb_reset_network_header(skb);
-
-	skb = skb_share_check(skb, GFP_ATOMIC);
-	if (!skb)
-		goto drop;
-
-	/* check that it's our buffer */
-	if (lowpan_is_ipv6(*skb_network_header(skb))) {
-		/* Pull off the 1-byte of 6lowpan header. */
-		skb_pull(skb, 1);
-
-		/* 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;
-		local_skb->dev = dev;
-
-		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++;
-
-		consume_skb(local_skb);
-		consume_skb(skb);
-	} else if (lowpan_is_iphc(*skb_network_header(skb))) {
-		local_skb = skb_clone(skb, GFP_ATOMIC);
-		if (!local_skb)
-			goto drop;
-
-		local_skb->dev = dev;
-
-		ret = iphc_decompress(local_skb, dev, chan);
-		if (ret < 0) {
-			kfree_skb(local_skb);
-			goto drop;
-		}
-
-		local_skb->protocol = htons(ETH_P_IPV6);
-		local_skb->pkt_type = PACKET_HOST;
-
-		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++;
-
-		consume_skb(local_skb);
-		consume_skb(skb);
-	} else {
-		goto drop;
-	}
-
-	return NET_RX_SUCCESS;
-
-drop:
-	dev->stats.rx_dropped++;
-	return NET_RX_DROP;
-}
-
-/* Packet from BT LE device */
-static int chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
-{
-	struct lowpan_btle_dev *dev;
-	struct lowpan_peer *peer;
-	int err;
-
-	peer = lookup_peer(chan->conn);
-	if (!peer)
-		return -ENOENT;
-
-	dev = lookup_dev(chan->conn);
-	if (!dev || !dev->netdev)
-		return -ENOENT;
-
-	err = recv_pkt(skb, dev->netdev, chan);
-	if (err) {
-		BT_DBG("recv pkt %d", err);
-		err = -EAGAIN;
-	}
-
-	return err;
-}
-
-static u8 get_addr_type_from_eui64(u8 byte)
-{
-	/* Is universal(0) or local(1) bit */
-	return ((byte & 0x02) ? BDADDR_LE_RANDOM : BDADDR_LE_PUBLIC);
-}
-
-static void copy_to_bdaddr(struct in6_addr *ip6_daddr, bdaddr_t *addr)
-{
-	u8 *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];
-}
-
-static void convert_dest_bdaddr(struct in6_addr *ip6_daddr,
-				bdaddr_t *addr, u8 *addr_type)
-{
-	copy_to_bdaddr(ip6_daddr, addr);
-
-	/* We need to toggle the U/L bit that we got from IPv6 address
-	 * so that we get the proper address and type of the BD address.
-	 */
-	addr->b[5] ^= 0x02;
-
-	*addr_type = get_addr_type_from_eui64(addr->b[5]);
-}
-
-static int setup_header(struct sk_buff *skb, struct net_device *netdev,
-			bdaddr_t *peer_addr, u8 *peer_addr_type)
-{
-	struct in6_addr ipv6_daddr;
-	struct ipv6hdr *hdr;
-	struct lowpan_btle_dev *dev;
-	struct lowpan_peer *peer;
-	bdaddr_t addr, *any = BDADDR_ANY;
-	u8 *daddr = any->b;
-	int err, status = 0;
-
-	hdr = ipv6_hdr(skb);
-
-	dev = lowpan_btle_dev(netdev);
-
-	memcpy(&ipv6_daddr, &hdr->daddr, sizeof(ipv6_daddr));
-
-	if (ipv6_addr_is_multicast(&ipv6_daddr)) {
-		lowpan_cb(skb)->chan = NULL;
-	} else {
-		u8 addr_type;
-
-		/* Get destination BT device from skb.
-		 * If there is no such peer then discard the packet.
-		 */
-		convert_dest_bdaddr(&ipv6_daddr, &addr, &addr_type);
-
-		BT_DBG("dest addr %pMR type %d IP %pI6c", &addr,
-		       addr_type, &ipv6_daddr);
-
-		peer = peer_lookup_ba(dev, &addr, addr_type);
-		if (!peer) {
-			/* The packet might be sent to 6lowpan interface
-			 * because of routing (either via default route
-			 * or user set route) so get peer according to
-			 * the destination address.
-			 */
-			peer = peer_lookup_dst(dev, &ipv6_daddr, skb);
-			if (!peer) {
-				BT_DBG("no such peer %pMR found", &addr);
-				return -ENOENT;
-			}
-		}
-
-		daddr = peer->eui64_addr;
-		*peer_addr = addr;
-		*peer_addr_type = addr_type;
-		lowpan_cb(skb)->chan = peer->chan;
-
-		status = 1;
-	}
-
-	lowpan_header_compress(skb, netdev, daddr, dev->netdev->dev_addr);
-
-	err = dev_hard_header(skb, netdev, ETH_P_IPV6, NULL, NULL, 0);
-	if (err < 0)
-		return err;
-
-	return status;
-}
-
-static int header_create(struct sk_buff *skb, struct net_device *netdev,
-			 unsigned short type, const void *_daddr,
-			 const void *_saddr, unsigned int len)
-{
-	if (type != ETH_P_IPV6)
-		return -EINVAL;
-
-	return 0;
-}
-
-/* Packet to BT LE device */
-static int send_pkt(struct l2cap_chan *chan, struct sk_buff *skb,
-		    struct net_device *netdev)
-{
-	struct msghdr msg;
-	struct kvec iv;
-	int err;
-
-	/* Remember the skb so that we can send EAGAIN to the caller if
-	 * we run out of credits.
-	 */
-	chan->data = skb;
-
-	iv.iov_base = skb->data;
-	iv.iov_len = skb->len;
-
-	memset(&msg, 0, sizeof(msg));
-	iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, &iv, 1, skb->len);
-
-	err = l2cap_chan_send(chan, &msg, skb->len);
-	if (err > 0) {
-		netdev->stats.tx_bytes += err;
-		netdev->stats.tx_packets++;
-		return 0;
-	}
-
-	if (!err)
-		err = lowpan_cb(skb)->status;
-
-	if (err < 0) {
-		if (err == -EAGAIN)
-			netdev->stats.tx_dropped++;
-		else
-			netdev->stats.tx_errors++;
-	}
-
-	return err;
-}
-
-static int send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev)
-{
-	struct sk_buff *local_skb;
-	struct lowpan_btle_dev *entry;
-	int err = 0;
-
-	rcu_read_lock();
-
-	list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
-		struct lowpan_peer *pentry;
-		struct lowpan_btle_dev *dev;
-
-		if (entry->netdev != netdev)
-			continue;
-
-		dev = lowpan_btle_dev(entry->netdev);
-
-		list_for_each_entry_rcu(pentry, &dev->peers, list) {
-			int ret;
-
-			local_skb = skb_clone(skb, GFP_ATOMIC);
-
-			BT_DBG("xmit %s to %pMR type %d IP %pI6c chan %p",
-			       netdev->name,
-			       &pentry->chan->dst, pentry->chan->dst_type,
-			       &pentry->peer_addr, pentry->chan);
-			ret = send_pkt(pentry->chan, local_skb, netdev);
-			if (ret < 0)
-				err = ret;
-
-			kfree_skb(local_skb);
-		}
-	}
-
-	rcu_read_unlock();
-
-	return err;
-}
-
-static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev)
-{
-	int err = 0;
-	bdaddr_t addr;
-	u8 addr_type;
-
-	/* We must take a copy of the skb before we modify/replace the ipv6
-	 * header as the header could be used elsewhere
-	 */
-	skb = skb_unshare(skb, GFP_ATOMIC);
-	if (!skb)
-		return NET_XMIT_DROP;
-
-	/* Return values from setup_header()
-	 *  <0 - error, packet is dropped
-	 *   0 - this is a multicast packet
-	 *   1 - this is unicast packet
-	 */
-	err = setup_header(skb, netdev, &addr, &addr_type);
-	if (err < 0) {
-		kfree_skb(skb);
-		return NET_XMIT_DROP;
-	}
-
-	if (err) {
-		if (lowpan_cb(skb)->chan) {
-			BT_DBG("xmit %s to %pMR type %d IP %pI6c chan %p",
-			       netdev->name, &addr, addr_type,
-			       &lowpan_cb(skb)->addr, lowpan_cb(skb)->chan);
-			err = send_pkt(lowpan_cb(skb)->chan, skb, netdev);
-		} else {
-			err = -ENOENT;
-		}
-	} else {
-		/* We need to send the packet to every device behind this
-		 * interface.
-		 */
-		err = send_mcast_pkt(skb, netdev);
-	}
-
-	dev_kfree_skb(skb);
-
-	if (err)
-		BT_DBG("ERROR: xmit failed (%d)", err);
-
-	return err < 0 ? NET_XMIT_DROP : err;
-}
-
-static int bt_dev_init(struct net_device *dev)
-{
-	netdev_lockdep_set_classes(dev);
-
-	return 0;
-}
-
-static const struct net_device_ops netdev_ops = {
-	.ndo_init		= bt_dev_init,
-	.ndo_start_xmit		= bt_xmit,
-};
-
-static struct header_ops header_ops = {
-	.create	= header_create,
-};
-
-static void netdev_setup(struct net_device *dev)
-{
-	dev->hard_header_len	= 0;
-	dev->needed_tailroom	= 0;
-	dev->flags		= IFF_RUNNING | IFF_POINTOPOINT |
-				  IFF_MULTICAST;
-	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];
-
-	/* Universal/local bit set, BT 6lowpan draft ch. 3.2.1 */
-	if (addr_type == BDADDR_LE_PUBLIC)
-		eui[0] &= ~0x02;
-	else
-		eui[0] |= 0x02;
-
-	BT_DBG("type %d addr %*phC", addr_type, 8, eui);
-}
-
-static void set_dev_addr(struct net_device *netdev, bdaddr_t *addr,
-		         u8 addr_type)
-{
-	netdev->addr_assign_type = NET_ADDR_PERM;
-	set_addr(netdev->dev_addr, addr->b, addr_type);
-}
-
-static void ifup(struct net_device *netdev)
-{
-	int err;
-
-	rtnl_lock();
-	err = dev_open(netdev);
-	if (err < 0)
-		BT_INFO("iface %s cannot be opened (%d)", netdev->name, err);
-	rtnl_unlock();
-}
-
-static void ifdown(struct net_device *netdev)
-{
-	int err;
-
-	rtnl_lock();
-	err = dev_close(netdev);
-	if (err < 0)
-		BT_INFO("iface %s cannot be closed (%d)", netdev->name, err);
-	rtnl_unlock();
-}
-
-static void do_notify_peers(struct work_struct *work)
-{
-	struct lowpan_btle_dev *dev = container_of(work, struct lowpan_btle_dev,
-						   notify_peers.work);
-
-	netdev_notify_peers(dev->netdev); /* send neighbour adv at startup */
-}
-
-static bool is_bt_6lowpan(struct hci_conn *hcon)
-{
-	if (hcon->type != LE_LINK)
-		return false;
-
-	if (!enable_6lowpan)
-		return false;
-
-	return true;
-}
-
-static struct l2cap_chan *chan_create(void)
-{
-	struct l2cap_chan *chan;
-
-	chan = l2cap_chan_create();
-	if (!chan)
-		return NULL;
-
-	l2cap_chan_set_defaults(chan);
-
-	chan->chan_type = L2CAP_CHAN_CONN_ORIENTED;
-	chan->mode = L2CAP_MODE_LE_FLOWCTL;
-	chan->imtu = 1280;
-
-	return chan;
-}
-
-static void set_ip_addr_bits(u8 addr_type, u8 *addr)
-{
-	if (addr_type == BDADDR_LE_PUBLIC)
-		*addr |= 0x02;
-	else
-		*addr &= ~0x02;
-}
-
-static struct l2cap_chan *add_peer_chan(struct l2cap_chan *chan,
-					struct lowpan_btle_dev *dev)
-{
-	struct lowpan_peer *peer;
-
-	peer = kzalloc(sizeof(*peer), GFP_ATOMIC);
-	if (!peer)
-		return NULL;
-
-	peer->chan = chan;
-	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, chan->dst.b,
-		 chan->dst_type);
-
-	memcpy(&peer->eui64_addr, (u8 *)&peer->peer_addr.s6_addr + 8,
-	       EUI64_ADDR_LEN);
-
-	/* IPv6 address needs to have the U/L bit set properly so toggle
-	 * it back here.
-	 */
-	set_ip_addr_bits(chan->dst_type, (u8 *)&peer->peer_addr.s6_addr + 8);
-
-	spin_lock(&devices_lock);
-	INIT_LIST_HEAD(&peer->list);
-	peer_add(dev, peer);
-	spin_unlock(&devices_lock);
-
-	/* 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));
-
-	return peer->chan;
-}
-
-static int setup_netdev(struct l2cap_chan *chan, struct lowpan_btle_dev **dev)
-{
-	struct net_device *netdev;
-	int err = 0;
-
-	netdev = alloc_netdev(LOWPAN_PRIV_SIZE(sizeof(struct lowpan_btle_dev)),
-			      IFACE_NAME_TEMPLATE, NET_NAME_UNKNOWN,
-			      netdev_setup);
-	if (!netdev)
-		return -ENOMEM;
-
-	set_dev_addr(netdev, &chan->src, chan->src_type);
-
-	netdev->netdev_ops = &netdev_ops;
-	SET_NETDEV_DEV(netdev, &chan->conn->hcon->hdev->dev);
-	SET_NETDEV_DEVTYPE(netdev, &bt_type);
-
-	*dev = lowpan_btle_dev(netdev);
-	(*dev)->netdev = netdev;
-	(*dev)->hdev = chan->conn->hcon->hdev;
-	INIT_LIST_HEAD(&(*dev)->peers);
-
-	spin_lock(&devices_lock);
-	INIT_LIST_HEAD(&(*dev)->list);
-	list_add_rcu(&(*dev)->list, &bt_6lowpan_devices);
-	spin_unlock(&devices_lock);
-
-	err = lowpan_register_netdev(netdev, LOWPAN_LLTYPE_BTLE);
-	if (err < 0) {
-		BT_INFO("register_netdev failed %d", err);
-		spin_lock(&devices_lock);
-		list_del_rcu(&(*dev)->list);
-		spin_unlock(&devices_lock);
-		free_netdev(netdev);
-		goto out;
-	}
-
-	BT_DBG("ifindex %d peer bdaddr %pMR type %d my addr %pMR type %d",
-	       netdev->ifindex, &chan->dst, chan->dst_type,
-	       &chan->src, chan->src_type);
-	set_bit(__LINK_STATE_PRESENT, &netdev->state);
-
-	return 0;
-
-out:
-	return err;
-}
-
-static inline void chan_ready_cb(struct l2cap_chan *chan)
-{
-	struct lowpan_btle_dev *dev;
-
-	dev = lookup_dev(chan->conn);
-
-	BT_DBG("chan %p conn %p dev %p", chan, chan->conn, dev);
-
-	if (!dev) {
-		if (setup_netdev(chan, &dev) < 0) {
-			l2cap_chan_del(chan, -ENOENT);
-			return;
-		}
-	}
-
-	if (!try_module_get(THIS_MODULE))
-		return;
-
-	add_peer_chan(chan, dev);
-	ifup(dev->netdev);
-}
-
-static inline struct l2cap_chan *chan_new_conn_cb(struct l2cap_chan *pchan)
-{
-	struct l2cap_chan *chan;
-
-	chan = chan_create();
-	if (!chan)
-		return NULL;
-
-	chan->ops = pchan->ops;
-
-	BT_DBG("chan %p pchan %p", chan, pchan);
-
-	return chan;
-}
-
-static void delete_netdev(struct work_struct *work)
-{
-	struct lowpan_btle_dev *entry = container_of(work,
-						     struct lowpan_btle_dev,
-						     delete_netdev);
-
-	lowpan_unregister_netdev(entry->netdev);
-
-	/* The entry pointer is deleted by the netdev destructor. */
-}
-
-static void chan_close_cb(struct l2cap_chan *chan)
-{
-	struct lowpan_btle_dev *entry;
-	struct lowpan_btle_dev *dev = NULL;
-	struct lowpan_peer *peer;
-	int err = -ENOENT;
-	bool last = false, remove = true;
-
-	BT_DBG("chan %p conn %p", chan, chan->conn);
-
-	if (chan->conn && chan->conn->hcon) {
-		if (!is_bt_6lowpan(chan->conn->hcon))
-			return;
-
-		/* If conn is set, then the netdev is also there and we should
-		 * not remove it.
-		 */
-		remove = false;
-	}
-
-	spin_lock(&devices_lock);
-
-	list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
-		dev = lowpan_btle_dev(entry->netdev);
-		peer = __peer_lookup_chan(dev, chan);
-		if (peer) {
-			last = peer_del(dev, peer);
-			err = 0;
-
-			BT_DBG("dev %p removing %speer %p", dev,
-			       last ? "last " : "1 ", peer);
-			BT_DBG("chan %p orig refcnt %d", chan,
-			       atomic_read(&chan->kref.refcount));
-
-			l2cap_chan_put(chan);
-			break;
-		}
-	}
-
-	if (!err && last && dev && !atomic_read(&dev->peer_count)) {
-		spin_unlock(&devices_lock);
-
-		cancel_delayed_work_sync(&dev->notify_peers);
-
-		ifdown(dev->netdev);
-
-		if (remove) {
-			INIT_WORK(&entry->delete_netdev, delete_netdev);
-			schedule_work(&entry->delete_netdev);
-		}
-	} else {
-		spin_unlock(&devices_lock);
-	}
-
-	return;
-}
-
-static void chan_state_change_cb(struct l2cap_chan *chan, int state, int err)
-{
-	BT_DBG("chan %p conn %p state %s err %d", chan, chan->conn,
-	       state_to_string(state), err);
-}
-
-static struct sk_buff *chan_alloc_skb_cb(struct l2cap_chan *chan,
-					 unsigned long hdr_len,
-					 unsigned long len, int nb)
-{
-	/* Note that we must allocate using GFP_ATOMIC here as
-	 * this function is called originally from netdev hard xmit
-	 * function in atomic context.
-	 */
-	return bt_skb_alloc(hdr_len + len, GFP_ATOMIC);
-}
-
-static void chan_suspend_cb(struct l2cap_chan *chan)
-{
-	struct sk_buff *skb = chan->data;
-
-	BT_DBG("chan %p conn %p skb %p", chan, chan->conn, skb);
-
-	if (!skb)
-		return;
-
-	lowpan_cb(skb)->status = -EAGAIN;
-}
-
-static void chan_resume_cb(struct l2cap_chan *chan)
-{
-	struct sk_buff *skb = chan->data;
-
-	BT_DBG("chan %p conn %p skb %p", chan, chan->conn, skb);
-
-	if (!skb)
-		return;
-
-	lowpan_cb(skb)->status = 0;
-}
-
-static long chan_get_sndtimeo_cb(struct l2cap_chan *chan)
-{
-	return L2CAP_CONN_TIMEOUT;
-}
-
-static const struct l2cap_ops bt_6lowpan_chan_ops = {
-	.name			= "L2CAP 6LoWPAN channel",
-	.new_connection		= chan_new_conn_cb,
-	.recv			= chan_recv_cb,
-	.close			= chan_close_cb,
-	.state_change		= chan_state_change_cb,
-	.ready			= chan_ready_cb,
-	.resume			= chan_resume_cb,
-	.suspend		= chan_suspend_cb,
-	.get_sndtimeo		= chan_get_sndtimeo_cb,
-	.alloc_skb		= chan_alloc_skb_cb,
-
-	.teardown		= l2cap_chan_no_teardown,
-	.defer			= l2cap_chan_no_defer,
-	.set_shutdown		= l2cap_chan_no_set_shutdown,
-};
-
-static inline __u8 bdaddr_type(__u8 type)
-{
-	if (type == ADDR_LE_DEV_PUBLIC)
-		return BDADDR_LE_PUBLIC;
-	else
-		return BDADDR_LE_RANDOM;
-}
-
-static int bt_6lowpan_connect(bdaddr_t *addr, u8 dst_type)
-{
-	struct l2cap_chan *chan;
-	int err;
-
-	chan = chan_create();
-	if (!chan)
-		return -EINVAL;
-
-	chan->ops = &bt_6lowpan_chan_ops;
-
-	err = l2cap_chan_connect(chan, cpu_to_le16(L2CAP_PSM_IPSP), 0,
-				 addr, dst_type);
-
-	BT_DBG("chan %p err %d", chan, err);
-	if (err < 0)
-		l2cap_chan_put(chan);
-
-	return err;
-}
-
-static int bt_6lowpan_disconnect(struct l2cap_conn *conn, u8 dst_type)
-{
-	struct lowpan_peer *peer;
-
-	BT_DBG("conn %p dst type %d", conn, dst_type);
-
-	peer = lookup_peer(conn);
-	if (!peer)
-		return -ENOENT;
-
-	BT_DBG("peer %p chan %p", peer, peer->chan);
-
-	l2cap_chan_close(peer->chan, ENOENT);
-
-	return 0;
-}
-
-static struct l2cap_chan *bt_6lowpan_listen(void)
-{
-	bdaddr_t *addr = BDADDR_ANY;
-	struct l2cap_chan *chan;
-	int err;
-
-	if (!enable_6lowpan)
-		return NULL;
-
-	chan = chan_create();
-	if (!chan)
-		return NULL;
-
-	chan->ops = &bt_6lowpan_chan_ops;
-	chan->state = BT_LISTEN;
-	chan->src_type = BDADDR_LE_PUBLIC;
-
-	atomic_set(&chan->nesting, L2CAP_NESTING_PARENT);
-
-	BT_DBG("chan %p src type %d", chan, chan->src_type);
-
-	err = l2cap_add_psm(chan, addr, cpu_to_le16(L2CAP_PSM_IPSP));
-	if (err) {
-		l2cap_chan_put(chan);
-		BT_ERR("psm cannot be added err %d", err);
-		return NULL;
-	}
-
-	return chan;
-}
-
-static int get_l2cap_conn(char *buf, bdaddr_t *addr, u8 *addr_type,
-			  struct l2cap_conn **conn)
-{
-	struct hci_conn *hcon;
-	struct hci_dev *hdev;
-	bdaddr_t *src = BDADDR_ANY;
-	int n;
-
-	n = sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu",
-		   &addr->b[5], &addr->b[4], &addr->b[3],
-		   &addr->b[2], &addr->b[1], &addr->b[0],
-		   addr_type);
-
-	if (n < 7)
-		return -EINVAL;
-
-	hdev = hci_get_route(addr, src);
-	if (!hdev)
-		return -ENOENT;
-
-	hci_dev_lock(hdev);
-	hcon = hci_conn_hash_lookup_le(hdev, addr, *addr_type);
-	hci_dev_unlock(hdev);
-
-	if (!hcon)
-		return -ENOENT;
-
-	*conn = (struct l2cap_conn *)hcon->l2cap_data;
-
-	BT_DBG("conn %p dst %pMR type %d", *conn, &hcon->dst, hcon->dst_type);
-
-	return 0;
-}
-
-static void disconnect_all_peers(void)
-{
-	struct lowpan_btle_dev *entry;
-	struct lowpan_peer *peer, *tmp_peer, *new_peer;
-	struct list_head peers;
-
-	INIT_LIST_HEAD(&peers);
-
-	/* We make a separate list of peers as the close_cb() will
-	 * modify the device peers list so it is better not to mess
-	 * with the same list at the same time.
-	 */
-
-	rcu_read_lock();
-
-	list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
-		list_for_each_entry_rcu(peer, &entry->peers, list) {
-			new_peer = kmalloc(sizeof(*new_peer), GFP_ATOMIC);
-			if (!new_peer)
-				break;
-
-			new_peer->chan = peer->chan;
-			INIT_LIST_HEAD(&new_peer->list);
-
-			list_add(&new_peer->list, &peers);
-		}
-	}
-
-	rcu_read_unlock();
-
-	spin_lock(&devices_lock);
-	list_for_each_entry_safe(peer, tmp_peer, &peers, list) {
-		l2cap_chan_close(peer->chan, ENOENT);
-
-		list_del_rcu(&peer->list);
-		kfree_rcu(peer, rcu);
-	}
-	spin_unlock(&devices_lock);
-}
-
-struct set_enable {
-	struct work_struct work;
-	bool flag;
-};
-
-static void do_enable_set(struct work_struct *work)
-{
-	struct set_enable *set_enable = container_of(work,
-						     struct set_enable, work);
-
-	if (!set_enable->flag || enable_6lowpan != set_enable->flag)
-		/* Disconnect existing connections if 6lowpan is
-		 * disabled
-		 */
-		disconnect_all_peers();
-
-	enable_6lowpan = set_enable->flag;
-
-	if (listen_chan) {
-		l2cap_chan_close(listen_chan, 0);
-		l2cap_chan_put(listen_chan);
-	}
-
-	listen_chan = bt_6lowpan_listen();
-
-	kfree(set_enable);
-}
-
-static int lowpan_enable_set(void *data, u64 val)
-{
-	struct set_enable *set_enable;
-
-	set_enable = kzalloc(sizeof(*set_enable), GFP_KERNEL);
-	if (!set_enable)
-		return -ENOMEM;
-
-	set_enable->flag = !!val;
-	INIT_WORK(&set_enable->work, do_enable_set);
-
-	schedule_work(&set_enable->work);
-
-	return 0;
-}
-
-static int lowpan_enable_get(void *data, u64 *val)
-{
-	*val = enable_6lowpan;
-	return 0;
-}
-
-DEFINE_SIMPLE_ATTRIBUTE(lowpan_enable_fops, lowpan_enable_get,
-			lowpan_enable_set, "%llu\n");
-
-static ssize_t lowpan_control_write(struct file *fp,
-				    const char __user *user_buffer,
-				    size_t count,
-				    loff_t *position)
-{
-	char buf[32];
-	size_t buf_size = min(count, sizeof(buf) - 1);
-	int ret;
-	bdaddr_t addr;
-	u8 addr_type;
-	struct l2cap_conn *conn = NULL;
-
-	if (copy_from_user(buf, user_buffer, buf_size))
-		return -EFAULT;
-
-	buf[buf_size] = '\0';
-
-	if (memcmp(buf, "connect ", 8) == 0) {
-		ret = get_l2cap_conn(&buf[8], &addr, &addr_type, &conn);
-		if (ret == -EINVAL)
-			return ret;
-
-		if (listen_chan) {
-			l2cap_chan_close(listen_chan, 0);
-			l2cap_chan_put(listen_chan);
-			listen_chan = NULL;
-		}
-
-		if (conn) {
-			struct lowpan_peer *peer;
-
-			if (!is_bt_6lowpan(conn->hcon))
-				return -EINVAL;
-
-			peer = lookup_peer(conn);
-			if (peer) {
-				BT_DBG("6LoWPAN connection already exists");
-				return -EALREADY;
-			}
-
-			BT_DBG("conn %p dst %pMR type %d user %d", conn,
-			       &conn->hcon->dst, conn->hcon->dst_type,
-			       addr_type);
-		}
-
-		ret = bt_6lowpan_connect(&addr, addr_type);
-		if (ret < 0)
-			return ret;
-
-		return count;
-	}
-
-	if (memcmp(buf, "disconnect ", 11) == 0) {
-		ret = get_l2cap_conn(&buf[11], &addr, &addr_type, &conn);
-		if (ret < 0)
-			return ret;
-
-		ret = bt_6lowpan_disconnect(conn, addr_type);
-		if (ret < 0)
-			return ret;
-
-		return count;
-	}
-
-	return count;
-}
-
-static int lowpan_control_show(struct seq_file *f, void *ptr)
-{
-	struct lowpan_btle_dev *entry;
-	struct lowpan_peer *peer;
-
-	spin_lock(&devices_lock);
-
-	list_for_each_entry(entry, &bt_6lowpan_devices, list) {
-		list_for_each_entry(peer, &entry->peers, list)
-			seq_printf(f, "%pMR (type %u)\n",
-				   &peer->chan->dst, peer->chan->dst_type);
-	}
-
-	spin_unlock(&devices_lock);
-
-	return 0;
-}
-
-static int lowpan_control_open(struct inode *inode, struct file *file)
-{
-	return single_open(file, lowpan_control_show, inode->i_private);
-}
-
-static const struct file_operations lowpan_control_fops = {
-	.open		= lowpan_control_open,
-	.read		= seq_read,
-	.write		= lowpan_control_write,
-	.llseek		= seq_lseek,
-	.release	= single_release,
-};
-
-static void disconnect_devices(void)
-{
-	struct lowpan_btle_dev *entry, *tmp, *new_dev;
-	struct list_head devices;
-
-	INIT_LIST_HEAD(&devices);
-
-	/* We make a separate list of devices because the unregister_netdev()
-	 * will call device_event() which will also want to modify the same
-	 * devices list.
-	 */
-
-	rcu_read_lock();
-
-	list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
-		new_dev = kmalloc(sizeof(*new_dev), GFP_ATOMIC);
-		if (!new_dev)
-			break;
-
-		new_dev->netdev = entry->netdev;
-		INIT_LIST_HEAD(&new_dev->list);
-
-		list_add_rcu(&new_dev->list, &devices);
-	}
-
-	rcu_read_unlock();
-
-	list_for_each_entry_safe(entry, tmp, &devices, list) {
-		ifdown(entry->netdev);
-		BT_DBG("Unregistering netdev %s %p",
-		       entry->netdev->name, entry->netdev);
-		lowpan_unregister_netdev(entry->netdev);
-		kfree(entry);
-	}
-}
-
-static int device_event(struct notifier_block *unused,
-			unsigned long event, void *ptr)
-{
-	struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
-	struct lowpan_btle_dev *entry;
-
-	if (netdev->type != ARPHRD_6LOWPAN)
-		return NOTIFY_DONE;
-
-	switch (event) {
-	case NETDEV_UNREGISTER:
-		spin_lock(&devices_lock);
-		list_for_each_entry(entry, &bt_6lowpan_devices, list) {
-			if (entry->netdev == netdev) {
-				BT_DBG("Unregistered netdev %s %p",
-				       netdev->name, netdev);
-				list_del(&entry->list);
-				break;
-			}
-		}
-		spin_unlock(&devices_lock);
-		break;
-	}
-
-	return NOTIFY_DONE;
-}
-
-static struct notifier_block bt_6lowpan_dev_notifier = {
-	.notifier_call = device_event,
-};
-
-static int __init bt_6lowpan_init(void)
-{
-	lowpan_enable_debugfs = debugfs_create_file("6lowpan_enable", 0644,
-						    bt_debugfs, NULL,
-						    &lowpan_enable_fops);
-	lowpan_control_debugfs = debugfs_create_file("6lowpan_control", 0644,
-						     bt_debugfs, NULL,
-						     &lowpan_control_fops);
-
-	return register_netdevice_notifier(&bt_6lowpan_dev_notifier);
-}
-
-static void __exit bt_6lowpan_exit(void)
-{
-	debugfs_remove(lowpan_enable_debugfs);
-	debugfs_remove(lowpan_control_debugfs);
-
-	if (listen_chan) {
-		l2cap_chan_close(listen_chan, 0);
-		l2cap_chan_put(listen_chan);
-	}
-
-	disconnect_devices();
-
-	unregister_netdevice_notifier(&bt_6lowpan_dev_notifier);
-}
-
-module_init(bt_6lowpan_init);
-module_exit(bt_6lowpan_exit);
-
-MODULE_AUTHOR("Jukka Rissanen <jukka.rissanen@linux.intel.com>");
-MODULE_DESCRIPTION("Bluetooth 6LoWPAN");
-MODULE_VERSION(VERSION);
-MODULE_LICENSE("GPL");
diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
index b3ff12e..e347828 100644
--- a/net/bluetooth/Makefile
+++ b/net/bluetooth/Makefile
@@ -7,9 +7,6 @@ obj-$(CONFIG_BT_RFCOMM)	+= rfcomm/
 obj-$(CONFIG_BT_BNEP)	+= bnep/
 obj-$(CONFIG_BT_CMTP)	+= cmtp/
 obj-$(CONFIG_BT_HIDP)	+= hidp/
-obj-$(CONFIG_BT_6LOWPAN) += bluetooth_6lowpan.o
-
-bluetooth_6lowpan-y := 6lowpan.o
 
 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 lib.o \
-- 
2.9.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFCv2 bluetooth-next 12/19] ieee802154: 6lowpan: move header create to 6lowpan
  2016-08-07 14:30 [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation Alexander Aring
                   ` (10 preceding siblings ...)
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 11/19] 6lowpan: bluetooth: remove implementation Alexander Aring
@ 2016-08-07 14:30 ` Alexander Aring
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 13/19] 6lowpan: move dev_init to generic Alexander Aring
                   ` (7 subsequent siblings)
  19 siblings, 0 replies; 23+ messages in thread
From: Alexander Aring @ 2016-08-07 14:30 UTC (permalink / raw)
  To: linux-wpan; +Cc: kernel, linux-bluetooth, Alexander Aring

The handling for the header_ops create callback should be on all 6LoWPAN
implementation the same. We move that now to generic 6LoWPAN.

Signed-off-by: Alexander Aring <aar@pengutronix.de>
---
 include/net/6lowpan.h              | 12 +++++
 net/6lowpan/core.c                 | 35 ++++++++++++++
 net/ieee802154/6lowpan/6lowpan_i.h |  3 --
 net/ieee802154/6lowpan/core.c      |  5 --
 net/ieee802154/6lowpan/tx.c        | 93 +++++++++++++-------------------------
 5 files changed, 79 insertions(+), 69 deletions(-)

diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h
index 90d9d08..9a6282b 100644
--- a/include/net/6lowpan.h
+++ b/include/net/6lowpan.h
@@ -133,6 +133,18 @@ lowpan_iphc_ctx_is_compression(const struct lowpan_iphc_ctx *ctx)
 	return test_bit(LOWPAN_IPHC_CTX_FLAG_COMPRESSION, &ctx->flags);
 }
 
+struct lowpan_addr_info {
+	unsigned char daddr[EUI64_ADDR_LEN];
+	unsigned char saddr[EUI64_ADDR_LEN];
+};
+
+static inline struct
+lowpan_addr_info *lowpan_addr_info(const struct sk_buff *skb)
+{
+	return (struct lowpan_addr_info *)(skb->data -
+					   sizeof(struct lowpan_addr_info));
+}
+
 struct lowpan_dev {
 	enum lowpan_lltypes lltype;
 	struct dentry *iface_debugfs;
diff --git a/net/6lowpan/core.c b/net/6lowpan/core.c
index 00ffab3..b01effd 100644
--- a/net/6lowpan/core.c
+++ b/net/6lowpan/core.c
@@ -18,6 +18,33 @@
 
 #include "6lowpan_i.h"
 
+/* TODO I think AF_PACKET DGRAM (sending/receiving) RAW (sending) makes no
+ * sense here. We should disable it, the right use-case would be AF_INET6
+ * RAW/DGRAM sockets.
+ */
+static int lowpan_header_create(struct sk_buff *skb, struct net_device *dev,
+				unsigned short type, const void *daddr,
+				const void *saddr, unsigned int len)
+{
+	struct lowpan_addr_info *info = lowpan_addr_info(skb);
+
+	if (WARN_ON_ONCE(type != ETH_P_IPV6))
+		return -EINVAL;
+
+	memcpy(info->daddr, daddr, dev->addr_len);
+
+	if (saddr)
+		memcpy(info->saddr, saddr, dev->addr_len);
+	else
+		memcpy(info->saddr, dev->dev_addr, dev->addr_len);
+
+	return 0;
+}
+
+static struct header_ops header_ops = {
+	.create	= lowpan_header_create,
+};
+
 int lowpan_register_netdevice(struct net_device *dev,
 			      enum lowpan_lltypes lltype)
 {
@@ -28,6 +55,14 @@ int lowpan_register_netdevice(struct net_device *dev,
 	dev->mtu = IPV6_MIN_MTU;
 	dev->priv_flags |= IFF_NO_QUEUE;
 
+	dev->header_ops = &header_ops;
+
+	/* We need at least headroom for lowpan_addr_info to get necessary
+	 * address information from header create to xmit callback.
+	 */
+	if (dev->needed_headroom < sizeof(struct lowpan_addr_info))
+		dev->needed_headroom += sizeof(struct lowpan_addr_info);
+
 	lowpan_dev(dev)->lltype = lltype;
 
 	spin_lock_init(&lowpan_dev(dev)->ctx.lock);
diff --git a/net/ieee802154/6lowpan/6lowpan_i.h b/net/ieee802154/6lowpan/6lowpan_i.h
index 39b739f..709c22c 100644
--- a/net/ieee802154/6lowpan/6lowpan_i.h
+++ b/net/ieee802154/6lowpan/6lowpan_i.h
@@ -48,9 +48,6 @@ int lowpan_net_frag_init(void);
 void lowpan_rx_init(void);
 void lowpan_rx_exit(void);
 
-int lowpan_header_create(struct sk_buff *skb, struct net_device *dev,
-			 unsigned short type, const void *_daddr,
-			 const void *_saddr, unsigned int len);
 netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev);
 
 int lowpan_iphc_decompress(struct sk_buff *skb);
diff --git a/net/ieee802154/6lowpan/core.c b/net/ieee802154/6lowpan/core.c
index f70edcc..096a194 100644
--- a/net/ieee802154/6lowpan/core.c
+++ b/net/ieee802154/6lowpan/core.c
@@ -54,10 +54,6 @@
 
 static int open_count;
 
-static struct header_ops lowpan_header_ops = {
-	.create	= lowpan_header_create,
-};
-
 static int lowpan_dev_init(struct net_device *ldev)
 {
 	netdev_lockdep_set_classes(ldev);
@@ -106,7 +102,6 @@ static void lowpan_setup(struct net_device *ldev)
 	ldev->flags		= IFF_BROADCAST | IFF_MULTICAST;
 
 	ldev->netdev_ops	= &lowpan_netdev_ops;
-	ldev->header_ops	= &lowpan_header_ops;
 	ldev->destructor	= free_netdev;
 	ldev->features		|= NETIF_F_NETNS_LOCAL;
 }
diff --git a/net/ieee802154/6lowpan/tx.c b/net/ieee802154/6lowpan/tx.c
index a7a1b12..f56b9cd 100644
--- a/net/ieee802154/6lowpan/tx.c
+++ b/net/ieee802154/6lowpan/tx.c
@@ -18,48 +18,23 @@
 #define LOWPAN_FRAG1_HEAD_SIZE	0x4
 #define LOWPAN_FRAGN_HEAD_SIZE	0x5
 
-struct lowpan_addr_info {
-	struct ieee802154_addr daddr;
-	struct ieee802154_addr saddr;
-};
-
-static inline struct
-lowpan_addr_info *lowpan_skb_priv(const struct sk_buff *skb)
-{
-	return (struct lowpan_addr_info *)(skb->data -
-			sizeof(struct lowpan_addr_info));
-}
-
-/* This callback will be called from AF_PACKET and IPv6 stack, the AF_PACKET
- * sockets gives an 8 byte array for addresses only!
- *
- * TODO I think AF_PACKET DGRAM (sending/receiving) RAW (sending) makes no
- * sense here. We should disable it, the right use-case would be AF_INET6
- * RAW/DGRAM sockets.
- */
-int lowpan_header_create(struct sk_buff *skb, struct net_device *ldev,
-			 unsigned short type, const void *daddr,
-			 const void *saddr, unsigned int len)
+static void lowpan_addr_lookup(struct net_device *ldev, struct sk_buff *skb,
+			       struct ieee802154_addr *daddr,
+			       struct ieee802154_addr *saddr)
 {
 	struct wpan_dev *wpan_dev = lowpan_802154_dev(ldev)->wdev->ieee802154_ptr;
-	struct lowpan_addr_info *info = lowpan_skb_priv(skb);
+	struct lowpan_addr_info *info = lowpan_addr_info(skb);
 	struct lowpan_802154_neigh *llneigh = NULL;
 	const struct ipv6hdr *hdr = ipv6_hdr(skb);
 	struct neighbour *n;
 
-	/* TODO:
-	 * if this package isn't ipv6 one, where should it be routed?
-	 */
-	if (type != ETH_P_IPV6)
-		return 0;
-
 	/* intra-pan communication */
-	info->saddr.pan_id = wpan_dev->pan_id;
-	info->daddr.pan_id = info->saddr.pan_id;
+	saddr->pan_id = wpan_dev->pan_id;
+	daddr->pan_id = saddr->pan_id;
 
-	if (!memcmp(daddr, ldev->broadcast, EUI64_ADDR_LEN)) {
-		info->daddr.short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
-		info->daddr.mode = IEEE802154_ADDR_SHORT;
+	if (!memcmp(info->daddr, ldev->broadcast, EUI64_ADDR_LEN)) {
+		daddr->short_addr = cpu_to_le16(IEEE802154_ADDR_BROADCAST);
+		daddr->mode = IEEE802154_ADDR_SHORT;
 	} else {
 		__le16 short_addr = cpu_to_le16(IEEE802154_ADDR_SHORT_UNSPEC);
 
@@ -73,32 +48,25 @@ int lowpan_header_create(struct sk_buff *skb, struct net_device *ldev,
 
 		if (llneigh &&
 		    lowpan_802154_is_valid_src_short_addr(short_addr)) {
-			info->daddr.short_addr = short_addr;
-			info->daddr.mode = IEEE802154_ADDR_SHORT;
+			daddr->short_addr = short_addr;
+			daddr->mode = IEEE802154_ADDR_SHORT;
 		} else {
-			info->daddr.mode = IEEE802154_ADDR_LONG;
-			ieee802154_be64_to_le64(&info->daddr.extended_addr,
-						daddr);
+			daddr->mode = IEEE802154_ADDR_LONG;
+			ieee802154_be64_to_le64(&daddr->extended_addr,
+						info->daddr);
 		}
 
 		if (n)
 			neigh_release(n);
 	}
 
-	if (!saddr) {
-		if (lowpan_802154_is_valid_src_short_addr(wpan_dev->short_addr)) {
-			info->saddr.mode = IEEE802154_ADDR_SHORT;
-			info->saddr.short_addr = wpan_dev->short_addr;
-		} else {
-			info->saddr.mode = IEEE802154_ADDR_LONG;
-			info->saddr.extended_addr = wpan_dev->extended_addr;
-		}
+	if (lowpan_802154_is_valid_src_short_addr(wpan_dev->short_addr)) {
+		saddr->mode = IEEE802154_ADDR_SHORT;
+		saddr->short_addr = wpan_dev->short_addr;
 	} else {
-		info->saddr.mode = IEEE802154_ADDR_LONG;
-		ieee802154_be64_to_le64(&info->saddr.extended_addr, saddr);
+		saddr->mode = IEEE802154_ADDR_LONG;
+		ieee802154_be64_to_le64(&saddr->extended_addr, info->saddr);
 	}
-
-	return 0;
 }
 
 static struct sk_buff*
@@ -227,33 +195,33 @@ err:
 }
 
 static int lowpan_header(struct sk_buff *skb, struct net_device *ldev,
-			 u16 *dgram_size, u16 *dgram_offset)
+			 u16 *dgram_size, u16 *dgram_offset,
+			 const struct ieee802154_addr *daddr,
+			 const struct ieee802154_addr *saddr)
 {
 	struct wpan_dev *wpan_dev = lowpan_802154_dev(ldev)->wdev->ieee802154_ptr;
 	struct ieee802154_mac_cb *cb = mac_cb_init(skb);
-	struct lowpan_addr_info info;
-
-	memcpy(&info, lowpan_skb_priv(skb), sizeof(info));
 
 	*dgram_size = skb->len;
-	lowpan_header_compress(skb, ldev, &info.daddr, &info.saddr);
+	lowpan_header_compress(skb, ldev, daddr, saddr);
 	/* dgram_offset = (saved bytes after compression) + lowpan header len */
 	*dgram_offset = (*dgram_size - skb->len) + skb_network_header_len(skb);
 
 	cb->type = IEEE802154_FC_TYPE_DATA;
 
-	if (info.daddr.mode == IEEE802154_ADDR_SHORT &&
-	    ieee802154_is_broadcast_short_addr(info.daddr.short_addr))
+	if (daddr->mode == IEEE802154_ADDR_SHORT &&
+	    ieee802154_is_broadcast_short_addr(daddr->short_addr))
 		cb->ackreq = false;
 	else
 		cb->ackreq = wpan_dev->ackreq;
 
-	return wpan_dev_hard_header(skb, lowpan_802154_dev(ldev)->wdev,
-				    &info.daddr, &info.saddr, 0);
+	return wpan_dev_hard_header(skb, lowpan_802154_dev(ldev)->wdev, daddr,
+				    saddr, 0);
 }
 
 netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *ldev)
 {
+	struct ieee802154_addr daddr, saddr;
 	struct ieee802154_hdr wpan_hdr;
 	int max_single, ret;
 	u16 dgram_size, dgram_offset;
@@ -262,6 +230,8 @@ netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *ldev)
 
 	WARN_ON_ONCE(skb->len > IPV6_MIN_MTU);
 
+	lowpan_addr_lookup(ldev, skb, &daddr, &saddr);
+
 	/* We must take a copy of the skb before we modify/replace the ipv6
 	 * header as the header could be used elsewhere
 	 */
@@ -269,7 +239,8 @@ netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *ldev)
 	if (!skb)
 		return NET_XMIT_DROP;
 
-	ret = lowpan_header(skb, ldev, &dgram_size, &dgram_offset);
+	ret = lowpan_header(skb, ldev, &dgram_size, &dgram_offset, &daddr,
+			    &saddr);
 	if (ret < 0) {
 		kfree_skb(skb);
 		return NET_XMIT_DROP;
-- 
2.9.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFCv2 bluetooth-next 13/19] 6lowpan: move dev_init to generic
  2016-08-07 14:30 [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation Alexander Aring
                   ` (11 preceding siblings ...)
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 12/19] ieee802154: 6lowpan: move header create to 6lowpan Alexander Aring
@ 2016-08-07 14:30 ` Alexander Aring
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 14/19] 6lowpan: iphc: override l2 packet information Alexander Aring
                   ` (6 subsequent siblings)
  19 siblings, 0 replies; 23+ messages in thread
From: Alexander Aring @ 2016-08-07 14:30 UTC (permalink / raw)
  To: linux-wpan; +Cc: kernel, linux-bluetooth, Alexander Aring

This functionality need to be implemented on all 6LoWPAN interfaces so
we move this to generic 6LoWPAN.

Signed-off-by: Alexander Aring <aar@pengutronix.de>
---
 include/net/6lowpan.h         | 2 ++
 net/6lowpan/core.c            | 8 ++++++++
 net/ieee802154/6lowpan/core.c | 7 -------
 3 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h
index 9a6282b..6a60df9 100644
--- a/include/net/6lowpan.h
+++ b/include/net/6lowpan.h
@@ -286,6 +286,8 @@ int lowpan_register_netdev(struct net_device *dev,
 void lowpan_unregister_netdevice(struct net_device *dev);
 void lowpan_unregister_netdev(struct net_device *dev);
 
+int lowpan_dev_init(struct net_device *dev);
+
 /**
  * lowpan_header_decompress - replace 6LoWPAN header with IPv6 header
  *
diff --git a/net/6lowpan/core.c b/net/6lowpan/core.c
index b01effd..a978000 100644
--- a/net/6lowpan/core.c
+++ b/net/6lowpan/core.c
@@ -45,6 +45,14 @@ static struct header_ops header_ops = {
 	.create	= lowpan_header_create,
 };
 
+int lowpan_dev_init(struct net_device *dev)
+{
+	netdev_lockdep_set_classes(dev);
+
+	return 0;
+}
+EXPORT_SYMBOL(lowpan_dev_init);
+
 int lowpan_register_netdevice(struct net_device *dev,
 			      enum lowpan_lltypes lltype)
 {
diff --git a/net/ieee802154/6lowpan/core.c b/net/ieee802154/6lowpan/core.c
index 096a194..228a711 100644
--- a/net/ieee802154/6lowpan/core.c
+++ b/net/ieee802154/6lowpan/core.c
@@ -54,13 +54,6 @@
 
 static int open_count;
 
-static int lowpan_dev_init(struct net_device *ldev)
-{
-	netdev_lockdep_set_classes(ldev);
-
-	return 0;
-}
-
 static int lowpan_open(struct net_device *dev)
 {
 	if (!open_count)
-- 
2.9.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFCv2 bluetooth-next 14/19] 6lowpan: iphc: override l2 packet information
  2016-08-07 14:30 [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation Alexander Aring
                   ` (12 preceding siblings ...)
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 13/19] 6lowpan: move dev_init to generic Alexander Aring
@ 2016-08-07 14:30 ` Alexander Aring
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 15/19] ipv6: addrconf: fix 48 bit 6lowpan autoconfiguration Alexander Aring
                   ` (5 subsequent siblings)
  19 siblings, 0 replies; 23+ messages in thread
From: Alexander Aring @ 2016-08-07 14:30 UTC (permalink / raw)
  To: linux-wpan; +Cc: kernel, linux-bluetooth, Alexander Aring

The skb->pkt_type need to be set by L2, but on 6LoWPAN there exists L2
e.g. BTLE which doesn't has multicast addressing. If it's a multicast or
not is detected by IPHC headers multicast bit. The IPv6 layer will
evaluate this pkt_type, so we force set this type while uncompressing.
Should be okay for 802.15.4 as well.

Signed-off-by: Alexander Aring <aar@pengutronix.de>
---
 net/6lowpan/iphc.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c
index 79f1fa2..fb5f6fa 100644
--- a/net/6lowpan/iphc.c
+++ b/net/6lowpan/iphc.c
@@ -666,6 +666,8 @@ int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
 
 	switch (iphc1 & (LOWPAN_IPHC_M | LOWPAN_IPHC_DAC)) {
 	case LOWPAN_IPHC_M | LOWPAN_IPHC_DAC:
+		skb->pkt_type = PACKET_BROADCAST;
+
 		spin_lock_bh(&lowpan_dev(dev)->ctx.lock);
 		ci = lowpan_iphc_ctx_get_by_id(dev, LOWPAN_IPHC_CID_DCI(cid));
 		if (!ci) {
@@ -681,11 +683,15 @@ int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
 		spin_unlock_bh(&lowpan_dev(dev)->ctx.lock);
 		break;
 	case LOWPAN_IPHC_M:
+		skb->pkt_type = PACKET_BROADCAST;
+
 		/* multicast */
 		err = lowpan_uncompress_multicast_daddr(skb, &hdr.daddr,
 							iphc1 & LOWPAN_IPHC_DAM_MASK);
 		break;
 	case LOWPAN_IPHC_DAC:
+		skb->pkt_type = PACKET_HOST;
+
 		spin_lock_bh(&lowpan_dev(dev)->ctx.lock);
 		ci = lowpan_iphc_ctx_get_by_id(dev, LOWPAN_IPHC_CID_DCI(cid));
 		if (!ci) {
@@ -701,6 +707,8 @@ int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
 		spin_unlock_bh(&lowpan_dev(dev)->ctx.lock);
 		break;
 	default:
+		skb->pkt_type = PACKET_HOST;
+
 		err = lowpan_iphc_uncompress_addr(skb, dev, &hdr.daddr,
 						  iphc1 & LOWPAN_IPHC_DAM_MASK,
 						  daddr);
-- 
2.9.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFCv2 bluetooth-next 15/19] ipv6: addrconf: fix 48 bit 6lowpan autoconfiguration
  2016-08-07 14:30 [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation Alexander Aring
                   ` (13 preceding siblings ...)
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 14/19] 6lowpan: iphc: override l2 packet information Alexander Aring
@ 2016-08-07 14:30 ` Alexander Aring
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 16/19] 6lowpan: iphc: add handling for btle Alexander Aring
                   ` (4 subsequent siblings)
  19 siblings, 0 replies; 23+ messages in thread
From: Alexander Aring @ 2016-08-07 14:30 UTC (permalink / raw)
  To: linux-wpan; +Cc: kernel, linux-bluetooth, Alexander Aring

This patch adds support for 48 bit 6LoWPAN address length
autoconfiguration which is the case for BTLE 6LoWPAN.

Signed-off-by: Alexander Aring <aar@pengutronix.de>
---
 net/ipv6/addrconf.c | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index ab3e796..f2d4de8 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -2007,12 +2007,21 @@ static void addrconf_leave_anycast(struct inet6_ifaddr *ifp)
 	__ipv6_dev_ac_dec(ifp->idev, &addr);
 }
 
-static int addrconf_ifid_eui64(u8 *eui, struct net_device *dev)
+static int addrconf_ifid_6lowpan(u8 *eui, struct net_device *dev)
 {
-	if (dev->addr_len != EUI64_ADDR_LEN)
+	switch (dev->addr_len) {
+	case ETH_ALEN:
+		return addrconf_ifid_eui48(eui, dev);
+	case EUI64_ADDR_LEN:
+		if (dev->addr_len != EUI64_ADDR_LEN)
+			return -1;
+		memcpy(eui, dev->dev_addr, EUI64_ADDR_LEN);
+		eui[0] ^= 2;
+		break;
+	default:
 		return -1;
-	memcpy(eui, dev->dev_addr, EUI64_ADDR_LEN);
-	eui[0] ^= 2;
+	}
+
 	return 0;
 }
 
@@ -2103,7 +2112,7 @@ static int ipv6_generate_eui64(u8 *eui, struct net_device *dev)
 	case ARPHRD_IPGRE:
 		return addrconf_ifid_gre(eui, dev);
 	case ARPHRD_6LOWPAN:
-		return addrconf_ifid_eui64(eui, dev);
+		return addrconf_ifid_6lowpan(eui, dev);
 	case ARPHRD_IEEE1394:
 		return addrconf_ifid_ieee1394(eui, dev);
 	case ARPHRD_TUNNEL6:
-- 
2.9.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFCv2 bluetooth-next 16/19] 6lowpan: iphc: add handling for btle
  2016-08-07 14:30 [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation Alexander Aring
                   ` (14 preceding siblings ...)
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 15/19] ipv6: addrconf: fix 48 bit 6lowpan autoconfiguration Alexander Aring
@ 2016-08-07 14:30 ` Alexander Aring
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 17/19] 6lowpan: move multicast flags to generic Alexander Aring
                   ` (3 subsequent siblings)
  19 siblings, 0 replies; 23+ messages in thread
From: Alexander Aring @ 2016-08-07 14:30 UTC (permalink / raw)
  To: linux-wpan; +Cc: kernel, linux-bluetooth, Alexander Aring

This patch adds right handling for uncompress/compress L3 addresses
which are compressed by BTLE L2 address.

Signed-off-by: Alexander Aring <aar@pengutronix.de>
---
 net/6lowpan/iphc.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 103 insertions(+)

diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c
index fb5f6fa..e93f656 100644
--- a/net/6lowpan/iphc.c
+++ b/net/6lowpan/iphc.c
@@ -50,6 +50,7 @@
 #include <linux/if_arp.h>
 #include <linux/netdevice.h>
 
+#include <net/bluetooth/bluetooth.h>
 #include <net/6lowpan.h>
 #include <net/ipv6.h>
 
@@ -186,6 +187,27 @@ lowpan_iphc_uncompress_802154_lladdr(struct in6_addr *ipaddr,
 	}
 }
 
+static inline void
+lowpan_iphc_uncompress_btle_lladdr(struct in6_addr *ipaddr, const void *lladdr)
+{
+	bdaddr_t be_bdaddr;
+
+	/* ipv6 addr needs big endian form here
+	 * TODO make src in baswap const?
+	 */
+	baswap(&be_bdaddr, (bdaddr_t *)lladdr);
+
+	ipaddr->s6_addr[0] = 0xFE;
+	ipaddr->s6_addr[1] = 0x80;
+
+	memcpy(&ipaddr->s6_addr[8], be_bdaddr.b, 3);
+	memcpy(&ipaddr->s6_addr[13], be_bdaddr.b + 3, 3);
+
+	ipaddr->s6_addr[11] = 0xFF;
+	ipaddr->s6_addr[12] = 0xFE;
+	ipaddr->s6_addr[8] ^= 2;
+}
+
 static struct lowpan_iphc_ctx *
 lowpan_iphc_ctx_get_by_id(const struct net_device *dev, u8 id)
 {
@@ -315,11 +337,19 @@ static int lowpan_iphc_uncompress_addr(struct sk_buff *skb,
 	case LOWPAN_IPHC_SAM_11:
 	case LOWPAN_IPHC_DAM_11:
 		fail = false;
+		/* TODO this can work to work as length here, ipv6 addrconf
+		 * has similar functionality to generate autoconfigured
+		 * addresses - use shared code here.
+		 */
 		switch (lowpan_dev(dev)->lltype) {
 		case LOWPAN_LLTYPE_IEEE802154:
 			lowpan_iphc_uncompress_802154_lladdr(ipaddr, lladdr);
 			break;
+		case LOWPAN_LLTYPE_BTLE:
+			lowpan_iphc_uncompress_btle_lladdr(ipaddr, lladdr);
+			break;
 		default:
+			/* TODO remove? */
 			lowpan_iphc_uncompress_eui64_lladdr(ipaddr, lladdr);
 			break;
 		}
@@ -380,6 +410,9 @@ static int lowpan_iphc_uncompress_ctx_addr(struct sk_buff *skb,
 		case LOWPAN_LLTYPE_IEEE802154:
 			lowpan_iphc_uncompress_802154_lladdr(ipaddr, lladdr);
 			break;
+		case LOWPAN_LLTYPE_BTLE:
+			lowpan_iphc_uncompress_btle_lladdr(ipaddr, lladdr);
+			break;
 		default:
 			lowpan_iphc_uncompress_eui64_lladdr(ipaddr, lladdr);
 			break;
@@ -810,6 +843,29 @@ lowpan_iphc_compress_ctx_802154_lladdr(const struct in6_addr *ipaddr,
 	return lladdr_compress;
 }
 
+static inline bool
+lowpan_iphc_compress_ctx_btle_lladdr(const struct in6_addr *ipaddr,
+				     const struct lowpan_iphc_ctx *ctx,
+				     const void *lladdr)
+{
+	struct in6_addr tmp = {};
+	bdaddr_t be_bdaddr;
+
+	/* ipv6 addr needs big endian form here */
+	baswap(&be_bdaddr, (bdaddr_t *)lladdr);
+
+	memcpy(&tmp.s6_addr[8], be_bdaddr.b, 3);
+	memcpy(&tmp.s6_addr[13], be_bdaddr.b + 3, 3);
+
+	tmp.s6_addr[11] = 0xFF;
+	tmp.s6_addr[12] = 0xFE;
+	tmp.s6_addr[8] ^= 2;
+
+	/* context information are always used */
+	ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen);
+	return ipv6_addr_equal(&tmp, ipaddr);
+}
+
 static u8 lowpan_compress_ctx_addr(u8 **hc_ptr, const struct net_device *dev,
 				   const struct in6_addr *ipaddr,
 				   const struct lowpan_iphc_ctx *ctx,
@@ -826,6 +882,13 @@ static u8 lowpan_compress_ctx_addr(u8 **hc_ptr, const struct net_device *dev,
 			goto out;
 		}
 		break;
+	case LOWPAN_LLTYPE_BTLE:
+		if (lowpan_iphc_compress_ctx_btle_lladdr(ipaddr, ctx,
+							 lladdr)) {
+			dam = LOWPAN_IPHC_DAM_11;
+			goto out;
+		}
+		break;
 	default:
 		/* check for SAM/DAM = 11 */
 		memcpy(&tmp.s6_addr[8], lladdr, EUI64_ADDR_LEN);
@@ -886,6 +949,7 @@ lowpan_iphc_compress_802154_lladdr(const struct in6_addr *ipaddr,
 	switch (addr->mode) {
 	case IEEE802154_ADDR_LONG:
 		ieee802154_le64_to_be64(&extended_addr, &addr->extended_addr);
+		/* TODO remove this macro and use ipv6_addr_equal */
 		if (is_addr_mac_addr_based(ipaddr, extended_addr))
 			lladdr_compress = true;
 		break;
@@ -914,12 +978,38 @@ lowpan_iphc_compress_802154_lladdr(const struct in6_addr *ipaddr,
 	return lladdr_compress;
 }
 
+static inline bool
+lowpan_iphc_compress_btle_lladdr(const struct in6_addr *ipaddr,
+				 const void *lladdr)
+{
+	struct in6_addr tmp = {};
+	bdaddr_t be_bdaddr;
+
+	/* ipv6 addr needs big endian form here */
+	baswap(&be_bdaddr, (bdaddr_t *)lladdr);
+
+	tmp.s6_addr[0] = 0xFE;
+	tmp.s6_addr[1] = 0x80;
+
+	memcpy(&tmp.s6_addr[8], be_bdaddr.b, 3);
+	memcpy(&tmp.s6_addr[13], be_bdaddr.b + 3, 3);
+
+	tmp.s6_addr[11] = 0xFF;
+	tmp.s6_addr[12] = 0xFE;
+	tmp.s6_addr[8] ^= 2;
+
+	return ipv6_addr_equal(&tmp, ipaddr);
+}
+
 static u8 lowpan_compress_addr_64(u8 **hc_ptr, const struct net_device *dev,
 				  const struct in6_addr *ipaddr,
 				  const unsigned char *lladdr, bool sam)
 {
 	u8 dam = LOWPAN_IPHC_DAM_01;
 
+	/* TODO share code with compress ctx stuff here, stateless compress
+	 * is the same like stateful except the prefix must be fe80::/64
+	 */
 	switch (lowpan_dev(dev)->lltype) {
 	case LOWPAN_LLTYPE_IEEE802154:
 		if (lowpan_iphc_compress_802154_lladdr(ipaddr, lladdr)) {
@@ -928,7 +1018,15 @@ static u8 lowpan_compress_addr_64(u8 **hc_ptr, const struct net_device *dev,
 			goto out;
 		}
 		break;
+	case LOWPAN_LLTYPE_BTLE:
+		if (lowpan_iphc_compress_btle_lladdr(ipaddr, lladdr)) {
+			dam = LOWPAN_IPHC_DAM_11; /* 0-bits */
+			pr_debug("address compression 0 bits\n");
+			goto out;
+		}
+		break;
 	default:
+		/* TODO remove? */
 		if (is_addr_mac_addr_based(ipaddr, lladdr)) {
 			dam = LOWPAN_IPHC_DAM_11; /* 0-bits */
 			pr_debug("address compression 0 bits\n");
@@ -1100,6 +1198,11 @@ static u8 lowpan_iphc_mcast_addr_compress(u8 **hc_ptr,
 	return val;
 }
 
+/* TODO maybe handle directly saddr, daddr as big endian? unnecessary byteswaps.
+ * Neighbour cachane and dev->dev_addr is big endian saved, don't use l2 format
+ * here maybe? Cons: Will confuse everything, because lladdr are saved always
+ * in format as mac header format. Same for lowpan_header_decompress.
+ */
 int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
 			   const void *daddr, const void *saddr)
 {
-- 
2.9.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFCv2 bluetooth-next 17/19] 6lowpan: move multicast flags to generic
  2016-08-07 14:30 [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation Alexander Aring
                   ` (15 preceding siblings ...)
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 16/19] 6lowpan: iphc: add handling for btle Alexander Aring
@ 2016-08-07 14:30 ` Alexander Aring
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 18/19] 6lowpan: move addr_len setting away from generic Alexander Aring
                   ` (2 subsequent siblings)
  19 siblings, 0 replies; 23+ messages in thread
From: Alexander Aring @ 2016-08-07 14:30 UTC (permalink / raw)
  To: linux-wpan; +Cc: kernel, linux-bluetooth, Alexander Aring

These flags should be all the same for 6LoWPAN so move it to 6LoWPAN generic.

Signed-off-by: Alexander Aring <aar@pengutronix.de>
---
 net/6lowpan/core.c            | 1 +
 net/ieee802154/6lowpan/core.c | 1 -
 2 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/6lowpan/core.c b/net/6lowpan/core.c
index a978000..6b7de14 100644
--- a/net/6lowpan/core.c
+++ b/net/6lowpan/core.c
@@ -62,6 +62,7 @@ int lowpan_register_netdevice(struct net_device *dev,
 	dev->type = ARPHRD_6LOWPAN;
 	dev->mtu = IPV6_MIN_MTU;
 	dev->priv_flags |= IFF_NO_QUEUE;
+	dev->flags = IFF_BROADCAST | IFF_MULTICAST;
 
 	dev->header_ops = &header_ops;
 
diff --git a/net/ieee802154/6lowpan/core.c b/net/ieee802154/6lowpan/core.c
index 228a711..a60abad 100644
--- a/net/ieee802154/6lowpan/core.c
+++ b/net/ieee802154/6lowpan/core.c
@@ -92,7 +92,6 @@ static void lowpan_setup(struct net_device *ldev)
 	memset(ldev->broadcast, 0xff, IEEE802154_ADDR_LEN);
 	/* We need an ipv6hdr as minimum len when calling xmit */
 	ldev->hard_header_len	= sizeof(struct ipv6hdr);
-	ldev->flags		= IFF_BROADCAST | IFF_MULTICAST;
 
 	ldev->netdev_ops	= &lowpan_netdev_ops;
 	ldev->destructor	= free_netdev;
-- 
2.9.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFCv2 bluetooth-next 18/19] 6lowpan: move addr_len setting away from generic
  2016-08-07 14:30 [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation Alexander Aring
                   ` (16 preceding siblings ...)
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 17/19] 6lowpan: move multicast flags to generic Alexander Aring
@ 2016-08-07 14:30 ` Alexander Aring
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 19/19] 6lowpan: bluetooth: add new implementation Alexander Aring
  2016-08-08 12:10 ` [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation Alexander Aring
  19 siblings, 0 replies; 23+ messages in thread
From: Alexander Aring @ 2016-08-07 14:30 UTC (permalink / raw)
  To: linux-wpan; +Cc: kernel, linux-bluetooth, Alexander Aring

The address length for BTLE 6LoWPAN is not 8 bytes, it's 6 bytes. We
need to move this setting away from generic branch.

Signed-off-by: Alexander Aring <aar@pengutronix.de>
---
 net/6lowpan/core.c            | 1 -
 net/ieee802154/6lowpan/core.c | 1 +
 2 files changed, 1 insertion(+), 1 deletion(-)

diff --git a/net/6lowpan/core.c b/net/6lowpan/core.c
index 6b7de14..e03cecf 100644
--- a/net/6lowpan/core.c
+++ b/net/6lowpan/core.c
@@ -58,7 +58,6 @@ int lowpan_register_netdevice(struct net_device *dev,
 {
 	int i, ret;
 
-	dev->addr_len = EUI64_ADDR_LEN;
 	dev->type = ARPHRD_6LOWPAN;
 	dev->mtu = IPV6_MIN_MTU;
 	dev->priv_flags |= IFF_NO_QUEUE;
diff --git a/net/ieee802154/6lowpan/core.c b/net/ieee802154/6lowpan/core.c
index a60abad..c97eb7a 100644
--- a/net/ieee802154/6lowpan/core.c
+++ b/net/ieee802154/6lowpan/core.c
@@ -134,6 +134,7 @@ static int lowpan_newlink(struct net *src_net, struct net_device *ldev,
 	}
 
 	lowpan_802154_dev(ldev)->wdev = wdev;
+	ldev->addr_len = IEEE802154_ADDR_LEN;
 	/* Set the lowpan hardware address to the wpan hardware address. */
 	memcpy(ldev->dev_addr, wdev->dev_addr, IEEE802154_ADDR_LEN);
 	/* We need headroom for possible wpan_dev_hard_header call and tailroom
-- 
2.9.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [RFCv2 bluetooth-next 19/19] 6lowpan: bluetooth: add new implementation
  2016-08-07 14:30 [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation Alexander Aring
                   ` (17 preceding siblings ...)
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 18/19] 6lowpan: move addr_len setting away from generic Alexander Aring
@ 2016-08-07 14:30 ` Alexander Aring
  2016-08-08 12:10 ` [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation Alexander Aring
  19 siblings, 0 replies; 23+ messages in thread
From: Alexander Aring @ 2016-08-07 14:30 UTC (permalink / raw)
  To: linux-wpan; +Cc: kernel, linux-bluetooth, Alexander Aring

This patch adds a new btle 6lowpan implementation in version 0.2. This
new implementation has a new userspace API for debugfs.

To test it:

Node A:
btmgmt power off
echo "1" > /sys/kernel/debug/bluetooth/6lowpan_enable
btmgmt power on

hciconfig hci0 leadv

Node B:
btmgmt power off
echo "1" > /sys/kernel/debug/bluetooth/6lowpan_enable
btmgmt power on

hcitool lecc $1
echo "connect $1 1" > /sys/kernel/debug/bluetooth/hci0/6lowpan_control

Where $1 is the address of Node A.

When the hci get's powered on the 6LoWPAN interface will be created with
a device address of 0...0, after the first connection is established
then the device address will be set. During this time it's not possible
to set the interface up.

The "6lowpan_enable" debugfs entry need to be 1 before setting hci power
on.

Signed-off-by: Alexander Aring <aar@pengutronix.de>
---
 include/net/bluetooth/hci_core.h |   4 +
 net/bluetooth/6lowpan.c          | 924 +++++++++++++++++++++++++++++++++++++++
 net/bluetooth/Makefile           |   3 +
 3 files changed, 931 insertions(+)
 create mode 100644 net/bluetooth/6lowpan.c

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index f808aa0..6d9ce5f 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -403,6 +403,10 @@ struct hci_dev {
 	struct led_trigger	*power_led;
 #endif
 
+#if IS_ENABLED(CONFIG_BT_6LOWPAN)
+	struct net_device *ldev;
+#endif
+
 	int (*open)(struct hci_dev *hdev);
 	int (*close)(struct hci_dev *hdev);
 	int (*flush)(struct hci_dev *hdev);
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
new file mode 100644
index 0000000..9ca9448
--- /dev/null
+++ b/net/bluetooth/6lowpan.c
@@ -0,0 +1,924 @@
+/*
+   (C) 2016 Pengutronix, Alexander Aring <aar@pengutronix.de>
+   Copyright (c) 2013-2014 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/if_arp.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <linux/debugfs.h>
+
+#include <net/ipv6.h>
+#include <net/ip6_route.h>
+#include <net/addrconf.h>
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/l2cap.h>
+
+#include <net/6lowpan.h>
+
+#define LOWPAN_BTLE_VERSION "0.2"
+
+#define lowpan_le48_to_be48(dst, src) baswap((bdaddr_t *)dst, (bdaddr_t *)src)
+#define lowpan_be48_to_le48(dst, src) baswap((bdaddr_t *)dst, (bdaddr_t *)src)
+
+struct lowpan_btle_cb {
+	struct l2cap_chan *chan;
+};
+
+struct lowpan_btle_dev {
+	struct hci_dev *hdev;
+	struct workqueue_struct *workqueue;
+	struct l2cap_chan *listen;
+	struct list_head peers;
+	struct dentry *control;
+};
+
+/* This flag avoids to run list_del_rcu in close when no ready callback was
+ * run before. This seems to be possible by l2cap_chan_timeout.
+ */
+#define LOWPAN_BTLE_PEER_WAS_READY	0
+
+struct lowpan_peer {
+	struct l2cap_chan *chan;
+	unsigned long flags;
+	struct list_head list;
+};
+
+struct lowpan_chan_data {
+	struct lowpan_peer peer;
+	struct net_device *dev;
+};
+
+struct lowpan_xmit_work {
+	struct work_struct work;
+	struct l2cap_chan *chan;
+	struct net_device *dev;
+	unsigned int uncompressed_len;
+	struct sk_buff *skb;
+};
+
+static inline struct lowpan_btle_cb *
+lowpan_btle_cb(const struct sk_buff *skb)
+{
+	return (struct lowpan_btle_cb *)skb->cb;
+}
+
+static inline struct lowpan_chan_data *
+lowpan_chan_data(const struct l2cap_chan *chan)
+{
+	return (struct lowpan_chan_data *)chan->data;
+}
+
+static inline struct lowpan_btle_dev *
+lowpan_btle_dev(const struct net_device *dev)
+{
+	return (struct lowpan_btle_dev *)lowpan_dev(dev)->priv;
+}
+
+static inline struct lowpan_peer *
+lowpan_lookup_peer(struct lowpan_btle_dev *btdev, bdaddr_t *addr)
+{
+	struct lowpan_peer *entry;
+
+	list_for_each_entry_rcu(entry, &btdev->peers, list) {
+		if (!bacmp(&entry->chan->dst, addr))
+			return entry;
+	}
+
+	return NULL;
+}
+
+static struct dentry *lowpan_enabled_dentry;
+static bool lowpan_enabled;
+
+static int lowpan_give_skb_to_device(struct sk_buff *skb)
+{
+	skb->protocol = htons(ETH_P_IPV6);
+	skb->dev->stats.rx_packets++;
+	skb->dev->stats.rx_bytes += skb->len;
+
+	return netif_rx_ni(skb);
+}
+
+static int lowpan_rx_handlers_result(struct sk_buff *skb, lowpan_rx_result res)
+{
+	switch (res) {
+	case RX_CONTINUE:
+		/* nobody cared about this packet */
+		net_warn_ratelimited("%s: received unknown dispatch\n",
+				     __func__);
+
+		/* fall-through */
+	case RX_DROP_UNUSABLE:
+		kfree_skb(skb);
+
+		/* fall-through */
+	case RX_DROP:
+		return NET_RX_DROP;
+	case RX_QUEUED:
+		return lowpan_give_skb_to_device(skb);
+	default:
+		break;
+	}
+
+	return NET_RX_DROP;
+}
+
+static lowpan_rx_result lowpan_rx_h_iphc(struct sk_buff *skb)
+{
+	struct l2cap_chan *chan = lowpan_btle_cb(skb)->chan;
+	bdaddr_t daddr, saddr;
+	int ret;
+
+	if (!lowpan_is_iphc(*skb_network_header(skb)))
+		return RX_CONTINUE;
+
+	BT_DBG("recv %s dst: %pMR type %d src: %pMR chan %p",
+	       skb->dev->name, &chan->dst, chan->dst_type, &chan->src, chan);
+
+	/* bluetooth chan view is vice-versa */
+	bacpy(&daddr, &chan->src);
+	bacpy(&saddr, &chan->dst);
+
+	ret = lowpan_header_decompress(skb, skb->dev, &daddr, &saddr);
+	if (ret < 0)
+		return RX_DROP_UNUSABLE;
+
+	return RX_QUEUED;
+}
+
+static int lowpan_invoke_rx_handlers(struct sk_buff *skb)
+{
+	lowpan_rx_result res;
+
+#define CALL_RXH(rxh)			\
+	do {				\
+		res = rxh(skb);		\
+		if (res != RX_CONTINUE)	\
+			goto rxh_next;	\
+	} while (0)
+
+	/* likely at first */
+	CALL_RXH(lowpan_rx_h_iphc);
+
+rxh_next:
+	return lowpan_rx_handlers_result(skb, res);
+#undef CALL_RXH
+}
+
+static int lowpan_chan_recv(struct l2cap_chan *chan, struct sk_buff *skb)
+{
+	struct lowpan_chan_data *data = lowpan_chan_data(chan);
+	struct net_device *dev = data->dev;
+	int ret;
+
+	/* TODO handle BT_CONNECTED in bluetooth subsytem?
+	 * when calling recv callback, I hit that case somehow
+	 */
+	if (!netif_running(dev) || chan->state != BT_CONNECTED ||
+	    !skb->len || !lowpan_is_iphc(skb->data[0]))
+		goto drop;
+
+	/* Replacing skb->dev and followed rx handlers will manipulate skb. */
+	skb = skb_unshare(skb, GFP_ATOMIC);
+	if (!skb)
+		goto out;
+
+	skb->dev = dev;
+	skb_reset_network_header(skb);
+
+	/* remember that one for dst bdaddr. TODO handle that as priv data for
+	 * lowpan_invoke_rx_handlers parameter. Not necessary for skb->cb.
+	 */
+	lowpan_btle_cb(skb)->chan = chan;
+
+	ret = lowpan_invoke_rx_handlers(skb);
+	if (ret == NET_RX_DROP)
+		BT_DBG("recv %s dropped chan %p", skb->dev->name, chan);
+
+	return 0;
+
+drop:
+	kfree_skb(skb);
+out:
+	/* we handle to free skb on error, so must 0
+	 * seems that callback free the skb on error
+	 * otherwise.
+	 */
+	return 0;
+}
+
+static void lowpan_xmit_worker(struct work_struct *work)
+{
+	struct lowpan_btle_dev *btdev;
+	struct lowpan_xmit_work *xw;
+	struct l2cap_chan *chan;
+	struct net_device *dev;
+	struct msghdr msg = { };
+	struct kvec iv;
+	int ret;
+
+	xw = container_of(work, struct lowpan_xmit_work, work);
+	dev = xw->dev;
+	chan = xw->chan;
+	btdev = lowpan_btle_dev(dev);
+
+	iv.iov_base = xw->skb->data;
+	iv.iov_len = xw->skb->len;
+	iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, &iv, 1, xw->skb->len);
+
+	BT_DBG("l2cap_chan_send %s dst: %pMR type %d src: %pMR chan %p",
+	       dev->name, &chan->dst, chan->dst_type, &chan->src, chan);
+
+	l2cap_chan_lock(chan);
+
+	ret = l2cap_chan_send(chan, &msg, xw->skb->len);
+	BT_DBG("transmit return value %d", ret);
+	if (ret < 0) {
+		BT_DBG("send %s failed chan %p", dev->name, chan);
+		kfree_skb(xw->skb);
+	} else {
+		consume_skb(xw->skb);
+		dev->stats.tx_bytes += xw->uncompressed_len;
+		dev->stats.tx_packets++;
+	}
+
+	l2cap_chan_unlock(chan);
+	l2cap_chan_put(chan);
+
+	kfree(xw);
+}
+
+static void lowpan_send_unicast_pkt(struct net_device *dev,
+				    struct l2cap_chan *chan,
+				    struct sk_buff *skb,
+				    unsigned int uncompressed_len)
+{
+	struct lowpan_xmit_work *xw;
+
+	/* copy to xmit work buffer */
+	xw = kzalloc(sizeof(*xw), GFP_ATOMIC);
+	if (!xw)
+		return;
+
+	/* chan->lock mutex need to be hold so change context to workqueue */
+	INIT_WORK(&xw->work, lowpan_xmit_worker);
+	xw->uncompressed_len = uncompressed_len;
+	/* freeing protected by ifdown workqueue sync */
+	xw->dev = dev;
+	/* disallow freeing of skb while context switch */
+	xw->skb = skb_get(skb);
+	/* disallow freeing while context switch */
+	l2cap_chan_hold(chan);
+	xw->chan = chan;
+
+	queue_work(lowpan_btle_dev(dev)->workqueue, &xw->work);
+}
+
+static void lowpan_send_mcast_pkt(struct net_device *dev, struct sk_buff *skb,
+				  unsigned int uncompressed_len)
+{
+	struct lowpan_btle_dev *btdev = lowpan_btle_dev(dev);
+	struct lowpan_peer *peer;
+
+	BT_DBG("xmit %s starts multicasting", dev->name);
+
+	/* We need to send the packet to every device behind this
+	 * interface, because multicasting.
+	 *
+	 * TODO, rfc7668:
+	 *
+	 * If the 6LBR needs to send
+	 * a multicast packet to all its 6LNs, it has to replicate the packet
+	 * and unicast it on each link.  However, this may not be energy
+	 * efficient, and particular care must be taken if the central is
+	 * battery powered.  To further conserve power, the 6LBR MUST keep track
+	 * of multicast listeners at Bluetooth LE link-level granularity (not at
+	 * subnet granularity), and it MUST NOT forward multicast packets to
+	 * 6LNs that have not registered as listeners for multicast groups the
+	 * packets belong to.
+	 */
+	rcu_read_lock();
+
+	list_for_each_entry_rcu(peer, &btdev->peers, list)
+		lowpan_send_unicast_pkt(dev, peer->chan, skb, uncompressed_len);
+
+	rcu_read_unlock();
+}
+
+static netdev_tx_t lowpan_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct lowpan_addr_info *info = lowpan_addr_info(skb);
+	struct lowpan_btle_dev *btdev = lowpan_btle_dev(dev);
+	unsigned int uncompressed_len = skb->len;
+	struct lowpan_peer *peer;
+	bdaddr_t daddr, saddr;
+	int ret;
+
+	/* We must take a copy of the skb before we modify/replace the ipv6
+	 * header as the header could be used elsewhere.
+	 */
+	skb = skb_unshare(skb, GFP_ATOMIC);
+	if (!skb) {
+		kfree_skb(skb);
+		goto out;
+	}
+
+	lowpan_be48_to_le48(&daddr, info->daddr);
+	lowpan_be48_to_le48(&saddr, info->saddr);
+
+	BT_DBG("xmit ndisc %s dst: %pMR src: %pMR",
+	       dev->name, &daddr, &saddr);
+
+	ret = lowpan_header_compress(skb, dev, &daddr, &saddr);
+	if (ret < 0) {
+		kfree_skb(skb);
+		goto out;
+	}
+
+	/* this should never be the case, otherwise iphc is broken */
+	WARN_ON_ONCE(skb->len > dev->mtu);
+
+	if (!memcmp(&daddr, dev->broadcast, dev->addr_len)) {
+		lowpan_send_mcast_pkt(dev, skb, uncompressed_len);
+	} else {
+		btdev = lowpan_btle_dev(dev);
+
+		rcu_read_lock();
+
+		peer = lowpan_lookup_peer(btdev, &daddr);
+		if (peer)
+			lowpan_send_unicast_pkt(dev, peer->chan, skb,
+						uncompressed_len);
+
+		rcu_read_unlock();
+	}
+
+	consume_skb(skb);
+
+out:
+	return NETDEV_TX_OK;
+}
+
+static int lowpan_open(struct net_device *dev)
+{
+	if (!memcmp(dev->dev_addr, BDADDR_ANY, dev->addr_len))
+		return -ENOTCONN;
+	else
+		return 0;
+}
+
+static int lowpan_stop(struct net_device *dev)
+{
+	struct lowpan_btle_dev *btdev = lowpan_btle_dev(dev);
+
+	/* synchronize with xmit worker */
+	flush_workqueue(btdev->workqueue);
+	return 0;
+}
+
+static struct sk_buff *lowpan_chan_alloc_skb(struct l2cap_chan *chan,
+					     unsigned long hdr_len,
+					     unsigned long len, int nb)
+{
+	return bt_skb_alloc(hdr_len + len, GFP_KERNEL);
+}
+
+static long lowpan_chan_get_sndtimeo(struct l2cap_chan *chan)
+{
+	return L2CAP_CONN_TIMEOUT;
+}
+
+static struct l2cap_chan *lowpan_chan_create(struct net_device *dev)
+{
+	struct lowpan_chan_data *data;
+	struct l2cap_chan *chan;
+
+	chan = l2cap_chan_create_priv(sizeof(*data));
+	if (!chan)
+		return ERR_PTR(-ENOMEM);
+
+	l2cap_chan_set_defaults(chan);
+	chan->chan_type = L2CAP_CHAN_CONN_ORIENTED;
+	chan->mode = L2CAP_MODE_LE_FLOWCTL;
+	chan->imtu = dev->mtu;
+
+	data = chan->data;
+	data->peer.chan = chan;
+	data->dev = dev;
+	dev_hold(dev);
+
+	return chan;
+}
+
+static struct l2cap_chan *lowpan_chan_new_conn(struct l2cap_chan *pchan)
+{
+	struct lowpan_chan_data *data = lowpan_chan_data(pchan);
+	struct l2cap_chan *chan;
+
+	chan = lowpan_chan_create(data->dev);
+	if (IS_ERR(chan))
+		return NULL;
+
+	chan->ops = pchan->ops;
+	return chan;
+}
+
+static void lowpan_chan_ready(struct l2cap_chan *chan)
+{
+	struct lowpan_chan_data *data = lowpan_chan_data(chan);
+	struct net_device *dev = data->dev;
+	struct lowpan_btle_dev *btdev = lowpan_btle_dev(dev);
+
+	rtnl_lock();
+
+	/* first connection which will be established */
+	if (list_empty(&btdev->peers)) {
+		bdaddr_t bdaddr;
+		u8 bdaddr_type;
+
+		/* set RPA device address to 6lo interface */
+		hci_copy_identity_address(btdev->hdev, &bdaddr, &bdaddr_type);
+
+		lowpan_le48_to_be48(dev->dev_addr, &bdaddr);
+		dev_open(dev);
+	}
+
+	BT_DBG("%s chan %p ready ", dev->name, chan);
+
+	/* make it visible for xmit */
+	list_add_tail_rcu(&data->peer.list, &btdev->peers);
+	synchronize_rcu();
+
+	set_bit(LOWPAN_BTLE_PEER_WAS_READY, &data->peer.flags);
+	rtnl_unlock();
+}
+
+static void lowpan_chan_close(struct l2cap_chan *chan)
+{
+	struct lowpan_chan_data *data = lowpan_chan_data(chan);
+	struct net_device *dev = data->dev;
+	struct lowpan_btle_dev *btdev = lowpan_btle_dev(dev);
+
+	rtnl_lock();
+
+	BT_DBG("%s chan %p closed ", dev->name, chan);
+
+	if (test_and_clear_bit(LOWPAN_BTLE_PEER_WAS_READY, &data->peer.flags)) {
+		/* make it unvisible for xmit */
+		list_del_rcu(&data->peer.list);
+		synchronize_rcu();
+	}
+
+	/* if no peers are connected anymore */
+	if (list_empty(&btdev->peers)) {
+		dev_close(dev);
+		memcpy(dev->dev_addr, BDADDR_ANY, dev->addr_len);
+	}
+
+	rtnl_unlock();
+	dev_put(dev);
+}
+
+static const struct l2cap_ops lowpan_chan_ops = {
+	.name			= "L2CAP 6LoWPAN channel",
+	.new_connection		= lowpan_chan_new_conn,
+	.recv			= lowpan_chan_recv,
+	.close			= lowpan_chan_close,
+	.state_change		= l2cap_chan_no_state_change,
+	.ready			= lowpan_chan_ready,
+	.get_sndtimeo		= lowpan_chan_get_sndtimeo,
+	.alloc_skb		= lowpan_chan_alloc_skb,
+	.teardown		= l2cap_chan_no_teardown,
+	.defer			= l2cap_chan_no_defer,
+	.set_shutdown		= l2cap_chan_no_set_shutdown,
+	.resume			= l2cap_chan_no_resume,
+	.suspend		= l2cap_chan_no_suspend,
+};
+
+static int lowpan_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct lowpan_btle_dev *btdev = lowpan_btle_dev(dev);
+
+	/* if dev is down, peers list are protected by RTNL */
+	if (netif_running(dev) || !list_empty(&btdev->peers))
+		return -EBUSY;
+
+	if (new_mtu < IPV6_MIN_MTU)
+		return -EINVAL;
+
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+static const struct net_device_ops netdev_ops = {
+	.ndo_init		= lowpan_dev_init,
+	.ndo_open		= lowpan_open,
+	.ndo_stop		= lowpan_stop,
+	.ndo_start_xmit		= lowpan_xmit,
+	.ndo_change_mtu		= lowpan_change_mtu,
+};
+
+static void lowpan_free_netdev(struct net_device *dev)
+{
+	struct lowpan_btle_dev *btdev = lowpan_btle_dev(dev);
+
+	destroy_workqueue(btdev->workqueue);
+	debugfs_remove(btdev->control);
+	hci_dev_put(btdev->hdev);
+}
+
+static void lowpan_setup(struct net_device *dev)
+{
+	memset(dev->broadcast, 0xff, sizeof(bdaddr_t));
+
+	dev->netdev_ops	= &netdev_ops;
+	dev->destructor	= lowpan_free_netdev;
+	dev->features	|= NETIF_F_NETNS_LOCAL;
+}
+
+static struct device_type bt_type = {
+	.name	= "bluetooth",
+};
+
+static struct l2cap_chan *lowpan_listen_chan_new_conn(struct l2cap_chan *pchan)
+{
+	struct l2cap_chan *chan;
+
+	chan = lowpan_chan_create(pchan->data);
+	if (IS_ERR(chan))
+		return NULL;
+
+	/* change ops with more functionality than listen,
+	 * which also free chan->data stuff.
+	 */
+	chan->ops = &lowpan_chan_ops;
+
+	return chan;
+}
+
+static const struct l2cap_ops lowpan_listen_chan_ops = {
+	.name			= "L2CAP 6LoWPAN listen channel",
+	.new_connection		= lowpan_listen_chan_new_conn,
+	.recv			= l2cap_chan_no_recv,
+	.close			= l2cap_chan_no_close,
+	.state_change		= l2cap_chan_no_state_change,
+	.ready			= l2cap_chan_no_ready,
+	.get_sndtimeo		= l2cap_chan_no_get_sndtimeo,
+	.alloc_skb		= l2cap_chan_no_alloc_skb,
+	.teardown		= l2cap_chan_no_teardown,
+	.defer			= l2cap_chan_no_defer,
+	.set_shutdown		= l2cap_chan_no_set_shutdown,
+	.resume			= l2cap_chan_no_resume,
+	.suspend		= l2cap_chan_no_suspend,
+};
+
+static int lowpan_create_listen_chan(struct net_device *dev)
+{
+	struct lowpan_btle_dev *btdev = lowpan_btle_dev(dev);
+	struct l2cap_chan *chan;
+	u8 bdaddr_type;
+	int ret;
+
+	/* don't use lowpan_chan_create here, because less functionality */
+	chan = l2cap_chan_create();
+	if (!chan)
+		return -ENOMEM;
+
+	chan->data = dev;
+	chan->ops = &lowpan_listen_chan_ops;
+	hci_copy_identity_address(btdev->hdev, &chan->src, &bdaddr_type);
+	if (bdaddr_type == ADDR_LE_DEV_PUBLIC)
+		chan->src_type = BDADDR_LE_PUBLIC;
+	else
+		chan->src_type = BDADDR_LE_RANDOM;
+
+	chan->state = BT_LISTEN;
+	atomic_set(&chan->nesting, L2CAP_NESTING_PARENT);
+
+	BT_DBG("chan %p src type %d", chan, chan->src_type);
+	ret = l2cap_add_psm(chan, BDADDR_ANY, cpu_to_le16(L2CAP_PSM_IPSP));
+	if (ret < 0) {
+		l2cap_chan_put(chan);
+		BT_ERR("psm cannot be added err %d", ret);
+		return ret;
+	}
+	btdev->listen = chan;
+
+	return 0;
+}
+
+static const struct file_operations lowpan_control_fops;
+
+static struct net_device *lowpan_btle_newlink(struct hci_dev *hdev)
+{
+	struct lowpan_btle_dev *btdev;
+	struct net_device *dev;
+	int err = -ENOMEM;
+
+	__module_get(THIS_MODULE);
+
+	dev = alloc_netdev(LOWPAN_PRIV_SIZE(sizeof(struct lowpan_btle_dev)),
+			   LOWPAN_IFNAME_TEMPLATE, NET_NAME_ENUM, lowpan_setup);
+	if (!dev)
+		goto out;
+
+	dev->addr_assign_type = NET_ADDR_PERM;
+	dev->addr_len = sizeof(bdaddr_t);
+	memcpy(dev->dev_addr, BDADDR_ANY, dev->addr_len);
+
+	SET_NETDEV_DEV(dev, &hdev->dev);
+	SET_NETDEV_DEVTYPE(dev, &bt_type);
+
+	btdev = lowpan_btle_dev(dev);
+	/* avoid freeing */
+	btdev->hdev = hci_dev_hold(hdev);
+	INIT_LIST_HEAD(&btdev->peers);
+	hdev->ldev = dev;
+
+	btdev->workqueue = alloc_ordered_workqueue(dev->name, WQ_MEM_RECLAIM);
+	if (!btdev->workqueue)
+		goto free_netdev;
+
+	err = lowpan_create_listen_chan(dev);
+	if (err < 0)
+		goto destroy_workqueue;
+
+	/* ignore error handling here, we cannot call unregister anymore
+	 * It's a bug, but it's debugfs... so ignore it.
+	 */
+	btdev->control = debugfs_create_file("6lowpan_control", 0644,
+					     hdev->debugfs, hdev,
+					     &lowpan_control_fops);
+	if (!btdev->control) {
+		err = -ENOMEM;
+		goto chan_close;
+	}
+
+	err = lowpan_register_netdevice(dev, LOWPAN_LLTYPE_BTLE);
+	if (err < 0)
+		goto debugfs_cleanup;
+
+	return dev;
+
+debugfs_cleanup:
+	debugfs_remove(btdev->control);
+chan_close:
+	l2cap_chan_close(btdev->listen, 0);
+	l2cap_chan_put(btdev->listen);
+destroy_workqueue:
+	destroy_workqueue(btdev->workqueue);
+free_netdev:
+	free_netdev(dev);
+out:
+	return ERR_PTR(err);
+}
+
+static void lowpan_btle_dellink(struct net_device *dev)
+{
+	lowpan_btle_dev(dev)->hdev->ldev = NULL;
+	debugfs_remove(lowpan_btle_dev(dev)->control);
+	lowpan_unregister_netdevice(dev);
+	module_put(THIS_MODULE);
+}
+
+static int lowpan_parse_le_bdaddr(struct hci_dev *hdev, unsigned char *buf,
+				  bdaddr_t *addr, u8 *addr_type)
+{
+	int n;
+
+	n = sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx %hhu",
+		   &addr->b[5], &addr->b[4], &addr->b[3],
+		   &addr->b[2], &addr->b[1], &addr->b[0],
+		   addr_type);
+	if (n < 7)
+		return -EINVAL;
+
+	/* check if we handle le addresses */
+	if (!bdaddr_type_is_le(*addr_type))
+		return -EINVAL;
+
+	return n;
+}
+
+static ssize_t lowpan_control_write(struct file *fp,
+				    const char __user *user_buffer,
+				    size_t count, loff_t *position)
+{
+	char buf[32] = { };
+	size_t buf_size = min(count, sizeof(buf) - 1);
+	struct seq_file *file = fp->private_data;
+	struct hci_dev *hdev = file->private;
+	struct lowpan_btle_dev *btdev = lowpan_btle_dev(hdev->ldev);
+	struct lowpan_peer *peer;
+	/* slave address */
+	bdaddr_t addr;
+	u8 addr_type;
+	int ret;
+
+	if (copy_from_user(buf, user_buffer, buf_size))
+		return -EFAULT;
+
+	if (memcmp(buf, "connect ", 8) == 0) {
+		struct lowpan_peer *peer;
+		struct l2cap_chan *chan;
+
+		ret = lowpan_parse_le_bdaddr(hdev, &buf[8], &addr, &addr_type);
+		if (ret < 0)
+			return ret;
+
+		/* check if we already know that slave */
+		rcu_read_lock();
+		peer = lowpan_lookup_peer(btdev, &addr);
+		if (peer) {
+			rcu_read_unlock();
+			BT_DBG("6LoWPAN connection already exists");
+			return -EEXIST;
+		}
+		rcu_read_unlock();
+
+		chan = lowpan_chan_create(hdev->ldev);
+		if (IS_ERR(chan))
+			return PTR_ERR(chan);
+		chan->ops = &lowpan_chan_ops;
+
+		ret = l2cap_hdev_chan_connect(hdev, chan,
+					      cpu_to_le16(L2CAP_PSM_IPSP),
+					      0, &addr, addr_type);
+		if (ret < 0) {
+			l2cap_chan_put(chan);
+			return ret;
+		}
+
+		return count;
+	} else if (memcmp(buf, "disconnect ", 11) == 0) {
+		ret = lowpan_parse_le_bdaddr(hdev, &buf[11], &addr, &addr_type);
+		if (ret < 0)
+			return ret;
+
+		/* check if we don't know that slave */
+		rcu_read_lock();
+		peer = lowpan_lookup_peer(btdev, &addr);
+		if (!peer) {
+			rcu_read_unlock();
+			BT_DBG("6LoWPAN connection not found in peers");
+			return -ENOENT;
+		}
+		rcu_read_unlock();
+
+		/* first delete the peer out of list,
+		 * which makes it visiable to netdev,
+		 * will be done by close callback.
+		 */
+		l2cap_chan_close(peer->chan, 0);
+		l2cap_chan_put(peer->chan);
+	} else {
+		return -EINVAL;
+	}
+
+	return count;
+}
+
+static int lowpan_control_show(struct seq_file *f, void *ptr)
+{
+	struct hci_dev *hdev = f->private;
+	struct lowpan_btle_dev *btdev = lowpan_btle_dev(hdev->ldev);
+	struct lowpan_peer *peer;
+
+	rcu_read_lock();
+
+	list_for_each_entry_rcu(peer, &btdev->peers, list) {
+		seq_printf(f, "%pMR (type %u) state: %s\n",
+			   &peer->chan->dst, peer->chan->dst_type,
+			   state_to_string(peer->chan->state));
+	}
+
+	rcu_read_unlock();
+
+	return 0;
+}
+
+static int lowpan_control_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, lowpan_control_show, inode->i_private);
+}
+
+static const struct file_operations lowpan_control_fops = {
+	.open		= lowpan_control_open,
+	.read		= seq_read,
+	.write		= lowpan_control_write,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+static int lowpan_hci_dev_event(struct notifier_block *unused,
+				unsigned long event, void *ptr)
+{
+	struct lowpan_btle_dev *btdev;
+	struct hci_dev *hdev = ptr;
+	struct net_device *dev;
+	int ret = NOTIFY_OK;
+
+	rtnl_lock();
+
+	/* bluetooth handles that event type as int,
+	 * but there is no overflow yet.
+	 */
+	switch (event) {
+	case HCI_DEV_UP:
+		if (lowpan_enabled && !hdev->ldev) {
+			dev = lowpan_btle_newlink(hdev);
+			if (IS_ERR(dev)) {
+				BT_ERR("failed to create 6lowpan interface\n");
+				break;
+			}
+		}
+
+		ret = NOTIFY_DONE;
+		break;
+	case HCI_DEV_DOWN:
+	case HCI_DEV_UNREG:
+		if (!hdev->ldev)
+			break;
+
+		btdev = lowpan_btle_dev(hdev->ldev);
+		l2cap_chan_close(btdev->listen, 0);
+		l2cap_chan_put(btdev->listen);
+
+		lowpan_btle_dellink(hdev->ldev);
+
+		ret = NOTIFY_DONE;
+		break;
+	default:
+		break;
+	}
+
+	rtnl_unlock();
+
+	return ret;
+}
+
+static struct notifier_block lowpan_hci_dev_notifier = {
+	.notifier_call = lowpan_hci_dev_event,
+};
+
+static int lowpan_enabled_set(void *data, u64 val)
+{
+	if (val != 0 && val != 1)
+		return -EINVAL;
+
+	lowpan_enabled = val;
+	return 0;
+}
+
+static int lowpan_enabled_get(void *data, u64 *val)
+{
+	*val = lowpan_enabled;
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(lowpan_enabled_fops, lowpan_enabled_get,
+			lowpan_enabled_set, "%llu\n");
+
+static int __init bt_6lowpan_init(void)
+{
+	int ret;
+
+	lowpan_enabled_dentry = debugfs_create_file("6lowpan_enable", 0644,
+						    bt_debugfs, NULL,
+						    &lowpan_enabled_fops);
+	if (!lowpan_enabled_dentry)
+		return -ENOMEM;
+
+	ret = register_hci_dev_notifier(&lowpan_hci_dev_notifier);
+	if (ret < 0)
+		debugfs_remove(lowpan_enabled_dentry);
+
+	return ret;
+}
+
+static void __exit bt_6lowpan_exit(void)
+{
+	unregister_hci_dev_notifier(&lowpan_hci_dev_notifier);
+	debugfs_remove(lowpan_enabled_dentry);
+}
+
+module_init(bt_6lowpan_init);
+module_exit(bt_6lowpan_exit);
+
+MODULE_AUTHOR("Jukka Rissanen <jukka.rissanen@linux.intel.com>");
+MODULE_DESCRIPTION("Bluetooth 6LoWPAN");
+MODULE_VERSION(LOWPAN_BTLE_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
index e347828..b3ff12e 100644
--- a/net/bluetooth/Makefile
+++ b/net/bluetooth/Makefile
@@ -7,6 +7,9 @@ obj-$(CONFIG_BT_RFCOMM)	+= rfcomm/
 obj-$(CONFIG_BT_BNEP)	+= bnep/
 obj-$(CONFIG_BT_CMTP)	+= cmtp/
 obj-$(CONFIG_BT_HIDP)	+= hidp/
+obj-$(CONFIG_BT_6LOWPAN) += bluetooth_6lowpan.o
+
+bluetooth_6lowpan-y := 6lowpan.o
 
 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 lib.o \
-- 
2.9.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation
  2016-08-07 14:30 [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation Alexander Aring
                   ` (18 preceding siblings ...)
  2016-08-07 14:30 ` [RFCv2 bluetooth-next 19/19] 6lowpan: bluetooth: add new implementation Alexander Aring
@ 2016-08-08 12:10 ` Alexander Aring
  2016-11-22 12:14   ` Luiz Augusto von Dentz
  19 siblings, 1 reply; 23+ messages in thread
From: Alexander Aring @ 2016-08-08 12:10 UTC (permalink / raw)
  To: linux-wpan; +Cc: kernel, linux-bluetooth

Hi,

On 08/07/2016 04:30 PM, Alexander Aring wrote:
> Hi,
> 
> This patch series is my second RFC for making btle 6lowpan into the right
> direction.
> 
> I added hopefully all suggestions which I got from RFCv1. The interface address
> will be assigned when the first l2cap chan connection gets in. This device
> address will be get by "hci_copy_identity_address" bluetooth API function and
> I hope this is the right function to get the "RPA device address".
> 
> Checkout commit message of Patch 19/19 to see how I used it.
> 
> Bad news are, I will start my master thesis shortly so I am not able to work
> on this patch series anymore.
> 

and I got the following warnings from bots/persons, I just send it here
again for the next person who like to work on that or I forget it again
the next time when I can work on this:

"ERROR: "baswap" [net/6lowpan/6lowpan.ko] undefined!"

This is because baswap is some compiled function in bluetooth module and
6lowpan doesn;t depend on that.

Another issue:

net/bluetooth/6lowpan.c:892:0-23: WARNING: lowpan_enabled_fops should be
defined with DEFINE_DEBUGFS_ATTRIBUTE

 Use DEFINE_DEBUGFS_ATTRIBUTE rather than DEFINE_SIMPLE_ATTRIBUTE
  for debugfs files.

which seems to be also affected in net/6lowpan/debugfs.c and
net/bluetooth/hci_debugfs.c

- Alex

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation
  2016-08-08 12:10 ` [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation Alexander Aring
@ 2016-11-22 12:14   ` Luiz Augusto von Dentz
  2016-11-22 15:41     ` Alexander Aring
  0 siblings, 1 reply; 23+ messages in thread
From: Luiz Augusto von Dentz @ 2016-11-22 12:14 UTC (permalink / raw)
  To: Alexander Aring; +Cc: linux-wpan, kernel, linux-bluetooth

Hi Alex,

On Mon, Aug 8, 2016 at 3:10 PM, Alexander Aring <aar@pengutronix.de> wrote:
> Hi,
>
> On 08/07/2016 04:30 PM, Alexander Aring wrote:
>> Hi,
>>
>> This patch series is my second RFC for making btle 6lowpan into the right
>> direction.
>>
>> I added hopefully all suggestions which I got from RFCv1. The interface address
>> will be assigned when the first l2cap chan connection gets in. This device
>> address will be get by "hci_copy_identity_address" bluetooth API function and
>> I hope this is the right function to get the "RPA device address".

Well this does not work is identity address might not be the same as
RPA, using hci_copy_identity_address might leak the identity address
to other peer participating in the network.

>> Checkout commit message of Patch 19/19 to see how I used it.
>>
>> Bad news are, I will start my master thesis shortly so I am not able to work
>> on this patch series anymore.
>>

Did you keep track what patches have been merged upstream? Id like to
first make the solution stable since even pings something makes the
kernel crash, so how about those:

  bluetooth: introduce l2cap_hdev_chan_connect
  bluetooth: add hci dev notifier
  bluetooth: introduce l2cap chan priv data
  bluetooth: export functions and variables

> and I got the following warnings from bots/persons, I just send it here
> again for the next person who like to work on that or I forget it again
> the next time when I can work on this:
>
> "ERROR: "baswap" [net/6lowpan/6lowpan.ko] undefined!"
>
> This is because baswap is some compiled function in bluetooth module and
> 6lowpan doesn;t depend on that.
>
> Another issue:
>
> net/bluetooth/6lowpan.c:892:0-23: WARNING: lowpan_enabled_fops should be
> defined with DEFINE_DEBUGFS_ATTRIBUTE
>
>  Use DEFINE_DEBUGFS_ATTRIBUTE rather than DEFINE_SIMPLE_ATTRIBUTE
>   for debugfs files.
>
> which seems to be also affected in net/6lowpan/debugfs.c and
> net/bluetooth/hci_debugfs.c
>
> - Alex
> --
> 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



-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation
  2016-11-22 12:14   ` Luiz Augusto von Dentz
@ 2016-11-22 15:41     ` Alexander Aring
  0 siblings, 0 replies; 23+ messages in thread
From: Alexander Aring @ 2016-11-22 15:41 UTC (permalink / raw)
  To: Luiz Augusto von Dentz; +Cc: linux-wpan, kernel, linux-bluetooth

Hi,

On 11/22/2016 01:14 PM, Luiz Augusto von Dentz wrote:
> Hi Alex,
> 
> On Mon, Aug 8, 2016 at 3:10 PM, Alexander Aring <aar@pengutronix.de> wrote:
>> Hi,
>>
>> On 08/07/2016 04:30 PM, Alexander Aring wrote:
>>> Hi,
>>>
>>> This patch series is my second RFC for making btle 6lowpan into the right
>>> direction.
>>>
>>> I added hopefully all suggestions which I got from RFCv1. The interface address
>>> will be assigned when the first l2cap chan connection gets in. This device
>>> address will be get by "hci_copy_identity_address" bluetooth API function and
>>> I hope this is the right function to get the "RPA device address".
> 
> Well this does not work is identity address might not be the same as
> RPA, using hci_copy_identity_address might leak the identity address
> to other peer participating in the network.
> 

ok. Don't know, we need to talk about which address again. What I
changed in this patch series is that a interface will not be
unregistered when connection get lost (very bad for ip capable
interfaces), it's going down and when it's down it has no address until
it's up again. While the interface is up, you cannot change the L2 address.

So if 6LoWPAN interface is down, you can set which adress you want to
use on L2 bluetooth layer, at least it need to be known when somebody
makes the interface up. If all connection get lost -> interface will down.

So far I remember correctly I replace register/unregister when first
connection comes in/last connection get lost with ifup/ifdown. So the
interface comes automatically up when first connection is there, I
thought that because if connection is there then the L2 address cannot
be changed -> which is good.

And with connection I mean a L2CAP connection which you did before with
btmgt connect stuff + running echo "connect ..." on debugs interface.

Sorry, I don't know the special words which bluetooth community use that
to describe the differences.

>>> Checkout commit message of Patch 19/19 to see how I used it.
>>>
>>> Bad news are, I will start my master thesis shortly so I am not able to work
>>> on this patch series anymore.
>>>
> 
> Did you keep track what patches have been merged upstream? Id like to
> first make the solution stable since even pings something makes the
> kernel crash, so how about those:
> 
>   bluetooth: introduce l2cap_hdev_chan_connect
>   bluetooth: add hci dev notifier
>   bluetooth: introduce l2cap chan priv data
>   bluetooth: export functions and variables
>

the actual btle 6lowpan code is full with races. I agree I need to
cleanup the patch series to write what I fixed "a race" or "interface
address stateless autoconfiguration handling -> remove the FF:FE in MAC" or
"neighbor discovery -> don't recover MAC address from L3 -> this stuff is
complete broken, ipv6 is not designed to work as such handling". I think
these are the most important topics which we have in this patch-series.

Badly I am still in my thesis and have no time to do that. Sorry.

- Alex

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2016-11-22 15:41 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-08-07 14:30 [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation Alexander Aring
2016-08-07 14:30 ` [RFCv2 bluetooth-next 01/19] ieee802154: 6lowpan: remove headroom check Alexander Aring
2016-08-07 14:30 ` [RFCv2 bluetooth-next 02/19] ieee802154: 6lowpan: move skb cb BUILD_BUG_ON check Alexander Aring
2016-08-07 14:30 ` [RFCv2 bluetooth-next 03/19] 6lowpan: remove LOWPAN_IPHC_MAX_HEADER_LEN Alexander Aring
2016-08-07 14:30 ` [RFCv2 bluetooth-next 04/19] 6lowpan: hold netdev while unregister Alexander Aring
2016-08-07 14:30 ` [RFCv2 bluetooth-next 05/19] 6lowpan: introduce generic default naming Alexander Aring
2016-08-07 14:30 ` [RFCv2 bluetooth-next 06/19] 6lowpan: move rx defines to generic Alexander Aring
2016-08-07 14:30 ` [RFCv2 bluetooth-next 07/19] bluetooth: introduce l2cap_hdev_chan_connect Alexander Aring
2016-08-07 14:30 ` [RFCv2 bluetooth-next 08/19] bluetooth: add hci dev notifier Alexander Aring
2016-08-07 14:30 ` [RFCv2 bluetooth-next 09/19] bluetooth: introduce l2cap chan priv data Alexander Aring
2016-08-07 14:30 ` [RFCv2 bluetooth-next 10/19] bluetooth: export functions and variables Alexander Aring
2016-08-07 14:30 ` [RFCv2 bluetooth-next 11/19] 6lowpan: bluetooth: remove implementation Alexander Aring
2016-08-07 14:30 ` [RFCv2 bluetooth-next 12/19] ieee802154: 6lowpan: move header create to 6lowpan Alexander Aring
2016-08-07 14:30 ` [RFCv2 bluetooth-next 13/19] 6lowpan: move dev_init to generic Alexander Aring
2016-08-07 14:30 ` [RFCv2 bluetooth-next 14/19] 6lowpan: iphc: override l2 packet information Alexander Aring
2016-08-07 14:30 ` [RFCv2 bluetooth-next 15/19] ipv6: addrconf: fix 48 bit 6lowpan autoconfiguration Alexander Aring
2016-08-07 14:30 ` [RFCv2 bluetooth-next 16/19] 6lowpan: iphc: add handling for btle Alexander Aring
2016-08-07 14:30 ` [RFCv2 bluetooth-next 17/19] 6lowpan: move multicast flags to generic Alexander Aring
2016-08-07 14:30 ` [RFCv2 bluetooth-next 18/19] 6lowpan: move addr_len setting away from generic Alexander Aring
2016-08-07 14:30 ` [RFCv2 bluetooth-next 19/19] 6lowpan: bluetooth: add new implementation Alexander Aring
2016-08-08 12:10 ` [RFCv2 bluetooth-next 00/19] bluetooth: rework 6lowpan implementation Alexander Aring
2016-11-22 12:14   ` Luiz Augusto von Dentz
2016-11-22 15:41     ` Alexander Aring

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.