From 17588f25f48d659bfa07fba5821d16014ab335a4 Mon Sep 17 00:00:00 2001 From: Wey-Yi Guy Date: Sat, 11 Dec 2010 08:46:56 -0800 Subject: [PATCH] --- yaml --- r: 225520 b: refs/heads/master c: e88735d711948a580741fd337afd4ec11c395174 h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/drivers/net/wireless/iwlwifi/iwl-led.c | 2 +- trunk/include/net/bluetooth/bluetooth.h | 1 - trunk/include/net/bluetooth/hci.h | 4 - trunk/include/net/bluetooth/hci_core.h | 9 +- trunk/include/net/bluetooth/mgmt.h | 87 ------ trunk/net/bluetooth/Makefile | 2 +- trunk/net/bluetooth/hci_core.c | 17 +- trunk/net/bluetooth/hci_event.c | 33 +- trunk/net/bluetooth/hci_sock.c | 52 +--- trunk/net/bluetooth/l2cap.c | 8 +- trunk/net/bluetooth/mgmt.c | 308 ------------------- 12 files changed, 25 insertions(+), 500 deletions(-) delete mode 100644 trunk/include/net/bluetooth/mgmt.h delete mode 100644 trunk/net/bluetooth/mgmt.c diff --git a/[refs] b/[refs] index 44a507543117..fc6bf81272f0 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 782a9e31e81956a271375c0ba8d46fbb0480983e +refs/heads/master: e88735d711948a580741fd337afd4ec11c395174 diff --git a/trunk/drivers/net/wireless/iwlwifi/iwl-led.c b/trunk/drivers/net/wireless/iwlwifi/iwl-led.c index 516e5577ed2a..46ccdf406e8e 100644 --- a/trunk/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/trunk/drivers/net/wireless/iwlwifi/iwl-led.c @@ -45,7 +45,7 @@ /* default: IWL_LED_BLINK(0) using blinking index table */ static int led_mode; module_param(led_mode, int, S_IRUGO); -MODULE_PARM_DESC(led_mode, "led mode: 0=system default, " +MODULE_PARM_DESC(led_mode, "0=system default, " "1=On(RF On)/Off(RF Off), 2=blinking"); static const struct { diff --git a/trunk/include/net/bluetooth/bluetooth.h b/trunk/include/net/bluetooth/bluetooth.h index 0c5e72503b77..d81ea7997701 100644 --- a/trunk/include/net/bluetooth/bluetooth.h +++ b/trunk/include/net/bluetooth/bluetooth.h @@ -144,7 +144,6 @@ struct bt_skb_cb { __u8 tx_seq; __u8 retries; __u8 sar; - unsigned short channel; }; #define bt_cb(skb) ((struct bt_skb_cb *)((skb)->cb)) diff --git a/trunk/include/net/bluetooth/hci.h b/trunk/include/net/bluetooth/hci.h index 29a7a8ca0438..f3c5ed6d7bda 100644 --- a/trunk/include/net/bluetooth/hci.h +++ b/trunk/include/net/bluetooth/hci.h @@ -934,13 +934,9 @@ static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb) struct sockaddr_hci { sa_family_t hci_family; unsigned short hci_dev; - unsigned short hci_channel; }; #define HCI_DEV_NONE 0xffff -#define HCI_CHANNEL_RAW 0 -#define HCI_CHANNEL_CONTROL 1 - struct hci_filter { unsigned long type_mask; unsigned long event_mask[2]; diff --git a/trunk/include/net/bluetooth/hci_core.h b/trunk/include/net/bluetooth/hci_core.h index a29feb01854e..9c08625617a1 100644 --- a/trunk/include/net/bluetooth/hci_core.h +++ b/trunk/include/net/bluetooth/hci_core.h @@ -129,7 +129,6 @@ struct hci_dev { wait_queue_head_t req_wait_q; __u32 req_status; __u32 req_result; - __u16 req_last_cmd; struct inquiry_cache inq_cache; struct hci_conn_hash conn_hash; @@ -661,11 +660,6 @@ 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); -int mgmt_index_added(u16 index); -int mgmt_index_removed(u16 index); - /* HCI info for socket */ #define hci_pi(sk) ((struct hci_pinfo *) sk) @@ -674,7 +668,6 @@ struct hci_pinfo { struct hci_dev *hdev; struct hci_filter filter; __u32 cmsg_mask; - unsigned short channel; }; /* HCI security filter */ @@ -694,6 +687,6 @@ struct hci_sec_filter { #define hci_req_lock(d) mutex_lock(&d->req_lock) #define hci_req_unlock(d) mutex_unlock(&d->req_lock) -void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result); +void hci_req_complete(struct hci_dev *hdev, int result); #endif /* __HCI_CORE_H */ diff --git a/trunk/include/net/bluetooth/mgmt.h b/trunk/include/net/bluetooth/mgmt.h deleted file mode 100644 index ca29c1367ffd..000000000000 --- a/trunk/include/net/bluetooth/mgmt.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - 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. -*/ - -struct mgmt_hdr { - __le16 opcode; - __le16 len; -} __packed; -#define MGMT_HDR_SIZE 4 - -#define MGMT_OP_READ_VERSION 0x0001 -struct mgmt_rp_read_version { - __u8 version; - __le16 revision; -} __packed; - -#define MGMT_OP_READ_INDEX_LIST 0x0003 -struct mgmt_rp_read_index_list { - __le16 num_controllers; - __le16 index[0]; -} __packed; - -#define MGMT_OP_READ_INFO 0x0004 -struct mgmt_cp_read_info { - __le16 index; -} __packed; -struct mgmt_rp_read_info { - __le16 index; - __u8 type; - __u8 powered; - __u8 discoverable; - __u8 pairable; - __u8 sec_mode; - bdaddr_t bdaddr; - __u8 dev_class[3]; - __u8 features[8]; - __u16 manufacturer; - __u8 hci_ver; - __u16 hci_rev; -} __packed; - -#define MGMT_EV_CMD_COMPLETE 0x0001 -struct mgmt_ev_cmd_complete { - __le16 opcode; - __u8 data[0]; -} __packed; - -#define MGMT_EV_CMD_STATUS 0x0002 -struct mgmt_ev_cmd_status { - __u8 status; - __le16 opcode; -} __packed; - -#define MGMT_EV_CONTROLLER_ERROR 0x0003 -struct mgmt_ev_controller_error { - __le16 index; - __u8 error_code; -} __packed; - -#define MGMT_EV_INDEX_ADDED 0x0004 -struct mgmt_ev_index_added { - __le16 index; -} __packed; - -#define MGMT_EV_INDEX_REMOVED 0x0005 -struct mgmt_ev_index_removed { - __le16 index; -} __packed; diff --git a/trunk/net/bluetooth/Makefile b/trunk/net/bluetooth/Makefile index 250f954f0213..d1e433f7d673 100644 --- a/trunk/net/bluetooth/Makefile +++ b/trunk/net/bluetooth/Makefile @@ -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 mgmt.o hci_sock.o hci_sysfs.o lib.o +bluetooth-objs := af_bluetooth.o hci_core.o hci_conn.o hci_event.o hci_sock.o hci_sysfs.o lib.o diff --git a/trunk/net/bluetooth/hci_core.c b/trunk/net/bluetooth/hci_core.c index 8b602d881fd7..51c61f75a797 100644 --- a/trunk/net/bluetooth/hci_core.c +++ b/trunk/net/bluetooth/hci_core.c @@ -91,16 +91,9 @@ static void hci_notify(struct hci_dev *hdev, int event) /* ---- HCI requests ---- */ -void hci_req_complete(struct hci_dev *hdev, __u16 cmd, int result) +void hci_req_complete(struct hci_dev *hdev, int result) { - BT_DBG("%s command 0x%04x result 0x%2.2x", hdev->name, cmd, result); - - /* If the request has set req_last_cmd (typical for multi-HCI - * command requests) check if the completed command matches - * this, and if not just return. Single HCI command requests - * typically leave req_last_cmd as 0 */ - if (hdev->req_last_cmd && cmd != hdev->req_last_cmd) - return; + BT_DBG("%s result 0x%2.2x", hdev->name, result); if (hdev->req_status == HCI_REQ_PEND) { hdev->req_result = result; @@ -156,7 +149,7 @@ static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, break; } - hdev->req_last_cmd = hdev->req_status = hdev->req_result = 0; + hdev->req_status = hdev->req_result = 0; BT_DBG("%s end: err %d", hdev->name, err); @@ -259,8 +252,6 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) /* Connection accept timeout ~20 secs */ param = cpu_to_le16(0x7d00); hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, ¶m); - - hdev->req_last_cmd = HCI_OP_WRITE_CA_TIMEOUT; } static void hci_scan_req(struct hci_dev *hdev, unsigned long opt) @@ -969,7 +960,6 @@ int hci_register_dev(struct hci_dev *hdev) } } - mgmt_index_added(hdev->id); hci_notify(hdev, HCI_DEV_REG); return id; @@ -999,7 +989,6 @@ int hci_unregister_dev(struct hci_dev *hdev) for (i = 0; i < NUM_REASSEMBLY; i++) kfree_skb(hdev->reassembly[i]); - mgmt_index_removed(hdev->id); hci_notify(hdev, HCI_DEV_UNREG); if (hdev->rfkill) { diff --git a/trunk/net/bluetooth/hci_event.c b/trunk/net/bluetooth/hci_event.c index 38100170d380..8923b36a67a2 100644 --- a/trunk/net/bluetooth/hci_event.c +++ b/trunk/net/bluetooth/hci_event.c @@ -58,7 +58,7 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb) clear_bit(HCI_INQUIRY, &hdev->flags); - hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status); + hci_req_complete(hdev, status); hci_conn_check_pending(hdev); } @@ -174,7 +174,7 @@ static void hci_cc_write_def_link_policy(struct hci_dev *hdev, struct sk_buff *s if (!status) hdev->link_policy = get_unaligned_le16(sent); - hci_req_complete(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, status); + hci_req_complete(hdev, status); } static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) @@ -183,7 +183,7 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s status 0x%x", hdev->name, status); - hci_req_complete(hdev, HCI_OP_RESET, status); + hci_req_complete(hdev, status); } static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) @@ -235,7 +235,7 @@ static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb) clear_bit(HCI_AUTH, &hdev->flags); } - hci_req_complete(hdev, HCI_OP_WRITE_AUTH_ENABLE, status); + hci_req_complete(hdev, status); } static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb) @@ -258,7 +258,7 @@ static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb) clear_bit(HCI_ENCRYPT, &hdev->flags); } - hci_req_complete(hdev, HCI_OP_WRITE_ENCRYPT_MODE, status); + hci_req_complete(hdev, status); } static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) @@ -285,7 +285,7 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb) set_bit(HCI_PSCAN, &hdev->flags); } - hci_req_complete(hdev, HCI_OP_WRITE_SCAN_ENABLE, status); + hci_req_complete(hdev, status); } static void hci_cc_read_class_of_dev(struct hci_dev *hdev, struct sk_buff *skb) @@ -383,7 +383,7 @@ static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s status 0x%x", hdev->name, status); - hci_req_complete(hdev, HCI_OP_HOST_BUFFER_SIZE, status); + hci_req_complete(hdev, status); } static void hci_cc_read_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb) @@ -536,16 +536,7 @@ static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb) if (!rp->status) bacpy(&hdev->bdaddr, &rp->bdaddr); - hci_req_complete(hdev, HCI_OP_READ_BD_ADDR, rp->status); -} - -static void hci_cc_write_ca_timeout(struct hci_dev *hdev, struct sk_buff *skb) -{ - __u8 status = *((__u8 *) skb->data); - - BT_DBG("%s status 0x%x", hdev->name, status); - - hci_req_complete(hdev, HCI_OP_WRITE_CA_TIMEOUT, status); + hci_req_complete(hdev, rp->status); } static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) @@ -553,7 +544,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) BT_DBG("%s status 0x%x", hdev->name, status); if (status) { - hci_req_complete(hdev, HCI_OP_INQUIRY, status); + hci_req_complete(hdev, status); hci_conn_check_pending(hdev); } else @@ -880,7 +871,7 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff clear_bit(HCI_INQUIRY, &hdev->flags); - hci_req_complete(hdev, HCI_OP_INQUIRY, status); + hci_req_complete(hdev, status); hci_conn_check_pending(hdev); } @@ -1388,10 +1379,6 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk hci_cc_read_bd_addr(hdev, skb); break; - case HCI_OP_WRITE_CA_TIMEOUT: - hci_cc_write_ca_timeout(hdev, skb); - break; - default: BT_DBG("%s opcode 0x%x", hdev->name, opcode); break; diff --git a/trunk/net/bluetooth/hci_sock.c b/trunk/net/bluetooth/hci_sock.c index 29827c77f6ce..b3753bad2a55 100644 --- a/trunk/net/bluetooth/hci_sock.c +++ b/trunk/net/bluetooth/hci_sock.c @@ -49,8 +49,6 @@ #include #include -static int enable_mgmt; - /* ----- HCI socket interface ----- */ static inline int hci_test_bit(int nr, void *addr) @@ -104,12 +102,6 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) if (skb->sk == sk) continue; - if (bt_cb(skb)->channel != hci_pi(sk)->channel) - continue; - - if (bt_cb(skb)->channel == HCI_CHANNEL_CONTROL) - goto clone; - /* Apply filter */ flt = &hci_pi(sk)->filter; @@ -133,14 +125,12 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb) continue; } -clone: nskb = skb_clone(skb, GFP_ATOMIC); if (!nskb) continue; /* Put type byte before the data */ - if (bt_cb(skb)->channel == HCI_CHANNEL_RAW) - memcpy(skb_push(nskb, 1), &bt_cb(nskb)->pkt_type, 1); + memcpy(skb_push(nskb, 1), &bt_cb(nskb)->pkt_type, 1); if (sock_queue_rcv_skb(sk, nskb)) kfree_skb(nskb); @@ -363,38 +353,25 @@ 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 *haddr = (struct sockaddr_hci *) addr; struct sock *sk = sock->sk; struct hci_dev *hdev = NULL; - int len, err = 0; + int err = 0; BT_DBG("sock %p sk %p", sock, sk); - 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_CONTROL) - return -EINVAL; - - if (haddr.hci_channel == HCI_CHANNEL_CONTROL && !enable_mgmt) + if (!haddr || haddr->hci_family != AF_BLUETOOTH) return -EINVAL; lock_sock(sk); - if (sk->sk_state == BT_BOUND || hci_pi(sk)->hdev) { + if (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; @@ -403,7 +380,6 @@ 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; @@ -526,17 +502,6 @@ 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; @@ -866,6 +831,3 @@ 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"); diff --git a/trunk/net/bluetooth/l2cap.c b/trunk/net/bluetooth/l2cap.c index c791fcda7b2d..c12eccfdfe01 100644 --- a/trunk/net/bluetooth/l2cap.c +++ b/trunk/net/bluetooth/l2cap.c @@ -3124,14 +3124,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (!sk) return -ENOENT; - if (sk->sk_state != BT_CONFIG) { - struct l2cap_cmd_rej rej; - - rej.reason = cpu_to_le16(0x0002); - l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ, - sizeof(rej), &rej); + if (sk->sk_state == BT_DISCONN) goto unlock; - } /* Reject if config buffer is too small. */ len = cmd_len - sizeof(*req); diff --git a/trunk/net/bluetooth/mgmt.c b/trunk/net/bluetooth/mgmt.c deleted file mode 100644 index f827fd908380..000000000000 --- a/trunk/net/bluetooth/mgmt.c +++ /dev/null @@ -1,308 +0,0 @@ -/* - 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 -#include - -#include -#include -#include - -#define MGMT_VERSION 0 -#define MGMT_REVISION 1 - -static int 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 -ENOMEM; - - 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); - - return 0; -} - -static int read_version(struct sock *sk) -{ - struct sk_buff *skb; - struct mgmt_hdr *hdr; - struct mgmt_ev_cmd_complete *ev; - struct mgmt_rp_read_version *rp; - - BT_DBG("sock %p", sk); - - skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - hdr = (void *) skb_put(skb, sizeof(*hdr)); - hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE); - hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp)); - - ev = (void *) skb_put(skb, sizeof(*ev)); - put_unaligned_le16(MGMT_OP_READ_VERSION, &ev->opcode); - - rp = (void *) skb_put(skb, sizeof(*rp)); - rp->version = MGMT_VERSION; - put_unaligned_le16(MGMT_REVISION, &rp->revision); - - if (sock_queue_rcv_skb(sk, skb) < 0) - kfree_skb(skb); - - return 0; -} - -static int read_index_list(struct sock *sk) -{ - struct sk_buff *skb; - struct mgmt_hdr *hdr; - struct mgmt_ev_cmd_complete *ev; - struct mgmt_rp_read_index_list *rp; - struct list_head *p; - size_t body_len; - u16 count; - int i; - - BT_DBG("sock %p", sk); - - read_lock(&hci_dev_list_lock); - - count = 0; - list_for_each(p, &hci_dev_list) { - count++; - } - - body_len = sizeof(*ev) + sizeof(*rp) + (2 * count); - skb = alloc_skb(sizeof(*hdr) + body_len, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - hdr = (void *) skb_put(skb, sizeof(*hdr)); - hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE); - hdr->len = cpu_to_le16(body_len); - - ev = (void *) skb_put(skb, sizeof(*ev)); - put_unaligned_le16(MGMT_OP_READ_INDEX_LIST, &ev->opcode); - - rp = (void *) skb_put(skb, sizeof(*rp) + (2 * count)); - put_unaligned_le16(count, &rp->num_controllers); - - i = 0; - list_for_each(p, &hci_dev_list) { - struct hci_dev *d = list_entry(p, struct hci_dev, list); - put_unaligned_le16(d->id, &rp->index[i++]); - BT_DBG("Added hci%u", d->id); - } - - read_unlock(&hci_dev_list_lock); - - if (sock_queue_rcv_skb(sk, skb) < 0) - kfree_skb(skb); - - return 0; -} - -static int read_controller_info(struct sock *sk, unsigned char *data, u16 len) -{ - struct sk_buff *skb; - struct mgmt_hdr *hdr; - struct mgmt_ev_cmd_complete *ev; - struct mgmt_rp_read_info *rp; - struct mgmt_cp_read_info *cp; - struct hci_dev *hdev; - u16 dev_id; - - BT_DBG("sock %p", sk); - - if (len != 2) - return cmd_status(sk, MGMT_OP_READ_INFO, EINVAL); - - skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + sizeof(*rp), GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - hdr = (void *) skb_put(skb, sizeof(*hdr)); - hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE); - hdr->len = cpu_to_le16(sizeof(*ev) + sizeof(*rp)); - - ev = (void *) skb_put(skb, sizeof(*ev)); - put_unaligned_le16(MGMT_OP_READ_INFO, &ev->opcode); - - rp = (void *) skb_put(skb, sizeof(*rp)); - - cp = (void *) data; - dev_id = get_unaligned_le16(&cp->index); - - BT_DBG("request for hci%u", dev_id); - - hdev = hci_dev_get(dev_id); - if (!hdev) { - kfree_skb(skb); - return cmd_status(sk, MGMT_OP_READ_INFO, ENODEV); - } - - hci_dev_lock_bh(hdev); - - put_unaligned_le16(hdev->id, &rp->index); - rp->type = hdev->dev_type; - - rp->powered = test_bit(HCI_UP, &hdev->flags); - rp->discoverable = test_bit(HCI_ISCAN, &hdev->flags); - rp->pairable = test_bit(HCI_PSCAN, &hdev->flags); - - if (test_bit(HCI_AUTH, &hdev->flags)) - rp->sec_mode = 3; - else if (hdev->ssp_mode > 0) - rp->sec_mode = 4; - else - rp->sec_mode = 2; - - bacpy(&rp->bdaddr, &hdev->bdaddr); - memcpy(rp->features, hdev->features, 8); - memcpy(rp->dev_class, hdev->dev_class, 3); - put_unaligned_le16(hdev->manufacturer, &rp->manufacturer); - rp->hci_ver = hdev->hci_ver; - put_unaligned_le16(hdev->hci_rev, &rp->hci_rev); - - hci_dev_unlock_bh(hdev); - hci_dev_put(hdev); - - if (sock_queue_rcv_skb(sk, skb) < 0) - kfree_skb(skb); - - return 0; -} - -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) { - case MGMT_OP_READ_VERSION: - err = read_version(sk); - break; - case MGMT_OP_READ_INDEX_LIST: - err = read_index_list(sk); - break; - case MGMT_OP_READ_INFO: - err = read_controller_info(sk, buf + sizeof(*hdr), len); - break; - default: - BT_DBG("Unknown op %u", opcode); - err = cmd_status(sk, opcode, 0x01); - break; - } - - if (err < 0) - goto done; - - err = msglen; - -done: - kfree(buf); - return err; -} - -static int mgmt_event(u16 event, void *data, u16 data_len) -{ - struct sk_buff *skb; - struct mgmt_hdr *hdr; - - skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - bt_cb(skb)->channel = HCI_CHANNEL_CONTROL; - - hdr = (void *) skb_put(skb, sizeof(*hdr)); - hdr->opcode = cpu_to_le16(event); - hdr->len = cpu_to_le16(data_len); - - memcpy(skb_put(skb, data_len), data, data_len); - - hci_send_to_sock(NULL, skb); - kfree_skb(skb); - - return 0; -} - -int mgmt_index_added(u16 index) -{ - struct mgmt_ev_index_added ev; - - put_unaligned_le16(index, &ev.index); - - return mgmt_event(MGMT_EV_INDEX_ADDED, &ev, sizeof(ev)); -} - -int mgmt_index_removed(u16 index) -{ - struct mgmt_ev_index_added ev; - - put_unaligned_le16(index, &ev.index); - - return mgmt_event(MGMT_EV_INDEX_REMOVED, &ev, sizeof(ev)); -}