Commit 801c1e8d authored by Johan Hedberg's avatar Johan Hedberg Committed by Marcel Holtmann

Bluetooth: Add mgmt HCI channel registration API

This patch adds an API for registering HCI channels with mgmt-like
semantics. For now the only user will be HCI_CHANNEL_CONTROL, but e.g.
6lowpan is intended to use this as well in the future.
Signed-off-by: default avatarJohan Hedberg <johan.hedberg@intel.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 93690c22
...@@ -1273,6 +1273,23 @@ void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb); ...@@ -1273,6 +1273,23 @@ void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb);
void hci_sock_dev_event(struct hci_dev *hdev, int event); void hci_sock_dev_event(struct hci_dev *hdev, int event);
struct hci_mgmt_handler {
int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
u16 data_len);
bool var_len;
size_t data_len;
};
struct hci_mgmt_chan {
struct list_head list;
unsigned short channel;
size_t handler_count;
const struct hci_mgmt_handler *handlers;
};
int hci_mgmt_chan_register(struct hci_mgmt_chan *c);
void hci_mgmt_chan_unregister(struct hci_mgmt_chan *c);
/* Management interface */ /* Management interface */
#define DISCOV_TYPE_BREDR (BIT(BDADDR_BREDR)) #define DISCOV_TYPE_BREDR (BIT(BDADDR_BREDR))
#define DISCOV_TYPE_LE (BIT(BDADDR_LE_PUBLIC) | \ #define DISCOV_TYPE_LE (BIT(BDADDR_LE_PUBLIC) | \
......
...@@ -31,6 +31,9 @@ ...@@ -31,6 +31,9 @@
#include <net/bluetooth/hci_core.h> #include <net/bluetooth/hci_core.h>
#include <net/bluetooth/hci_mon.h> #include <net/bluetooth/hci_mon.h>
static LIST_HEAD(mgmt_chan_list);
static DEFINE_MUTEX(mgmt_chan_list_lock);
static atomic_t monitor_promisc = ATOMIC_INIT(0); static atomic_t monitor_promisc = ATOMIC_INIT(0);
/* ----- HCI socket interface ----- */ /* ----- HCI socket interface ----- */
...@@ -401,6 +404,56 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event) ...@@ -401,6 +404,56 @@ void hci_sock_dev_event(struct hci_dev *hdev, int event)
} }
} }
static struct hci_mgmt_chan *__hci_mgmt_chan_find(unsigned short channel)
{
struct hci_mgmt_chan *c;
list_for_each_entry(c, &mgmt_chan_list, list) {
if (c->channel == channel)
return c;
}
return NULL;
}
static struct hci_mgmt_chan *hci_mgmt_chan_find(unsigned short channel)
{
struct hci_mgmt_chan *c;
mutex_lock(&mgmt_chan_list_lock);
c = __hci_mgmt_chan_find(channel);
mutex_unlock(&mgmt_chan_list_lock);
return c;
}
int hci_mgmt_chan_register(struct hci_mgmt_chan *c)
{
if (c->channel < HCI_CHANNEL_CONTROL)
return -EINVAL;
mutex_lock(&mgmt_chan_list_lock);
if (__hci_mgmt_chan_find(c->channel)) {
mutex_unlock(&mgmt_chan_list_lock);
return -EALREADY;
}
list_add_tail(&c->list, &mgmt_chan_list);
mutex_unlock(&mgmt_chan_list_lock);
return 0;
}
EXPORT_SYMBOL(hci_mgmt_chan_register);
void hci_mgmt_chan_unregister(struct hci_mgmt_chan *c)
{
mutex_lock(&mgmt_chan_list_lock);
list_del(&c->list);
mutex_unlock(&mgmt_chan_list_lock);
}
EXPORT_SYMBOL(hci_mgmt_chan_unregister);
static int hci_sock_release(struct socket *sock) static int hci_sock_release(struct socket *sock)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
...@@ -718,10 +771,24 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, ...@@ -718,10 +771,24 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
break; break;
default: default:
if (!hci_mgmt_chan_find(haddr.hci_channel)) {
err = -EINVAL; err = -EINVAL;
goto done; goto done;
} }
if (haddr.hci_dev != HCI_DEV_NONE) {
err = -EINVAL;
goto done;
}
if (!capable(CAP_NET_ADMIN)) {
err = -EPERM;
goto done;
}
break;
}
hci_pi(sk)->channel = haddr.hci_channel; hci_pi(sk)->channel = haddr.hci_channel;
sk->sk_state = BT_BOUND; sk->sk_state = BT_BOUND;
...@@ -837,6 +904,10 @@ static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, ...@@ -837,6 +904,10 @@ static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
case HCI_CHANNEL_MONITOR: case HCI_CHANNEL_MONITOR:
sock_recv_timestamp(msg, sk, skb); sock_recv_timestamp(msg, sk, skb);
break; break;
default:
if (hci_mgmt_chan_find(hci_pi(sk)->channel))
sock_recv_timestamp(msg, sk, skb);
break;
} }
skb_free_datagram(sk, skb); skb_free_datagram(sk, skb);
...@@ -848,6 +919,7 @@ static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, ...@@ -848,6 +919,7 @@ static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg,
size_t len) size_t len)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct hci_mgmt_chan *chan;
struct hci_dev *hdev; struct hci_dev *hdev;
struct sk_buff *skb; struct sk_buff *skb;
int err; int err;
...@@ -876,7 +948,14 @@ static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg, ...@@ -876,7 +948,14 @@ static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg,
err = -EOPNOTSUPP; err = -EOPNOTSUPP;
goto done; goto done;
default: default:
mutex_lock(&mgmt_chan_list_lock);
chan = __hci_mgmt_chan_find(hci_pi(sk)->channel);
if (chan)
err = -ENOSYS; /* FIXME: call handler */
else
err = -EINVAL; err = -EINVAL;
mutex_unlock(&mgmt_chan_list_lock);
goto done; goto done;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment