Bluetooth: Add initial Bluetooth Management interface callbacks
Add initial code for handling Bluetooth Management interface messages. Signed-off-by: Johan Hedberg <johan.hedberg@nokia.com> Acked-by: Marcel Holtmann <marcel@holtmann.org> Acked-by: Andrei Emeltchenko <andrei.emeltchenko@nokia.com> Signed-off-by: Gustavo F. Padovan <padovan@profusion.mobi>
This commit is contained in:
parent
c02178d22b
commit
0381101fd6
|
@ -660,6 +660,9 @@ void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data);
|
|||
/* ----- HCI Sockets ----- */
|
||||
void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb);
|
||||
|
||||
/* Management interface */
|
||||
int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len);
|
||||
|
||||
/* HCI info for socket */
|
||||
#define hci_pi(sk) ((struct hci_pinfo *) sk)
|
||||
|
||||
|
|
|
@ -10,4 +10,4 @@ obj-$(CONFIG_BT_BNEP) += bnep/
|
|||
obj-$(CONFIG_BT_CMTP) += cmtp/
|
||||
obj-$(CONFIG_BT_HIDP) += hidp/
|
||||
|
||||
bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o hci_sysfs.o lib.o
|
||||
bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o hci_sock.o hci_sysfs.o lib.o
|
||||
|
|
|
@ -49,6 +49,8 @@
|
|||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
|
||||
static int enable_mgmt;
|
||||
|
||||
/* ----- HCI socket interface ----- */
|
||||
|
||||
static inline int hci_test_bit(int nr, void *addr)
|
||||
|
@ -353,25 +355,35 @@ static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long a
|
|||
|
||||
static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
|
||||
{
|
||||
struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr;
|
||||
struct sockaddr_hci haddr;
|
||||
struct sock *sk = sock->sk;
|
||||
struct hci_dev *hdev = NULL;
|
||||
int err = 0;
|
||||
int len, err = 0;
|
||||
|
||||
BT_DBG("sock %p sk %p", sock, sk);
|
||||
|
||||
if (!haddr || haddr->hci_family != AF_BLUETOOTH)
|
||||
if (!addr)
|
||||
return -EINVAL;
|
||||
|
||||
memset(&haddr, 0, sizeof(haddr));
|
||||
len = min_t(unsigned int, sizeof(haddr), addr_len);
|
||||
memcpy(&haddr, addr, len);
|
||||
|
||||
if (haddr.hci_family != AF_BLUETOOTH)
|
||||
return -EINVAL;
|
||||
|
||||
if (haddr.hci_channel != HCI_CHANNEL_RAW && !enable_mgmt)
|
||||
return -EINVAL;
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
if (hci_pi(sk)->hdev) {
|
||||
if (sk->sk_state == BT_BOUND || hci_pi(sk)->hdev) {
|
||||
err = -EALREADY;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (haddr->hci_dev != HCI_DEV_NONE) {
|
||||
hdev = hci_dev_get(haddr->hci_dev);
|
||||
if (haddr.hci_dev != HCI_DEV_NONE) {
|
||||
hdev = hci_dev_get(haddr.hci_dev);
|
||||
if (!hdev) {
|
||||
err = -ENODEV;
|
||||
goto done;
|
||||
|
@ -380,6 +392,7 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
|
|||
atomic_inc(&hdev->promisc);
|
||||
}
|
||||
|
||||
hci_pi(sk)->channel = haddr.hci_channel;
|
||||
hci_pi(sk)->hdev = hdev;
|
||||
sk->sk_state = BT_BOUND;
|
||||
|
||||
|
@ -502,6 +515,17 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
|
|||
|
||||
lock_sock(sk);
|
||||
|
||||
switch (hci_pi(sk)->channel) {
|
||||
case HCI_CHANNEL_RAW:
|
||||
break;
|
||||
case HCI_CHANNEL_CONTROL:
|
||||
err = mgmt_control(sk, msg, len);
|
||||
goto done;
|
||||
default:
|
||||
err = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
hdev = hci_pi(sk)->hdev;
|
||||
if (!hdev) {
|
||||
err = -EBADFD;
|
||||
|
@ -831,3 +855,6 @@ void __exit hci_sock_cleanup(void)
|
|||
|
||||
proto_unregister(&hci_sk_proto);
|
||||
}
|
||||
|
||||
module_param(enable_mgmt, bool, 0644);
|
||||
MODULE_PARM_DESC(enable_mgmt, "Enable Management interface");
|
||||
|
|
99
net/bluetooth/mgmt.c
Normal file
99
net/bluetooth/mgmt.c
Normal file
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
BlueZ - Bluetooth protocol stack for Linux
|
||||
Copyright (C) 2010 Nokia Corporation
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 as
|
||||
published by the Free Software Foundation;
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
|
||||
IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
|
||||
CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
|
||||
COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
|
||||
SOFTWARE IS DISCLAIMED.
|
||||
*/
|
||||
|
||||
/* Bluetooth HCI Management interface */
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
#include <net/bluetooth/mgmt.h>
|
||||
|
||||
static void cmd_status(struct sock *sk, u16 cmd, u8 status)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct mgmt_hdr *hdr;
|
||||
struct mgmt_ev_cmd_status *ev;
|
||||
|
||||
BT_DBG("sock %p", sk);
|
||||
|
||||
skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
|
||||
if (!skb)
|
||||
return;
|
||||
|
||||
hdr = (void *) skb_put(skb, sizeof(*hdr));
|
||||
|
||||
hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
|
||||
hdr->len = cpu_to_le16(sizeof(*ev));
|
||||
|
||||
ev = (void *) skb_put(skb, sizeof(*ev));
|
||||
ev->status = status;
|
||||
put_unaligned_le16(cmd, &ev->opcode);
|
||||
|
||||
if (sock_queue_rcv_skb(sk, skb) < 0)
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
|
||||
{
|
||||
unsigned char *buf;
|
||||
struct mgmt_hdr *hdr;
|
||||
u16 opcode, len;
|
||||
int err;
|
||||
|
||||
BT_DBG("got %zu bytes", msglen);
|
||||
|
||||
if (msglen < sizeof(*hdr))
|
||||
return -EINVAL;
|
||||
|
||||
buf = kmalloc(msglen, GFP_ATOMIC);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
|
||||
err = -EFAULT;
|
||||
goto done;
|
||||
}
|
||||
|
||||
hdr = (struct mgmt_hdr *) buf;
|
||||
opcode = get_unaligned_le16(&hdr->opcode);
|
||||
len = get_unaligned_le16(&hdr->len);
|
||||
|
||||
if (len != msglen - sizeof(*hdr)) {
|
||||
err = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
switch (opcode) {
|
||||
default:
|
||||
BT_DBG("Unknown op %u", opcode);
|
||||
cmd_status(sk, opcode, 0x01);
|
||||
break;
|
||||
}
|
||||
|
||||
err = msglen;
|
||||
|
||||
done:
|
||||
kfree(buf);
|
||||
return err;
|
||||
}
|
Loading…
Reference in a new issue