2016-03-04 11:40:39

by Patrik Flykt

[permalink] [raw]
Subject: [RFC 0/5] Implement BTLE Network Management interface API

Hi,

This patch set implements kernel support for RFC v3 of the Management
Interface Network API. The current implementation reuses existing
Bluetooth 6LowPAN functionality except for the debugfs interface parts
that are replace by the Management API.

The debugfs implementation for enabling and disabling incoming connection
support is still used, here it is anticipated that it will be replaced
by device whitelisting using the Add Device command in the future.

Please review,

Patrik


Patrik Flykt (5):
bluetooth: Merge Bluetooth 6lowpan functionality to bluetooth module
bluetooth: Implement Get Networks Management API command
l2cap: Pass hci_dev to l2cap_chan_connect()
bluetooth: Implement Add Network Management API command
bluetooth: Implement Remove Network Management API command

include/net/bluetooth/l2cap.h | 4 +-
include/net/bluetooth/mgmt.h | 40 ++++
net/bluetooth/6lowpan.c | 495 ++++++++++++++++++++++++++++--------------
net/bluetooth/Kconfig | 2 +-
net/bluetooth/Makefile | 4 +-
net/bluetooth/af_bluetooth.c | 11 +
net/bluetooth/l2cap_core.c | 6 +-
net/bluetooth/l2cap_sock.c | 5 +-
net/bluetooth/mgmt.c | 9 +
9 files changed, 397 insertions(+), 179 deletions(-)

--
2.1.4



2016-03-05 21:15:52

by Alexander Aring

[permalink] [raw]
Subject: Re: [RFC 1/5] bluetooth: Merge Bluetooth 6lowpan functionality to bluetooth module

On Sat, Mar 05, 2016 at 10:06:44PM +0100, Alexander Aring wrote:
> Hi,
>
> tried that patch out and it fails:
>
> net/bluetooth/af_bluetooth.c:32:35: fatal error:
> net/bluetooth/6lowpan.h: No such file or directory #include <net/bluetooth/6lowpan.h>
>
> There is some missing file. :-)
>
> Actually while review I tried to find the prototypes for init/exit
> functionality. So this file is missing somehow but I think it should include:
>
> #ifdef CONFIG_BT_6LOWPAN
> ... prototypes ...
> #else
> static inline empty files of prototypes

s/files/functions/

Also if the above is true to put the prototypes there, why putting it
into a "global" header file. Use some local header #include "6lowpan.h"
or something else. :-)

Maybe I oversight something here and there are good arguments to put it
into a global header.

- Alex

2016-03-05 21:06:46

by Alexander Aring

[permalink] [raw]
Subject: Re: [RFC 1/5] bluetooth: Merge Bluetooth 6lowpan functionality to bluetooth module

Hi,

tried that patch out and it fails:

net/bluetooth/af_bluetooth.c:32:35: fatal error:
net/bluetooth/6lowpan.h: No such file or directory #include <net/bluetooth/6lowpan.h>

There is some missing file. :-)

Actually while review I tried to find the prototypes for init/exit
functionality. So this file is missing somehow but I think it should include:

#ifdef CONFIG_BT_6LOWPAN
... prototypes ...
#else
static inline empty files of prototypes
#endif

- Alex

2016-03-04 17:30:45

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [RFC 5/5] bluetooth: Implement Remove Network Management API command

Hi Patrik,

> Queue Remove Network Management API command and disconnect the L2CAP
> channel. Once the channel has been removed, reply to the command in
> l2cap_ops close callback. On error reply with a failure in the
> l2cap_ops status callback.
>
> Remove the remaining part of the debugfs code handling the control
> file.
>
> The MGMT_OP_REMOVE_NETWORK command is defined as:
>
> Command Code: 0x0044
> Controller Index: <controller id>
> Command Parameters: Address (6 Octets)
> Address_Type (1 Octet)
> Return Parameters: Address (6 Octets)
> Address_Type (1 Octet)
>
> This command is used to disconnect a network connection from a
> remote BTLE node. A pre-requisite is that LE is already
> enabled, otherwise this command will return a "rejected"
> response.
>
> Possible values for the Address_Type parameter:
> 0 Reserved
> 1 LE Public
> 2 LE Random
>
> This command generates a Command Complete event on success
> or failure.
>
> Possible errors: Busy
> Not Connected
> Invalid Parameters
> Not Powered
> Invalid Index
>
> The MGMT_EV_NETWORK_REMOVED event is defined as:
>
> Event Code: 0x0026
> Controller Index: <controller id>
> Event Parameters: Address (6 Octets)
> Address_Type (1 Octet)
>
> This event indicates that the BTLE network connection to a remote
> node has been lost.
>
> Possible values for the Address_Type parameter:
> 1 LE Public
> 2 LE Random
>
> For devices using resolvable random addresses with a known
> identity resolving key, the Address and Address_Type will
> contain the identity information.
> ---
> include/net/bluetooth/mgmt.h | 14 ++++
> net/bluetooth/6lowpan.c | 174 ++++++++++++++++++++++---------------------
> net/bluetooth/mgmt.c | 3 +
> 3 files changed, 106 insertions(+), 85 deletions(-)
>
> diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
> index f6bc80f..62d0583 100644
> --- a/include/net/bluetooth/mgmt.h
> +++ b/include/net/bluetooth/mgmt.h
> @@ -606,6 +606,15 @@ struct mgmt_rp_add_network {
> int ifindex;
> } __packed;
>
> +#define MGMT_OP_REMOVE_NETWORK 0x0044
> +#define MGMT_REMOVE_NETWORK_SIZE 7
> +struct mgmt_cp_remove_network {
> + struct mgmt_addr_info dst;
> +} __packed;
> +struct mgmt_rp_remove_network {
> + struct mgmt_addr_info dst;
> +} __packed;
> +
> #define MGMT_EV_CMD_COMPLETE 0x0001
> struct mgmt_ev_cmd_complete {
> __le16 opcode;
> @@ -825,3 +834,8 @@ struct mgmt_ev_network_added {
> struct mgmt_addr_info dst;
> int ifindex;
> } __packed;
> +
> +#define MGMT_EV_NETWORK_REMOVED 0x0026
> +struct mgmt_ev_network_removed {
> + struct mgmt_addr_info dst;
> +} __packed;
> diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
> index 9f12eb1..f62ac14 100644
> --- a/net/bluetooth/6lowpan.c
> +++ b/net/bluetooth/6lowpan.c
> @@ -33,7 +33,6 @@
> #define VERSION "0.1"
>
> static struct dentry *lowpan_enable_debugfs;
> -static struct dentry *lowpan_control_debugfs;
>
> #define IFACE_NAME_TEMPLATE "bt%d"
>
> @@ -929,6 +928,46 @@ static void cmd_add_network_complete(struct l2cap_chan *chan, int status,
> mgmt_pending_remove(cmd);
> }
>
> +static void cmd_remove_network_complete(struct l2cap_chan *chan, int status)
> +{
> + struct hci_dev *hdev;
> + struct mgmt_pending_cmd *cmd;
> +
> + hdev = hci_get_route(NULL, &chan->src);
> +
> + if (!hdev) {
> + BT_DBG("No matching hci_dev for l2cap_chan %p", chan);
> + return;
> + }
> +
> + cmd = mgmt_pending_find(HCI_CHANNEL_CONTROL, MGMT_OP_REMOVE_NETWORK,
> + hdev);
> + if (cmd) {
> + struct mgmt_cp_remove_network *cp = cmd->param;
> + struct mgmt_rp_remove_network rp;
> +
> + bacpy(&rp.dst.bdaddr, &cp->dst.bdaddr);
> + rp.dst.type = cp->dst.type;
> +
> + mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
> + status, &rp, sizeof(rp));
> + }
> +
> + if (status == MGMT_STATUS_SUCCESS && chan->state == BT_DISCONN) {
> + struct mgmt_ev_network_removed ep;
> +
> + bacpy(&ep.dst.bdaddr, &chan->dst);
> + ep.dst.type = chan->dst_type;
> +
> + mgmt_send_event(MGMT_EV_NETWORK_REMOVED, hdev,
> + HCI_CHANNEL_CONTROL, &ep, sizeof(ep),
> + HCI_SOCK_TRUSTED, cmd? cmd->sk: NULL);
> + }
> +
> + if (cmd)
> + mgmt_pending_remove(cmd);
> +}
> +
> static inline void chan_ready_cb(struct l2cap_chan *chan)
> {
> struct lowpan_dev *dev;
> @@ -1000,6 +1039,7 @@ static void chan_close_cb(struct l2cap_chan *chan)
> }
>
> cmd_add_network_complete(chan, MGMT_STATUS_CONNECT_FAILED, 0);
> + cmd_remove_network_complete(chan, MGMT_STATUS_SUCCESS);
>
> spin_lock(&devices_lock);
>
> @@ -1045,6 +1085,7 @@ static void chan_state_change_cb(struct l2cap_chan *chan, int state, int err)
>
> if (err < 0) {
> cmd_add_network_complete(chan, MGMT_STATUS_CONNECT_FAILED, 0);
> + cmd_remove_network_complete(chan, MGMT_STATUS_CONNECT_FAILED);
> }
> }
>
> @@ -1270,21 +1311,60 @@ unlock:
> return err;
> }
>
> -static int bt_6lowpan_disconnect(struct l2cap_conn *conn, u8 dst_type)
> +int bt_6lowpan_remove_network(struct sock *sk, struct hci_dev *hdev,
> + void *data, u16 data_len)
> {
> + struct mgmt_cp_remove_network *cp = data;
> + int err = 0;
> struct lowpan_peer *peer;
> + struct mgmt_pending_cmd *cmd;
>
> - BT_DBG("conn %p dst type %d", conn, dst_type);
> + BT_DBG("remove network hdev %p data %p data len %d",
> + hdev, data, data_len);
>
> - peer = lookup_peer(conn);
> - if (!peer)
> - return -ENOENT;
> + if (!lmp_le_capable(hdev)) {
> + err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_NETWORK,
> + MGMT_STATUS_NOT_SUPPORTED, cp,
> + sizeof(*cp));
> + goto failed;
> + }
>
> - BT_DBG("peer %p chan %p", peer, peer->chan);
> + if (!bdaddr_type_is_le(cp->dst.type)) {
> + err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_NETWORK,
> + MGMT_STATUS_INVALID_PARAMS, cp,
> + sizeof(*cp));
> + goto failed;
> + }
>
> - l2cap_chan_close(peer->chan, ENOENT);
> + hci_dev_lock(hdev);
>
> - return 0;
> + if (mgmt_pending_find(HCI_CHANNEL_CONTROL, MGMT_OP_REMOVE_NETWORK,
> + hdev)) {
> + err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_NETWORK,
> + MGMT_STATUS_BUSY);
> + goto unlock;
> + }
> +
> + peer = lookup_bdaddr(hdev, &cp->dst.bdaddr, cp->dst.type);
> + if (!peer) {
> + err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_NETWORK,
> + MGMT_STATUS_FAILED,
> + cp, sizeof(*cp));
> + goto unlock;
> + }
> +
> + cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_NETWORK, hdev,
> + data, data_len);
> + if (!cmd)
> + err = -ENOMEM;
> +
> + l2cap_chan_close(peer->chan, 0);
> +
> +unlock:
> + hci_dev_unlock(hdev);
> +
> +failed:
> + return err;
> }
>
> static struct l2cap_chan *bt_6lowpan_listen(void)
> @@ -1318,40 +1398,6 @@ static struct l2cap_chan *bt_6lowpan_listen(void)
> 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_dev *entry;
> @@ -1445,44 +1491,6 @@ static int lowpan_enable_get(void *data, u64 *val)
> 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, "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 const struct file_operations lowpan_control_fops = {
> - .write = lowpan_control_write,
> - .llseek = seq_lseek,
> - .release = single_release,
> -};

removing the debugfs stuff should be a separate cleanup at the end of the series. I prefer we do not intermix this.

Regards

Marcel


2016-03-04 17:29:00

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [RFC 3/5] l2cap: Pass hci_dev to l2cap_chan_connect()

Hi Patrik,

> Since the Bluetooth Management Interface already associates
> commands with a hci_dev, pass the hci_dev when calling
> l2cap_chan_connect(). This indicates which specific hci_dev to
> use for the l2cap connection and will be useful when connecting
> or disconnecting Bluetooth IPSP.
>
> Modify the existing code to do a hci_dev lookup before calling
> connect.
>
> Signed-off-by: Patrik Flykt <[email protected]>
> ---
> include/net/bluetooth/l2cap.h | 4 ++--
> net/bluetooth/6lowpan.c | 4 +++-
> net/bluetooth/l2cap_core.c | 6 ++----
> net/bluetooth/l2cap_sock.c | 5 ++++-
> 4 files changed, 11 insertions(+), 8 deletions(-)
>
> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> index 5ee3c68..b65ca60 100644
> --- a/include/net/bluetooth/l2cap.h
> +++ b/include/net/bluetooth/l2cap.h
> @@ -926,8 +926,8 @@ int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid);
>
> 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_chan_connect(struct l2cap_chan *chan, struct hci_dev *hdev,
> + __le16 psm, u16 cid, bdaddr_t *dst, u8 dst_type);

actually lets not do that. I am pretty much against hacking just more parameters into this function. Do that in the l2cap_chan abstraction. It already knows which hci_dev it needs to pick.

Regards

Marcel


2016-03-04 14:16:58

by Patrik Flykt

[permalink] [raw]
Subject: Re: [RFC 2/5] bluetooth: Implement Get Networks Management API command

On Fri, 2016-03-04 at 13:40 +0200, Patrik Flykt wrote:
> --- a/net/bluetooth/mgmt.c
> +++ b/net/bluetooth/mgmt.c
> @@ -31,6 +31,7 @@
> #include <net/bluetooth/hci_core.h>
> #include <net/bluetooth/hci_sock.h>
> #include <net/bluetooth/l2cap.h>
> +#include <net/bluetooth/6lowpan.h>

And of course the header file gets left behind. I'll fix...

Cheers,

Patrik


2016-03-04 11:40:43

by Patrik Flykt

[permalink] [raw]
Subject: [RFC 4/5] bluetooth: Implement Add Network Management API command

Queue Add Network Management API command and initiate a L2CAP connect
to the destination. Reply to the command in the l2cap_ops ready callback
when the channel is successfully created and inidcate failure in both
l2cap_ops close and state callbacks when an error is indicated.

On success add the remote peer to the internal data structures and create
the network interface as before. Remove the debugfs implementation doing
the same thing.

The MGMT_OP_ADD_NETWORK command is defined as:

Command Code: 0x0043
Controller Index: <controller id>
Command Parameters: Address (6 Octets)
Address_Type (1 Octet)
Return Parameters: Address (6 Octets)
Address_Type (1 Octet)
Interface Index (4 Octets)

This command is used to connect to establish a network connection
to a remote BTLE node. A pre-requisite is that LE is already
enabled, otherwise this command will return a "rejected"
response.

Possible values for the Address_Type parameter:
0 Reserved
1 LE Public
2 LE Random

This command generates a Command Complete event on success
or failure.

Possible errors: Busy
Refused
Invalid Parameters
Not Powered
Invalid Index
Already Connected

The MGMT_EV_NETWORK_ADDED event is defined as:

Event Code: 0x0025
Controller Index: <controller id>
Event Parameters: Address (6 Octets)
Address_Type (1 Octet)
Interface Index (4 Octets)

This event indicates that a network connection to a remote
BTLE node has been established successfully.

Possible values for the Address_Type parameter:
1 LE Public
2 LE Random

For devices using resolvable random addresses with a known
identity resolving key, the Address and Address_Type will
contain the identity information.
---
include/net/bluetooth/mgmt.h | 16 ++++
net/bluetooth/6lowpan.c | 205 ++++++++++++++++++++++++++++++++-----------
net/bluetooth/mgmt.c | 3 +
3 files changed, 172 insertions(+), 52 deletions(-)

diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index 813224b..f6bc80f 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -596,6 +596,16 @@ struct mgmt_rp_network {
int ifindex;
} __packed;

+#define MGMT_OP_ADD_NETWORK 0x0043
+#define MGMT_ADD_NETWORK_SIZE 7
+struct mgmt_cp_add_network {
+ struct mgmt_addr_info dst;
+} __packed;
+struct mgmt_rp_add_network {
+ struct mgmt_addr_info dst;
+ int ifindex;
+} __packed;
+
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
__le16 opcode;
@@ -809,3 +819,9 @@ struct mgmt_ev_advertising_added {
struct mgmt_ev_advertising_removed {
__u8 instance;
} __packed;
+
+#define MGMT_EV_NETWORK_ADDED 0x0025
+struct mgmt_ev_network_added {
+ struct mgmt_addr_info dst;
+ int ifindex;
+} __packed;
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index a582a736..9f12eb1 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -258,6 +258,36 @@ static struct lowpan_dev *lookup_dev(struct l2cap_conn *conn)
return dev;
}

+static struct lowpan_peer *lookup_bdaddr(struct hci_dev *hdev, bdaddr_t *dst,
+ u8 dst_type)
+{
+ struct lowpan_dev *dev;
+ struct lowpan_peer *peer, *target = NULL;
+
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(dev, &bt_6lowpan_devices, list) {
+ if (dev->hdev != hdev)
+ continue;
+
+ list_for_each_entry_rcu(peer, &dev->peers, list) {
+ if(!peer->chan)
+ continue;
+
+ if (!bacmp(dst, &peer->chan->dst) &&
+ dst_type == peer->chan->dst_type) {
+ target = peer;
+ goto rcu_unlock;
+ }
+ }
+ }
+
+rcu_unlock:
+ rcu_read_unlock();
+
+ return target;
+}
+
static int give_skb_to_upper(struct sk_buff *skb, struct net_device *dev)
{
struct sk_buff *skb_cp;
@@ -854,6 +884,51 @@ out:
return err;
}

+static void cmd_add_network_complete(struct l2cap_chan *chan, int status,
+ int ifindex)
+{
+ struct hci_dev *hdev;
+ struct mgmt_pending_cmd *cmd;
+
+ hdev = hci_get_route(NULL, &chan->src);
+
+ if (!hdev) {
+ BT_DBG("No matching hci_dev for l2cap_chan %p", chan);
+ return;
+ }
+
+ cmd = mgmt_pending_find(HCI_CHANNEL_CONTROL, MGMT_OP_ADD_NETWORK,
+ hdev);
+ BT_DBG("cmd %p status %d state %d", cmd, status, chan->state);
+
+ if (cmd) {
+ struct mgmt_cp_add_network *cp = cmd->param;
+ struct mgmt_rp_add_network rp;
+
+ rp.ifindex = ifindex;
+ bacpy(&rp.dst.bdaddr, &cp->dst.bdaddr);
+ rp.dst.type = cp->dst.type;
+
+ mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
+ status, &rp, sizeof(rp));
+ }
+
+ if (status == MGMT_STATUS_SUCCESS && chan->state == BT_CONNECTED) {
+ struct mgmt_ev_network_added ep;
+
+ ep.ifindex = ifindex;
+ bacpy(&ep.dst.bdaddr, &chan->dst);
+ ep.dst.type = chan->dst_type;
+
+ mgmt_send_event(MGMT_EV_NETWORK_ADDED, hdev,
+ HCI_CHANNEL_CONTROL, &ep, sizeof(ep),
+ HCI_SOCK_TRUSTED, cmd? cmd->sk: NULL);
+ }
+
+ if (cmd)
+ mgmt_pending_remove(cmd);
+}
+
static inline void chan_ready_cb(struct l2cap_chan *chan)
{
struct lowpan_dev *dev;
@@ -874,6 +949,9 @@ static inline void chan_ready_cb(struct l2cap_chan *chan)

add_peer_chan(chan, dev);
ifup(dev->netdev);
+
+ cmd_add_network_complete(chan, MGMT_STATUS_SUCCESS,
+ dev->netdev->ifindex);
}

static inline struct l2cap_chan *chan_new_conn_cb(struct l2cap_chan *pchan)
@@ -921,6 +999,8 @@ static void chan_close_cb(struct l2cap_chan *chan)
remove = false;
}

+ cmd_add_network_complete(chan, MGMT_STATUS_CONNECT_FAILED, 0);
+
spin_lock(&devices_lock);

list_for_each_entry_rcu(entry, &bt_6lowpan_devices, list) {
@@ -962,6 +1042,10 @@ 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);
+
+ if (err < 0) {
+ cmd_add_network_complete(chan, MGMT_STATUS_CONNECT_FAILED, 0);
+ }
}

static struct sk_buff *chan_alloc_skb_cb(struct l2cap_chan *chan,
@@ -1103,34 +1187,86 @@ unlock:
return err;
}

-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)
+int bt_6lowpan_add_network(struct sock *sk, struct hci_dev *hdev,
+ void *data, u16 data_len)
{
- struct hci_dev *hdev;
- struct l2cap_chan *chan;
+ struct mgmt_cp_add_network *cp = data;
+ struct mgmt_rp_add_network rp;
+ struct mgmt_pending_cmd *cmd;
int err;
+ struct l2cap_chan *chan;
+
+ BT_DBG("add network hdev %p data %p data len %d",
+ hdev, data, data_len);
+
+ rp.ifindex = 0;
+ bacpy(&rp.dst.bdaddr, &cp->dst.bdaddr);
+ rp.dst.type = cp->dst.type;
+
+ if (!lmp_le_capable(hdev))
+ return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_NETWORK,
+ MGMT_STATUS_NOT_SUPPORTED, &rp,
+ sizeof(rp));
+
+ if (!bdaddr_type_is_le(cp->dst.type))
+ return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_NETWORK,
+ MGMT_STATUS_NOT_SUPPORTED, &rp,
+ sizeof(rp));
+
+ hci_dev_lock(hdev);
+ if (mgmt_pending_find(HCI_CHANNEL_CONTROL, MGMT_OP_ADD_NETWORK,
+ hdev)) {
+ err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_NETWORK,
+ MGMT_STATUS_BUSY);
+ goto unlock;
+ }
+
+ if (lookup_bdaddr(hdev, &rp.dst.bdaddr, rp.dst.type)) {
+ err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_NETWORK,
+ MGMT_STATUS_ALREADY_CONNECTED,
+ &rp, sizeof(rp));
+ goto unlock;
+ }
+
+ cmd = mgmt_pending_add(sk, MGMT_OP_ADD_NETWORK, hdev, data, data_len);
+ if (!cmd) {
+ err = -ENOMEM;
+ goto unlock;
+ }

chan = chan_create();
- if (!chan)
- return -EINVAL;
+ if (!chan) {
+ err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_NETWORK,
+ MGMT_STATUS_NO_RESOURCES,
+ &rp, sizeof(rp));
+ goto pending_remove;
+ }

chan->ops = &bt_6lowpan_chan_ops;

- hdev = hci_get_route(addr, NULL);
+ hci_dev_unlock(hdev);
+
err = l2cap_chan_connect(chan, hdev, cpu_to_le16(L2CAP_PSM_IPSP), 0,
- addr, dst_type);
+ &cp->dst.bdaddr, cp->dst.type);

- BT_DBG("chan %p err %d", chan, err);
- if (err < 0)
+ if (err < 0) {
l2cap_chan_put(chan);

+ hci_dev_lock(hdev);
+ err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_NETWORK,
+ MGMT_STATUS_REJECTED,
+ &rp, sizeof(rp));
+ goto pending_remove;
+ }
+
+ return err;
+
+pending_remove:
+ mgmt_pending_remove(cmd);
+
+unlock:
+ hci_dev_unlock(hdev);
+
return err;
}

@@ -1326,41 +1462,6 @@ static ssize_t lowpan_control_write(struct file *fp,

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)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 722cc17..2c2824e 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -106,6 +106,7 @@ static const u16 mgmt_commands[] = {
MGMT_OP_GET_ADV_SIZE_INFO,
MGMT_OP_START_LIMITED_DISCOVERY,
MGMT_OP_GET_NETWORKS,
+ MGMT_OP_ADD_NETWORK,
};

static const u16 mgmt_events[] = {
@@ -143,6 +144,7 @@ static const u16 mgmt_events[] = {
MGMT_EV_LOCAL_OOB_DATA_UPDATED,
MGMT_EV_ADVERTISING_ADDED,
MGMT_EV_ADVERTISING_REMOVED,
+ MGMT_EV_NETWORK_ADDED,
};

static const u16 mgmt_untrusted_commands[] = {
@@ -6339,6 +6341,7 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
{ get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
{ start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
{ bt_6lowpan_get_networks, MGMT_GET_NETWORKS_SIZE },
+ { bt_6lowpan_add_network, MGMT_ADD_NETWORK_SIZE },
};

void mgmt_index_added(struct hci_dev *hdev)
--
2.1.4


2016-03-04 11:40:44

by Patrik Flykt

[permalink] [raw]
Subject: [RFC 5/5] bluetooth: Implement Remove Network Management API command

Queue Remove Network Management API command and disconnect the L2CAP
channel. Once the channel has been removed, reply to the command in
l2cap_ops close callback. On error reply with a failure in the
l2cap_ops status callback.

Remove the remaining part of the debugfs code handling the control
file.

The MGMT_OP_REMOVE_NETWORK command is defined as:

Command Code: 0x0044
Controller Index: <controller id>
Command Parameters: Address (6 Octets)
Address_Type (1 Octet)
Return Parameters: Address (6 Octets)
Address_Type (1 Octet)

This command is used to disconnect a network connection from a
remote BTLE node. A pre-requisite is that LE is already
enabled, otherwise this command will return a "rejected"
response.

Possible values for the Address_Type parameter:
0 Reserved
1 LE Public
2 LE Random

This command generates a Command Complete event on success
or failure.

Possible errors: Busy
Not Connected
Invalid Parameters
Not Powered
Invalid Index

The MGMT_EV_NETWORK_REMOVED event is defined as:

Event Code: 0x0026
Controller Index: <controller id>
Event Parameters: Address (6 Octets)
Address_Type (1 Octet)

This event indicates that the BTLE network connection to a remote
node has been lost.

Possible values for the Address_Type parameter:
1 LE Public
2 LE Random

For devices using resolvable random addresses with a known
identity resolving key, the Address and Address_Type will
contain the identity information.
---
include/net/bluetooth/mgmt.h | 14 ++++
net/bluetooth/6lowpan.c | 174 ++++++++++++++++++++++---------------------
net/bluetooth/mgmt.c | 3 +
3 files changed, 106 insertions(+), 85 deletions(-)

diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index f6bc80f..62d0583 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -606,6 +606,15 @@ struct mgmt_rp_add_network {
int ifindex;
} __packed;

+#define MGMT_OP_REMOVE_NETWORK 0x0044
+#define MGMT_REMOVE_NETWORK_SIZE 7
+struct mgmt_cp_remove_network {
+ struct mgmt_addr_info dst;
+} __packed;
+struct mgmt_rp_remove_network {
+ struct mgmt_addr_info dst;
+} __packed;
+
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
__le16 opcode;
@@ -825,3 +834,8 @@ struct mgmt_ev_network_added {
struct mgmt_addr_info dst;
int ifindex;
} __packed;
+
+#define MGMT_EV_NETWORK_REMOVED 0x0026
+struct mgmt_ev_network_removed {
+ struct mgmt_addr_info dst;
+} __packed;
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index 9f12eb1..f62ac14 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -33,7 +33,6 @@
#define VERSION "0.1"

static struct dentry *lowpan_enable_debugfs;
-static struct dentry *lowpan_control_debugfs;

#define IFACE_NAME_TEMPLATE "bt%d"

@@ -929,6 +928,46 @@ static void cmd_add_network_complete(struct l2cap_chan *chan, int status,
mgmt_pending_remove(cmd);
}

+static void cmd_remove_network_complete(struct l2cap_chan *chan, int status)
+{
+ struct hci_dev *hdev;
+ struct mgmt_pending_cmd *cmd;
+
+ hdev = hci_get_route(NULL, &chan->src);
+
+ if (!hdev) {
+ BT_DBG("No matching hci_dev for l2cap_chan %p", chan);
+ return;
+ }
+
+ cmd = mgmt_pending_find(HCI_CHANNEL_CONTROL, MGMT_OP_REMOVE_NETWORK,
+ hdev);
+ if (cmd) {
+ struct mgmt_cp_remove_network *cp = cmd->param;
+ struct mgmt_rp_remove_network rp;
+
+ bacpy(&rp.dst.bdaddr, &cp->dst.bdaddr);
+ rp.dst.type = cp->dst.type;
+
+ mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
+ status, &rp, sizeof(rp));
+ }
+
+ if (status == MGMT_STATUS_SUCCESS && chan->state == BT_DISCONN) {
+ struct mgmt_ev_network_removed ep;
+
+ bacpy(&ep.dst.bdaddr, &chan->dst);
+ ep.dst.type = chan->dst_type;
+
+ mgmt_send_event(MGMT_EV_NETWORK_REMOVED, hdev,
+ HCI_CHANNEL_CONTROL, &ep, sizeof(ep),
+ HCI_SOCK_TRUSTED, cmd? cmd->sk: NULL);
+ }
+
+ if (cmd)
+ mgmt_pending_remove(cmd);
+}
+
static inline void chan_ready_cb(struct l2cap_chan *chan)
{
struct lowpan_dev *dev;
@@ -1000,6 +1039,7 @@ static void chan_close_cb(struct l2cap_chan *chan)
}

cmd_add_network_complete(chan, MGMT_STATUS_CONNECT_FAILED, 0);
+ cmd_remove_network_complete(chan, MGMT_STATUS_SUCCESS);

spin_lock(&devices_lock);

@@ -1045,6 +1085,7 @@ static void chan_state_change_cb(struct l2cap_chan *chan, int state, int err)

if (err < 0) {
cmd_add_network_complete(chan, MGMT_STATUS_CONNECT_FAILED, 0);
+ cmd_remove_network_complete(chan, MGMT_STATUS_CONNECT_FAILED);
}
}

@@ -1270,21 +1311,60 @@ unlock:
return err;
}

-static int bt_6lowpan_disconnect(struct l2cap_conn *conn, u8 dst_type)
+int bt_6lowpan_remove_network(struct sock *sk, struct hci_dev *hdev,
+ void *data, u16 data_len)
{
+ struct mgmt_cp_remove_network *cp = data;
+ int err = 0;
struct lowpan_peer *peer;
+ struct mgmt_pending_cmd *cmd;

- BT_DBG("conn %p dst type %d", conn, dst_type);
+ BT_DBG("remove network hdev %p data %p data len %d",
+ hdev, data, data_len);

- peer = lookup_peer(conn);
- if (!peer)
- return -ENOENT;
+ if (!lmp_le_capable(hdev)) {
+ err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_NETWORK,
+ MGMT_STATUS_NOT_SUPPORTED, cp,
+ sizeof(*cp));
+ goto failed;
+ }

- BT_DBG("peer %p chan %p", peer, peer->chan);
+ if (!bdaddr_type_is_le(cp->dst.type)) {
+ err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_NETWORK,
+ MGMT_STATUS_INVALID_PARAMS, cp,
+ sizeof(*cp));
+ goto failed;
+ }

- l2cap_chan_close(peer->chan, ENOENT);
+ hci_dev_lock(hdev);

- return 0;
+ if (mgmt_pending_find(HCI_CHANNEL_CONTROL, MGMT_OP_REMOVE_NETWORK,
+ hdev)) {
+ err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_NETWORK,
+ MGMT_STATUS_BUSY);
+ goto unlock;
+ }
+
+ peer = lookup_bdaddr(hdev, &cp->dst.bdaddr, cp->dst.type);
+ if (!peer) {
+ err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_NETWORK,
+ MGMT_STATUS_FAILED,
+ cp, sizeof(*cp));
+ goto unlock;
+ }
+
+ cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_NETWORK, hdev,
+ data, data_len);
+ if (!cmd)
+ err = -ENOMEM;
+
+ l2cap_chan_close(peer->chan, 0);
+
+unlock:
+ hci_dev_unlock(hdev);
+
+failed:
+ return err;
}

static struct l2cap_chan *bt_6lowpan_listen(void)
@@ -1318,40 +1398,6 @@ static struct l2cap_chan *bt_6lowpan_listen(void)
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_dev *entry;
@@ -1445,44 +1491,6 @@ static int lowpan_enable_get(void *data, u64 *val)
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, "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 const struct file_operations lowpan_control_fops = {
- .write = lowpan_control_write,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
static void disconnect_devices(void)
{
struct lowpan_dev *entry, *tmp, *new_dev;
@@ -1555,9 +1563,6 @@ int 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);
}
@@ -1565,7 +1570,6 @@ int bt_6lowpan_init(void)
void bt_6lowpan_exit(void)
{
debugfs_remove(lowpan_enable_debugfs);
- debugfs_remove(lowpan_control_debugfs);

if (listen_chan) {
l2cap_chan_close(listen_chan, 0);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 2c2824e..909c723 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -107,6 +107,7 @@ static const u16 mgmt_commands[] = {
MGMT_OP_START_LIMITED_DISCOVERY,
MGMT_OP_GET_NETWORKS,
MGMT_OP_ADD_NETWORK,
+ MGMT_OP_REMOVE_NETWORK,
};

static const u16 mgmt_events[] = {
@@ -145,6 +146,7 @@ static const u16 mgmt_events[] = {
MGMT_EV_ADVERTISING_ADDED,
MGMT_EV_ADVERTISING_REMOVED,
MGMT_EV_NETWORK_ADDED,
+ MGMT_EV_NETWORK_REMOVED,
};

static const u16 mgmt_untrusted_commands[] = {
@@ -6342,6 +6344,7 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
{ start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
{ bt_6lowpan_get_networks, MGMT_GET_NETWORKS_SIZE },
{ bt_6lowpan_add_network, MGMT_ADD_NETWORK_SIZE },
+ { bt_6lowpan_remove_network, MGMT_REMOVE_NETWORK_SIZE },
};

void mgmt_index_added(struct hci_dev *hdev)
--
2.1.4


2016-03-04 11:40:41

by Patrik Flykt

[permalink] [raw]
Subject: [RFC 2/5] bluetooth: Implement Get Networks Management API command

Implement MGMT_OP_GET_NETWORKS command by replying with the addresses
and address types of all 6LowPAN peers. If none are found, return
peer count and interface as zero.

Remove the debugfs implementation for achieving the same thing.

The MGMT_OP_GET_NETWORKS command is defined as:
Command Code: 0x0042
Controller Index: <controller id>
Command Parameters:
Return Parameters: Connection_Count (2 Octets)
Network1 {
Address (6 Octets)
Address_Type (1 Octet)
Interface Index (4 Octets)
}
Network2 { }
...

This command is used to retrieve a list of BTLE network
connections. A pre-requisite is that LE is already
enabled, otherwise this command will return a "rejected"
response.

Possible values for the Address_Type parameter:
0 Reserved
1 LE Public
2 LE Random

For devices using resolvable random addresses with a known
identity resolving key, the Address and Address_Type will
contain the identity information.

This command can only be used when the controller is powered.

This command generates a Command Complete event on success or
a Command Status event on failure.

Possible errors: Invalid Parameters
Not Powered
Invalid Index

Signed-off-by: Patrik Flykt <[email protected]>
---
include/net/bluetooth/mgmt.h | 10 ++++
net/bluetooth/6lowpan.c | 110 +++++++++++++++++++++++++++++++++----------
net/bluetooth/mgmt.c | 3 ++
3 files changed, 98 insertions(+), 25 deletions(-)

diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index ea73e08..813224b 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -586,6 +586,16 @@ struct mgmt_rp_get_adv_size_info {

#define MGMT_OP_START_LIMITED_DISCOVERY 0x0041

+#define MGMT_OP_GET_NETWORKS 0x0042
+#define MGMT_GET_NETWORKS_SIZE 0
+struct mgmt_rp_get_networks {
+ __u16 count;
+} __packed; /* followed by zero or more struct mgmt_rp_network */
+struct mgmt_rp_network {
+ struct mgmt_addr_info dst;
+ int ifindex;
+} __packed;
+
#define MGMT_EV_CMD_COMPLETE 0x0001
struct mgmt_ev_cmd_complete {
__le16 opcode;
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index b675448..198e158 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -24,6 +24,9 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
+#include <net/bluetooth/mgmt.h>
+
+#include "mgmt_util.h"

#include <net/6lowpan.h> /* for the compression support */

@@ -1018,6 +1021,88 @@ static const struct l2cap_ops bt_6lowpan_chan_ops = {
.set_shutdown = l2cap_chan_no_set_shutdown,
};

+int bt_6lowpan_get_networks(struct sock *sk, struct hci_dev *hdev,
+ void *data, u16 data_len)
+{
+ int err = 0;
+ struct mgmt_rp_get_networks *rp = NULL;
+ size_t size;
+ struct lowpan_dev *dev;
+ struct lowpan_peer *peer;
+
+ hci_dev_lock(hdev);
+
+ if (!lmp_le_capable(hdev)) {
+ err = mgmt_cmd_complete(sk, hdev->id,
+ MGMT_OP_GET_NETWORKS,
+ MGMT_STATUS_NOT_SUPPORTED, NULL, 0);
+ goto unlock;
+ }
+
+ spin_lock(&devices_lock);
+
+ list_for_each_entry(dev, &bt_6lowpan_devices, list) {
+ int count;
+ struct mgmt_rp_network *nw;
+
+ if (dev->hdev != hdev)
+ continue;
+
+ count = atomic_read(&dev->peer_count);
+
+ size = sizeof(*rp) + count * sizeof(*nw);
+ rp = kmalloc(size, GFP_ATOMIC);
+ if (!rp) {
+ err = -ENOMEM;
+ goto spin_unlock;
+ }
+
+ memset(rp, 0, size);
+ rp->count = count;
+
+ if (!rp->count)
+ break;
+
+ nw = (struct mgmt_rp_network *)(rp + 1);
+
+ list_for_each_entry(peer, &dev->peers, list) {
+ if (!peer->chan)
+ continue;
+
+ bacpy(&nw->dst.bdaddr, &peer->chan->dst);
+ nw->dst.type = peer->chan->dst_type;
+ nw->ifindex = dev->netdev->ifindex;
+ nw++;
+ }
+
+ break;
+ }
+
+ if (!rp) {
+ size = sizeof(*rp);
+ rp = kmalloc(size, GFP_ATOMIC);
+ if (!rp)
+ goto spin_unlock;
+
+ rp->count = 0;
+ }
+
+ BT_DBG("rp %p size %zd count %d", rp, size, rp->count);
+
+ err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_GET_NETWORKS,
+ MGMT_STATUS_SUCCESS, rp, size);
+
+ kfree(rp);
+
+spin_unlock:
+ spin_unlock(&devices_lock);
+
+unlock:
+ hci_dev_unlock(hdev);
+
+ return err;
+}
+
static inline __u8 bdaddr_type(__u8 type)
{
if (type == ADDR_LE_DEV_PUBLIC)
@@ -1289,32 +1374,7 @@ static ssize_t lowpan_control_write(struct file *fp,
return count;
}

-static int lowpan_control_show(struct seq_file *f, void *ptr)
-{
- struct lowpan_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,
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 5a5089c..722cc17 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -31,6 +31,7 @@
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/hci_sock.h>
#include <net/bluetooth/l2cap.h>
+#include <net/bluetooth/6lowpan.h>
#include <net/bluetooth/mgmt.h>

#include "hci_request.h"
@@ -104,6 +105,7 @@ static const u16 mgmt_commands[] = {
MGMT_OP_REMOVE_ADVERTISING,
MGMT_OP_GET_ADV_SIZE_INFO,
MGMT_OP_START_LIMITED_DISCOVERY,
+ MGMT_OP_GET_NETWORKS,
};

static const u16 mgmt_events[] = {
@@ -6336,6 +6338,7 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
{ remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
{ get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
{ start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
+ { bt_6lowpan_get_networks, MGMT_GET_NETWORKS_SIZE },
};

void mgmt_index_added(struct hci_dev *hdev)
--
2.1.4


2016-03-04 11:40:42

by Patrik Flykt

[permalink] [raw]
Subject: [RFC 3/5] l2cap: Pass hci_dev to l2cap_chan_connect()

Since the Bluetooth Management Interface already associates
commands with a hci_dev, pass the hci_dev when calling
l2cap_chan_connect(). This indicates which specific hci_dev to
use for the l2cap connection and will be useful when connecting
or disconnecting Bluetooth IPSP.

Modify the existing code to do a hci_dev lookup before calling
connect.

Signed-off-by: Patrik Flykt <[email protected]>
---
include/net/bluetooth/l2cap.h | 4 ++--
net/bluetooth/6lowpan.c | 4 +++-
net/bluetooth/l2cap_core.c | 6 ++----
net/bluetooth/l2cap_sock.c | 5 ++++-
4 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index 5ee3c68..b65ca60 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -926,8 +926,8 @@ int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid);

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_chan_connect(struct l2cap_chan *chan, struct hci_dev *hdev,
+ __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/6lowpan.c b/net/bluetooth/6lowpan.c
index 198e158..a582a736 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -1113,6 +1113,7 @@ static inline __u8 bdaddr_type(__u8 type)

static int bt_6lowpan_connect(bdaddr_t *addr, u8 dst_type)
{
+ struct hci_dev *hdev;
struct l2cap_chan *chan;
int err;

@@ -1122,7 +1123,8 @@ static int bt_6lowpan_connect(bdaddr_t *addr, u8 dst_type)

chan->ops = &bt_6lowpan_chan_ops;

- err = l2cap_chan_connect(chan, cpu_to_le16(L2CAP_PSM_IPSP), 0,
+ hdev = hci_get_route(addr, NULL);
+ err = l2cap_chan_connect(chan, hdev, cpu_to_le16(L2CAP_PSM_IPSP), 0,
addr, dst_type);

BT_DBG("chan %p err %d", chan, err);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index eb4f5f2..8a87a0d 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -7041,18 +7041,16 @@ 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_chan_connect(struct l2cap_chan *chan, struct hci_dev *hdev,
+ __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;

diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index e4cae72..abcb508 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -176,6 +176,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr,
struct sock *sk = sock->sk;
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
struct sockaddr_l2 la;
+ struct hci_dev *hdev;
int len, err = 0;

BT_DBG("sk %p", sk);
@@ -233,7 +234,9 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr,
if (chan->psm && bdaddr_type_is_le(chan->src_type))
chan->mode = L2CAP_MODE_LE_FLOWCTL;

- err = l2cap_chan_connect(chan, la.l2_psm, __le16_to_cpu(la.l2_cid),
+ hdev = hci_get_route(&la.l2_bdaddr, &chan->src);
+ err = l2cap_chan_connect(chan, hdev, la.l2_psm,
+ __le16_to_cpu(la.l2_cid),
&la.l2_bdaddr, la.l2_bdaddr_type);
if (err)
return err;
--
2.1.4


2016-03-04 11:40:40

by Patrik Flykt

[permalink] [raw]
Subject: [RFC 1/5] bluetooth: Merge Bluetooth 6lowpan functionality to bluetooth module

The bluetooth_6lowpan.ko module functionality is compiled into the
bluetooth module and a new header file 6lowpan.h is created. Kconfig
and Makefile are updated accordingly. 6lowpan init and exit functions
are called from the bluetooth module.

Signed-off-by: Patrik Flykt <[email protected]>
---
net/bluetooth/6lowpan.c | 12 ++----------
net/bluetooth/Kconfig | 2 +-
net/bluetooth/Makefile | 4 +---
net/bluetooth/af_bluetooth.c | 11 +++++++++++
4 files changed, 15 insertions(+), 14 deletions(-)

diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index 8a4cc2f..b675448 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -1387,7 +1387,7 @@ static struct notifier_block bt_6lowpan_dev_notifier = {
.notifier_call = device_event,
};

-static int __init bt_6lowpan_init(void)
+int bt_6lowpan_init(void)
{
lowpan_enable_debugfs = debugfs_create_file("6lowpan_enable", 0644,
bt_debugfs, NULL,
@@ -1399,7 +1399,7 @@ static int __init bt_6lowpan_init(void)
return register_netdevice_notifier(&bt_6lowpan_dev_notifier);
}

-static void __exit bt_6lowpan_exit(void)
+void bt_6lowpan_exit(void)
{
debugfs_remove(lowpan_enable_debugfs);
debugfs_remove(lowpan_control_debugfs);
@@ -1413,11 +1413,3 @@ static void __exit bt_6lowpan_exit(void)

unregister_netdevice_notifier(&bt_6lowpan_dev_notifier);
}
-
-module_init(bt_6lowpan_init);
-module_exit(bt_6lowpan_exit);
-
-MODULE_AUTHOR("Jukka Rissanen <[email protected]>");
-MODULE_DESCRIPTION("Bluetooth 6LoWPAN");
-MODULE_VERSION(VERSION);
-MODULE_LICENSE("GPL");
diff --git a/net/bluetooth/Kconfig b/net/bluetooth/Kconfig
index 06c31b9..5f29659 100644
--- a/net/bluetooth/Kconfig
+++ b/net/bluetooth/Kconfig
@@ -64,7 +64,7 @@ config BT_LE
default y

config BT_6LOWPAN
- tristate "Bluetooth 6LoWPAN support"
+ bool "Bluetooth 6LoWPAN support"
depends on BT_LE && 6LOWPAN
help
IPv6 compression over Bluetooth Low Energy.
diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
index b3ff12e..57b02ba 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 \
@@ -18,6 +15,7 @@ bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
bluetooth-$(CONFIG_BT_BREDR) += sco.o
bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o
bluetooth-$(CONFIG_BT_LEDS) += leds.o
+bluetooth-$(CONFIG_BT_6LOWPAN) += 6lowpan.o
bluetooth-$(CONFIG_BT_DEBUGFS) += hci_debugfs.o
bluetooth-$(CONFIG_BT_SELFTEST) += selftest.o

diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 955eda9..571a324 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -29,6 +29,7 @@
#include <asm/ioctls.h>

#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/6lowpan.h>
#include <linux/proc_fs.h>

#include "selftest.h"
@@ -747,8 +748,16 @@ static int __init bt_init(void)
goto sock_err;
}

+ err = bt_6lowpan_init();
+ if (err < 0) {
+ sco_exit();
+ l2cap_exit();
+ goto sock_err;
+ }
+
err = mgmt_init();
if (err < 0) {
+ bt_6lowpan_exit();
sco_exit();
l2cap_exit();
goto sock_err;
@@ -770,6 +779,8 @@ static void __exit bt_exit(void)
{
mgmt_exit();

+ bt_6lowpan_exit();
+
sco_exit();

l2cap_exit();
--
2.1.4