Skip to content

Commit

Permalink
Bluetooth: Move generic mgmt command dispatcher to hci_sock.c
Browse files Browse the repository at this point in the history
The mgmt.c file should be reserved purely for HCI_CHANNEL_CONTROL. The
mgmt_control() function in it is already completely generic and has a
single user in hci_sock.c. This patch moves the function there and
renames it a bit more appropriately to hci_mgmt_cmd() (as it's a command
dispatcher).

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
  • Loading branch information
Johan Hedberg authored and Marcel Holtmann committed Mar 17, 2015
1 parent 88b94ce commit fa4335d
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 115 deletions.
3 changes: 0 additions & 3 deletions include/net/bluetooth/hci_core.h
Original file line number Diff line number Diff line change
Expand Up @@ -1330,9 +1330,6 @@ void hci_mgmt_chan_unregister(struct hci_mgmt_chan *c);
#define DISCOV_BREDR_INQUIRY_LEN 0x08
#define DISCOV_LE_RESTART_DELAY msecs_to_jiffies(200) /* msec */

int mgmt_control(struct hci_mgmt_chan *chan, struct sock *sk,
struct msghdr *msg, size_t msglen);

int mgmt_new_settings(struct hci_dev *hdev);
void mgmt_index_added(struct hci_dev *hdev);
void mgmt_index_removed(struct hci_dev *hdev);
Expand Down
116 changes: 115 additions & 1 deletion net/bluetooth/hci_sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/hci_mon.h>
#include <net/bluetooth/mgmt.h>

#include "mgmt_util.h"

static LIST_HEAD(mgmt_chan_list);
static DEFINE_MUTEX(mgmt_chan_list_lock);
Expand Down Expand Up @@ -951,6 +954,117 @@ static int hci_sock_recvmsg(struct socket *sock, struct msghdr *msg, size_t len,
return err ? : copied;
}

static int hci_mgmt_cmd(struct hci_mgmt_chan *chan, struct sock *sk,
struct msghdr *msg, size_t msglen)
{
void *buf;
u8 *cp;
struct mgmt_hdr *hdr;
u16 opcode, index, len;
struct hci_dev *hdev = NULL;
const struct hci_mgmt_handler *handler;
bool var_len, no_hdev;
int err;

BT_DBG("got %zu bytes", msglen);

if (msglen < sizeof(*hdr))
return -EINVAL;

buf = kmalloc(msglen, GFP_KERNEL);
if (!buf)
return -ENOMEM;

if (memcpy_from_msg(buf, msg, msglen)) {
err = -EFAULT;
goto done;
}

hdr = buf;
opcode = __le16_to_cpu(hdr->opcode);
index = __le16_to_cpu(hdr->index);
len = __le16_to_cpu(hdr->len);

if (len != msglen - sizeof(*hdr)) {
err = -EINVAL;
goto done;
}

if (opcode >= chan->handler_count ||
chan->handlers[opcode].func == NULL) {
BT_DBG("Unknown op %u", opcode);
err = mgmt_cmd_status(sk, index, opcode,
MGMT_STATUS_UNKNOWN_COMMAND);
goto done;
}

handler = &chan->handlers[opcode];

if (!hci_sock_test_flag(sk, HCI_SOCK_TRUSTED) &&
!(handler->flags & HCI_MGMT_UNTRUSTED)) {
err = mgmt_cmd_status(sk, index, opcode,
MGMT_STATUS_PERMISSION_DENIED);
goto done;
}

if (index != MGMT_INDEX_NONE) {
hdev = hci_dev_get(index);
if (!hdev) {
err = mgmt_cmd_status(sk, index, opcode,
MGMT_STATUS_INVALID_INDEX);
goto done;
}

if (hci_dev_test_flag(hdev, HCI_SETUP) ||
hci_dev_test_flag(hdev, HCI_CONFIG) ||
hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) {
err = mgmt_cmd_status(sk, index, opcode,
MGMT_STATUS_INVALID_INDEX);
goto done;
}

if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) &&
!(handler->flags & HCI_MGMT_UNCONFIGURED)) {
err = mgmt_cmd_status(sk, index, opcode,
MGMT_STATUS_INVALID_INDEX);
goto done;
}
}

no_hdev = (handler->flags & HCI_MGMT_NO_HDEV);
if (no_hdev != !hdev) {
err = mgmt_cmd_status(sk, index, opcode,
MGMT_STATUS_INVALID_INDEX);
goto done;
}

var_len = (handler->flags & HCI_MGMT_VAR_LEN);
if ((var_len && len < handler->data_len) ||
(!var_len && len != handler->data_len)) {
err = mgmt_cmd_status(sk, index, opcode,
MGMT_STATUS_INVALID_PARAMS);
goto done;
}

if (hdev && chan->hdev_init)
chan->hdev_init(sk, hdev);

cp = buf + sizeof(*hdr);

err = handler->func(sk, hdev, cp, len);
if (err < 0)
goto done;

err = msglen;

done:
if (hdev)
hci_dev_put(hdev);

kfree(buf);
return err;
}

static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg,
size_t len)
{
Expand Down Expand Up @@ -984,7 +1098,7 @@ static int hci_sock_sendmsg(struct socket *sock, struct msghdr *msg,
mutex_lock(&mgmt_chan_list_lock);
chan = __hci_mgmt_chan_find(hci_pi(sk)->channel);
if (chan)
err = mgmt_control(chan, sk, msg, len);
err = hci_mgmt_cmd(chan, sk, msg, len);
else
err = -EINVAL;

Expand Down
111 changes: 0 additions & 111 deletions net/bluetooth/mgmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -6401,117 +6401,6 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
{ read_adv_features, MGMT_READ_ADV_FEATURES_SIZE },
};

int mgmt_control(struct hci_mgmt_chan *chan, struct sock *sk,
struct msghdr *msg, size_t msglen)
{
void *buf;
u8 *cp;
struct mgmt_hdr *hdr;
u16 opcode, index, len;
struct hci_dev *hdev = NULL;
const struct hci_mgmt_handler *handler;
bool var_len, no_hdev;
int err;

BT_DBG("got %zu bytes", msglen);

if (msglen < sizeof(*hdr))
return -EINVAL;

buf = kmalloc(msglen, GFP_KERNEL);
if (!buf)
return -ENOMEM;

if (memcpy_from_msg(buf, msg, msglen)) {
err = -EFAULT;
goto done;
}

hdr = buf;
opcode = __le16_to_cpu(hdr->opcode);
index = __le16_to_cpu(hdr->index);
len = __le16_to_cpu(hdr->len);

if (len != msglen - sizeof(*hdr)) {
err = -EINVAL;
goto done;
}

if (opcode >= chan->handler_count ||
chan->handlers[opcode].func == NULL) {
BT_DBG("Unknown op %u", opcode);
err = mgmt_cmd_status(sk, index, opcode,
MGMT_STATUS_UNKNOWN_COMMAND);
goto done;
}

handler = &chan->handlers[opcode];

if (!hci_sock_test_flag(sk, HCI_SOCK_TRUSTED) &&
!(handler->flags & HCI_MGMT_UNTRUSTED)) {
err = mgmt_cmd_status(sk, index, opcode,
MGMT_STATUS_PERMISSION_DENIED);
goto done;
}

if (index != MGMT_INDEX_NONE) {
hdev = hci_dev_get(index);
if (!hdev) {
err = mgmt_cmd_status(sk, index, opcode,
MGMT_STATUS_INVALID_INDEX);
goto done;
}

if (hci_dev_test_flag(hdev, HCI_SETUP) ||
hci_dev_test_flag(hdev, HCI_CONFIG) ||
hci_dev_test_flag(hdev, HCI_USER_CHANNEL)) {
err = mgmt_cmd_status(sk, index, opcode,
MGMT_STATUS_INVALID_INDEX);
goto done;
}

if (hci_dev_test_flag(hdev, HCI_UNCONFIGURED) &&
!(handler->flags & HCI_MGMT_UNCONFIGURED)) {
err = mgmt_cmd_status(sk, index, opcode,
MGMT_STATUS_INVALID_INDEX);
goto done;
}
}

no_hdev = (handler->flags & HCI_MGMT_NO_HDEV);
if (no_hdev != !hdev) {
err = mgmt_cmd_status(sk, index, opcode,
MGMT_STATUS_INVALID_INDEX);
goto done;
}

var_len = (handler->flags & HCI_MGMT_VAR_LEN);
if ((var_len && len < handler->data_len) ||
(!var_len && len != handler->data_len)) {
err = mgmt_cmd_status(sk, index, opcode,
MGMT_STATUS_INVALID_PARAMS);
goto done;
}

if (hdev && chan->hdev_init)
chan->hdev_init(sk, hdev);

cp = buf + sizeof(*hdr);

err = handler->func(sk, hdev, cp, len);
if (err < 0)
goto done;

err = msglen;

done:
if (hdev)
hci_dev_put(hdev);

kfree(buf);
return err;
}

void mgmt_index_added(struct hci_dev *hdev)
{
struct mgmt_ev_ext_index ev;
Expand Down

0 comments on commit fa4335d

Please sign in to comment.