Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
This commit is contained in:
commit
ec8eb9ae58
|
@ -231,12 +231,12 @@ static void bluecard_write_wakeup(bluecard_info_t *info)
|
|||
}
|
||||
|
||||
do {
|
||||
register unsigned int iobase = info->p_dev->resource[0]->start;
|
||||
register unsigned int offset;
|
||||
register unsigned char command;
|
||||
register unsigned long ready_bit;
|
||||
unsigned int iobase = info->p_dev->resource[0]->start;
|
||||
unsigned int offset;
|
||||
unsigned char command;
|
||||
unsigned long ready_bit;
|
||||
register struct sk_buff *skb;
|
||||
register int len;
|
||||
int len;
|
||||
|
||||
clear_bit(XMIT_WAKEUP, &(info->tx_state));
|
||||
|
||||
|
|
|
@ -470,7 +470,7 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id *
|
|||
hdev->flush = bpa10x_flush;
|
||||
hdev->send = bpa10x_send_frame;
|
||||
|
||||
set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
|
||||
set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
|
||||
|
||||
err = hci_register_dev(hdev);
|
||||
if (err < 0) {
|
||||
|
|
|
@ -186,9 +186,9 @@ static void bt3c_write_wakeup(bt3c_info_t *info)
|
|||
return;
|
||||
|
||||
do {
|
||||
register unsigned int iobase = info->p_dev->resource[0]->start;
|
||||
unsigned int iobase = info->p_dev->resource[0]->start;
|
||||
register struct sk_buff *skb;
|
||||
register int len;
|
||||
int len;
|
||||
|
||||
if (!pcmcia_dev_present(info->p_dev))
|
||||
break;
|
||||
|
|
|
@ -110,6 +110,9 @@ static const struct sdio_device_id btmrvl_sdio_ids[] = {
|
|||
/* Marvell SD8787 Bluetooth device */
|
||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911A),
|
||||
.driver_data = (unsigned long) &btmrvl_sdio_sd8787 },
|
||||
/* Marvell SD8787 Bluetooth AMP device */
|
||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x911B),
|
||||
.driver_data = (unsigned long) &btmrvl_sdio_sd8787 },
|
||||
/* Marvell SD8797 Bluetooth device */
|
||||
{ SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, 0x912A),
|
||||
.driver_data = (unsigned long) &btmrvl_sdio_sd8797 },
|
||||
|
|
|
@ -140,9 +140,9 @@ static void btuart_write_wakeup(btuart_info_t *info)
|
|||
}
|
||||
|
||||
do {
|
||||
register unsigned int iobase = info->p_dev->resource[0]->start;
|
||||
unsigned int iobase = info->p_dev->resource[0]->start;
|
||||
register struct sk_buff *skb;
|
||||
register int len;
|
||||
int len;
|
||||
|
||||
clear_bit(XMIT_WAKEUP, &(info->tx_state));
|
||||
|
||||
|
|
|
@ -21,15 +21,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
|
@ -1026,7 +1018,7 @@ static int btusb_probe(struct usb_interface *intf,
|
|||
data->isoc = usb_ifnum_to_if(data->udev, 1);
|
||||
|
||||
if (!reset)
|
||||
set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
|
||||
set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
|
||||
|
||||
if (force_scofix || id->driver_info & BTUSB_WRONG_SCO_MTU) {
|
||||
if (!disable_scofix)
|
||||
|
@ -1038,7 +1030,7 @@ static int btusb_probe(struct usb_interface *intf,
|
|||
|
||||
if (id->driver_info & BTUSB_DIGIANSWER) {
|
||||
data->cmdreq_type = USB_TYPE_VENDOR;
|
||||
set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
|
||||
set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
|
||||
}
|
||||
|
||||
if (id->driver_info & BTUSB_CSR) {
|
||||
|
@ -1046,7 +1038,7 @@ static int btusb_probe(struct usb_interface *intf,
|
|||
|
||||
/* Old firmware would otherwise execute USB reset */
|
||||
if (le16_to_cpu(udev->descriptor.bcdDevice) < 0x117)
|
||||
set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
|
||||
set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
|
||||
}
|
||||
|
||||
if (id->driver_info & BTUSB_SNIFFER) {
|
||||
|
|
|
@ -144,9 +144,9 @@ static void dtl1_write_wakeup(dtl1_info_t *info)
|
|||
}
|
||||
|
||||
do {
|
||||
register unsigned int iobase = info->p_dev->resource[0]->start;
|
||||
unsigned int iobase = info->p_dev->resource[0]->start;
|
||||
register struct sk_buff *skb;
|
||||
register int len;
|
||||
int len;
|
||||
|
||||
clear_bit(XMIT_WAKEUP, &(info->tx_state));
|
||||
|
||||
|
|
|
@ -552,7 +552,7 @@ static u16 bscp_get_crc(struct bcsp_struct *bcsp)
|
|||
static int bcsp_recv(struct hci_uart *hu, void *data, int count)
|
||||
{
|
||||
struct bcsp_struct *bcsp = hu->priv;
|
||||
register unsigned char *ptr;
|
||||
unsigned char *ptr;
|
||||
|
||||
BT_DBG("hu %p count %d rx_state %d rx_count %ld",
|
||||
hu, count, bcsp->rx_state, bcsp->rx_count);
|
||||
|
|
|
@ -126,7 +126,7 @@ static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb)
|
|||
|
||||
static inline int h4_check_data_len(struct h4_struct *h4, int len)
|
||||
{
|
||||
register int room = skb_tailroom(h4->rx_skb);
|
||||
int room = skb_tailroom(h4->rx_skb);
|
||||
|
||||
BT_DBG("len %d room %d", len, room);
|
||||
|
||||
|
|
|
@ -394,7 +394,7 @@ static int hci_uart_register_dev(struct hci_uart *hu)
|
|||
set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
|
||||
|
||||
if (!test_bit(HCI_UART_RESET_ON_INIT, &hu->hdev_flags))
|
||||
set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
|
||||
set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
|
||||
|
||||
if (test_bit(HCI_UART_CREATE_AMP, &hu->hdev_flags))
|
||||
hdev->dev_type = HCI_AMP;
|
||||
|
|
|
@ -348,7 +348,7 @@ static int ll_enqueue(struct hci_uart *hu, struct sk_buff *skb)
|
|||
|
||||
static inline int ll_check_data_len(struct ll_struct *ll, int len)
|
||||
{
|
||||
register int room = skb_tailroom(ll->rx_skb);
|
||||
int room = skb_tailroom(ll->rx_skb);
|
||||
|
||||
BT_DBG("len %d room %d", len, room);
|
||||
|
||||
|
@ -374,11 +374,11 @@ static inline int ll_check_data_len(struct ll_struct *ll, int len)
|
|||
static int ll_recv(struct hci_uart *hu, void *data, int count)
|
||||
{
|
||||
struct ll_struct *ll = hu->priv;
|
||||
register char *ptr;
|
||||
char *ptr;
|
||||
struct hci_event_hdr *eh;
|
||||
struct hci_acl_hdr *ah;
|
||||
struct hci_sco_hdr *sh;
|
||||
register int len, type, dlen;
|
||||
int len, type, dlen;
|
||||
|
||||
BT_DBG("hu %p count %d rx_state %ld rx_count %ld", hu, count, ll->rx_state, ll->rx_count);
|
||||
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
Copyright (c) 2010,2011 Code Aurora Forum. All rights reserved.
|
||||
Copyright (c) 2011,2012 Intel Corp.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 and
|
||||
only version 2 as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __A2MP_H
|
||||
#define __A2MP_H
|
||||
|
||||
#include <net/bluetooth/l2cap.h>
|
||||
|
||||
#define A2MP_FEAT_EXT 0x8000
|
||||
|
||||
struct amp_mgr {
|
||||
struct l2cap_conn *l2cap_conn;
|
||||
struct l2cap_chan *a2mp_chan;
|
||||
struct kref kref;
|
||||
__u8 ident;
|
||||
__u8 handle;
|
||||
unsigned long flags;
|
||||
};
|
||||
|
||||
struct a2mp_cmd {
|
||||
__u8 code;
|
||||
__u8 ident;
|
||||
__le16 len;
|
||||
__u8 data[0];
|
||||
} __packed;
|
||||
|
||||
/* A2MP command codes */
|
||||
#define A2MP_COMMAND_REJ 0x01
|
||||
struct a2mp_cmd_rej {
|
||||
__le16 reason;
|
||||
__u8 data[0];
|
||||
} __packed;
|
||||
|
||||
#define A2MP_DISCOVER_REQ 0x02
|
||||
struct a2mp_discov_req {
|
||||
__le16 mtu;
|
||||
__le16 ext_feat;
|
||||
} __packed;
|
||||
|
||||
struct a2mp_cl {
|
||||
__u8 id;
|
||||
__u8 type;
|
||||
__u8 status;
|
||||
} __packed;
|
||||
|
||||
#define A2MP_DISCOVER_RSP 0x03
|
||||
struct a2mp_discov_rsp {
|
||||
__le16 mtu;
|
||||
__le16 ext_feat;
|
||||
struct a2mp_cl cl[0];
|
||||
} __packed;
|
||||
|
||||
#define A2MP_CHANGE_NOTIFY 0x04
|
||||
#define A2MP_CHANGE_RSP 0x05
|
||||
|
||||
#define A2MP_GETINFO_REQ 0x06
|
||||
struct a2mp_info_req {
|
||||
__u8 id;
|
||||
} __packed;
|
||||
|
||||
#define A2MP_GETINFO_RSP 0x07
|
||||
struct a2mp_info_rsp {
|
||||
__u8 id;
|
||||
__u8 status;
|
||||
__le32 total_bw;
|
||||
__le32 max_bw;
|
||||
__le32 min_latency;
|
||||
__le16 pal_cap;
|
||||
__le16 assoc_size;
|
||||
} __packed;
|
||||
|
||||
#define A2MP_GETAMPASSOC_REQ 0x08
|
||||
struct a2mp_amp_assoc_req {
|
||||
__u8 id;
|
||||
} __packed;
|
||||
|
||||
#define A2MP_GETAMPASSOC_RSP 0x09
|
||||
struct a2mp_amp_assoc_rsp {
|
||||
__u8 id;
|
||||
__u8 status;
|
||||
__u8 amp_assoc[0];
|
||||
} __packed;
|
||||
|
||||
#define A2MP_CREATEPHYSLINK_REQ 0x0A
|
||||
#define A2MP_DISCONNPHYSLINK_REQ 0x0C
|
||||
struct a2mp_physlink_req {
|
||||
__u8 local_id;
|
||||
__u8 remote_id;
|
||||
__u8 amp_assoc[0];
|
||||
} __packed;
|
||||
|
||||
#define A2MP_CREATEPHYSLINK_RSP 0x0B
|
||||
#define A2MP_DISCONNPHYSLINK_RSP 0x0D
|
||||
struct a2mp_physlink_rsp {
|
||||
__u8 local_id;
|
||||
__u8 remote_id;
|
||||
__u8 status;
|
||||
} __packed;
|
||||
|
||||
/* A2MP response status */
|
||||
#define A2MP_STATUS_SUCCESS 0x00
|
||||
#define A2MP_STATUS_INVALID_CTRL_ID 0x01
|
||||
#define A2MP_STATUS_UNABLE_START_LINK_CREATION 0x02
|
||||
#define A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS 0x02
|
||||
#define A2MP_STATUS_COLLISION_OCCURED 0x03
|
||||
#define A2MP_STATUS_DISCONN_REQ_RECVD 0x04
|
||||
#define A2MP_STATUS_PHYS_LINK_EXISTS 0x05
|
||||
#define A2MP_STATUS_SECURITY_VIOLATION 0x06
|
||||
|
||||
void amp_mgr_get(struct amp_mgr *mgr);
|
||||
int amp_mgr_put(struct amp_mgr *mgr);
|
||||
struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
|
||||
struct sk_buff *skb);
|
||||
|
||||
#endif /* __A2MP_H */
|
|
@ -25,9 +25,6 @@
|
|||
#ifndef __BLUETOOTH_H
|
||||
#define __BLUETOOTH_H
|
||||
|
||||
#include <asm/types.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/poll.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
|
@ -249,7 +246,8 @@ static inline struct sk_buff *bt_skb_alloc(unsigned int len, gfp_t how)
|
|||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
if ((skb = alloc_skb(len + BT_SKB_RESERVE, how))) {
|
||||
skb = alloc_skb(len + BT_SKB_RESERVE, how);
|
||||
if (skb) {
|
||||
skb_reserve(skb, BT_SKB_RESERVE);
|
||||
bt_cb(skb)->incoming = 0;
|
||||
}
|
||||
|
@ -261,7 +259,8 @@ static inline struct sk_buff *bt_skb_send_alloc(struct sock *sk,
|
|||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
if ((skb = sock_alloc_send_skb(sk, len + BT_SKB_RESERVE, nb, err))) {
|
||||
skb = sock_alloc_send_skb(sk, len + BT_SKB_RESERVE, nb, err);
|
||||
if (skb) {
|
||||
skb_reserve(skb, BT_SKB_RESERVE);
|
||||
bt_cb(skb)->incoming = 0;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,9 @@
|
|||
#define HCI_MAX_EVENT_SIZE 260
|
||||
#define HCI_MAX_FRAME_SIZE (HCI_MAX_ACL_SIZE + 4)
|
||||
|
||||
#define HCI_LINK_KEY_SIZE 16
|
||||
#define HCI_AMP_LINK_KEY_SIZE (2 * HCI_LINK_KEY_SIZE)
|
||||
|
||||
/* HCI dev events */
|
||||
#define HCI_DEV_REG 1
|
||||
#define HCI_DEV_UNREG 2
|
||||
|
@ -56,9 +59,12 @@
|
|||
#define HCI_BREDR 0x00
|
||||
#define HCI_AMP 0x01
|
||||
|
||||
/* First BR/EDR Controller shall have ID = 0 */
|
||||
#define HCI_BREDR_ID 0
|
||||
|
||||
/* HCI device quirks */
|
||||
enum {
|
||||
HCI_QUIRK_NO_RESET,
|
||||
HCI_QUIRK_RESET_ON_CLOSE,
|
||||
HCI_QUIRK_RAW_DEVICE,
|
||||
HCI_QUIRK_FIXUP_BUFFER_SIZE
|
||||
};
|
||||
|
@ -133,10 +139,8 @@ enum {
|
|||
#define HCIINQUIRY _IOR('H', 240, int)
|
||||
|
||||
/* HCI timeouts */
|
||||
#define HCI_CONNECT_TIMEOUT (40000) /* 40 seconds */
|
||||
#define HCI_DISCONN_TIMEOUT (2000) /* 2 seconds */
|
||||
#define HCI_PAIRING_TIMEOUT (60000) /* 60 seconds */
|
||||
#define HCI_IDLE_TIMEOUT (6000) /* 6 seconds */
|
||||
#define HCI_INIT_TIMEOUT (10000) /* 10 seconds */
|
||||
#define HCI_CMD_TIMEOUT (1000) /* 1 seconds */
|
||||
#define HCI_ACL_TX_TIMEOUT (45000) /* 45 seconds */
|
||||
|
@ -371,7 +375,7 @@ struct hci_cp_reject_conn_req {
|
|||
#define HCI_OP_LINK_KEY_REPLY 0x040b
|
||||
struct hci_cp_link_key_reply {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 link_key[16];
|
||||
__u8 link_key[HCI_LINK_KEY_SIZE];
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_LINK_KEY_NEG_REPLY 0x040c
|
||||
|
@ -523,6 +527,28 @@ struct hci_cp_io_capability_neg_reply {
|
|||
__u8 reason;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_CREATE_PHY_LINK 0x0435
|
||||
struct hci_cp_create_phy_link {
|
||||
__u8 phy_handle;
|
||||
__u8 key_len;
|
||||
__u8 key_type;
|
||||
__u8 key[HCI_AMP_LINK_KEY_SIZE];
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_ACCEPT_PHY_LINK 0x0436
|
||||
struct hci_cp_accept_phy_link {
|
||||
__u8 phy_handle;
|
||||
__u8 key_len;
|
||||
__u8 key_type;
|
||||
__u8 key[HCI_AMP_LINK_KEY_SIZE];
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_DISCONN_PHY_LINK 0x0437
|
||||
struct hci_cp_disconn_phy_link {
|
||||
__u8 phy_handle;
|
||||
__u8 reason;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_SNIFF_MODE 0x0803
|
||||
struct hci_cp_sniff_mode {
|
||||
__le16 handle;
|
||||
|
@ -818,6 +844,31 @@ struct hci_rp_read_local_amp_info {
|
|||
__le32 be_flush_to;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_READ_LOCAL_AMP_ASSOC 0x140a
|
||||
struct hci_cp_read_local_amp_assoc {
|
||||
__u8 phy_handle;
|
||||
__le16 len_so_far;
|
||||
__le16 max_len;
|
||||
} __packed;
|
||||
struct hci_rp_read_local_amp_assoc {
|
||||
__u8 status;
|
||||
__u8 phy_handle;
|
||||
__le16 rem_len;
|
||||
__u8 frag[0];
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_WRITE_REMOTE_AMP_ASSOC 0x140b
|
||||
struct hci_cp_write_remote_amp_assoc {
|
||||
__u8 phy_handle;
|
||||
__le16 len_so_far;
|
||||
__le16 rem_len;
|
||||
__u8 frag[0];
|
||||
} __packed;
|
||||
struct hci_rp_write_remote_amp_assoc {
|
||||
__u8 status;
|
||||
__u8 phy_handle;
|
||||
} __packed;
|
||||
|
||||
#define HCI_OP_LE_SET_EVENT_MASK 0x2001
|
||||
struct hci_cp_le_set_event_mask {
|
||||
__u8 mask[8];
|
||||
|
@ -1048,7 +1099,7 @@ struct hci_ev_link_key_req {
|
|||
#define HCI_EV_LINK_KEY_NOTIFY 0x18
|
||||
struct hci_ev_link_key_notify {
|
||||
bdaddr_t bdaddr;
|
||||
__u8 link_key[16];
|
||||
__u8 link_key[HCI_LINK_KEY_SIZE];
|
||||
__u8 key_type;
|
||||
} __packed;
|
||||
|
||||
|
@ -1190,6 +1241,39 @@ struct hci_ev_le_meta {
|
|||
__u8 subevent;
|
||||
} __packed;
|
||||
|
||||
#define HCI_EV_PHY_LINK_COMPLETE 0x40
|
||||
struct hci_ev_phy_link_complete {
|
||||
__u8 status;
|
||||
__u8 phy_handle;
|
||||
} __packed;
|
||||
|
||||
#define HCI_EV_CHANNEL_SELECTED 0x41
|
||||
struct hci_ev_channel_selected {
|
||||
__u8 phy_handle;
|
||||
} __packed;
|
||||
|
||||
#define HCI_EV_DISCONN_PHY_LINK_COMPLETE 0x42
|
||||
struct hci_ev_disconn_phy_link_complete {
|
||||
__u8 status;
|
||||
__u8 phy_handle;
|
||||
__u8 reason;
|
||||
} __packed;
|
||||
|
||||
#define HCI_EV_LOGICAL_LINK_COMPLETE 0x45
|
||||
struct hci_ev_logical_link_complete {
|
||||
__u8 status;
|
||||
__le16 handle;
|
||||
__u8 phy_handle;
|
||||
__u8 flow_spec_id;
|
||||
} __packed;
|
||||
|
||||
#define HCI_EV_DISCONN_LOGICAL_LINK_COMPLETE 0x46
|
||||
struct hci_ev_disconn_logical_link_complete {
|
||||
__u8 status;
|
||||
__le16 handle;
|
||||
__u8 reason;
|
||||
} __packed;
|
||||
|
||||
#define HCI_EV_NUM_COMP_BLOCKS 0x48
|
||||
struct hci_comp_blocks_info {
|
||||
__le16 handle;
|
||||
|
@ -1290,7 +1374,6 @@ struct hci_sco_hdr {
|
|||
__u8 dlen;
|
||||
} __packed;
|
||||
|
||||
#include <linux/skbuff.h>
|
||||
static inline struct hci_event_hdr *hci_event_hdr(const struct sk_buff *skb)
|
||||
{
|
||||
return (struct hci_event_hdr *) skb->data;
|
||||
|
@ -1307,12 +1390,12 @@ static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb)
|
|||
}
|
||||
|
||||
/* Command opcode pack/unpack */
|
||||
#define hci_opcode_pack(ogf, ocf) (__u16) ((ocf & 0x03ff)|(ogf << 10))
|
||||
#define hci_opcode_pack(ogf, ocf) ((__u16) ((ocf & 0x03ff)|(ogf << 10)))
|
||||
#define hci_opcode_ogf(op) (op >> 10)
|
||||
#define hci_opcode_ocf(op) (op & 0x03ff)
|
||||
|
||||
/* ACL handle and flags pack/unpack */
|
||||
#define hci_handle_pack(h, f) (__u16) ((h & 0x0fff)|(f << 12))
|
||||
#define hci_handle_pack(h, f) ((__u16) ((h & 0x0fff)|(f << 12)))
|
||||
#define hci_handle(h) (h & 0x0fff)
|
||||
#define hci_flags(h) (h >> 12)
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#ifndef __HCI_CORE_H
|
||||
#define __HCI_CORE_H
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <net/bluetooth/hci.h>
|
||||
|
||||
/* HCI priority */
|
||||
|
@ -105,7 +104,7 @@ struct link_key {
|
|||
struct list_head list;
|
||||
bdaddr_t bdaddr;
|
||||
u8 type;
|
||||
u8 val[16];
|
||||
u8 val[HCI_LINK_KEY_SIZE];
|
||||
u8 pin_len;
|
||||
};
|
||||
|
||||
|
@ -333,6 +332,7 @@ struct hci_conn {
|
|||
void *l2cap_data;
|
||||
void *sco_data;
|
||||
void *smp_conn;
|
||||
struct amp_mgr *amp_mgr;
|
||||
|
||||
struct hci_conn *link;
|
||||
|
||||
|
@ -360,7 +360,8 @@ extern int l2cap_connect_cfm(struct hci_conn *hcon, u8 status);
|
|||
extern int l2cap_disconn_ind(struct hci_conn *hcon);
|
||||
extern int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason);
|
||||
extern int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt);
|
||||
extern int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags);
|
||||
extern int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb,
|
||||
u16 flags);
|
||||
|
||||
extern int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
||||
extern int sco_connect_cfm(struct hci_conn *hcon, __u8 status);
|
||||
|
@ -429,8 +430,8 @@ enum {
|
|||
static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
|
||||
{
|
||||
struct hci_dev *hdev = conn->hdev;
|
||||
return (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
|
||||
test_bit(HCI_CONN_SSP_ENABLED, &conn->flags));
|
||||
return test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
|
||||
test_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
|
||||
}
|
||||
|
||||
static inline void hci_conn_hash_init(struct hci_dev *hdev)
|
||||
|
@ -640,6 +641,19 @@ static inline void hci_set_drvdata(struct hci_dev *hdev, void *data)
|
|||
dev_set_drvdata(&hdev->dev, data);
|
||||
}
|
||||
|
||||
/* hci_dev_list shall be locked */
|
||||
static inline uint8_t __hci_num_ctrl(void)
|
||||
{
|
||||
uint8_t count = 0;
|
||||
struct list_head *p;
|
||||
|
||||
list_for_each(p, &hci_dev_list) {
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
struct hci_dev *hci_dev_get(int index);
|
||||
struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
|
||||
|
||||
|
@ -661,7 +675,8 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg);
|
|||
int hci_get_auth_info(struct hci_dev *hdev, void __user *arg);
|
||||
int hci_inquiry(void __user *arg);
|
||||
|
||||
struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr);
|
||||
struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev,
|
||||
bdaddr_t *bdaddr);
|
||||
int hci_blacklist_clear(struct hci_dev *hdev);
|
||||
int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
|
||||
int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
|
||||
|
|
|
@ -40,11 +40,11 @@
|
|||
#define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */
|
||||
#define L2CAP_DEFAULT_MAX_PDU_SIZE 1009 /* Sized for 3-DH5 packet */
|
||||
#define L2CAP_DEFAULT_ACK_TO 200
|
||||
#define L2CAP_LE_DEFAULT_MTU 23
|
||||
#define L2CAP_DEFAULT_MAX_SDU_SIZE 0xFFFF
|
||||
#define L2CAP_DEFAULT_SDU_ITIME 0xFFFFFFFF
|
||||
#define L2CAP_DEFAULT_ACC_LAT 0xFFFFFFFF
|
||||
#define L2CAP_BREDR_MAX_PAYLOAD 1019 /* 3-DH5 packet */
|
||||
#define L2CAP_LE_MIN_MTU 23
|
||||
|
||||
#define L2CAP_DISC_TIMEOUT msecs_to_jiffies(100)
|
||||
#define L2CAP_DISC_REJ_TIMEOUT msecs_to_jiffies(5000)
|
||||
|
@ -52,6 +52,8 @@
|
|||
#define L2CAP_CONN_TIMEOUT msecs_to_jiffies(40000)
|
||||
#define L2CAP_INFO_TIMEOUT msecs_to_jiffies(4000)
|
||||
|
||||
#define L2CAP_A2MP_DEFAULT_MTU 670
|
||||
|
||||
/* L2CAP socket address */
|
||||
struct sockaddr_l2 {
|
||||
sa_family_t l2_family;
|
||||
|
@ -229,9 +231,14 @@ struct l2cap_conn_rsp {
|
|||
__le16 status;
|
||||
} __packed;
|
||||
|
||||
/* protocol/service multiplexer (PSM) */
|
||||
#define L2CAP_PSM_SDP 0x0001
|
||||
#define L2CAP_PSM_RFCOMM 0x0003
|
||||
|
||||
/* channel indentifier */
|
||||
#define L2CAP_CID_SIGNALING 0x0001
|
||||
#define L2CAP_CID_CONN_LESS 0x0002
|
||||
#define L2CAP_CID_A2MP 0x0003
|
||||
#define L2CAP_CID_LE_DATA 0x0004
|
||||
#define L2CAP_CID_LE_SIGNALING 0x0005
|
||||
#define L2CAP_CID_SMP 0x0006
|
||||
|
@ -271,6 +278,9 @@ struct l2cap_conf_rsp {
|
|||
#define L2CAP_CONF_PENDING 0x0004
|
||||
#define L2CAP_CONF_EFS_REJECT 0x0005
|
||||
|
||||
/* configuration req/rsp continuation flag */
|
||||
#define L2CAP_CONF_FLAG_CONTINUATION 0x0001
|
||||
|
||||
struct l2cap_conf_opt {
|
||||
__u8 type;
|
||||
__u8 len;
|
||||
|
@ -419,11 +429,6 @@ struct l2cap_seq_list {
|
|||
#define L2CAP_SEQ_LIST_CLEAR 0xFFFF
|
||||
#define L2CAP_SEQ_LIST_TAIL 0x8000
|
||||
|
||||
struct srej_list {
|
||||
__u16 tx_seq;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct l2cap_chan {
|
||||
struct sock *sk;
|
||||
|
||||
|
@ -475,14 +480,12 @@ struct l2cap_chan {
|
|||
__u16 expected_ack_seq;
|
||||
__u16 expected_tx_seq;
|
||||
__u16 buffer_seq;
|
||||
__u16 buffer_seq_srej;
|
||||
__u16 srej_save_reqseq;
|
||||
__u16 last_acked_seq;
|
||||
__u16 frames_sent;
|
||||
__u16 unacked_frames;
|
||||
__u8 retry_count;
|
||||
__u16 srej_queue_next;
|
||||
__u8 num_acked;
|
||||
__u16 sdu_len;
|
||||
struct sk_buff *sdu;
|
||||
struct sk_buff *sdu_last_frag;
|
||||
|
@ -515,7 +518,6 @@ struct l2cap_chan {
|
|||
struct sk_buff_head srej_q;
|
||||
struct l2cap_seq_list srej_list;
|
||||
struct l2cap_seq_list retrans_list;
|
||||
struct list_head srej_l;
|
||||
|
||||
struct list_head list;
|
||||
struct list_head global_l;
|
||||
|
@ -528,10 +530,14 @@ struct l2cap_chan {
|
|||
struct l2cap_ops {
|
||||
char *name;
|
||||
|
||||
struct l2cap_chan *(*new_connection) (void *data);
|
||||
int (*recv) (void *data, struct sk_buff *skb);
|
||||
void (*close) (void *data);
|
||||
void (*state_change) (void *data, int state);
|
||||
struct l2cap_chan *(*new_connection) (struct l2cap_chan *chan);
|
||||
int (*recv) (struct l2cap_chan * chan,
|
||||
struct sk_buff *skb);
|
||||
void (*teardown) (struct l2cap_chan *chan, int err);
|
||||
void (*close) (struct l2cap_chan *chan);
|
||||
void (*state_change) (struct l2cap_chan *chan,
|
||||
int state);
|
||||
void (*ready) (struct l2cap_chan *chan);
|
||||
struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan,
|
||||
unsigned long len, int nb);
|
||||
};
|
||||
|
@ -575,6 +581,7 @@ struct l2cap_conn {
|
|||
#define L2CAP_CHAN_RAW 1
|
||||
#define L2CAP_CHAN_CONN_LESS 2
|
||||
#define L2CAP_CHAN_CONN_ORIENTED 3
|
||||
#define L2CAP_CHAN_CONN_FIX_A2MP 4
|
||||
|
||||
/* ----- L2CAP socket info ----- */
|
||||
#define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
|
||||
|
@ -597,6 +604,7 @@ enum {
|
|||
CONF_EWS_RECV,
|
||||
CONF_LOC_CONF_PEND,
|
||||
CONF_REM_CONF_PEND,
|
||||
CONF_NOT_COMPLETE,
|
||||
};
|
||||
|
||||
#define L2CAP_CONF_MAX_CONF_REQ 2
|
||||
|
@ -713,11 +721,7 @@ static inline bool l2cap_clear_timer(struct l2cap_chan *chan,
|
|||
|
||||
#define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
|
||||
#define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer)
|
||||
#define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \
|
||||
msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO));
|
||||
#define __clear_retrans_timer(c) l2cap_clear_timer(c, &c->retrans_timer)
|
||||
#define __set_monitor_timer(c) l2cap_set_timer(c, &c->monitor_timer, \
|
||||
msecs_to_jiffies(L2CAP_DEFAULT_MONITOR_TO));
|
||||
#define __clear_monitor_timer(c) l2cap_clear_timer(c, &c->monitor_timer)
|
||||
#define __set_ack_timer(c) l2cap_set_timer(c, &chan->ack_timer, \
|
||||
msecs_to_jiffies(L2CAP_DEFAULT_ACK_TO));
|
||||
|
@ -736,173 +740,17 @@ static inline __u16 __next_seq(struct l2cap_chan *chan, __u16 seq)
|
|||
return (seq + 1) % (chan->tx_win_max + 1);
|
||||
}
|
||||
|
||||
static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
|
||||
static inline struct l2cap_chan *l2cap_chan_no_new_connection(struct l2cap_chan *chan)
|
||||
{
|
||||
int sub;
|
||||
|
||||
sub = (ch->next_tx_seq - ch->expected_ack_seq) % 64;
|
||||
|
||||
if (sub < 0)
|
||||
sub += 64;
|
||||
|
||||
return sub == ch->remote_tx_win;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline __u16 __get_reqseq(struct l2cap_chan *chan, __u32 ctrl)
|
||||
static inline void l2cap_chan_no_teardown(struct l2cap_chan *chan, int err)
|
||||
{
|
||||
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
|
||||
return (ctrl & L2CAP_EXT_CTRL_REQSEQ) >>
|
||||
L2CAP_EXT_CTRL_REQSEQ_SHIFT;
|
||||
else
|
||||
return (ctrl & L2CAP_CTRL_REQSEQ) >> L2CAP_CTRL_REQSEQ_SHIFT;
|
||||
}
|
||||
|
||||
static inline __u32 __set_reqseq(struct l2cap_chan *chan, __u32 reqseq)
|
||||
static inline void l2cap_chan_no_ready(struct l2cap_chan *chan)
|
||||
{
|
||||
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
|
||||
return (reqseq << L2CAP_EXT_CTRL_REQSEQ_SHIFT) &
|
||||
L2CAP_EXT_CTRL_REQSEQ;
|
||||
else
|
||||
return (reqseq << L2CAP_CTRL_REQSEQ_SHIFT) & L2CAP_CTRL_REQSEQ;
|
||||
}
|
||||
|
||||
static inline __u16 __get_txseq(struct l2cap_chan *chan, __u32 ctrl)
|
||||
{
|
||||
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
|
||||
return (ctrl & L2CAP_EXT_CTRL_TXSEQ) >>
|
||||
L2CAP_EXT_CTRL_TXSEQ_SHIFT;
|
||||
else
|
||||
return (ctrl & L2CAP_CTRL_TXSEQ) >> L2CAP_CTRL_TXSEQ_SHIFT;
|
||||
}
|
||||
|
||||
static inline __u32 __set_txseq(struct l2cap_chan *chan, __u32 txseq)
|
||||
{
|
||||
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
|
||||
return (txseq << L2CAP_EXT_CTRL_TXSEQ_SHIFT) &
|
||||
L2CAP_EXT_CTRL_TXSEQ;
|
||||
else
|
||||
return (txseq << L2CAP_CTRL_TXSEQ_SHIFT) & L2CAP_CTRL_TXSEQ;
|
||||
}
|
||||
|
||||
static inline bool __is_sframe(struct l2cap_chan *chan, __u32 ctrl)
|
||||
{
|
||||
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
|
||||
return ctrl & L2CAP_EXT_CTRL_FRAME_TYPE;
|
||||
else
|
||||
return ctrl & L2CAP_CTRL_FRAME_TYPE;
|
||||
}
|
||||
|
||||
static inline __u32 __set_sframe(struct l2cap_chan *chan)
|
||||
{
|
||||
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
|
||||
return L2CAP_EXT_CTRL_FRAME_TYPE;
|
||||
else
|
||||
return L2CAP_CTRL_FRAME_TYPE;
|
||||
}
|
||||
|
||||
static inline __u8 __get_ctrl_sar(struct l2cap_chan *chan, __u32 ctrl)
|
||||
{
|
||||
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
|
||||
return (ctrl & L2CAP_EXT_CTRL_SAR) >> L2CAP_EXT_CTRL_SAR_SHIFT;
|
||||
else
|
||||
return (ctrl & L2CAP_CTRL_SAR) >> L2CAP_CTRL_SAR_SHIFT;
|
||||
}
|
||||
|
||||
static inline __u32 __set_ctrl_sar(struct l2cap_chan *chan, __u32 sar)
|
||||
{
|
||||
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
|
||||
return (sar << L2CAP_EXT_CTRL_SAR_SHIFT) & L2CAP_EXT_CTRL_SAR;
|
||||
else
|
||||
return (sar << L2CAP_CTRL_SAR_SHIFT) & L2CAP_CTRL_SAR;
|
||||
}
|
||||
|
||||
static inline bool __is_sar_start(struct l2cap_chan *chan, __u32 ctrl)
|
||||
{
|
||||
return __get_ctrl_sar(chan, ctrl) == L2CAP_SAR_START;
|
||||
}
|
||||
|
||||
static inline __u32 __get_sar_mask(struct l2cap_chan *chan)
|
||||
{
|
||||
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
|
||||
return L2CAP_EXT_CTRL_SAR;
|
||||
else
|
||||
return L2CAP_CTRL_SAR;
|
||||
}
|
||||
|
||||
static inline __u8 __get_ctrl_super(struct l2cap_chan *chan, __u32 ctrl)
|
||||
{
|
||||
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
|
||||
return (ctrl & L2CAP_EXT_CTRL_SUPERVISE) >>
|
||||
L2CAP_EXT_CTRL_SUPER_SHIFT;
|
||||
else
|
||||
return (ctrl & L2CAP_CTRL_SUPERVISE) >> L2CAP_CTRL_SUPER_SHIFT;
|
||||
}
|
||||
|
||||
static inline __u32 __set_ctrl_super(struct l2cap_chan *chan, __u32 super)
|
||||
{
|
||||
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
|
||||
return (super << L2CAP_EXT_CTRL_SUPER_SHIFT) &
|
||||
L2CAP_EXT_CTRL_SUPERVISE;
|
||||
else
|
||||
return (super << L2CAP_CTRL_SUPER_SHIFT) &
|
||||
L2CAP_CTRL_SUPERVISE;
|
||||
}
|
||||
|
||||
static inline __u32 __set_ctrl_final(struct l2cap_chan *chan)
|
||||
{
|
||||
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
|
||||
return L2CAP_EXT_CTRL_FINAL;
|
||||
else
|
||||
return L2CAP_CTRL_FINAL;
|
||||
}
|
||||
|
||||
static inline bool __is_ctrl_final(struct l2cap_chan *chan, __u32 ctrl)
|
||||
{
|
||||
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
|
||||
return ctrl & L2CAP_EXT_CTRL_FINAL;
|
||||
else
|
||||
return ctrl & L2CAP_CTRL_FINAL;
|
||||
}
|
||||
|
||||
static inline __u32 __set_ctrl_poll(struct l2cap_chan *chan)
|
||||
{
|
||||
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
|
||||
return L2CAP_EXT_CTRL_POLL;
|
||||
else
|
||||
return L2CAP_CTRL_POLL;
|
||||
}
|
||||
|
||||
static inline bool __is_ctrl_poll(struct l2cap_chan *chan, __u32 ctrl)
|
||||
{
|
||||
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
|
||||
return ctrl & L2CAP_EXT_CTRL_POLL;
|
||||
else
|
||||
return ctrl & L2CAP_CTRL_POLL;
|
||||
}
|
||||
|
||||
static inline __u32 __get_control(struct l2cap_chan *chan, void *p)
|
||||
{
|
||||
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
|
||||
return get_unaligned_le32(p);
|
||||
else
|
||||
return get_unaligned_le16(p);
|
||||
}
|
||||
|
||||
static inline void __put_control(struct l2cap_chan *chan, __u32 control,
|
||||
void *p)
|
||||
{
|
||||
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
|
||||
return put_unaligned_le32(control, p);
|
||||
else
|
||||
return put_unaligned_le16(control, p);
|
||||
}
|
||||
|
||||
static inline __u8 __ctrl_size(struct l2cap_chan *chan)
|
||||
{
|
||||
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
|
||||
return L2CAP_EXT_HDR_SIZE - L2CAP_HDR_SIZE;
|
||||
else
|
||||
return L2CAP_ENH_HDR_SIZE - L2CAP_HDR_SIZE;
|
||||
}
|
||||
|
||||
extern bool disable_ertm;
|
||||
|
@ -926,5 +774,8 @@ 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);
|
||||
void l2cap_chan_set_defaults(struct l2cap_chan *chan);
|
||||
int l2cap_ertm_init(struct l2cap_chan *chan);
|
||||
void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
|
||||
void l2cap_chan_del(struct l2cap_chan *chan, int err);
|
||||
|
||||
#endif /* __L2CAP_H */
|
||||
|
|
|
@ -9,4 +9,5 @@ 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 l2cap_core.o l2cap_sock.o smp.o sco.o lib.o
|
||||
hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
|
||||
a2mp.o
|
||||
|
|
|
@ -0,0 +1,568 @@
|
|||
/*
|
||||
Copyright (c) 2010,2011 Code Aurora Forum. All rights reserved.
|
||||
Copyright (c) 2011,2012 Intel Corp.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License version 2 and
|
||||
only version 2 as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
#include <net/bluetooth/l2cap.h>
|
||||
#include <net/bluetooth/a2mp.h>
|
||||
|
||||
/* A2MP build & send command helper functions */
|
||||
static struct a2mp_cmd *__a2mp_build(u8 code, u8 ident, u16 len, void *data)
|
||||
{
|
||||
struct a2mp_cmd *cmd;
|
||||
int plen;
|
||||
|
||||
plen = sizeof(*cmd) + len;
|
||||
cmd = kzalloc(plen, GFP_KERNEL);
|
||||
if (!cmd)
|
||||
return NULL;
|
||||
|
||||
cmd->code = code;
|
||||
cmd->ident = ident;
|
||||
cmd->len = cpu_to_le16(len);
|
||||
|
||||
memcpy(cmd->data, data, len);
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
||||
static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
|
||||
void *data)
|
||||
{
|
||||
struct l2cap_chan *chan = mgr->a2mp_chan;
|
||||
struct a2mp_cmd *cmd;
|
||||
u16 total_len = len + sizeof(*cmd);
|
||||
struct kvec iv;
|
||||
struct msghdr msg;
|
||||
|
||||
cmd = __a2mp_build(code, ident, len, data);
|
||||
if (!cmd)
|
||||
return;
|
||||
|
||||
iv.iov_base = cmd;
|
||||
iv.iov_len = total_len;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
|
||||
msg.msg_iov = (struct iovec *) &iv;
|
||||
msg.msg_iovlen = 1;
|
||||
|
||||
l2cap_chan_send(chan, &msg, total_len, 0);
|
||||
|
||||
kfree(cmd);
|
||||
}
|
||||
|
||||
static inline void __a2mp_cl_bredr(struct a2mp_cl *cl)
|
||||
{
|
||||
cl->id = 0;
|
||||
cl->type = 0;
|
||||
cl->status = 1;
|
||||
}
|
||||
|
||||
/* hci_dev_list shall be locked */
|
||||
static void __a2mp_add_cl(struct amp_mgr *mgr, struct a2mp_cl *cl, u8 num_ctrl)
|
||||
{
|
||||
int i = 0;
|
||||
struct hci_dev *hdev;
|
||||
|
||||
__a2mp_cl_bredr(cl);
|
||||
|
||||
list_for_each_entry(hdev, &hci_dev_list, list) {
|
||||
/* Iterate through AMP controllers */
|
||||
if (hdev->id == HCI_BREDR_ID)
|
||||
continue;
|
||||
|
||||
/* Starting from second entry */
|
||||
if (++i >= num_ctrl)
|
||||
return;
|
||||
|
||||
cl[i].id = hdev->id;
|
||||
cl[i].type = hdev->amp_type;
|
||||
cl[i].status = hdev->amp_status;
|
||||
}
|
||||
}
|
||||
|
||||
/* Processing A2MP messages */
|
||||
static int a2mp_command_rej(struct amp_mgr *mgr, struct sk_buff *skb,
|
||||
struct a2mp_cmd *hdr)
|
||||
{
|
||||
struct a2mp_cmd_rej *rej = (void *) skb->data;
|
||||
|
||||
if (le16_to_cpu(hdr->len) < sizeof(*rej))
|
||||
return -EINVAL;
|
||||
|
||||
BT_DBG("ident %d reason %d", hdr->ident, le16_to_cpu(rej->reason));
|
||||
|
||||
skb_pull(skb, sizeof(*rej));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb,
|
||||
struct a2mp_cmd *hdr)
|
||||
{
|
||||
struct a2mp_discov_req *req = (void *) skb->data;
|
||||
u16 len = le16_to_cpu(hdr->len);
|
||||
struct a2mp_discov_rsp *rsp;
|
||||
u16 ext_feat;
|
||||
u8 num_ctrl;
|
||||
|
||||
if (len < sizeof(*req))
|
||||
return -EINVAL;
|
||||
|
||||
skb_pull(skb, sizeof(*req));
|
||||
|
||||
ext_feat = le16_to_cpu(req->ext_feat);
|
||||
|
||||
BT_DBG("mtu %d efm 0x%4.4x", le16_to_cpu(req->mtu), ext_feat);
|
||||
|
||||
/* check that packet is not broken for now */
|
||||
while (ext_feat & A2MP_FEAT_EXT) {
|
||||
if (len < sizeof(ext_feat))
|
||||
return -EINVAL;
|
||||
|
||||
ext_feat = get_unaligned_le16(skb->data);
|
||||
BT_DBG("efm 0x%4.4x", ext_feat);
|
||||
len -= sizeof(ext_feat);
|
||||
skb_pull(skb, sizeof(ext_feat));
|
||||
}
|
||||
|
||||
read_lock(&hci_dev_list_lock);
|
||||
|
||||
num_ctrl = __hci_num_ctrl();
|
||||
len = num_ctrl * sizeof(struct a2mp_cl) + sizeof(*rsp);
|
||||
rsp = kmalloc(len, GFP_ATOMIC);
|
||||
if (!rsp) {
|
||||
read_unlock(&hci_dev_list_lock);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
rsp->mtu = __constant_cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU);
|
||||
rsp->ext_feat = 0;
|
||||
|
||||
__a2mp_add_cl(mgr, rsp->cl, num_ctrl);
|
||||
|
||||
read_unlock(&hci_dev_list_lock);
|
||||
|
||||
a2mp_send(mgr, A2MP_DISCOVER_RSP, hdr->ident, len, rsp);
|
||||
|
||||
kfree(rsp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int a2mp_change_notify(struct amp_mgr *mgr, struct sk_buff *skb,
|
||||
struct a2mp_cmd *hdr)
|
||||
{
|
||||
struct a2mp_cl *cl = (void *) skb->data;
|
||||
|
||||
while (skb->len >= sizeof(*cl)) {
|
||||
BT_DBG("Controller id %d type %d status %d", cl->id, cl->type,
|
||||
cl->status);
|
||||
cl = (struct a2mp_cl *) skb_pull(skb, sizeof(*cl));
|
||||
}
|
||||
|
||||
/* TODO send A2MP_CHANGE_RSP */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
|
||||
struct a2mp_cmd *hdr)
|
||||
{
|
||||
struct a2mp_info_req *req = (void *) skb->data;
|
||||
struct a2mp_info_rsp rsp;
|
||||
struct hci_dev *hdev;
|
||||
|
||||
if (le16_to_cpu(hdr->len) < sizeof(*req))
|
||||
return -EINVAL;
|
||||
|
||||
BT_DBG("id %d", req->id);
|
||||
|
||||
rsp.id = req->id;
|
||||
rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
|
||||
|
||||
hdev = hci_dev_get(req->id);
|
||||
if (hdev && hdev->amp_type != HCI_BREDR) {
|
||||
rsp.status = 0;
|
||||
rsp.total_bw = cpu_to_le32(hdev->amp_total_bw);
|
||||
rsp.max_bw = cpu_to_le32(hdev->amp_max_bw);
|
||||
rsp.min_latency = cpu_to_le32(hdev->amp_min_latency);
|
||||
rsp.pal_cap = cpu_to_le16(hdev->amp_pal_cap);
|
||||
rsp.assoc_size = cpu_to_le16(hdev->amp_assoc_size);
|
||||
}
|
||||
|
||||
if (hdev)
|
||||
hci_dev_put(hdev);
|
||||
|
||||
a2mp_send(mgr, A2MP_GETINFO_RSP, hdr->ident, sizeof(rsp), &rsp);
|
||||
|
||||
skb_pull(skb, sizeof(*req));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int a2mp_getampassoc_req(struct amp_mgr *mgr, struct sk_buff *skb,
|
||||
struct a2mp_cmd *hdr)
|
||||
{
|
||||
struct a2mp_amp_assoc_req *req = (void *) skb->data;
|
||||
struct hci_dev *hdev;
|
||||
|
||||
if (le16_to_cpu(hdr->len) < sizeof(*req))
|
||||
return -EINVAL;
|
||||
|
||||
BT_DBG("id %d", req->id);
|
||||
|
||||
hdev = hci_dev_get(req->id);
|
||||
if (!hdev || hdev->amp_type == HCI_BREDR) {
|
||||
struct a2mp_amp_assoc_rsp rsp;
|
||||
rsp.id = req->id;
|
||||
rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
|
||||
|
||||
a2mp_send(mgr, A2MP_GETAMPASSOC_RSP, hdr->ident, sizeof(rsp),
|
||||
&rsp);
|
||||
goto clean;
|
||||
}
|
||||
|
||||
/* Placeholder for HCI Read AMP Assoc */
|
||||
|
||||
clean:
|
||||
if (hdev)
|
||||
hci_dev_put(hdev);
|
||||
|
||||
skb_pull(skb, sizeof(*req));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
|
||||
struct a2mp_cmd *hdr)
|
||||
{
|
||||
struct a2mp_physlink_req *req = (void *) skb->data;
|
||||
|
||||
struct a2mp_physlink_rsp rsp;
|
||||
struct hci_dev *hdev;
|
||||
|
||||
if (le16_to_cpu(hdr->len) < sizeof(*req))
|
||||
return -EINVAL;
|
||||
|
||||
BT_DBG("local_id %d, remote_id %d", req->local_id, req->remote_id);
|
||||
|
||||
rsp.local_id = req->remote_id;
|
||||
rsp.remote_id = req->local_id;
|
||||
|
||||
hdev = hci_dev_get(req->remote_id);
|
||||
if (!hdev || hdev->amp_type != HCI_AMP) {
|
||||
rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
|
||||
goto send_rsp;
|
||||
}
|
||||
|
||||
/* TODO process physlink create */
|
||||
|
||||
rsp.status = A2MP_STATUS_SUCCESS;
|
||||
|
||||
send_rsp:
|
||||
if (hdev)
|
||||
hci_dev_put(hdev);
|
||||
|
||||
a2mp_send(mgr, A2MP_CREATEPHYSLINK_RSP, hdr->ident, sizeof(rsp),
|
||||
&rsp);
|
||||
|
||||
skb_pull(skb, le16_to_cpu(hdr->len));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int a2mp_discphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
|
||||
struct a2mp_cmd *hdr)
|
||||
{
|
||||
struct a2mp_physlink_req *req = (void *) skb->data;
|
||||
struct a2mp_physlink_rsp rsp;
|
||||
struct hci_dev *hdev;
|
||||
|
||||
if (le16_to_cpu(hdr->len) < sizeof(*req))
|
||||
return -EINVAL;
|
||||
|
||||
BT_DBG("local_id %d remote_id %d", req->local_id, req->remote_id);
|
||||
|
||||
rsp.local_id = req->remote_id;
|
||||
rsp.remote_id = req->local_id;
|
||||
rsp.status = A2MP_STATUS_SUCCESS;
|
||||
|
||||
hdev = hci_dev_get(req->local_id);
|
||||
if (!hdev) {
|
||||
rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
|
||||
goto send_rsp;
|
||||
}
|
||||
|
||||
/* TODO Disconnect Phys Link here */
|
||||
|
||||
hci_dev_put(hdev);
|
||||
|
||||
send_rsp:
|
||||
a2mp_send(mgr, A2MP_DISCONNPHYSLINK_RSP, hdr->ident, sizeof(rsp), &rsp);
|
||||
|
||||
skb_pull(skb, sizeof(*req));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int a2mp_cmd_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
|
||||
struct a2mp_cmd *hdr)
|
||||
{
|
||||
BT_DBG("ident %d code %d", hdr->ident, hdr->code);
|
||||
|
||||
skb_pull(skb, le16_to_cpu(hdr->len));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Handle A2MP signalling */
|
||||
static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
|
||||
{
|
||||
struct a2mp_cmd *hdr = (void *) skb->data;
|
||||
struct amp_mgr *mgr = chan->data;
|
||||
int err = 0;
|
||||
|
||||
amp_mgr_get(mgr);
|
||||
|
||||
while (skb->len >= sizeof(*hdr)) {
|
||||
struct a2mp_cmd *hdr = (void *) skb->data;
|
||||
u16 len = le16_to_cpu(hdr->len);
|
||||
|
||||
BT_DBG("code 0x%02x id %d len %d", hdr->code, hdr->ident, len);
|
||||
|
||||
skb_pull(skb, sizeof(*hdr));
|
||||
|
||||
if (len > skb->len || !hdr->ident) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
mgr->ident = hdr->ident;
|
||||
|
||||
switch (hdr->code) {
|
||||
case A2MP_COMMAND_REJ:
|
||||
a2mp_command_rej(mgr, skb, hdr);
|
||||
break;
|
||||
|
||||
case A2MP_DISCOVER_REQ:
|
||||
err = a2mp_discover_req(mgr, skb, hdr);
|
||||
break;
|
||||
|
||||
case A2MP_CHANGE_NOTIFY:
|
||||
err = a2mp_change_notify(mgr, skb, hdr);
|
||||
break;
|
||||
|
||||
case A2MP_GETINFO_REQ:
|
||||
err = a2mp_getinfo_req(mgr, skb, hdr);
|
||||
break;
|
||||
|
||||
case A2MP_GETAMPASSOC_REQ:
|
||||
err = a2mp_getampassoc_req(mgr, skb, hdr);
|
||||
break;
|
||||
|
||||
case A2MP_CREATEPHYSLINK_REQ:
|
||||
err = a2mp_createphyslink_req(mgr, skb, hdr);
|
||||
break;
|
||||
|
||||
case A2MP_DISCONNPHYSLINK_REQ:
|
||||
err = a2mp_discphyslink_req(mgr, skb, hdr);
|
||||
break;
|
||||
|
||||
case A2MP_CHANGE_RSP:
|
||||
case A2MP_DISCOVER_RSP:
|
||||
case A2MP_GETINFO_RSP:
|
||||
case A2MP_GETAMPASSOC_RSP:
|
||||
case A2MP_CREATEPHYSLINK_RSP:
|
||||
case A2MP_DISCONNPHYSLINK_RSP:
|
||||
err = a2mp_cmd_rsp(mgr, skb, hdr);
|
||||
break;
|
||||
|
||||
default:
|
||||
BT_ERR("Unknown A2MP sig cmd 0x%2.2x", hdr->code);
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (err) {
|
||||
struct a2mp_cmd_rej rej;
|
||||
rej.reason = __constant_cpu_to_le16(0);
|
||||
|
||||
BT_DBG("Send A2MP Rej: cmd 0x%2.2x err %d", hdr->code, err);
|
||||
|
||||
a2mp_send(mgr, A2MP_COMMAND_REJ, hdr->ident, sizeof(rej),
|
||||
&rej);
|
||||
}
|
||||
|
||||
/* Always free skb and return success error code to prevent
|
||||
from sending L2CAP Disconnect over A2MP channel */
|
||||
kfree_skb(skb);
|
||||
|
||||
amp_mgr_put(mgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void a2mp_chan_close_cb(struct l2cap_chan *chan)
|
||||
{
|
||||
l2cap_chan_destroy(chan);
|
||||
}
|
||||
|
||||
static void a2mp_chan_state_change_cb(struct l2cap_chan *chan, int state)
|
||||
{
|
||||
struct amp_mgr *mgr = chan->data;
|
||||
|
||||
if (!mgr)
|
||||
return;
|
||||
|
||||
BT_DBG("chan %p state %s", chan, state_to_string(state));
|
||||
|
||||
chan->state = state;
|
||||
|
||||
switch (state) {
|
||||
case BT_CLOSED:
|
||||
if (mgr)
|
||||
amp_mgr_put(mgr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static struct sk_buff *a2mp_chan_alloc_skb_cb(struct l2cap_chan *chan,
|
||||
unsigned long len, int nb)
|
||||
{
|
||||
return bt_skb_alloc(len, GFP_KERNEL);
|
||||
}
|
||||
|
||||
static struct l2cap_ops a2mp_chan_ops = {
|
||||
.name = "L2CAP A2MP channel",
|
||||
.recv = a2mp_chan_recv_cb,
|
||||
.close = a2mp_chan_close_cb,
|
||||
.state_change = a2mp_chan_state_change_cb,
|
||||
.alloc_skb = a2mp_chan_alloc_skb_cb,
|
||||
|
||||
/* Not implemented for A2MP */
|
||||
.new_connection = l2cap_chan_no_new_connection,
|
||||
.teardown = l2cap_chan_no_teardown,
|
||||
.ready = l2cap_chan_no_ready,
|
||||
};
|
||||
|
||||
static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
|
||||
{
|
||||
struct l2cap_chan *chan;
|
||||
int err;
|
||||
|
||||
chan = l2cap_chan_create();
|
||||
if (!chan)
|
||||
return NULL;
|
||||
|
||||
BT_DBG("chan %p", chan);
|
||||
|
||||
chan->chan_type = L2CAP_CHAN_CONN_FIX_A2MP;
|
||||
chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
|
||||
|
||||
chan->ops = &a2mp_chan_ops;
|
||||
|
||||
l2cap_chan_set_defaults(chan);
|
||||
chan->remote_max_tx = chan->max_tx;
|
||||
chan->remote_tx_win = chan->tx_win;
|
||||
|
||||
chan->retrans_timeout = L2CAP_DEFAULT_RETRANS_TO;
|
||||
chan->monitor_timeout = L2CAP_DEFAULT_MONITOR_TO;
|
||||
|
||||
skb_queue_head_init(&chan->tx_q);
|
||||
|
||||
chan->mode = L2CAP_MODE_ERTM;
|
||||
|
||||
err = l2cap_ertm_init(chan);
|
||||
if (err < 0) {
|
||||
l2cap_chan_del(chan, 0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
chan->conf_state = 0;
|
||||
|
||||
l2cap_chan_add(conn, chan);
|
||||
|
||||
chan->remote_mps = chan->omtu;
|
||||
chan->mps = chan->omtu;
|
||||
|
||||
chan->state = BT_CONNECTED;
|
||||
|
||||
return chan;
|
||||
}
|
||||
|
||||
/* AMP Manager functions */
|
||||
void amp_mgr_get(struct amp_mgr *mgr)
|
||||
{
|
||||
BT_DBG("mgr %p", mgr);
|
||||
|
||||
kref_get(&mgr->kref);
|
||||
}
|
||||
|
||||
static void amp_mgr_destroy(struct kref *kref)
|
||||
{
|
||||
struct amp_mgr *mgr = container_of(kref, struct amp_mgr, kref);
|
||||
|
||||
BT_DBG("mgr %p", mgr);
|
||||
|
||||
kfree(mgr);
|
||||
}
|
||||
|
||||
int amp_mgr_put(struct amp_mgr *mgr)
|
||||
{
|
||||
BT_DBG("mgr %p", mgr);
|
||||
|
||||
return kref_put(&mgr->kref, &_mgr_destroy);
|
||||
}
|
||||
|
||||
static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
|
||||
{
|
||||
struct amp_mgr *mgr;
|
||||
struct l2cap_chan *chan;
|
||||
|
||||
mgr = kzalloc(sizeof(*mgr), GFP_KERNEL);
|
||||
if (!mgr)
|
||||
return NULL;
|
||||
|
||||
BT_DBG("conn %p mgr %p", conn, mgr);
|
||||
|
||||
mgr->l2cap_conn = conn;
|
||||
|
||||
chan = a2mp_chan_open(conn);
|
||||
if (!chan) {
|
||||
kfree(mgr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mgr->a2mp_chan = chan;
|
||||
chan->data = mgr;
|
||||
|
||||
conn->hcon->amp_mgr = mgr;
|
||||
|
||||
kref_init(&mgr->kref);
|
||||
|
||||
return mgr;
|
||||
}
|
||||
|
||||
struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct amp_mgr *mgr;
|
||||
|
||||
mgr = amp_mgr_create(conn);
|
||||
if (!mgr) {
|
||||
BT_ERR("Could not create AMP manager");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BT_DBG("mgr: %p chan %p", mgr, mgr->a2mp_chan);
|
||||
|
||||
return mgr->a2mp_chan;
|
||||
}
|
|
@ -25,18 +25,7 @@
|
|||
/* Bluetooth address family and sockets. */
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/poll.h>
|
||||
#include <net/sock.h>
|
||||
#include <asm/ioctls.h>
|
||||
#include <linux/kmod.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
|
||||
|
@ -418,7 +407,8 @@ static inline unsigned int bt_accept_poll(struct sock *parent)
|
|||
return 0;
|
||||
}
|
||||
|
||||
unsigned int bt_sock_poll(struct file *file, struct socket *sock, poll_table *wait)
|
||||
unsigned int bt_sock_poll(struct file *file, struct socket *sock,
|
||||
poll_table *wait)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
unsigned int mask = 0;
|
||||
|
|
|
@ -26,26 +26,9 @@
|
|||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
#include <linux/socket.h>
|
||||
#include <linux/file.h>
|
||||
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
|
@ -306,7 +289,7 @@ static u8 __bnep_rx_hlen[] = {
|
|||
ETH_ALEN + 2 /* BNEP_COMPRESSED_DST_ONLY */
|
||||
};
|
||||
|
||||
static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
|
||||
static int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *dev = s->dev;
|
||||
struct sk_buff *nskb;
|
||||
|
@ -404,7 +387,7 @@ static u8 __bnep_tx_types[] = {
|
|||
BNEP_COMPRESSED
|
||||
};
|
||||
|
||||
static inline int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
|
||||
static int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
|
||||
{
|
||||
struct ethhdr *eh = (void *) skb->data;
|
||||
struct socket *sock = s->sock;
|
||||
|
|
|
@ -25,16 +25,8 @@
|
|||
SOFTWARE IS DISCLAIMED.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/socket.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/wait.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
|
@ -128,7 +120,7 @@ static void bnep_net_timeout(struct net_device *dev)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_BT_BNEP_MC_FILTER
|
||||
static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s)
|
||||
static int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s)
|
||||
{
|
||||
struct ethhdr *eh = (void *) skb->data;
|
||||
|
||||
|
@ -140,7 +132,7 @@ static inline int bnep_net_mc_filter(struct sk_buff *skb, struct bnep_session *s
|
|||
|
||||
#ifdef CONFIG_BT_BNEP_PROTO_FILTER
|
||||
/* Determine ether protocol. Based on eth_type_trans. */
|
||||
static inline u16 bnep_net_eth_proto(struct sk_buff *skb)
|
||||
static u16 bnep_net_eth_proto(struct sk_buff *skb)
|
||||
{
|
||||
struct ethhdr *eh = (void *) skb->data;
|
||||
u16 proto = ntohs(eh->h_proto);
|
||||
|
@ -154,7 +146,7 @@ static inline u16 bnep_net_eth_proto(struct sk_buff *skb)
|
|||
return ETH_P_802_2;
|
||||
}
|
||||
|
||||
static inline int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s)
|
||||
static int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session *s)
|
||||
{
|
||||
u16 proto = bnep_net_eth_proto(skb);
|
||||
struct bnep_proto_filter *f = s->proto_filter;
|
||||
|
|
|
@ -24,24 +24,8 @@
|
|||
SOFTWARE IS DISCLAIMED.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
|
||||
#include "bnep.h"
|
||||
|
||||
|
|
|
@ -24,24 +24,11 @@
|
|||
|
||||
/* Bluetooth HCI connection handling. */
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
#include <net/bluetooth/a2mp.h>
|
||||
|
||||
static void hci_le_connect(struct hci_conn *conn)
|
||||
{
|
||||
|
@ -54,15 +41,15 @@ static void hci_le_connect(struct hci_conn *conn)
|
|||
conn->sec_level = BT_SECURITY_LOW;
|
||||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
cp.scan_interval = cpu_to_le16(0x0060);
|
||||
cp.scan_window = cpu_to_le16(0x0030);
|
||||
cp.scan_interval = __constant_cpu_to_le16(0x0060);
|
||||
cp.scan_window = __constant_cpu_to_le16(0x0030);
|
||||
bacpy(&cp.peer_addr, &conn->dst);
|
||||
cp.peer_addr_type = conn->dst_type;
|
||||
cp.conn_interval_min = cpu_to_le16(0x0028);
|
||||
cp.conn_interval_max = cpu_to_le16(0x0038);
|
||||
cp.supervision_timeout = cpu_to_le16(0x002a);
|
||||
cp.min_ce_len = cpu_to_le16(0x0000);
|
||||
cp.max_ce_len = cpu_to_le16(0x0000);
|
||||
cp.conn_interval_min = __constant_cpu_to_le16(0x0028);
|
||||
cp.conn_interval_max = __constant_cpu_to_le16(0x0038);
|
||||
cp.supervision_timeout = __constant_cpu_to_le16(0x002a);
|
||||
cp.min_ce_len = __constant_cpu_to_le16(0x0000);
|
||||
cp.max_ce_len = __constant_cpu_to_le16(0x0000);
|
||||
|
||||
hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
|
||||
}
|
||||
|
@ -99,7 +86,7 @@ void hci_acl_connect(struct hci_conn *conn)
|
|||
cp.pscan_rep_mode = ie->data.pscan_rep_mode;
|
||||
cp.pscan_mode = ie->data.pscan_mode;
|
||||
cp.clock_offset = ie->data.clock_offset |
|
||||
cpu_to_le16(0x8000);
|
||||
__constant_cpu_to_le16(0x8000);
|
||||
}
|
||||
|
||||
memcpy(conn->dev_class, ie->data.dev_class, 3);
|
||||
|
@ -175,9 +162,9 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
|
|||
cp.handle = cpu_to_le16(handle);
|
||||
cp.pkt_type = cpu_to_le16(conn->pkt_type);
|
||||
|
||||
cp.tx_bandwidth = cpu_to_le32(0x00001f40);
|
||||
cp.rx_bandwidth = cpu_to_le32(0x00001f40);
|
||||
cp.max_latency = cpu_to_le16(0xffff);
|
||||
cp.tx_bandwidth = __constant_cpu_to_le32(0x00001f40);
|
||||
cp.rx_bandwidth = __constant_cpu_to_le32(0x00001f40);
|
||||
cp.max_latency = __constant_cpu_to_le16(0xffff);
|
||||
cp.voice_setting = cpu_to_le16(hdev->voice_setting);
|
||||
cp.retrans_effort = 0xff;
|
||||
|
||||
|
@ -197,12 +184,11 @@ void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
|
|||
cp.conn_interval_max = cpu_to_le16(max);
|
||||
cp.conn_latency = cpu_to_le16(latency);
|
||||
cp.supervision_timeout = cpu_to_le16(to_multiplier);
|
||||
cp.min_ce_len = cpu_to_le16(0x0001);
|
||||
cp.max_ce_len = cpu_to_le16(0x0001);
|
||||
cp.min_ce_len = __constant_cpu_to_le16(0x0001);
|
||||
cp.max_ce_len = __constant_cpu_to_le16(0x0001);
|
||||
|
||||
hci_send_cmd(hdev, HCI_OP_LE_CONN_UPDATE, sizeof(cp), &cp);
|
||||
}
|
||||
EXPORT_SYMBOL(hci_le_conn_update);
|
||||
|
||||
void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
|
||||
__u8 ltk[16])
|
||||
|
@ -221,7 +207,6 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
|
|||
|
||||
hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp);
|
||||
}
|
||||
EXPORT_SYMBOL(hci_le_start_enc);
|
||||
|
||||
/* Device _must_ be locked */
|
||||
void hci_sco_setup(struct hci_conn *conn, __u8 status)
|
||||
|
@ -295,9 +280,9 @@ static void hci_conn_enter_sniff_mode(struct hci_conn *conn)
|
|||
if (lmp_sniffsubr_capable(hdev) && lmp_sniffsubr_capable(conn)) {
|
||||
struct hci_cp_sniff_subrate cp;
|
||||
cp.handle = cpu_to_le16(conn->handle);
|
||||
cp.max_latency = cpu_to_le16(0);
|
||||
cp.min_remote_timeout = cpu_to_le16(0);
|
||||
cp.min_local_timeout = cpu_to_le16(0);
|
||||
cp.max_latency = __constant_cpu_to_le16(0);
|
||||
cp.min_remote_timeout = __constant_cpu_to_le16(0);
|
||||
cp.min_local_timeout = __constant_cpu_to_le16(0);
|
||||
hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
|
@ -306,8 +291,8 @@ static void hci_conn_enter_sniff_mode(struct hci_conn *conn)
|
|||
cp.handle = cpu_to_le16(conn->handle);
|
||||
cp.max_interval = cpu_to_le16(hdev->sniff_max_interval);
|
||||
cp.min_interval = cpu_to_le16(hdev->sniff_min_interval);
|
||||
cp.attempt = cpu_to_le16(4);
|
||||
cp.timeout = cpu_to_le16(1);
|
||||
cp.attempt = __constant_cpu_to_le16(4);
|
||||
cp.timeout = __constant_cpu_to_le16(1);
|
||||
hci_send_cmd(hdev, HCI_OP_SNIFF_MODE, sizeof(cp), &cp);
|
||||
}
|
||||
}
|
||||
|
@ -425,9 +410,11 @@ int hci_conn_del(struct hci_conn *conn)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
hci_chan_list_flush(conn);
|
||||
|
||||
if (conn->amp_mgr)
|
||||
amp_mgr_put(conn->amp_mgr);
|
||||
|
||||
hci_conn_hash_del(hdev, conn);
|
||||
if (hdev->notify)
|
||||
hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
|
||||
|
@ -454,7 +441,8 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
|
|||
read_lock(&hci_dev_list_lock);
|
||||
|
||||
list_for_each_entry(d, &hci_dev_list, list) {
|
||||
if (!test_bit(HCI_UP, &d->flags) || test_bit(HCI_RAW, &d->flags))
|
||||
if (!test_bit(HCI_UP, &d->flags) ||
|
||||
test_bit(HCI_RAW, &d->flags))
|
||||
continue;
|
||||
|
||||
/* Simple routing:
|
||||
|
@ -495,6 +483,11 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
|
|||
if (type == LE_LINK) {
|
||||
le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
|
||||
if (!le) {
|
||||
le = hci_conn_hash_lookup_state(hdev, LE_LINK,
|
||||
BT_CONNECT);
|
||||
if (le)
|
||||
return ERR_PTR(-EBUSY);
|
||||
|
||||
le = hci_conn_add(hdev, LE_LINK, dst);
|
||||
if (!le)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
@ -560,7 +553,6 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
|
|||
|
||||
return sco;
|
||||
}
|
||||
EXPORT_SYMBOL(hci_connect);
|
||||
|
||||
/* Check link security requirement */
|
||||
int hci_conn_check_link_mode(struct hci_conn *conn)
|
||||
|
@ -572,7 +564,6 @@ int hci_conn_check_link_mode(struct hci_conn *conn)
|
|||
|
||||
return 1;
|
||||
}
|
||||
EXPORT_SYMBOL(hci_conn_check_link_mode);
|
||||
|
||||
/* Authenticate remote device */
|
||||
static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
|
||||
|
@ -648,8 +639,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
|
|||
/* An unauthenticated combination key has sufficient security for
|
||||
security level 1 and 2. */
|
||||
if (conn->key_type == HCI_LK_UNAUTH_COMBINATION &&
|
||||
(sec_level == BT_SECURITY_MEDIUM ||
|
||||
sec_level == BT_SECURITY_LOW))
|
||||
(sec_level == BT_SECURITY_MEDIUM || sec_level == BT_SECURITY_LOW))
|
||||
goto encrypt;
|
||||
|
||||
/* A combination key has always sufficient security for the security
|
||||
|
@ -657,8 +647,7 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
|
|||
is generated using maximum PIN code length (16).
|
||||
For pre 2.1 units. */
|
||||
if (conn->key_type == HCI_LK_COMBINATION &&
|
||||
(sec_level != BT_SECURITY_HIGH ||
|
||||
conn->pin_length == 16))
|
||||
(sec_level != BT_SECURITY_HIGH || conn->pin_length == 16))
|
||||
goto encrypt;
|
||||
|
||||
auth:
|
||||
|
@ -706,7 +695,6 @@ int hci_conn_change_link_key(struct hci_conn *conn)
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(hci_conn_change_link_key);
|
||||
|
||||
/* Switch role */
|
||||
int hci_conn_switch_role(struct hci_conn *conn, __u8 role)
|
||||
|
@ -802,7 +790,7 @@ EXPORT_SYMBOL(hci_conn_put_device);
|
|||
|
||||
int hci_get_conn_list(void __user *arg)
|
||||
{
|
||||
register struct hci_conn *c;
|
||||
struct hci_conn *c;
|
||||
struct hci_conn_list_req req, *cl;
|
||||
struct hci_conn_info *ci;
|
||||
struct hci_dev *hdev;
|
||||
|
|
|
@ -25,28 +25,10 @@
|
|||
|
||||
/* Bluetooth HCI core. */
|
||||
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/idr.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/rfkill.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/crypto.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
|
@ -65,6 +47,9 @@ DEFINE_RWLOCK(hci_dev_list_lock);
|
|||
LIST_HEAD(hci_cb_list);
|
||||
DEFINE_RWLOCK(hci_cb_list_lock);
|
||||
|
||||
/* HCI ID Numbering */
|
||||
static DEFINE_IDA(hci_index_ida);
|
||||
|
||||
/* ---- HCI notifications ---- */
|
||||
|
||||
static void hci_notify(struct hci_dev *hdev, int event)
|
||||
|
@ -124,7 +109,8 @@ static void hci_req_cancel(struct hci_dev *hdev, int err)
|
|||
}
|
||||
|
||||
/* Execute request and wait for completion. */
|
||||
static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
|
||||
static int __hci_request(struct hci_dev *hdev,
|
||||
void (*req)(struct hci_dev *hdev, unsigned long opt),
|
||||
unsigned long opt, __u32 timeout)
|
||||
{
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
|
@ -166,7 +152,8 @@ static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev,
|
|||
return err;
|
||||
}
|
||||
|
||||
static inline int hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, unsigned long opt),
|
||||
static int hci_request(struct hci_dev *hdev,
|
||||
void (*req)(struct hci_dev *hdev, unsigned long opt),
|
||||
unsigned long opt, __u32 timeout)
|
||||
{
|
||||
int ret;
|
||||
|
@ -202,7 +189,7 @@ static void bredr_init(struct hci_dev *hdev)
|
|||
/* Mandatory initialization */
|
||||
|
||||
/* Reset */
|
||||
if (!test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) {
|
||||
if (!test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) {
|
||||
set_bit(HCI_RESET, &hdev->flags);
|
||||
hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL);
|
||||
}
|
||||
|
@ -235,7 +222,7 @@ static void bredr_init(struct hci_dev *hdev)
|
|||
hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
|
||||
|
||||
/* Connection accept timeout ~20 secs */
|
||||
param = cpu_to_le16(0x7d00);
|
||||
param = __constant_cpu_to_le16(0x7d00);
|
||||
hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, ¶m);
|
||||
|
||||
bacpy(&cp.bdaddr, BDADDR_ANY);
|
||||
|
@ -417,7 +404,8 @@ static void inquiry_cache_flush(struct hci_dev *hdev)
|
|||
INIT_LIST_HEAD(&cache->resolve);
|
||||
}
|
||||
|
||||
struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *bdaddr)
|
||||
struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev,
|
||||
bdaddr_t *bdaddr)
|
||||
{
|
||||
struct discovery_state *cache = &hdev->discovery;
|
||||
struct inquiry_entry *e;
|
||||
|
@ -605,8 +593,7 @@ int hci_inquiry(void __user *arg)
|
|||
|
||||
hci_dev_lock(hdev);
|
||||
if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX ||
|
||||
inquiry_cache_empty(hdev) ||
|
||||
ir.flags & IREQ_CACHE_FLUSH) {
|
||||
inquiry_cache_empty(hdev) || ir.flags & IREQ_CACHE_FLUSH) {
|
||||
inquiry_cache_flush(hdev);
|
||||
do_inquiry = 1;
|
||||
}
|
||||
|
@ -620,7 +607,9 @@ int hci_inquiry(void __user *arg)
|
|||
goto done;
|
||||
}
|
||||
|
||||
/* for unlimited number of responses we will use buffer with 255 entries */
|
||||
/* for unlimited number of responses we will use buffer with
|
||||
* 255 entries
|
||||
*/
|
||||
max_rsp = (ir.num_rsp == 0) ? 255 : ir.num_rsp;
|
||||
|
||||
/* cache_dump can't sleep. Therefore we allocate temp buffer and then
|
||||
|
@ -791,7 +780,7 @@ static int hci_dev_do_close(struct hci_dev *hdev)
|
|||
skb_queue_purge(&hdev->cmd_q);
|
||||
atomic_set(&hdev->cmd_cnt, 1);
|
||||
if (!test_bit(HCI_RAW, &hdev->flags) &&
|
||||
test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) {
|
||||
test_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks)) {
|
||||
set_bit(HCI_INIT, &hdev->flags);
|
||||
__hci_request(hdev, hci_reset_req, 0,
|
||||
msecs_to_jiffies(250));
|
||||
|
@ -1242,7 +1231,6 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8])
|
|||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(hci_find_ltk);
|
||||
|
||||
struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
u8 addr_type)
|
||||
|
@ -1256,7 +1244,6 @@ struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
|||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(hci_find_ltk_by_addr);
|
||||
|
||||
int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
|
||||
bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len)
|
||||
|
@ -1283,15 +1270,14 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
|
|||
* combination key for legacy pairing even when there's no
|
||||
* previous key */
|
||||
if (type == HCI_LK_CHANGED_COMBINATION &&
|
||||
(!conn || conn->remote_auth == 0xff) &&
|
||||
old_key_type == 0xff) {
|
||||
(!conn || conn->remote_auth == 0xff) && old_key_type == 0xff) {
|
||||
type = HCI_LK_COMBINATION;
|
||||
if (conn)
|
||||
conn->key_type = type;
|
||||
}
|
||||
|
||||
bacpy(&key->bdaddr, bdaddr);
|
||||
memcpy(key->val, val, 16);
|
||||
memcpy(key->val, val, HCI_LINK_KEY_SIZE);
|
||||
key->pin_len = pin_len;
|
||||
|
||||
if (type == HCI_LK_CHANGED_COMBINATION)
|
||||
|
@ -1540,6 +1526,7 @@ static void le_scan_enable_req(struct hci_dev *hdev, unsigned long opt)
|
|||
|
||||
memset(&cp, 0, sizeof(cp));
|
||||
cp.enable = 1;
|
||||
cp.filter_dup = 1;
|
||||
|
||||
hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
|
||||
}
|
||||
|
@ -1707,37 +1694,35 @@ EXPORT_SYMBOL(hci_free_dev);
|
|||
/* Register HCI device */
|
||||
int hci_register_dev(struct hci_dev *hdev)
|
||||
{
|
||||
struct list_head *head, *p;
|
||||
int id, error;
|
||||
|
||||
if (!hdev->open || !hdev->close)
|
||||
return -EINVAL;
|
||||
|
||||
write_lock(&hci_dev_list_lock);
|
||||
|
||||
/* Do not allow HCI_AMP devices to register at index 0,
|
||||
* so the index can be used as the AMP controller ID.
|
||||
*/
|
||||
id = (hdev->dev_type == HCI_BREDR) ? 0 : 1;
|
||||
head = &hci_dev_list;
|
||||
|
||||
/* Find first available device id */
|
||||
list_for_each(p, &hci_dev_list) {
|
||||
int nid = list_entry(p, struct hci_dev, list)->id;
|
||||
if (nid > id)
|
||||
switch (hdev->dev_type) {
|
||||
case HCI_BREDR:
|
||||
id = ida_simple_get(&hci_index_ida, 0, 0, GFP_KERNEL);
|
||||
break;
|
||||
if (nid == id)
|
||||
id++;
|
||||
head = p;
|
||||
case HCI_AMP:
|
||||
id = ida_simple_get(&hci_index_ida, 1, 0, GFP_KERNEL);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
sprintf(hdev->name, "hci%d", id);
|
||||
hdev->id = id;
|
||||
|
||||
BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
|
||||
|
||||
list_add(&hdev->list, head);
|
||||
|
||||
write_lock(&hci_dev_list_lock);
|
||||
list_add(&hdev->list, &hci_dev_list);
|
||||
write_unlock(&hci_dev_list_lock);
|
||||
|
||||
hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI | WQ_UNBOUND |
|
||||
|
@ -1752,7 +1737,8 @@ int hci_register_dev(struct hci_dev *hdev)
|
|||
goto err_wqueue;
|
||||
|
||||
hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
|
||||
RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, hdev);
|
||||
RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops,
|
||||
hdev);
|
||||
if (hdev->rfkill) {
|
||||
if (rfkill_register(hdev->rfkill) < 0) {
|
||||
rfkill_destroy(hdev->rfkill);
|
||||
|
@ -1772,6 +1758,7 @@ int hci_register_dev(struct hci_dev *hdev)
|
|||
err_wqueue:
|
||||
destroy_workqueue(hdev->workqueue);
|
||||
err:
|
||||
ida_simple_remove(&hci_index_ida, hdev->id);
|
||||
write_lock(&hci_dev_list_lock);
|
||||
list_del(&hdev->list);
|
||||
write_unlock(&hci_dev_list_lock);
|
||||
|
@ -1783,12 +1770,14 @@ EXPORT_SYMBOL(hci_register_dev);
|
|||
/* Unregister HCI device */
|
||||
void hci_unregister_dev(struct hci_dev *hdev)
|
||||
{
|
||||
int i;
|
||||
int i, id;
|
||||
|
||||
BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
|
||||
|
||||
set_bit(HCI_UNREGISTER, &hdev->dev_flags);
|
||||
|
||||
id = hdev->id;
|
||||
|
||||
write_lock(&hci_dev_list_lock);
|
||||
list_del(&hdev->list);
|
||||
write_unlock(&hci_dev_list_lock);
|
||||
|
@ -1829,6 +1818,8 @@ void hci_unregister_dev(struct hci_dev *hdev)
|
|||
hci_dev_unlock(hdev);
|
||||
|
||||
hci_dev_put(hdev);
|
||||
|
||||
ida_simple_remove(&hci_index_ida, id);
|
||||
}
|
||||
EXPORT_SYMBOL(hci_unregister_dev);
|
||||
|
||||
|
@ -2216,7 +2207,6 @@ void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags)
|
|||
|
||||
queue_work(hdev->workqueue, &hdev->tx_work);
|
||||
}
|
||||
EXPORT_SYMBOL(hci_send_acl);
|
||||
|
||||
/* Send SCO data */
|
||||
void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
|
||||
|
@ -2239,12 +2229,12 @@ void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb)
|
|||
skb_queue_tail(&conn->data_q, skb);
|
||||
queue_work(hdev->workqueue, &hdev->tx_work);
|
||||
}
|
||||
EXPORT_SYMBOL(hci_send_sco);
|
||||
|
||||
/* ---- HCI TX task (outgoing data) ---- */
|
||||
|
||||
/* HCI Connection scheduler */
|
||||
static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int *quote)
|
||||
static struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type,
|
||||
int *quote)
|
||||
{
|
||||
struct hci_conn_hash *h = &hdev->conn_hash;
|
||||
struct hci_conn *conn = NULL, *c;
|
||||
|
@ -2303,7 +2293,7 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
|
|||
return conn;
|
||||
}
|
||||
|
||||
static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
|
||||
static void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
|
||||
{
|
||||
struct hci_conn_hash *h = &hdev->conn_hash;
|
||||
struct hci_conn *c;
|
||||
|
@ -2317,14 +2307,14 @@ static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
|
|||
if (c->type == type && c->sent) {
|
||||
BT_ERR("%s killing stalled connection %s",
|
||||
hdev->name, batostr(&c->dst));
|
||||
hci_acl_disconn(c, 0x13);
|
||||
hci_acl_disconn(c, HCI_ERROR_REMOTE_USER_TERM);
|
||||
}
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
|
||||
static struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
|
||||
int *quote)
|
||||
{
|
||||
struct hci_conn_hash *h = &hdev->conn_hash;
|
||||
|
@ -2459,7 +2449,7 @@ static inline int __get_blocks(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
return DIV_ROUND_UP(skb->len - HCI_ACL_HDR_SIZE, hdev->block_len);
|
||||
}
|
||||
|
||||
static inline void __check_timeout(struct hci_dev *hdev, unsigned int cnt)
|
||||
static void __check_timeout(struct hci_dev *hdev, unsigned int cnt)
|
||||
{
|
||||
if (!test_bit(HCI_RAW, &hdev->flags)) {
|
||||
/* ACL tx timeout must be longer than maximum
|
||||
|
@ -2470,7 +2460,7 @@ static inline void __check_timeout(struct hci_dev *hdev, unsigned int cnt)
|
|||
}
|
||||
}
|
||||
|
||||
static inline void hci_sched_acl_pkt(struct hci_dev *hdev)
|
||||
static void hci_sched_acl_pkt(struct hci_dev *hdev)
|
||||
{
|
||||
unsigned int cnt = hdev->acl_cnt;
|
||||
struct hci_chan *chan;
|
||||
|
@ -2508,7 +2498,7 @@ static inline void hci_sched_acl_pkt(struct hci_dev *hdev)
|
|||
hci_prio_recalculate(hdev, ACL_LINK);
|
||||
}
|
||||
|
||||
static inline void hci_sched_acl_blk(struct hci_dev *hdev)
|
||||
static void hci_sched_acl_blk(struct hci_dev *hdev)
|
||||
{
|
||||
unsigned int cnt = hdev->block_cnt;
|
||||
struct hci_chan *chan;
|
||||
|
@ -2554,7 +2544,7 @@ static inline void hci_sched_acl_blk(struct hci_dev *hdev)
|
|||
hci_prio_recalculate(hdev, ACL_LINK);
|
||||
}
|
||||
|
||||
static inline void hci_sched_acl(struct hci_dev *hdev)
|
||||
static void hci_sched_acl(struct hci_dev *hdev)
|
||||
{
|
||||
BT_DBG("%s", hdev->name);
|
||||
|
||||
|
@ -2573,7 +2563,7 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
|
|||
}
|
||||
|
||||
/* Schedule SCO */
|
||||
static inline void hci_sched_sco(struct hci_dev *hdev)
|
||||
static void hci_sched_sco(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_conn *conn;
|
||||
struct sk_buff *skb;
|
||||
|
@ -2596,7 +2586,7 @@ static inline void hci_sched_sco(struct hci_dev *hdev)
|
|||
}
|
||||
}
|
||||
|
||||
static inline void hci_sched_esco(struct hci_dev *hdev)
|
||||
static void hci_sched_esco(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_conn *conn;
|
||||
struct sk_buff *skb;
|
||||
|
@ -2607,7 +2597,8 @@ static inline void hci_sched_esco(struct hci_dev *hdev)
|
|||
if (!hci_conn_num(hdev, ESCO_LINK))
|
||||
return;
|
||||
|
||||
while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK, "e))) {
|
||||
while (hdev->sco_cnt && (conn = hci_low_sent(hdev, ESCO_LINK,
|
||||
"e))) {
|
||||
while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
|
||||
BT_DBG("skb %p len %d", skb, skb->len);
|
||||
hci_send_frame(skb);
|
||||
|
@ -2619,7 +2610,7 @@ static inline void hci_sched_esco(struct hci_dev *hdev)
|
|||
}
|
||||
}
|
||||
|
||||
static inline void hci_sched_le(struct hci_dev *hdev)
|
||||
static void hci_sched_le(struct hci_dev *hdev)
|
||||
{
|
||||
struct hci_chan *chan;
|
||||
struct sk_buff *skb;
|
||||
|
@ -2696,7 +2687,7 @@ static void hci_tx_work(struct work_struct *work)
|
|||
/* ----- HCI RX task (incoming data processing) ----- */
|
||||
|
||||
/* ACL data packet */
|
||||
static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_acl_hdr *hdr = (void *) skb->data;
|
||||
struct hci_conn *conn;
|
||||
|
@ -2708,7 +2699,8 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
flags = hci_flags(handle);
|
||||
handle = hci_handle(handle);
|
||||
|
||||
BT_DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len, handle, flags);
|
||||
BT_DBG("%s len %d handle 0x%x flags 0x%x", hdev->name, skb->len,
|
||||
handle, flags);
|
||||
|
||||
hdev->stat.acl_rx++;
|
||||
|
||||
|
@ -2739,7 +2731,7 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
}
|
||||
|
||||
/* SCO data packet */
|
||||
static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_sco_hdr *hdr = (void *) skb->data;
|
||||
struct hci_conn *conn;
|
||||
|
|
|
@ -24,20 +24,7 @@
|
|||
|
||||
/* Bluetooth HCI event handling. */
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/export.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
|
@ -95,7 +82,8 @@ static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
hci_conn_check_pending(hdev);
|
||||
}
|
||||
|
||||
static void hci_cc_remote_name_req_cancel(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_cc_remote_name_req_cancel(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
BT_DBG("%s", hdev->name);
|
||||
}
|
||||
|
@ -166,7 +154,8 @@ static void hci_cc_write_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static void hci_cc_read_def_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_cc_read_def_link_policy(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_rp_read_def_link_policy *rp = (void *) skb->data;
|
||||
|
||||
|
@ -178,7 +167,8 @@ static void hci_cc_read_def_link_policy(struct hci_dev *hdev, struct sk_buff *sk
|
|||
hdev->link_policy = __le16_to_cpu(rp->policy);
|
||||
}
|
||||
|
||||
static void hci_cc_write_def_link_policy(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_cc_write_def_link_policy(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
__u8 status = *((__u8 *) skb->data);
|
||||
void *sent;
|
||||
|
@ -406,7 +396,8 @@ static void hci_cc_read_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
|
||||
}
|
||||
|
||||
static void hci_cc_write_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_cc_write_voice_setting(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
__u8 status = *((__u8 *) skb->data);
|
||||
__u16 setting;
|
||||
|
@ -566,7 +557,7 @@ static void hci_setup(struct hci_dev *hdev)
|
|||
if (hdev->hci_ver > BLUETOOTH_VER_1_1)
|
||||
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
|
||||
|
||||
if (hdev->features[6] & LMP_SIMPLE_PAIR) {
|
||||
if (lmp_ssp_capable(hdev)) {
|
||||
if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
|
||||
u8 mode = 0x01;
|
||||
hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE,
|
||||
|
@ -618,8 +609,7 @@ static void hci_cc_read_local_version(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
hdev->lmp_subver = __le16_to_cpu(rp->lmp_subver);
|
||||
|
||||
BT_DBG("%s manufacturer %d hci ver %d:%d", hdev->name,
|
||||
hdev->manufacturer,
|
||||
hdev->hci_ver, hdev->hci_rev);
|
||||
hdev->manufacturer, hdev->hci_ver, hdev->hci_rev);
|
||||
|
||||
if (test_bit(HCI_INIT, &hdev->flags))
|
||||
hci_setup(hdev);
|
||||
|
@ -646,7 +636,8 @@ static void hci_setup_link_policy(struct hci_dev *hdev)
|
|||
hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, sizeof(cp), &cp);
|
||||
}
|
||||
|
||||
static void hci_cc_read_local_commands(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_cc_read_local_commands(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_rp_read_local_commands *rp = (void *) skb->data;
|
||||
|
||||
|
@ -664,7 +655,8 @@ done:
|
|||
hci_req_complete(hdev, HCI_OP_READ_LOCAL_COMMANDS, rp->status);
|
||||
}
|
||||
|
||||
static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_cc_read_local_features(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_rp_read_local_features *rp = (void *) skb->data;
|
||||
|
||||
|
@ -798,9 +790,8 @@ static void hci_cc_read_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
hdev->acl_cnt = hdev->acl_pkts;
|
||||
hdev->sco_cnt = hdev->sco_pkts;
|
||||
|
||||
BT_DBG("%s acl mtu %d:%d sco mtu %d:%d", hdev->name,
|
||||
hdev->acl_mtu, hdev->acl_pkts,
|
||||
hdev->sco_mtu, hdev->sco_pkts);
|
||||
BT_DBG("%s acl mtu %d:%d sco mtu %d:%d", hdev->name, hdev->acl_mtu,
|
||||
hdev->acl_pkts, hdev->sco_mtu, hdev->sco_pkts);
|
||||
}
|
||||
|
||||
static void hci_cc_read_bd_addr(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
|
@ -1156,7 +1147,7 @@ static void hci_cc_le_ltk_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
hci_req_complete(hdev, HCI_OP_LE_LTK_NEG_REPLY, rp->status);
|
||||
}
|
||||
|
||||
static inline void hci_cc_write_le_host_supported(struct hci_dev *hdev,
|
||||
static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_cp_write_le_host_supported *sent;
|
||||
|
@ -1182,7 +1173,7 @@ static inline void hci_cc_write_le_host_supported(struct hci_dev *hdev,
|
|||
hci_req_complete(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, status);
|
||||
}
|
||||
|
||||
static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
|
||||
static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
|
||||
{
|
||||
BT_DBG("%s status 0x%x", hdev->name, status);
|
||||
|
||||
|
@ -1203,7 +1194,7 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
|
||||
static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
|
||||
{
|
||||
struct hci_cp_create_conn *cp;
|
||||
struct hci_conn *conn;
|
||||
|
@ -1343,15 +1334,14 @@ static int hci_outgoing_auth_needed(struct hci_dev *hdev,
|
|||
|
||||
/* Only request authentication for SSP connections or non-SSP
|
||||
* devices with sec_level HIGH or if MITM protection is requested */
|
||||
if (!hci_conn_ssp_enabled(conn) &&
|
||||
conn->pending_sec_level != BT_SECURITY_HIGH &&
|
||||
!(conn->auth_type & 0x01))
|
||||
if (!hci_conn_ssp_enabled(conn) && !(conn->auth_type & 0x01) &&
|
||||
conn->pending_sec_level != BT_SECURITY_HIGH)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int hci_resolve_name(struct hci_dev *hdev,
|
||||
static int hci_resolve_name(struct hci_dev *hdev,
|
||||
struct inquiry_entry *e)
|
||||
{
|
||||
struct hci_cp_remote_name_req cp;
|
||||
|
@ -1668,7 +1658,7 @@ static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
|
|||
BT_DBG("%s status 0x%x", hdev->name, status);
|
||||
}
|
||||
|
||||
static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
__u8 status = *((__u8 *) skb->data);
|
||||
struct discovery_state *discov = &hdev->discovery;
|
||||
|
@ -1708,7 +1698,7 @@ unlock:
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct inquiry_data data;
|
||||
struct inquiry_info *info = (void *) (skb->data + 1);
|
||||
|
@ -1745,7 +1735,7 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_conn_complete *ev = (void *) skb->data;
|
||||
struct hci_conn *conn;
|
||||
|
@ -1823,13 +1813,13 @@ unlock:
|
|||
hci_conn_check_pending(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_conn_request *ev = (void *) skb->data;
|
||||
int mask = hdev->link_mode;
|
||||
|
||||
BT_DBG("%s bdaddr %s type 0x%x", hdev->name,
|
||||
batostr(&ev->bdaddr), ev->link_type);
|
||||
BT_DBG("%s bdaddr %s type 0x%x", hdev->name, batostr(&ev->bdaddr),
|
||||
ev->link_type);
|
||||
|
||||
mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);
|
||||
|
||||
|
@ -1845,7 +1835,8 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
|
|||
if (ie)
|
||||
memcpy(ie->data.dev_class, ev->dev_class, 3);
|
||||
|
||||
conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
|
||||
conn = hci_conn_hash_lookup_ba(hdev, ev->link_type,
|
||||
&ev->bdaddr);
|
||||
if (!conn) {
|
||||
conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr);
|
||||
if (!conn) {
|
||||
|
@ -1878,9 +1869,9 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
|
|||
bacpy(&cp.bdaddr, &ev->bdaddr);
|
||||
cp.pkt_type = cpu_to_le16(conn->pkt_type);
|
||||
|
||||
cp.tx_bandwidth = cpu_to_le32(0x00001f40);
|
||||
cp.rx_bandwidth = cpu_to_le32(0x00001f40);
|
||||
cp.max_latency = cpu_to_le16(0xffff);
|
||||
cp.tx_bandwidth = __constant_cpu_to_le32(0x00001f40);
|
||||
cp.rx_bandwidth = __constant_cpu_to_le32(0x00001f40);
|
||||
cp.max_latency = __constant_cpu_to_le16(0xffff);
|
||||
cp.content_format = cpu_to_le16(hdev->voice_setting);
|
||||
cp.retrans_effort = 0xff;
|
||||
|
||||
|
@ -1897,7 +1888,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
|
|||
}
|
||||
}
|
||||
|
||||
static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_disconn_complete *ev = (void *) skb->data;
|
||||
struct hci_conn *conn;
|
||||
|
@ -1934,7 +1925,7 @@ unlock:
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_auth_complete *ev = (void *) skb->data;
|
||||
struct hci_conn *conn;
|
||||
|
@ -2000,7 +1991,7 @@ unlock:
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_remote_name *ev = (void *) skb->data;
|
||||
struct hci_conn *conn;
|
||||
|
@ -2039,7 +2030,7 @@ unlock:
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_encrypt_change *ev = (void *) skb->data;
|
||||
struct hci_conn *conn;
|
||||
|
@ -2082,7 +2073,8 @@ unlock:
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_change_link_key_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_change_link_key_complete_evt(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_change_link_key_complete *ev = (void *) skb->data;
|
||||
struct hci_conn *conn;
|
||||
|
@ -2104,7 +2096,8 @@ static inline void hci_change_link_key_complete_evt(struct hci_dev *hdev, struct
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_remote_features_evt(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_remote_features *ev = (void *) skb->data;
|
||||
struct hci_conn *conn;
|
||||
|
@ -2153,17 +2146,18 @@ unlock:
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_remote_version_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_remote_version_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
BT_DBG("%s", hdev->name);
|
||||
}
|
||||
|
||||
static inline void hci_qos_setup_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_qos_setup_complete_evt(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
BT_DBG("%s", hdev->name);
|
||||
}
|
||||
|
||||
static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_cmd_complete *ev = (void *) skb->data;
|
||||
__u16 opcode;
|
||||
|
@ -2384,7 +2378,7 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
|
|||
}
|
||||
}
|
||||
|
||||
static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_cmd_status *ev = (void *) skb->data;
|
||||
__u16 opcode;
|
||||
|
@ -2465,7 +2459,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
}
|
||||
}
|
||||
|
||||
static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_role_change *ev = (void *) skb->data;
|
||||
struct hci_conn *conn;
|
||||
|
@ -2491,7 +2485,7 @@ static inline void hci_role_change_evt(struct hci_dev *hdev, struct sk_buff *skb
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_num_comp_pkts *ev = (void *) skb->data;
|
||||
int i;
|
||||
|
@ -2557,8 +2551,7 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
|
|||
queue_work(hdev->workqueue, &hdev->tx_work);
|
||||
}
|
||||
|
||||
static inline void hci_num_comp_blocks_evt(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
static void hci_num_comp_blocks_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_num_comp_blocks *ev = (void *) skb->data;
|
||||
int i;
|
||||
|
@ -2607,7 +2600,7 @@ static inline void hci_num_comp_blocks_evt(struct hci_dev *hdev,
|
|||
queue_work(hdev->workqueue, &hdev->tx_work);
|
||||
}
|
||||
|
||||
static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_mode_change *ev = (void *) skb->data;
|
||||
struct hci_conn *conn;
|
||||
|
@ -2621,7 +2614,8 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb
|
|||
conn->mode = ev->mode;
|
||||
conn->interval = __le16_to_cpu(ev->interval);
|
||||
|
||||
if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) {
|
||||
if (!test_and_clear_bit(HCI_CONN_MODE_CHANGE_PEND,
|
||||
&conn->flags)) {
|
||||
if (conn->mode == HCI_CM_ACTIVE)
|
||||
set_bit(HCI_CONN_POWER_SAVE, &conn->flags);
|
||||
else
|
||||
|
@ -2635,7 +2629,7 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_pin_code_req *ev = (void *) skb->data;
|
||||
struct hci_conn *conn;
|
||||
|
@ -2672,7 +2666,7 @@ unlock:
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_link_key_req *ev = (void *) skb->data;
|
||||
struct hci_cp_link_key_reply cp;
|
||||
|
@ -2705,16 +2699,15 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff
|
|||
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
|
||||
if (conn) {
|
||||
if (key->type == HCI_LK_UNAUTH_COMBINATION &&
|
||||
conn->auth_type != 0xff &&
|
||||
(conn->auth_type & 0x01)) {
|
||||
conn->auth_type != 0xff && (conn->auth_type & 0x01)) {
|
||||
BT_DBG("%s ignoring unauthenticated key", hdev->name);
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
if (key->type == HCI_LK_COMBINATION && key->pin_len < 16 &&
|
||||
conn->pending_sec_level == BT_SECURITY_HIGH) {
|
||||
BT_DBG("%s ignoring key unauthenticated for high \
|
||||
security", hdev->name);
|
||||
BT_DBG("%s ignoring key unauthenticated for high security",
|
||||
hdev->name);
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
|
@ -2723,7 +2716,7 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff
|
|||
}
|
||||
|
||||
bacpy(&cp.bdaddr, &ev->bdaddr);
|
||||
memcpy(cp.link_key, key->val, 16);
|
||||
memcpy(cp.link_key, key->val, HCI_LINK_KEY_SIZE);
|
||||
|
||||
hci_send_cmd(hdev, HCI_OP_LINK_KEY_REPLY, sizeof(cp), &cp);
|
||||
|
||||
|
@ -2736,7 +2729,7 @@ not_found:
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_link_key_notify *ev = (void *) skb->data;
|
||||
struct hci_conn *conn;
|
||||
|
@ -2765,7 +2758,7 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_clock_offset *ev = (void *) skb->data;
|
||||
struct hci_conn *conn;
|
||||
|
@ -2788,7 +2781,7 @@ static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *sk
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_pkt_type_change *ev = (void *) skb->data;
|
||||
struct hci_conn *conn;
|
||||
|
@ -2804,7 +2797,7 @@ static inline void hci_pkt_type_change_evt(struct hci_dev *hdev, struct sk_buff
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_pscan_rep_mode *ev = (void *) skb->data;
|
||||
struct inquiry_entry *ie;
|
||||
|
@ -2822,7 +2815,8 @@ static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct inquiry_data data;
|
||||
int num_rsp = *((__u8 *) skb->data);
|
||||
|
@ -2881,7 +2875,8 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_remote_ext_features_evt(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_remote_ext_features *ev = (void *) skb->data;
|
||||
struct hci_conn *conn;
|
||||
|
@ -2929,7 +2924,8 @@ unlock:
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_sync_conn_complete_evt(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_sync_conn_complete *ev = (void *) skb->data;
|
||||
struct hci_conn *conn;
|
||||
|
@ -2984,19 +2980,20 @@ unlock:
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_sync_conn_changed_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
BT_DBG("%s", hdev->name);
|
||||
}
|
||||
|
||||
static inline void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_sniff_subrate_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_sniff_subrate *ev = (void *) skb->data;
|
||||
|
||||
BT_DBG("%s status %d", hdev->name, ev->status);
|
||||
}
|
||||
|
||||
static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_extended_inquiry_result_evt(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct inquiry_data data;
|
||||
struct extended_inquiry_info *info = (void *) (skb->data + 1);
|
||||
|
@ -3043,7 +3040,7 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline u8 hci_get_auth_req(struct hci_conn *conn)
|
||||
static u8 hci_get_auth_req(struct hci_conn *conn)
|
||||
{
|
||||
/* If remote requests dedicated bonding follow that lead */
|
||||
if (conn->remote_auth == 0x02 || conn->remote_auth == 0x03) {
|
||||
|
@ -3062,7 +3059,7 @@ static inline u8 hci_get_auth_req(struct hci_conn *conn)
|
|||
return conn->auth_type;
|
||||
}
|
||||
|
||||
static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_io_capa_request *ev = (void *) skb->data;
|
||||
struct hci_conn *conn;
|
||||
|
@ -3092,8 +3089,8 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
|
|||
conn->auth_type = hci_get_auth_req(conn);
|
||||
cp.authentication = conn->auth_type;
|
||||
|
||||
if ((conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags)) &&
|
||||
hci_find_remote_oob_data(hdev, &conn->dst))
|
||||
if (hci_find_remote_oob_data(hdev, &conn->dst) &&
|
||||
(conn->out || test_bit(HCI_CONN_REMOTE_OOB, &conn->flags)))
|
||||
cp.oob_data = 0x01;
|
||||
else
|
||||
cp.oob_data = 0x00;
|
||||
|
@ -3114,7 +3111,7 @@ unlock:
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_io_capa_reply_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_io_capa_reply_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_io_capa_reply *ev = (void *) skb->data;
|
||||
struct hci_conn *conn;
|
||||
|
@ -3136,7 +3133,7 @@ unlock:
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
|
||||
static void hci_user_confirm_request_evt(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_user_confirm_req *ev = (void *) skb->data;
|
||||
|
@ -3204,7 +3201,7 @@ unlock:
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_user_passkey_request_evt(struct hci_dev *hdev,
|
||||
static void hci_user_passkey_request_evt(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_user_passkey_req *ev = (void *) skb->data;
|
||||
|
@ -3219,7 +3216,8 @@ static inline void hci_user_passkey_request_evt(struct hci_dev *hdev,
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_simple_pair_complete_evt(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_simple_pair_complete *ev = (void *) skb->data;
|
||||
struct hci_conn *conn;
|
||||
|
@ -3247,7 +3245,8 @@ unlock:
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_remote_host_features_evt(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_remote_host_features *ev = (void *) skb->data;
|
||||
struct inquiry_entry *ie;
|
||||
|
@ -3263,7 +3262,7 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
|
||||
static void hci_remote_oob_data_request_evt(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_remote_oob_data_request *ev = (void *) skb->data;
|
||||
|
@ -3298,7 +3297,7 @@ unlock:
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_le_conn_complete *ev = (void *) skb->data;
|
||||
struct hci_conn *conn;
|
||||
|
@ -3307,6 +3306,19 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
|
|||
|
||||
hci_dev_lock(hdev);
|
||||
|
||||
if (ev->status) {
|
||||
conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
|
||||
if (!conn)
|
||||
goto unlock;
|
||||
|
||||
mgmt_connect_failed(hdev, &conn->dst, conn->type,
|
||||
conn->dst_type, ev->status);
|
||||
hci_proto_connect_cfm(conn, ev->status);
|
||||
conn->state = BT_CLOSED;
|
||||
hci_conn_del(conn);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &ev->bdaddr);
|
||||
if (!conn) {
|
||||
conn = hci_conn_add(hdev, LE_LINK, &ev->bdaddr);
|
||||
|
@ -3319,15 +3331,6 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
|
|||
conn->dst_type = ev->bdaddr_type;
|
||||
}
|
||||
|
||||
if (ev->status) {
|
||||
mgmt_connect_failed(hdev, &ev->bdaddr, conn->type,
|
||||
conn->dst_type, ev->status);
|
||||
hci_proto_connect_cfm(conn, ev->status);
|
||||
conn->state = BT_CLOSED;
|
||||
hci_conn_del(conn);
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, &conn->flags))
|
||||
mgmt_device_connected(hdev, &ev->bdaddr, conn->type,
|
||||
conn->dst_type, 0, NULL, 0, NULL);
|
||||
|
@ -3345,8 +3348,7 @@ unlock:
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
u8 num_reports = skb->data[0];
|
||||
void *ptr = &skb->data[1];
|
||||
|
@ -3367,8 +3369,7 @@ static inline void hci_le_adv_report_evt(struct hci_dev *hdev,
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_le_ltk_request_evt(struct hci_dev *hdev,
|
||||
struct sk_buff *skb)
|
||||
static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_le_ltk_req *ev = (void *) skb->data;
|
||||
struct hci_cp_le_ltk_reply cp;
|
||||
|
@ -3411,7 +3412,7 @@ not_found:
|
|||
hci_dev_unlock(hdev);
|
||||
}
|
||||
|
||||
static inline void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||
{
|
||||
struct hci_ev_le_meta *le_ev = (void *) skb->data;
|
||||
|
||||
|
|
|
@ -24,25 +24,7 @@
|
|||
|
||||
/* Bluetooth HCI sockets. */
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/export.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
|
@ -113,11 +95,12 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
flt = &hci_pi(sk)->filter;
|
||||
|
||||
if (!test_bit((bt_cb(skb)->pkt_type == HCI_VENDOR_PKT) ?
|
||||
0 : (bt_cb(skb)->pkt_type & HCI_FLT_TYPE_BITS), &flt->type_mask))
|
||||
0 : (bt_cb(skb)->pkt_type & HCI_FLT_TYPE_BITS),
|
||||
&flt->type_mask))
|
||||
continue;
|
||||
|
||||
if (bt_cb(skb)->pkt_type == HCI_EVENT_PKT) {
|
||||
register int evt = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS);
|
||||
int evt = (*(__u8 *)skb->data & HCI_FLT_EVENT_BITS);
|
||||
|
||||
if (!hci_test_bit(evt, &flt->event_mask))
|
||||
continue;
|
||||
|
@ -240,7 +223,8 @@ void hci_send_to_monitor(struct hci_dev *hdev, struct sk_buff *skb)
|
|||
struct hci_mon_hdr *hdr;
|
||||
|
||||
/* Create a private copy with headroom */
|
||||
skb_copy = __pskb_copy(skb, HCI_MON_HDR_SIZE, GFP_ATOMIC);
|
||||
skb_copy = __pskb_copy(skb, HCI_MON_HDR_SIZE,
|
||||
GFP_ATOMIC);
|
||||
if (!skb_copy)
|
||||
continue;
|
||||
|
||||
|
@ -495,7 +479,8 @@ static int hci_sock_blacklist_del(struct hci_dev *hdev, void __user *arg)
|
|||
}
|
||||
|
||||
/* Ioctls that require bound socket */
|
||||
static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsigned long arg)
|
||||
static int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct hci_dev *hdev = hci_pi(sk)->hdev;
|
||||
|
||||
|
@ -540,7 +525,8 @@ static inline int hci_sock_bound_ioctl(struct sock *sk, unsigned int cmd, unsign
|
|||
}
|
||||
}
|
||||
|
||||
static int hci_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
|
||||
static int hci_sock_ioctl(struct socket *sock, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
void __user *argp = (void __user *) arg;
|
||||
|
@ -601,7 +587,8 @@ 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)
|
||||
static int hci_sock_bind(struct socket *sock, struct sockaddr *addr,
|
||||
int addr_len)
|
||||
{
|
||||
struct sockaddr_hci haddr;
|
||||
struct sock *sk = sock->sk;
|
||||
|
@ -690,7 +677,8 @@ done:
|
|||
return err;
|
||||
}
|
||||
|
||||
static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, int *addr_len, int peer)
|
||||
static int hci_sock_getname(struct socket *sock, struct sockaddr *addr,
|
||||
int *addr_len, int peer)
|
||||
{
|
||||
struct sockaddr_hci *haddr = (struct sockaddr_hci *) addr;
|
||||
struct sock *sk = sock->sk;
|
||||
|
@ -711,13 +699,15 @@ static int hci_sock_getname(struct socket *sock, struct sockaddr *addr, int *add
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_buff *skb)
|
||||
static void hci_sock_cmsg(struct sock *sk, struct msghdr *msg,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
__u32 mask = hci_pi(sk)->cmsg_mask;
|
||||
|
||||
if (mask & HCI_CMSG_DIR) {
|
||||
int incoming = bt_cb(skb)->incoming;
|
||||
put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(incoming), &incoming);
|
||||
put_cmsg(msg, SOL_HCI, HCI_CMSG_DIR, sizeof(incoming),
|
||||
&incoming);
|
||||
}
|
||||
|
||||
if (mask & HCI_CMSG_TSTAMP) {
|
||||
|
@ -857,7 +847,8 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
|
|||
u16 ocf = hci_opcode_ocf(opcode);
|
||||
|
||||
if (((ogf > HCI_SFLT_MAX_OGF) ||
|
||||
!hci_test_bit(ocf & HCI_FLT_OCF_BITS, &hci_sec_filter.ocf_mask[ogf])) &&
|
||||
!hci_test_bit(ocf & HCI_FLT_OCF_BITS,
|
||||
&hci_sec_filter.ocf_mask[ogf])) &&
|
||||
!capable(CAP_NET_RAW)) {
|
||||
err = -EPERM;
|
||||
goto drop;
|
||||
|
@ -891,7 +882,8 @@ drop:
|
|||
goto done;
|
||||
}
|
||||
|
||||
static int hci_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int len)
|
||||
static int hci_sock_setsockopt(struct socket *sock, int level, int optname,
|
||||
char __user *optval, unsigned int len)
|
||||
{
|
||||
struct hci_ufilter uf = { .opcode = 0 };
|
||||
struct sock *sk = sock->sk;
|
||||
|
@ -973,7 +965,8 @@ done:
|
|||
return err;
|
||||
}
|
||||
|
||||
static int hci_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
|
||||
static int hci_sock_getsockopt(struct socket *sock, int level, int optname,
|
||||
char __user *optval, int __user *optlen)
|
||||
{
|
||||
struct hci_ufilter uf;
|
||||
struct sock *sk = sock->sk;
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
/* Bluetooth HCI driver model support. */
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
|
@ -31,19 +27,22 @@ static inline char *link_typetostr(int type)
|
|||
}
|
||||
}
|
||||
|
||||
static ssize_t show_link_type(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_link_type(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_conn *conn = to_hci_conn(dev);
|
||||
return sprintf(buf, "%s\n", link_typetostr(conn->type));
|
||||
}
|
||||
|
||||
static ssize_t show_link_address(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_link_address(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_conn *conn = to_hci_conn(dev);
|
||||
return sprintf(buf, "%s\n", batostr(&conn->dst));
|
||||
}
|
||||
|
||||
static ssize_t show_link_features(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_link_features(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_conn *conn = to_hci_conn(dev);
|
||||
|
||||
|
@ -185,19 +184,22 @@ static inline char *host_typetostr(int type)
|
|||
}
|
||||
}
|
||||
|
||||
static ssize_t show_bus(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_bus(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
return sprintf(buf, "%s\n", host_bustostr(hdev->bus));
|
||||
}
|
||||
|
||||
static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_type(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
return sprintf(buf, "%s\n", host_typetostr(hdev->dev_type));
|
||||
}
|
||||
|
||||
static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_name(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
char name[HCI_MAX_NAME_LENGTH + 1];
|
||||
|
@ -210,20 +212,23 @@ static ssize_t show_name(struct device *dev, struct device_attribute *attr, char
|
|||
return sprintf(buf, "%s\n", name);
|
||||
}
|
||||
|
||||
static ssize_t show_class(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_class(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
return sprintf(buf, "0x%.2x%.2x%.2x\n",
|
||||
hdev->dev_class[2], hdev->dev_class[1], hdev->dev_class[0]);
|
||||
return sprintf(buf, "0x%.2x%.2x%.2x\n", hdev->dev_class[2],
|
||||
hdev->dev_class[1], hdev->dev_class[0]);
|
||||
}
|
||||
|
||||
static ssize_t show_address(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_address(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
return sprintf(buf, "%s\n", batostr(&hdev->bdaddr));
|
||||
}
|
||||
|
||||
static ssize_t show_features(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_features(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
|
||||
|
@ -234,31 +239,37 @@ static ssize_t show_features(struct device *dev, struct device_attribute *attr,
|
|||
hdev->features[6], hdev->features[7]);
|
||||
}
|
||||
|
||||
static ssize_t show_manufacturer(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_manufacturer(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
return sprintf(buf, "%d\n", hdev->manufacturer);
|
||||
}
|
||||
|
||||
static ssize_t show_hci_version(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_hci_version(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
return sprintf(buf, "%d\n", hdev->hci_ver);
|
||||
}
|
||||
|
||||
static ssize_t show_hci_revision(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_hci_revision(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
return sprintf(buf, "%d\n", hdev->hci_rev);
|
||||
}
|
||||
|
||||
static ssize_t show_idle_timeout(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_idle_timeout(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
return sprintf(buf, "%d\n", hdev->idle_timeout);
|
||||
}
|
||||
|
||||
static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
static ssize_t store_idle_timeout(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
unsigned int val;
|
||||
|
@ -276,13 +287,16 @@ static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *a
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_sniff_max_interval(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_sniff_max_interval(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
return sprintf(buf, "%d\n", hdev->sniff_max_interval);
|
||||
}
|
||||
|
||||
static ssize_t store_sniff_max_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
static ssize_t store_sniff_max_interval(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
u16 val;
|
||||
|
@ -300,13 +314,16 @@ static ssize_t store_sniff_max_interval(struct device *dev, struct device_attrib
|
|||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_sniff_min_interval(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
static ssize_t show_sniff_min_interval(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
return sprintf(buf, "%d\n", hdev->sniff_min_interval);
|
||||
}
|
||||
|
||||
static ssize_t store_sniff_min_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
|
||||
static ssize_t store_sniff_min_interval(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct hci_dev *hdev = to_hci_dev(dev);
|
||||
u16 val;
|
||||
|
@ -455,8 +472,8 @@ static void print_bt_uuid(struct seq_file *f, u8 *uuid)
|
|||
memcpy(&data5, &uuid[14], 2);
|
||||
|
||||
seq_printf(f, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x\n",
|
||||
ntohl(data0), ntohs(data1), ntohs(data2),
|
||||
ntohs(data3), ntohl(data4), ntohs(data5));
|
||||
ntohl(data0), ntohs(data1), ntohs(data2), ntohs(data3),
|
||||
ntohl(data4), ntohs(data5));
|
||||
}
|
||||
|
||||
static int uuids_show(struct seq_file *f, void *p)
|
||||
|
|
|
@ -21,27 +21,8 @@
|
|||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/freezer.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
#include <linux/input.h>
|
||||
#include <linux/hid.h>
|
||||
#include <linux/hidraw.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
|
@ -244,7 +225,8 @@ static void hidp_input_report(struct hidp_session *session, struct sk_buff *skb)
|
|||
}
|
||||
|
||||
static int __hidp_send_ctrl_message(struct hidp_session *session,
|
||||
unsigned char hdr, unsigned char *data, int size)
|
||||
unsigned char hdr, unsigned char *data,
|
||||
int size)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
|
@ -268,7 +250,7 @@ static int __hidp_send_ctrl_message(struct hidp_session *session,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int hidp_send_ctrl_message(struct hidp_session *session,
|
||||
static int hidp_send_ctrl_message(struct hidp_session *session,
|
||||
unsigned char hdr, unsigned char *data, int size)
|
||||
{
|
||||
int err;
|
||||
|
@ -471,7 +453,7 @@ static void hidp_set_timer(struct hidp_session *session)
|
|||
mod_timer(&session->timer, jiffies + HZ * session->idle_to);
|
||||
}
|
||||
|
||||
static inline void hidp_del_timer(struct hidp_session *session)
|
||||
static void hidp_del_timer(struct hidp_session *session)
|
||||
{
|
||||
if (session->idle_to > 0)
|
||||
del_timer(&session->timer);
|
||||
|
|
|
@ -20,22 +20,8 @@
|
|||
SOFTWARE IS DISCLAIMED.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/file.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/compat.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
#include "hidp.h"
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -27,7 +27,6 @@
|
|||
|
||||
/* Bluetooth L2CAP sockets. */
|
||||
|
||||
#include <linux/security.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
|
@ -89,8 +88,8 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
|
|||
if (err < 0)
|
||||
goto done;
|
||||
|
||||
if (__le16_to_cpu(la.l2_psm) == 0x0001 ||
|
||||
__le16_to_cpu(la.l2_psm) == 0x0003)
|
||||
if (__le16_to_cpu(la.l2_psm) == L2CAP_PSM_SDP ||
|
||||
__le16_to_cpu(la.l2_psm) == L2CAP_PSM_RFCOMM)
|
||||
chan->sec_level = BT_SECURITY_SDP;
|
||||
|
||||
bacpy(&bt_sk(sk)->src, &la.l2_bdaddr);
|
||||
|
@ -446,6 +445,22 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
|
|||
return err;
|
||||
}
|
||||
|
||||
static bool l2cap_valid_mtu(struct l2cap_chan *chan, u16 mtu)
|
||||
{
|
||||
switch (chan->scid) {
|
||||
case L2CAP_CID_LE_DATA:
|
||||
if (mtu < L2CAP_LE_MIN_MTU)
|
||||
return false;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (mtu < L2CAP_DEFAULT_MIN_MTU)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
|
@ -484,6 +499,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
|
|||
break;
|
||||
}
|
||||
|
||||
if (!l2cap_valid_mtu(chan, opts.imtu)) {
|
||||
err = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
chan->mode = opts.mode;
|
||||
switch (chan->mode) {
|
||||
case L2CAP_MODE_BASIC:
|
||||
|
@ -873,9 +893,34 @@ static int l2cap_sock_release(struct socket *sock)
|
|||
return err;
|
||||
}
|
||||
|
||||
static struct l2cap_chan *l2cap_sock_new_connection_cb(void *data)
|
||||
static void l2cap_sock_cleanup_listen(struct sock *parent)
|
||||
{
|
||||
struct sock *sk, *parent = data;
|
||||
struct sock *sk;
|
||||
|
||||
BT_DBG("parent %p", parent);
|
||||
|
||||
/* Close not yet accepted channels */
|
||||
while ((sk = bt_accept_dequeue(parent, NULL))) {
|
||||
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
|
||||
|
||||
l2cap_chan_lock(chan);
|
||||
__clear_chan_timer(chan);
|
||||
l2cap_chan_close(chan, ECONNRESET);
|
||||
l2cap_chan_unlock(chan);
|
||||
|
||||
l2cap_sock_kill(sk);
|
||||
}
|
||||
}
|
||||
|
||||
static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan)
|
||||
{
|
||||
struct sock *sk, *parent = chan->data;
|
||||
|
||||
/* Check for backlog size */
|
||||
if (sk_acceptq_is_full(parent)) {
|
||||
BT_DBG("backlog full %d", parent->sk_ack_backlog);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP,
|
||||
GFP_ATOMIC);
|
||||
|
@ -889,10 +934,10 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(void *data)
|
|||
return l2cap_pi(sk)->chan;
|
||||
}
|
||||
|
||||
static int l2cap_sock_recv_cb(void *data, struct sk_buff *skb)
|
||||
static int l2cap_sock_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
|
||||
{
|
||||
int err;
|
||||
struct sock *sk = data;
|
||||
struct sock *sk = chan->data;
|
||||
struct l2cap_pinfo *pi = l2cap_pi(sk);
|
||||
|
||||
lock_sock(sk);
|
||||
|
@ -925,16 +970,57 @@ done:
|
|||
return err;
|
||||
}
|
||||
|
||||
static void l2cap_sock_close_cb(void *data)
|
||||
static void l2cap_sock_close_cb(struct l2cap_chan *chan)
|
||||
{
|
||||
struct sock *sk = data;
|
||||
struct sock *sk = chan->data;
|
||||
|
||||
l2cap_sock_kill(sk);
|
||||
}
|
||||
|
||||
static void l2cap_sock_state_change_cb(void *data, int state)
|
||||
static void l2cap_sock_teardown_cb(struct l2cap_chan *chan, int err)
|
||||
{
|
||||
struct sock *sk = data;
|
||||
struct sock *sk = chan->data;
|
||||
struct sock *parent;
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
parent = bt_sk(sk)->parent;
|
||||
|
||||
sock_set_flag(sk, SOCK_ZAPPED);
|
||||
|
||||
switch (chan->state) {
|
||||
case BT_OPEN:
|
||||
case BT_BOUND:
|
||||
case BT_CLOSED:
|
||||
break;
|
||||
case BT_LISTEN:
|
||||
l2cap_sock_cleanup_listen(sk);
|
||||
sk->sk_state = BT_CLOSED;
|
||||
chan->state = BT_CLOSED;
|
||||
|
||||
break;
|
||||
default:
|
||||
sk->sk_state = BT_CLOSED;
|
||||
chan->state = BT_CLOSED;
|
||||
|
||||
sk->sk_err = err;
|
||||
|
||||
if (parent) {
|
||||
bt_accept_unlink(sk);
|
||||
parent->sk_data_ready(parent, 0);
|
||||
} else {
|
||||
sk->sk_state_change(sk);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
release_sock(sk);
|
||||
}
|
||||
|
||||
static void l2cap_sock_state_change_cb(struct l2cap_chan *chan, int state)
|
||||
{
|
||||
struct sock *sk = chan->data;
|
||||
|
||||
sk->sk_state = state;
|
||||
}
|
||||
|
@ -955,12 +1041,34 @@ static struct sk_buff *l2cap_sock_alloc_skb_cb(struct l2cap_chan *chan,
|
|||
return skb;
|
||||
}
|
||||
|
||||
static void l2cap_sock_ready_cb(struct l2cap_chan *chan)
|
||||
{
|
||||
struct sock *sk = chan->data;
|
||||
struct sock *parent;
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
parent = bt_sk(sk)->parent;
|
||||
|
||||
BT_DBG("sk %p, parent %p", sk, parent);
|
||||
|
||||
sk->sk_state = BT_CONNECTED;
|
||||
sk->sk_state_change(sk);
|
||||
|
||||
if (parent)
|
||||
parent->sk_data_ready(parent, 0);
|
||||
|
||||
release_sock(sk);
|
||||
}
|
||||
|
||||
static struct l2cap_ops l2cap_chan_ops = {
|
||||
.name = "L2CAP Socket Interface",
|
||||
.new_connection = l2cap_sock_new_connection_cb,
|
||||
.recv = l2cap_sock_recv_cb,
|
||||
.close = l2cap_sock_close_cb,
|
||||
.teardown = l2cap_sock_teardown_cb,
|
||||
.state_change = l2cap_sock_state_change_cb,
|
||||
.ready = l2cap_sock_ready_cb,
|
||||
.alloc_skb = l2cap_sock_alloc_skb_cb,
|
||||
};
|
||||
|
||||
|
|
|
@ -26,12 +26,7 @@
|
|||
|
||||
#define pr_fmt(fmt) "Bluetooth: " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/string.h>
|
||||
#include <asm/errno.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
|
||||
|
|
|
@ -24,8 +24,6 @@
|
|||
|
||||
/* Bluetooth HCI Management interface */
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
|
@ -714,7 +712,8 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
|
|||
}
|
||||
|
||||
static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
|
||||
void (*cb)(struct pending_cmd *cmd, void *data),
|
||||
void (*cb)(struct pending_cmd *cmd,
|
||||
void *data),
|
||||
void *data)
|
||||
{
|
||||
struct list_head *p, *n;
|
||||
|
@ -1594,7 +1593,8 @@ static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
|
|||
}
|
||||
|
||||
if (cp->addr.type == BDADDR_BREDR)
|
||||
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
|
||||
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
|
||||
&cp->addr.bdaddr);
|
||||
else
|
||||
conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
|
||||
|
||||
|
@ -1821,7 +1821,7 @@ static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
|
|||
0);
|
||||
}
|
||||
|
||||
static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
|
||||
static struct pending_cmd *find_pairing(struct hci_conn *conn)
|
||||
{
|
||||
struct hci_dev *hdev = conn->hdev;
|
||||
struct pending_cmd *cmd;
|
||||
|
@ -1911,8 +1911,15 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
|
|||
rp.addr.type = cp->addr.type;
|
||||
|
||||
if (IS_ERR(conn)) {
|
||||
int status;
|
||||
|
||||
if (PTR_ERR(conn) == -EBUSY)
|
||||
status = MGMT_STATUS_BUSY;
|
||||
else
|
||||
status = MGMT_STATUS_CONNECT_FAILED;
|
||||
|
||||
err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
|
||||
MGMT_STATUS_CONNECT_FAILED, &rp,
|
||||
status, &rp,
|
||||
sizeof(rp));
|
||||
goto unlock;
|
||||
}
|
||||
|
@ -2955,7 +2962,7 @@ int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
|
|||
bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
|
||||
ev.key.addr.type = BDADDR_BREDR;
|
||||
ev.key.type = key->type;
|
||||
memcpy(ev.key.val, key->val, 16);
|
||||
memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
|
||||
ev.key.pin_len = key->pin_len;
|
||||
|
||||
return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
|
||||
|
@ -3226,7 +3233,8 @@ int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
|||
u8 link_type, u8 addr_type, u8 status)
|
||||
{
|
||||
return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
|
||||
status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
|
||||
status,
|
||||
MGMT_OP_USER_CONFIRM_NEG_REPLY);
|
||||
}
|
||||
|
||||
int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
||||
|
@ -3240,7 +3248,8 @@ int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
|||
u8 link_type, u8 addr_type, u8 status)
|
||||
{
|
||||
return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
|
||||
status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
|
||||
status,
|
||||
MGMT_OP_USER_PASSKEY_NEG_REPLY);
|
||||
}
|
||||
|
||||
int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
|
||||
|
|
|
@ -26,22 +26,8 @@
|
|||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/net.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <net/sock.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
|
@ -115,14 +101,14 @@ static void rfcomm_session_del(struct rfcomm_session *s);
|
|||
#define __get_rpn_stop_bits(line) (((line) >> 2) & 0x1)
|
||||
#define __get_rpn_parity(line) (((line) >> 3) & 0x7)
|
||||
|
||||
static inline void rfcomm_schedule(void)
|
||||
static void rfcomm_schedule(void)
|
||||
{
|
||||
if (!rfcomm_thread)
|
||||
return;
|
||||
wake_up_process(rfcomm_thread);
|
||||
}
|
||||
|
||||
static inline void rfcomm_session_put(struct rfcomm_session *s)
|
||||
static void rfcomm_session_put(struct rfcomm_session *s)
|
||||
{
|
||||
if (atomic_dec_and_test(&s->refcnt))
|
||||
rfcomm_session_del(s);
|
||||
|
@ -227,7 +213,7 @@ static int rfcomm_l2sock_create(struct socket **sock)
|
|||
return err;
|
||||
}
|
||||
|
||||
static inline int rfcomm_check_security(struct rfcomm_dlc *d)
|
||||
static int rfcomm_check_security(struct rfcomm_dlc *d)
|
||||
{
|
||||
struct sock *sk = d->session->sock->sk;
|
||||
struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn;
|
||||
|
@ -1750,7 +1736,7 @@ static void rfcomm_process_connect(struct rfcomm_session *s)
|
|||
/* Send data queued for the DLC.
|
||||
* Return number of frames left in the queue.
|
||||
*/
|
||||
static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
|
||||
static int rfcomm_process_tx(struct rfcomm_dlc *d)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int err;
|
||||
|
@ -1798,7 +1784,7 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
|
|||
return skb_queue_len(&d->tx_queue);
|
||||
}
|
||||
|
||||
static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
|
||||
static void rfcomm_process_dlcs(struct rfcomm_session *s)
|
||||
{
|
||||
struct rfcomm_dlc *d;
|
||||
struct list_head *p, *n;
|
||||
|
@ -1858,7 +1844,7 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
|
|||
}
|
||||
}
|
||||
|
||||
static inline void rfcomm_process_rx(struct rfcomm_session *s)
|
||||
static void rfcomm_process_rx(struct rfcomm_session *s)
|
||||
{
|
||||
struct socket *sock = s->sock;
|
||||
struct sock *sk = sock->sk;
|
||||
|
@ -1883,7 +1869,7 @@ static inline void rfcomm_process_rx(struct rfcomm_session *s)
|
|||
}
|
||||
}
|
||||
|
||||
static inline void rfcomm_accept_connection(struct rfcomm_session *s)
|
||||
static void rfcomm_accept_connection(struct rfcomm_session *s)
|
||||
{
|
||||
struct socket *sock = s->sock, *nsock;
|
||||
int err;
|
||||
|
@ -1917,7 +1903,7 @@ static inline void rfcomm_accept_connection(struct rfcomm_session *s)
|
|||
sock_release(nsock);
|
||||
}
|
||||
|
||||
static inline void rfcomm_check_connection(struct rfcomm_session *s)
|
||||
static void rfcomm_check_connection(struct rfcomm_session *s)
|
||||
{
|
||||
struct sock *sk = s->sock->sk;
|
||||
|
||||
|
@ -1941,7 +1927,7 @@ static inline void rfcomm_check_connection(struct rfcomm_session *s)
|
|||
}
|
||||
}
|
||||
|
||||
static inline void rfcomm_process_sessions(void)
|
||||
static void rfcomm_process_sessions(void)
|
||||
{
|
||||
struct list_head *p, *n;
|
||||
|
||||
|
|
|
@ -25,27 +25,8 @@
|
|||
* RFCOMM sockets.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/security.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
|
|
|
@ -31,11 +31,6 @@
|
|||
#include <linux/tty_driver.h>
|
||||
#include <linux/tty_flip.h>
|
||||
|
||||
#include <linux/capability.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
#include <net/bluetooth/rfcomm.h>
|
||||
|
@ -132,7 +127,7 @@ static struct rfcomm_dev *__rfcomm_dev_get(int id)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static inline struct rfcomm_dev *rfcomm_dev_get(int id)
|
||||
static struct rfcomm_dev *rfcomm_dev_get(int id)
|
||||
{
|
||||
struct rfcomm_dev *dev;
|
||||
|
||||
|
@ -345,7 +340,7 @@ static void rfcomm_wfree(struct sk_buff *skb)
|
|||
tty_port_put(&dev->port);
|
||||
}
|
||||
|
||||
static inline void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev)
|
||||
static void rfcomm_set_owner_w(struct sk_buff *skb, struct rfcomm_dev *dev)
|
||||
{
|
||||
tty_port_get(&dev->port);
|
||||
atomic_add(skb->truesize, &dev->wmem_alloc);
|
||||
|
|
|
@ -25,26 +25,8 @@
|
|||
/* Bluetooth SCO sockets. */
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/security.h>
|
||||
#include <net/sock.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
|
@ -123,7 +105,7 @@ static struct sco_conn *sco_conn_add(struct hci_conn *hcon)
|
|||
return conn;
|
||||
}
|
||||
|
||||
static inline struct sock *sco_chan_get(struct sco_conn *conn)
|
||||
static struct sock *sco_chan_get(struct sco_conn *conn)
|
||||
{
|
||||
struct sock *sk = NULL;
|
||||
sco_conn_lock(conn);
|
||||
|
@ -157,7 +139,8 @@ static int sco_conn_del(struct hci_conn *hcon, int err)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int sco_chan_add(struct sco_conn *conn, struct sock *sk, struct sock *parent)
|
||||
static int sco_chan_add(struct sco_conn *conn, struct sock *sk,
|
||||
struct sock *parent)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
|
@ -228,7 +211,7 @@ done:
|
|||
return err;
|
||||
}
|
||||
|
||||
static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
|
||||
static int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
|
||||
{
|
||||
struct sco_conn *conn = sco_pi(sk)->conn;
|
||||
struct sk_buff *skb;
|
||||
|
@ -254,7 +237,7 @@ static inline int sco_send_frame(struct sock *sk, struct msghdr *msg, int len)
|
|||
return len;
|
||||
}
|
||||
|
||||
static inline void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
|
||||
static void sco_recv_frame(struct sco_conn *conn, struct sk_buff *skb)
|
||||
{
|
||||
struct sock *sk = sco_chan_get(conn);
|
||||
|
||||
|
@ -907,7 +890,7 @@ done:
|
|||
/* ----- SCO interface with lower layer (HCI) ----- */
|
||||
int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
|
||||
{
|
||||
register struct sock *sk;
|
||||
struct sock *sk;
|
||||
struct hlist_node *node;
|
||||
int lm = 0;
|
||||
|
||||
|
@ -1044,8 +1027,8 @@ int __init sco_init(void)
|
|||
}
|
||||
|
||||
if (bt_debugfs) {
|
||||
sco_debugfs = debugfs_create_file("sco", 0444,
|
||||
bt_debugfs, NULL, &sco_debugfs_fops);
|
||||
sco_debugfs = debugfs_create_file("sco", 0444, bt_debugfs,
|
||||
NULL, &sco_debugfs_fops);
|
||||
if (!sco_debugfs)
|
||||
BT_ERR("Failed to create SCO debug file");
|
||||
}
|
||||
|
|
|
@ -20,14 +20,15 @@
|
|||
SOFTWARE IS DISCLAIMED.
|
||||
*/
|
||||
|
||||
#include <linux/crypto.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <crypto/b128ops.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
#include <net/bluetooth/l2cap.h>
|
||||
#include <net/bluetooth/mgmt.h>
|
||||
#include <net/bluetooth/smp.h>
|
||||
#include <linux/crypto.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <crypto/b128ops.h>
|
||||
|
||||
#define SMP_TIMEOUT msecs_to_jiffies(30000)
|
||||
|
||||
|
|
Loading…
Reference in New Issue