Commit 312fef7d authored by John W. Linville's avatar John W. Linville

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/padovan/bluetooth-next

Conflicts:
	net/bluetooth/l2cap_sock.c
	net/bluetooth/mgmt.c
parents 5e819059 2aeabcbe
......@@ -30,6 +30,7 @@
#include <net/bluetooth/bluetooth.h>
#define VERSION "1.0"
#define ATH3K_FIRMWARE "ath3k-1.fw"
#define ATH3K_DNLOAD 0x01
#define ATH3K_GETSTATE 0x05
......@@ -400,9 +401,15 @@ static int ath3k_probe(struct usb_interface *intf,
return 0;
}
if (request_firmware(&firmware, "ath3k-1.fw", &udev->dev) < 0) {
BT_ERR("Error loading firmware");
return -EIO;
ret = request_firmware(&firmware, ATH3K_FIRMWARE, &udev->dev);
if (ret < 0) {
if (ret == -ENOENT)
BT_ERR("Firmware file \"%s\" not found",
ATH3K_FIRMWARE);
else
BT_ERR("Firmware file \"%s\" request failed (err=%d)",
ATH3K_FIRMWARE, ret);
return ret;
}
ret = ath3k_load_firmware(udev, firmware);
......@@ -441,4 +448,4 @@ MODULE_AUTHOR("Atheros Communications");
MODULE_DESCRIPTION("Atheros AR30xx firmware driver");
MODULE_VERSION(VERSION);
MODULE_LICENSE("GPL");
MODULE_FIRMWARE("ath3k-1.fw");
MODULE_FIRMWARE(ATH3K_FIRMWARE);
......@@ -751,9 +751,7 @@ static void bfusb_disconnect(struct usb_interface *intf)
bfusb_close(hdev);
if (hci_unregister_dev(hdev) < 0)
BT_ERR("Can't unregister HCI device %s", hdev->name);
hci_unregister_dev(hdev);
hci_free_dev(hdev);
}
......
......@@ -844,9 +844,7 @@ static int bluecard_close(bluecard_info_t *info)
/* Turn FPGA off */
outb(0x80, iobase + 0x30);
if (hci_unregister_dev(hdev) < 0)
BT_ERR("Can't unregister HCI device %s", hdev->name);
hci_unregister_dev(hdev);
hci_free_dev(hdev);
return 0;
......
......@@ -636,9 +636,7 @@ static int bt3c_close(bt3c_info_t *info)
bt3c_hci_close(hdev);
if (hci_unregister_dev(hdev) < 0)
BT_ERR("Can't unregister HCI device %s", hdev->name);
hci_unregister_dev(hdev);
hci_free_dev(hdev);
return 0;
......
......@@ -565,9 +565,7 @@ static int btuart_close(btuart_info_t *info)
spin_unlock_irqrestore(&(info->lock), flags);
if (hci_unregister_dev(hdev) < 0)
BT_ERR("Can't unregister HCI device %s", hdev->name);
hci_unregister_dev(hdev);
hci_free_dev(hdev);
return 0;
......
......@@ -315,6 +315,7 @@ static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags)
err = usb_submit_urb(urb, mem_flags);
if (err < 0) {
if (err != -EPERM && err != -ENODEV)
BT_ERR("%s urb %p submission failed (%d)",
hdev->name, urb, -err);
usb_unanchor_urb(urb);
......@@ -400,6 +401,7 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags)
err = usb_submit_urb(urb, mem_flags);
if (err < 0) {
if (err != -EPERM && err != -ENODEV)
BT_ERR("%s urb %p submission failed (%d)",
hdev->name, urb, -err);
usb_unanchor_urb(urb);
......@@ -523,6 +525,7 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags)
err = usb_submit_urb(urb, mem_flags);
if (err < 0) {
if (err != -EPERM && err != -ENODEV)
BT_ERR("%s urb %p submission failed (%d)",
hdev->name, urb, -err);
usb_unanchor_urb(urb);
......@@ -727,6 +730,9 @@ static int btusb_send_frame(struct sk_buff *skb)
usb_fill_bulk_urb(urb, data->udev, pipe,
skb->data, skb->len, btusb_tx_complete, skb);
if (skb->priority >= HCI_PRIO_MAX - 1)
urb->transfer_flags = URB_ISO_ASAP;
hdev->stat.acl_tx++;
break;
......@@ -770,7 +776,9 @@ static int btusb_send_frame(struct sk_buff *skb)
err = usb_submit_urb(urb, GFP_ATOMIC);
if (err < 0) {
BT_ERR("%s urb %p submission failed", hdev->name, urb);
if (err != -EPERM && err != -ENODEV)
BT_ERR("%s urb %p submission failed (%d)",
hdev->name, urb, -err);
kfree(urb->setup_packet);
usb_unanchor_urb(urb);
} else {
......
......@@ -551,9 +551,7 @@ static int dtl1_close(dtl1_info_t *info)
spin_unlock_irqrestore(&(info->lock), flags);
if (hci_unregister_dev(hdev) < 0)
BT_ERR("Can't unregister HCI device %s", hdev->name);
hci_unregister_dev(hdev);
hci_free_dev(hdev);
return 0;
......
......@@ -264,10 +264,7 @@ static int vhci_release(struct inode *inode, struct file *file)
struct vhci_data *data = file->private_data;
struct hci_dev *hdev = data->hdev;
if (hci_unregister_dev(hdev) < 0) {
BT_ERR("Can't unregister HCI device %s", hdev->name);
}
hci_unregister_dev(hdev);
hci_free_dev(hdev);
file->private_data = NULL;
......
......@@ -77,6 +77,33 @@ struct bt_power {
#define BT_POWER_FORCE_ACTIVE_OFF 0
#define BT_POWER_FORCE_ACTIVE_ON 1
#define BT_CHANNEL_POLICY 10
/* BR/EDR only (default policy)
* AMP controllers cannot be used.
* Channel move requests from the remote device are denied.
* If the L2CAP channel is currently using AMP, move the channel to BR/EDR.
*/
#define BT_CHANNEL_POLICY_BREDR_ONLY 0
/* BR/EDR Preferred
* Allow use of AMP controllers.
* If the L2CAP channel is currently on AMP, move it to BR/EDR.
* Channel move requests from the remote device are allowed.
*/
#define BT_CHANNEL_POLICY_BREDR_PREFERRED 1
/* AMP Preferred
* Allow use of AMP controllers
* If the L2CAP channel is currently on BR/EDR and AMP controller
* resources are available, initiate a channel move to AMP.
* Channel move requests from the remote device are allowed.
* If the L2CAP socket has not been connected yet, try to create
* and configure the channel directly on an AMP controller rather
* than BR/EDR.
*/
#define BT_CHANNEL_POLICY_AMP_PREFERRED 2
__attribute__((format (printf, 2, 3)))
int bt_printk(const char *level, const char *fmt, ...);
......@@ -158,7 +185,7 @@ struct bt_skb_cb {
__u8 pkt_type;
__u8 incoming;
__u16 expect;
__u8 tx_seq;
__u16 tx_seq;
__u8 retries;
__u8 sar;
unsigned short channel;
......
......@@ -264,6 +264,13 @@ enum {
#define HCI_LK_SMP_IRK 0x82
#define HCI_LK_SMP_CSRK 0x83
/* ---- HCI Error Codes ---- */
#define HCI_ERROR_AUTH_FAILURE 0x05
#define HCI_ERROR_REJ_BAD_ADDR 0x0f
#define HCI_ERROR_REMOTE_USER_TERM 0x13
#define HCI_ERROR_LOCAL_HOST_TERM 0x16
#define HCI_ERROR_PAIRING_NOT_ALLOWED 0x18
/* ----- HCI Commands ---- */
#define HCI_OP_NOP 0x0000
......@@ -726,6 +733,21 @@ struct hci_cp_write_page_scan_activity {
#define PAGE_SCAN_TYPE_STANDARD 0x00
#define PAGE_SCAN_TYPE_INTERLACED 0x01
#define HCI_OP_READ_LOCAL_AMP_INFO 0x1409
struct hci_rp_read_local_amp_info {
__u8 status;
__u8 amp_status;
__le32 total_bw;
__le32 max_bw;
__le32 min_latency;
__le32 max_pdu;
__u8 amp_type;
__le16 pal_cap;
__le16 max_assoc_size;
__le32 max_flush_to;
__le32 be_flush_to;
} __packed;
#define HCI_OP_LE_SET_EVENT_MASK 0x2001
struct hci_cp_le_set_event_mask {
__u8 mask[8];
......
......@@ -32,6 +32,9 @@
#define HCI_PROTO_L2CAP 0
#define HCI_PROTO_SCO 1
/* HCI priority */
#define HCI_PRIO_MAX 7
/* HCI Core structures */
struct inquiry_data {
bdaddr_t bdaddr;
......@@ -64,6 +67,12 @@ struct hci_conn_hash {
unsigned int le_num;
};
struct hci_chan_hash {
struct list_head list;
spinlock_t lock;
unsigned int num;
};
struct bdaddr_list {
struct list_head list;
bdaddr_t bdaddr;
......@@ -150,6 +159,17 @@ struct hci_dev {
__u16 sniff_min_interval;
__u16 sniff_max_interval;
__u8 amp_status;
__u32 amp_total_bw;
__u32 amp_max_bw;
__u32 amp_min_latency;
__u32 amp_max_pdu;
__u8 amp_type;
__u16 amp_pal_cap;
__u16 amp_assoc_size;
__u32 amp_max_flush_to;
__u32 amp_be_flush_to;
unsigned int auto_accept_delay;
unsigned long quirks;
......@@ -173,8 +193,10 @@ struct hci_dev {
struct workqueue_struct *workqueue;
struct work_struct power_on;
struct work_struct power_off;
struct timer_list off_timer;
struct delayed_work power_off;
__u16 discov_timeout;
struct delayed_work discov_off;
struct timer_list cmd_timer;
struct tasklet_struct cmd_task;
......@@ -195,6 +217,8 @@ struct hci_dev {
__u16 init_last_cmd;
struct list_head mgmt_pending;
struct inquiry_cache inq_cache;
struct hci_conn_hash conn_hash;
struct list_head blacklist;
......@@ -273,6 +297,7 @@ struct hci_conn {
unsigned int sent;
struct sk_buff_head data_q;
struct hci_chan_hash chan_hash;
struct timer_list disc_timer;
struct timer_list idle_timer;
......@@ -295,6 +320,14 @@ struct hci_conn {
void (*disconn_cfm_cb) (struct hci_conn *conn, u8 reason);
};
struct hci_chan {
struct list_head list;
struct hci_conn *conn;
struct sk_buff_head data_q;
unsigned int sent;
};
extern struct hci_proto *hci_proto[];
extern struct list_head hci_dev_list;
extern struct list_head hci_cb_list;
......@@ -455,6 +488,28 @@ static inline struct hci_conn *hci_conn_hash_lookup_state(struct hci_dev *hdev,
return NULL;
}
static inline void hci_chan_hash_init(struct hci_conn *c)
{
struct hci_chan_hash *h = &c->chan_hash;
INIT_LIST_HEAD(&h->list);
spin_lock_init(&h->lock);
h->num = 0;
}
static inline void hci_chan_hash_add(struct hci_conn *c, struct hci_chan *chan)
{
struct hci_chan_hash *h = &c->chan_hash;
list_add(&chan->list, &h->list);
h->num++;
}
static inline void hci_chan_hash_del(struct hci_conn *c, struct hci_chan *chan)
{
struct hci_chan_hash *h = &c->chan_hash;
list_del(&chan->list);
h->num--;
}
void hci_acl_connect(struct hci_conn *conn);
void hci_acl_disconn(struct hci_conn *conn, __u8 reason);
void hci_add_sco(struct hci_conn *conn, __u16 handle);
......@@ -466,6 +521,10 @@ int hci_conn_del(struct hci_conn *conn);
void hci_conn_hash_flush(struct hci_dev *hdev);
void hci_conn_check_pending(struct hci_dev *hdev);
struct hci_chan *hci_chan_create(struct hci_conn *conn);
int hci_chan_del(struct hci_chan *chan);
void hci_chan_hash_flush(struct hci_conn *conn);
struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
__u8 sec_level, __u8 auth_type);
int hci_conn_check_link_mode(struct hci_conn *conn);
......@@ -543,7 +602,7 @@ struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
struct hci_dev *hci_alloc_dev(void);
void hci_free_dev(struct hci_dev *hdev);
int hci_register_dev(struct hci_dev *hdev);
int hci_unregister_dev(struct hci_dev *hdev);
void hci_unregister_dev(struct hci_dev *hdev);
int hci_suspend_dev(struct hci_dev *hdev);
int hci_resume_dev(struct hci_dev *hdev);
int hci_dev_open(__u16 dev);
......@@ -597,8 +656,9 @@ int hci_recv_frame(struct sk_buff *skb);
int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count);
int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count);
int hci_register_sysfs(struct hci_dev *hdev);
void hci_unregister_sysfs(struct hci_dev *hdev);
void hci_init_sysfs(struct hci_dev *hdev);
int hci_add_sysfs(struct hci_dev *hdev);
void hci_del_sysfs(struct hci_dev *hdev);
void hci_conn_init_sysfs(struct hci_conn *conn);
void hci_conn_add_sysfs(struct hci_conn *conn);
void hci_conn_del_sysfs(struct hci_conn *conn);
......@@ -674,7 +734,7 @@ static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status)
static inline int hci_proto_disconn_ind(struct hci_conn *conn)
{
register struct hci_proto *hp;
int reason = 0x13;
int reason = HCI_ERROR_REMOTE_USER_TERM;
hp = hci_proto[HCI_PROTO_L2CAP];
if (hp && hp->disconn_ind)
......@@ -834,7 +894,7 @@ int hci_register_notifier(struct notifier_block *nb);
int hci_unregister_notifier(struct notifier_block *nb);
int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen, void *param);
void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags);
void hci_send_sco(struct hci_conn *conn, struct sk_buff *skb);
void *hci_sent_cmd_data(struct hci_dev *hdev, __u16 opcode);
......@@ -847,34 +907,41 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb,
/* Management interface */
int mgmt_control(struct sock *sk, struct msghdr *msg, size_t len);
int mgmt_index_added(u16 index);
int mgmt_index_removed(u16 index);
int mgmt_powered(u16 index, u8 powered);
int mgmt_discoverable(u16 index, u8 discoverable);
int mgmt_connectable(u16 index, u8 connectable);
int mgmt_new_key(u16 index, struct link_key *key, u8 persistent);
int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type);
int mgmt_disconnected(u16 index, bdaddr_t *bdaddr);
int mgmt_disconnect_failed(u16 index);
int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status);
int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure);
int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
u8 confirm_hint);
int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status);
int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr,
int mgmt_index_added(struct hci_dev *hdev);
int mgmt_index_removed(struct hci_dev *hdev);
int mgmt_powered(struct hci_dev *hdev, u8 powered);
int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable);
int mgmt_connectable(struct hci_dev *hdev, u8 connectable);
int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status);
int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
u8 persistent);
int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
int mgmt_disconnect_failed(struct hci_dev *hdev);
int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
u8 status);
int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status);
int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status);
int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure);
int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 status);
int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
u8 *eir);
int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name);
int mgmt_discovering(u16 index, u8 discovering);
int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr);
int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr);
int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 status);
int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
__le32 value, u8 confirm_hint);
int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 status);
int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
bdaddr_t *bdaddr, u8 status);
int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status);
int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status);
int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
u8 *randomizer, u8 status);
int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
u8 *dev_class, s8 rssi, u8 *eir);
int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name);
int mgmt_inquiry_failed(struct hci_dev *hdev, u8 status);
int mgmt_discovering(struct hci_dev *hdev, u8 discovering);
int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr);
int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr);
/* HCI info for socket */
#define hci_pi(sk) ((struct hci_pinfo *) sk)
......@@ -913,4 +980,7 @@ void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
void hci_le_ltk_reply(struct hci_conn *conn, u8 ltk[16]);
void hci_le_ltk_neg_reply(struct hci_conn *conn);
int hci_do_inquiry(struct hci_dev *hdev, u8 length);
int hci_cancel_inquiry(struct hci_dev *hdev);
#endif /* __HCI_CORE_H */
......@@ -27,17 +27,23 @@
#ifndef __L2CAP_H
#define __L2CAP_H
#include <asm/unaligned.h>
/* L2CAP defaults */
#define L2CAP_DEFAULT_MTU 672
#define L2CAP_DEFAULT_MIN_MTU 48
#define L2CAP_DEFAULT_FLUSH_TO 0xffff
#define L2CAP_DEFAULT_TX_WINDOW 63
#define L2CAP_DEFAULT_EXT_WINDOW 0x3FFF
#define L2CAP_DEFAULT_MAX_TX 3
#define L2CAP_DEFAULT_RETRANS_TO 2000 /* 2 seconds */
#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_DISC_TIMEOUT (100)
#define L2CAP_DISC_REJ_TIMEOUT (5000) /* 5 seconds */
......@@ -91,59 +97,95 @@ struct l2cap_conninfo {
#define L2CAP_ECHO_RSP 0x09
#define L2CAP_INFO_REQ 0x0a
#define L2CAP_INFO_RSP 0x0b
#define L2CAP_CREATE_CHAN_REQ 0x0c
#define L2CAP_CREATE_CHAN_RSP 0x0d
#define L2CAP_MOVE_CHAN_REQ 0x0e
#define L2CAP_MOVE_CHAN_RSP 0x0f
#define L2CAP_MOVE_CHAN_CFM 0x10
#define L2CAP_MOVE_CHAN_CFM_RSP 0x11
#define L2CAP_CONN_PARAM_UPDATE_REQ 0x12
#define L2CAP_CONN_PARAM_UPDATE_RSP 0x13
/* L2CAP feature mask */
/* L2CAP extended feature mask */
#define L2CAP_FEAT_FLOWCTL 0x00000001
#define L2CAP_FEAT_RETRANS 0x00000002
#define L2CAP_FEAT_BIDIR_QOS 0x00000004
#define L2CAP_FEAT_ERTM 0x00000008
#define L2CAP_FEAT_STREAMING 0x00000010
#define L2CAP_FEAT_FCS 0x00000020
#define L2CAP_FEAT_EXT_FLOW 0x00000040
#define L2CAP_FEAT_FIXED_CHAN 0x00000080
#define L2CAP_FEAT_EXT_WINDOW 0x00000100
#define L2CAP_FEAT_UCD 0x00000200
/* L2CAP checksum option */
#define L2CAP_FCS_NONE 0x00
#define L2CAP_FCS_CRC16 0x01
/* L2CAP fixed channels */
#define L2CAP_FC_L2CAP 0x02
#define L2CAP_FC_A2MP 0x08
/* L2CAP Control Field bit masks */
#define L2CAP_CTRL_SAR 0xC000
#define L2CAP_CTRL_REQSEQ 0x3F00
#define L2CAP_CTRL_TXSEQ 0x007E
#define L2CAP_CTRL_SUPERVISE 0x000C
#define L2CAP_CTRL_RETRANS 0x0080
#define L2CAP_CTRL_FINAL 0x0080
#define L2CAP_CTRL_POLL 0x0010
#define L2CAP_CTRL_SUPERVISE 0x000C
#define L2CAP_CTRL_FRAME_TYPE 0x0001 /* I- or S-Frame */
#define L2CAP_CTRL_TXSEQ_SHIFT 1
#define L2CAP_CTRL_SUPER_SHIFT 2
#define L2CAP_CTRL_REQSEQ_SHIFT 8
#define L2CAP_CTRL_SAR_SHIFT 14
/* L2CAP Extended Control Field bit mask */
#define L2CAP_EXT_CTRL_TXSEQ 0xFFFC0000
#define L2CAP_EXT_CTRL_SAR 0x00030000
#define L2CAP_EXT_CTRL_SUPERVISE 0x00030000
#define L2CAP_EXT_CTRL_REQSEQ 0x0000FFFC
#define L2CAP_EXT_CTRL_POLL 0x00040000
#define L2CAP_EXT_CTRL_FINAL 0x00000002
#define L2CAP_EXT_CTRL_FRAME_TYPE 0x00000001 /* I- or S-Frame */
#define L2CAP_EXT_CTRL_REQSEQ_SHIFT 2
#define L2CAP_EXT_CTRL_SAR_SHIFT 16
#define L2CAP_EXT_CTRL_SUPER_SHIFT 16
#define L2CAP_EXT_CTRL_TXSEQ_SHIFT 18
/* L2CAP Supervisory Function */
#define L2CAP_SUPER_RCV_READY 0x0000
#define L2CAP_SUPER_REJECT 0x0004
#define L2CAP_SUPER_RCV_NOT_READY 0x0008
#define L2CAP_SUPER_SELECT_REJECT 0x000C
#define L2CAP_SUPER_RR 0x00
#define L2CAP_SUPER_REJ 0x01
#define L2CAP_SUPER_RNR 0x02
#define L2CAP_SUPER_SREJ 0x03
/* L2CAP Segmentation and Reassembly */
#define L2CAP_SDU_UNSEGMENTED 0x0000
#define L2CAP_SDU_START 0x4000
#define L2CAP_SDU_END 0x8000
#define L2CAP_SDU_CONTINUE 0xC000
#define L2CAP_SAR_UNSEGMENTED 0x00
#define L2CAP_SAR_START 0x01
#define L2CAP_SAR_END 0x02
#define L2CAP_SAR_CONTINUE 0x03
/* L2CAP Command rej. reasons */
#define L2CAP_REJ_NOT_UNDERSTOOD 0x0000
#define L2CAP_REJ_MTU_EXCEEDED 0x0001
#define L2CAP_REJ_INVALID_CID 0x0002
/* L2CAP structures */
struct l2cap_hdr {
__le16 len;
__le16 cid;
} __packed;
#define L2CAP_HDR_SIZE 4
#define L2CAP_ENH_HDR_SIZE 6
#define L2CAP_EXT_HDR_SIZE 8
#define L2CAP_FCS_SIZE 2
#define L2CAP_SDULEN_SIZE 2
#define L2CAP_PSMLEN_SIZE 2
struct l2cap_cmd_hdr {
__u8 code;
......@@ -188,14 +230,15 @@ struct l2cap_conn_rsp {
#define L2CAP_CID_DYN_START 0x0040
#define L2CAP_CID_DYN_END 0xffff
/* connect result */
/* connect/create channel results */
#define L2CAP_CR_SUCCESS 0x0000
#define L2CAP_CR_PEND 0x0001
#define L2CAP_CR_BAD_PSM 0x0002
#define L2CAP_CR_SEC_BLOCK 0x0003
#define L2CAP_CR_NO_MEM 0x0004
#define L2CAP_CR_BAD_AMP 0x0005
/* connect status */
/* connect/create channel status */
#define L2CAP_CS_NO_INFO 0x0000
#define L2CAP_CS_AUTHEN_PEND 0x0001
#define L2CAP_CS_AUTHOR_PEND 0x0002
......@@ -217,6 +260,8 @@ struct l2cap_conf_rsp {
#define L2CAP_CONF_UNACCEPT 0x0001
#define L2CAP_CONF_REJECT 0x0002
#define L2CAP_CONF_UNKNOWN 0x0003
#define L2CAP_CONF_PENDING 0x0004
#define L2CAP_CONF_EFS_REJECT 0x0005
struct l2cap_conf_opt {
__u8 type;
......@@ -233,6 +278,8 @@ struct l2cap_conf_opt {
#define L2CAP_CONF_QOS 0x03
#define L2CAP_CONF_RFC 0x04
#define L2CAP_CONF_FCS 0x05
#define L2CAP_CONF_EFS 0x06
#define L2CAP_CONF_EWS 0x07
#define L2CAP_CONF_MAX_SIZE 22
......@@ -251,6 +298,21 @@ struct l2cap_conf_rfc {
#define L2CAP_MODE_ERTM 0x03
#define L2CAP_MODE_STREAMING 0x04
struct l2cap_conf_efs {
__u8 id;
__u8 stype;
__le16 msdu;
__le32 sdu_itime;
__le32 acc_lat;
__le32 flush_to;
} __packed;
#define L2CAP_SERV_NOTRAFIC 0x00
#define L2CAP_SERV_BESTEFFORT 0x01
#define L2CAP_SERV_GUARANTEED 0x02
#define L2CAP_BESTEFFORT_ID 0x01
struct l2cap_disconn_req {
__le16 dcid;
__le16 scid;
......@@ -271,6 +333,49 @@ struct l2cap_info_rsp {
__u8 data[0];
} __packed;
struct l2cap_create_chan_req {
__le16 psm;
__le16 scid;
__u8 amp_id;
} __packed;
struct l2cap_create_chan_rsp {
__le16 dcid;
__le16 scid;
__le16 result;
__le16 status;
} __packed;
struct l2cap_move_chan_req {
__le16 icid;
__u8 dest_amp_id;
} __packed;
struct l2cap_move_chan_rsp {
__le16 icid;
__le16 result;
} __packed;
#define L2CAP_MR_SUCCESS 0x0000
#define L2CAP_MR_PEND 0x0001
#define L2CAP_MR_BAD_ID 0x0002
#define L2CAP_MR_SAME_ID 0x0003
#define L2CAP_MR_NOT_SUPP 0x0004
#define L2CAP_MR_COLLISION 0x0005
#define L2CAP_MR_NOT_ALLOWED 0x0006
struct l2cap_move_chan_cfm {
__le16 icid;
__le16 result;
} __packed;
#define L2CAP_MC_CONFIRMED 0x0000
#define L2CAP_MC_UNCONFIRMED 0x0001
struct l2cap_move_chan_cfm_rsp {
__le16 icid;
} __packed;
/* info type */
#define L2CAP_IT_CL_MTU 0x0001
#define L2CAP_IT_FEAT_MASK 0x0002
......@@ -297,7 +402,7 @@ struct l2cap_conn_param_update_rsp {
/* ----- L2CAP channels and connections ----- */
struct srej_list {
__u8 tx_seq;
__u16 tx_seq;
struct list_head list;
};
......@@ -319,14 +424,11 @@ struct l2cap_chan {
__u16 flush_to;
__u8 mode;
__u8 chan_type;
__u8 chan_policy;
__le16 sport;
__u8 sec_level;
__u8 role_switch;
__u8 force_reliable;
__u8 flushable;
__u8 force_active;
__u8 ident;
......@@ -337,7 +439,8 @@ struct l2cap_chan {
__u8 fcs;
__u8 tx_win;
__u16 tx_win;
__u16 tx_win_max;
__u8 max_tx;
__u16 retrans_timeout;
__u16 monitor_timeout;
......@@ -345,25 +448,40 @@ struct l2cap_chan {
unsigned long conf_state;
unsigned long conn_state;
__u8 next_tx_seq;
__u8 expected_ack_seq;
__u8 expected_tx_seq;
__u8 buffer_seq;
__u8 buffer_seq_srej;
__u8 srej_save_reqseq;
__u8 frames_sent;
__u8 unacked_frames;
unsigned long flags;
__u16 next_tx_seq;
__u16 expected_ack_seq;
__u16 expected_tx_seq;
__u16 buffer_seq;
__u16 buffer_seq_srej;
__u16 srej_save_reqseq;
__u16 frames_sent;
__u16 unacked_frames;
__u8 retry_count;
__u8 num_acked;
__u16 sdu_len;
struct sk_buff *sdu;
struct sk_buff *sdu_last_frag;
__u8 remote_tx_win;
__u16 remote_tx_win;
__u8 remote_max_tx;
__u16 remote_mps;
__u8 local_id;
__u8 local_stype;
__u16 local_msdu;
__u32 local_sdu_itime;
__u32 local_acc_lat;
__u32 local_flush_to;
__u8 remote_id;
__u8 remote_stype;
__u16 remote_msdu;
__u32 remote_sdu_itime;
__u32 remote_acc_lat;
__u32 remote_flush_to;
struct timer_list chan_timer;
struct timer_list retrans_timer;
struct timer_list monitor_timer;
......@@ -391,6 +509,7 @@ struct l2cap_ops {
struct l2cap_conn {
struct hci_conn *hcon;
struct hci_chan *hchan;
bdaddr_t *dst;
bdaddr_t *src;
......@@ -445,6 +564,9 @@ enum {
CONF_CONNECT_PEND,
CONF_NO_FCS_RECV,
CONF_STATE2_DEVICE,
CONF_EWS_RECV,
CONF_LOC_CONF_PEND,
CONF_REM_CONF_PEND,
};
#define L2CAP_CONF_MAX_CONF_REQ 2
......@@ -462,6 +584,16 @@ enum {
CONN_RNR_SENT,
};
/* Definitions for flags in l2cap_chan */
enum {
FLAG_ROLE_SWITCH,
FLAG_FORCE_ACTIVE,
FLAG_FORCE_RELIABLE,
FLAG_FLUSHABLE,
FLAG_EXT_CTRL,
FLAG_EFS_ENABLE,
};
#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, \
......@@ -474,6 +606,22 @@ enum {
L2CAP_DEFAULT_ACK_TO);
#define __clear_ack_timer(c) l2cap_clear_timer(c, &c->ack_timer)
static inline int __seq_offset(struct l2cap_chan *chan, __u16 seq1, __u16 seq2)
{
int offset;
offset = (seq1 - seq2) % (chan->tx_win_max + 1);
if (offset < 0)
offset += (chan->tx_win_max + 1);
return offset;
}
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)
{
int sub;
......@@ -486,13 +634,165 @@ static inline int l2cap_tx_window_full(struct l2cap_chan *ch)
return sub == ch->remote_tx_win;
}
#define __get_txseq(ctrl) (((ctrl) & L2CAP_CTRL_TXSEQ) >> 1)
#define __get_reqseq(ctrl) (((ctrl) & L2CAP_CTRL_REQSEQ) >> 8)
#define __is_iframe(ctrl) (!((ctrl) & L2CAP_CTRL_FRAME_TYPE))
#define __is_sframe(ctrl) ((ctrl) & L2CAP_CTRL_FRAME_TYPE)
#define __is_sar_start(ctrl) (((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START)
static inline __u16 __get_reqseq(struct l2cap_chan *chan, __u32 ctrl)
{
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)
{
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 int disable_ertm;
extern int enable_hs;
int l2cap_init_sockets(void);
void l2cap_cleanup_sockets(void);
......@@ -507,7 +807,8 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk);
void l2cap_chan_close(struct l2cap_chan *chan, int reason);
void l2cap_chan_destroy(struct l2cap_chan *chan);
int l2cap_chan_connect(struct l2cap_chan *chan);
int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len);
int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
u32 priority);
void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
#endif /* __L2CAP_H */
......@@ -69,6 +69,10 @@ struct mgmt_mode {
#define MGMT_OP_SET_POWERED 0x0005
#define MGMT_OP_SET_DISCOVERABLE 0x0006
struct mgmt_cp_set_discoverable {
__u8 val;
__u16 timeout;
} __packed;
#define MGMT_OP_SET_CONNECTABLE 0x0007
......@@ -96,24 +100,22 @@ struct mgmt_cp_set_service_cache {
__u8 enable;
} __packed;
struct mgmt_key_info {
struct mgmt_link_key_info {
bdaddr_t bdaddr;
u8 type;
u8 val[16];
u8 pin_len;
u8 dlen;
u8 data[0];
} __packed;
#define MGMT_OP_LOAD_KEYS 0x000D
struct mgmt_cp_load_keys {
#define MGMT_OP_LOAD_LINK_KEYS 0x000D
struct mgmt_cp_load_link_keys {
__u8 debug_keys;
__le16 key_count;
struct mgmt_key_info keys[0];
struct mgmt_link_key_info keys[0];
} __packed;
#define MGMT_OP_REMOVE_KEY 0x000E
struct mgmt_cp_remove_key {
#define MGMT_OP_REMOVE_KEYS 0x000E
struct mgmt_cp_remove_keys {
bdaddr_t bdaddr;
__u8 disconnect;
} __packed;
......@@ -126,10 +128,20 @@ struct mgmt_rp_disconnect {
bdaddr_t bdaddr;
} __packed;
#define MGMT_ADDR_BREDR 0x00
#define MGMT_ADDR_LE 0x01
#define MGMT_ADDR_BREDR_LE 0x02
#define MGMT_ADDR_INVALID 0xff
struct mgmt_addr_info {
bdaddr_t bdaddr;
__u8 type;
} __packed;
#define MGMT_OP_GET_CONNECTIONS 0x0010
struct mgmt_rp_get_connections {
__le16 conn_count;
bdaddr_t conn[0];
struct mgmt_addr_info addr[0];
} __packed;
#define MGMT_OP_PIN_CODE_REPLY 0x0011
......@@ -245,26 +257,19 @@ struct mgmt_ev_controller_error {
#define MGMT_EV_PAIRABLE 0x0009
#define MGMT_EV_NEW_KEY 0x000A
struct mgmt_ev_new_key {
#define MGMT_EV_NEW_LINK_KEY 0x000A
struct mgmt_ev_new_link_key {
__u8 store_hint;
struct mgmt_key_info key;
struct mgmt_link_key_info key;
} __packed;
#define MGMT_EV_CONNECTED 0x000B
struct mgmt_ev_connected {
bdaddr_t bdaddr;
__u8 link_type;
} __packed;
#define MGMT_EV_DISCONNECTED 0x000C
struct mgmt_ev_disconnected {
bdaddr_t bdaddr;
} __packed;
#define MGMT_EV_CONNECT_FAILED 0x000D
struct mgmt_ev_connect_failed {
bdaddr_t bdaddr;
struct mgmt_addr_info addr;
__u8 status;
} __packed;
......@@ -294,7 +299,7 @@ struct mgmt_ev_local_name_changed {
#define MGMT_EV_DEVICE_FOUND 0x0012
struct mgmt_ev_device_found {
bdaddr_t bdaddr;
struct mgmt_addr_info addr;
__u8 dev_class[3];
__s8 rssi;
__u8 eir[HCI_MAX_EIR_LENGTH];
......
......@@ -65,15 +65,13 @@ static DECLARE_RWSEM(bnep_session_sem);
static struct bnep_session *__bnep_get_session(u8 *dst)
{
struct bnep_session *s;
struct list_head *p;
BT_DBG("");
list_for_each(p, &bnep_session_list) {
s = list_entry(p, struct bnep_session, list);
list_for_each_entry(s, &bnep_session_list, list)
if (!compare_ether_addr(dst, s->eh.h_source))
return s;
}
return NULL;
}
......@@ -667,17 +665,14 @@ static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
int bnep_get_connlist(struct bnep_connlist_req *req)
{
struct list_head *p;
struct bnep_session *s;
int err = 0, n = 0;
down_read(&bnep_session_sem);
list_for_each(p, &bnep_session_list) {
struct bnep_session *s;
list_for_each_entry(s, &bnep_session_list, list) {
struct bnep_conninfo ci;
s = list_entry(p, struct bnep_session, list);
__bnep_copy_ci(&ci, s);
if (copy_to_user(req->ci, &ci, sizeof(ci))) {
......
......@@ -53,15 +53,13 @@ static LIST_HEAD(cmtp_session_list);
static struct cmtp_session *__cmtp_get_session(bdaddr_t *bdaddr)
{
struct cmtp_session *session;
struct list_head *p;
BT_DBG("");
list_for_each(p, &cmtp_session_list) {
session = list_entry(p, struct cmtp_session, list);
list_for_each_entry(session, &cmtp_session_list, list)
if (!bacmp(bdaddr, &session->bdaddr))
return session;
}
return NULL;
}
......@@ -431,19 +429,16 @@ int cmtp_del_connection(struct cmtp_conndel_req *req)
int cmtp_get_connlist(struct cmtp_connlist_req *req)
{
struct list_head *p;
struct cmtp_session *session;
int err = 0, n = 0;
BT_DBG("");
down_read(&cmtp_session_sem);
list_for_each(p, &cmtp_session_list) {
struct cmtp_session *session;
list_for_each_entry(session, &cmtp_session_list, list) {
struct cmtp_conninfo ci;
session = list_entry(p, struct cmtp_session, list);
__cmtp_copy_session(session, &ci);
if (copy_to_user(req->ci, &ci, sizeof(ci))) {
......
......@@ -374,6 +374,8 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
skb_queue_head_init(&conn->data_q);
hci_chan_hash_init(conn);
setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn);
setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn);
setup_timer(&conn->auto_accept_timer, hci_conn_auto_accept,
......@@ -432,6 +434,8 @@ int hci_conn_del(struct hci_conn *conn)
tasklet_disable(&hdev->tx_task);
hci_chan_hash_flush(conn);
hci_conn_hash_del(hdev, conn);
if (hdev->notify)
hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
......@@ -453,16 +457,13 @@ int hci_conn_del(struct hci_conn *conn)
struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
{
int use_src = bacmp(src, BDADDR_ANY);
struct hci_dev *hdev = NULL;
struct list_head *p;
struct hci_dev *hdev = NULL, *d;
BT_DBG("%s -> %s", batostr(src), batostr(dst));
read_lock_bh(&hci_dev_list_lock);
list_for_each(p, &hci_dev_list) {
struct hci_dev *d = list_entry(p, struct hci_dev, list);
list_for_each_entry(d, &hci_dev_list, list) {
if (!test_bit(HCI_UP, &d->flags) || test_bit(HCI_RAW, &d->flags))
continue;
......@@ -819,7 +820,7 @@ void hci_conn_hash_flush(struct hci_dev *hdev)
c->state = BT_CLOSED;
hci_proto_disconn_cfm(c, 0x16);
hci_proto_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM);
hci_conn_del(c);
}
}
......@@ -855,10 +856,10 @@ EXPORT_SYMBOL(hci_conn_put_device);
int hci_get_conn_list(void __user *arg)
{
register struct hci_conn *c;
struct hci_conn_list_req req, *cl;
struct hci_conn_info *ci;
struct hci_dev *hdev;
struct list_head *p;
int n = 0, size, err;
if (copy_from_user(&req, arg, sizeof(req)))
......@@ -882,10 +883,7 @@ int hci_get_conn_list(void __user *arg)
ci = cl->conn_info;
hci_dev_lock_bh(hdev);
list_for_each(p, &hdev->conn_hash.list) {
register struct hci_conn *c;
c = list_entry(p, struct hci_conn, list);
list_for_each_entry(c, &hdev->conn_hash.list, list) {
bacpy(&(ci + n)->bdaddr, &c->dst);
(ci + n)->handle = c->handle;
(ci + n)->type = c->type;
......@@ -956,3 +954,52 @@ int hci_get_auth_info(struct hci_dev *hdev, void __user *arg)
return copy_to_user(arg, &req, sizeof(req)) ? -EFAULT : 0;
}
struct hci_chan *hci_chan_create(struct hci_conn *conn)
{
struct hci_dev *hdev = conn->hdev;
struct hci_chan *chan;
BT_DBG("%s conn %p", hdev->name, conn);
chan = kzalloc(sizeof(struct hci_chan), GFP_ATOMIC);
if (!chan)
return NULL;
chan->conn = conn;
skb_queue_head_init(&chan->data_q);
tasklet_disable(&hdev->tx_task);
hci_chan_hash_add(conn, chan);
tasklet_enable(&hdev->tx_task);
return chan;
}
int hci_chan_del(struct hci_chan *chan)
{
struct hci_conn *conn = chan->conn;
struct hci_dev *hdev = conn->hdev;
BT_DBG("%s conn %p chan %p", hdev->name, conn, chan);
tasklet_disable(&hdev->tx_task);
hci_chan_hash_del(conn, chan);
tasklet_enable(&hdev->tx_task);
skb_queue_purge(&chan->data_q);
kfree(chan);
return 0;
}
void hci_chan_hash_flush(struct hci_conn *conn)
{
struct hci_chan_hash *h = &conn->chan_hash;
struct hci_chan *chan, *tmp;
BT_DBG("conn %p", conn);
list_for_each_entry_safe(chan, tmp, &h->list, list)
hci_chan_del(chan);
}
......@@ -319,8 +319,7 @@ static void hci_linkpol_req(struct hci_dev *hdev, unsigned long opt)
* Device is held on return. */
struct hci_dev *hci_dev_get(int index)
{
struct hci_dev *hdev = NULL;
struct list_head *p;
struct hci_dev *hdev = NULL, *d;
BT_DBG("%d", index);
......@@ -328,8 +327,7 @@ struct hci_dev *hci_dev_get(int index)
return NULL;
read_lock(&hci_dev_list_lock);
list_for_each(p, &hci_dev_list) {
struct hci_dev *d = list_entry(p, struct hci_dev, list);
list_for_each_entry(d, &hci_dev_list, list) {
if (d->id == index) {
hdev = hci_dev_hold(d);
break;
......@@ -551,8 +549,11 @@ int hci_dev_open(__u16 dev)
hci_dev_hold(hdev);
set_bit(HCI_UP, &hdev->flags);
hci_notify(hdev, HCI_DEV_UP);
if (!test_bit(HCI_SETUP, &hdev->flags))
mgmt_powered(hdev->id, 1);
if (!test_bit(HCI_SETUP, &hdev->flags)) {
hci_dev_lock_bh(hdev);
mgmt_powered(hdev, 1);
hci_dev_unlock_bh(hdev);
}
} else {
/* Init failed, cleanup */
tasklet_kill(&hdev->rx_task);
......@@ -597,6 +598,14 @@ static int hci_dev_do_close(struct hci_dev *hdev)
tasklet_kill(&hdev->rx_task);
tasklet_kill(&hdev->tx_task);
if (hdev->discov_timeout > 0) {
cancel_delayed_work(&hdev->discov_off);
hdev->discov_timeout = 0;
}
if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
cancel_delayed_work(&hdev->power_off);
hci_dev_lock_bh(hdev);
inquiry_cache_flush(hdev);
hci_conn_hash_flush(hdev);
......@@ -636,7 +645,9 @@ static int hci_dev_do_close(struct hci_dev *hdev)
* and no tasks are scheduled. */
hdev->close(hdev);
mgmt_powered(hdev->id, 0);
hci_dev_lock_bh(hdev);
mgmt_powered(hdev, 0);
hci_dev_unlock_bh(hdev);
/* Clear flags */
hdev->flags = 0;
......@@ -794,9 +805,9 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
int hci_get_dev_list(void __user *arg)
{
struct hci_dev *hdev;
struct hci_dev_list_req *dl;
struct hci_dev_req *dr;
struct list_head *p;
int n = 0, size, err;
__u16 dev_num;
......@@ -815,12 +826,9 @@ int hci_get_dev_list(void __user *arg)
dr = dl->dev_req;
read_lock_bh(&hci_dev_list_lock);
list_for_each(p, &hci_dev_list) {
struct hci_dev *hdev;
hdev = list_entry(p, struct hci_dev, list);
hci_del_off_timer(hdev);
list_for_each_entry(hdev, &hci_dev_list, list) {
if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
cancel_delayed_work(&hdev->power_off);
if (!test_bit(HCI_MGMT, &hdev->flags))
set_bit(HCI_PAIRABLE, &hdev->flags);
......@@ -855,7 +863,8 @@ int hci_get_dev_info(void __user *arg)
if (!hdev)
return -ENODEV;
hci_del_off_timer(hdev);
if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
cancel_delayed_work_sync(&hdev->power_off);
if (!test_bit(HCI_MGMT, &hdev->flags))
set_bit(HCI_PAIRABLE, &hdev->flags);
......@@ -912,6 +921,7 @@ struct hci_dev *hci_alloc_dev(void)
if (!hdev)
return NULL;
hci_init_sysfs(hdev);
skb_queue_head_init(&hdev->driver_init);
return hdev;
......@@ -938,39 +948,41 @@ static void hci_power_on(struct work_struct *work)
return;
if (test_bit(HCI_AUTO_OFF, &hdev->flags))
mod_timer(&hdev->off_timer,
jiffies + msecs_to_jiffies(AUTO_OFF_TIMEOUT));
queue_delayed_work(hdev->workqueue, &hdev->power_off,
msecs_to_jiffies(AUTO_OFF_TIMEOUT));
if (test_and_clear_bit(HCI_SETUP, &hdev->flags))
mgmt_index_added(hdev->id);
mgmt_index_added(hdev);
}
static void hci_power_off(struct work_struct *work)
{
struct hci_dev *hdev = container_of(work, struct hci_dev, power_off);
struct hci_dev *hdev = container_of(work, struct hci_dev,
power_off.work);
BT_DBG("%s", hdev->name);
clear_bit(HCI_AUTO_OFF, &hdev->flags);
hci_dev_close(hdev->id);
}
static void hci_auto_off(unsigned long data)
static void hci_discov_off(struct work_struct *work)
{
struct hci_dev *hdev = (struct hci_dev *) data;
struct hci_dev *hdev;
u8 scan = SCAN_PAGE;
hdev = container_of(work, struct hci_dev, discov_off.work);
BT_DBG("%s", hdev->name);
clear_bit(HCI_AUTO_OFF, &hdev->flags);
hci_dev_lock_bh(hdev);
queue_work(hdev->workqueue, &hdev->power_off);
}
hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
void hci_del_off_timer(struct hci_dev *hdev)
{
BT_DBG("%s", hdev->name);
hdev->discov_timeout = 0;
clear_bit(HCI_AUTO_OFF, &hdev->flags);
del_timer(&hdev->off_timer);
hci_dev_unlock_bh(hdev);
}
int hci_uuids_clear(struct hci_dev *hdev)
......@@ -1007,16 +1019,11 @@ int hci_link_keys_clear(struct hci_dev *hdev)
struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
{
struct list_head *p;
list_for_each(p, &hdev->link_keys) {
struct link_key *k;
k = list_entry(p, struct link_key, list);
list_for_each_entry(k, &hdev->link_keys, list)
if (bacmp(bdaddr, &k->bdaddr) == 0)
return k;
}
return NULL;
}
......@@ -1138,7 +1145,7 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
persistent = hci_persistent_key(hdev, conn, type, old_key_type);
mgmt_new_key(hdev->id, key, persistent);
mgmt_new_link_key(hdev, key, persistent);
if (!persistent) {
list_del(&key->list);
......@@ -1181,7 +1188,7 @@ int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr,
memcpy(id->rand, rand, sizeof(id->rand));
if (new_key)
mgmt_new_key(hdev->id, key, old_key_type);
mgmt_new_link_key(hdev, key, old_key_type);
return 0;
}
......@@ -1279,16 +1286,11 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
struct bdaddr_list *hci_blacklist_lookup(struct hci_dev *hdev,
bdaddr_t *bdaddr)
{
struct list_head *p;
list_for_each(p, &hdev->blacklist) {
struct bdaddr_list *b;
b = list_entry(p, struct bdaddr_list, list);
list_for_each_entry(b, &hdev->blacklist, list)
if (bacmp(bdaddr, &b->bdaddr) == 0)
return b;
}
return NULL;
}
......@@ -1327,7 +1329,7 @@ int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr)
list_add(&entry->list, &hdev->blacklist);
return mgmt_device_blocked(hdev->id, bdaddr);
return mgmt_device_blocked(hdev, bdaddr);
}
int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
......@@ -1346,7 +1348,7 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr)
list_del(&entry->list);
kfree(entry);
return mgmt_device_unblocked(hdev->id, bdaddr);
return mgmt_device_unblocked(hdev, bdaddr);
}
static void hci_clear_adv_cache(unsigned long arg)
......@@ -1425,7 +1427,7 @@ int hci_add_adv_entry(struct hci_dev *hdev,
int hci_register_dev(struct hci_dev *hdev)
{
struct list_head *head = &hci_dev_list, *p;
int i, id = 0;
int i, id, error;
BT_DBG("%p name %s bus %d owner %p", hdev, hdev->name,
hdev->bus, hdev->owner);
......@@ -1433,6 +1435,11 @@ int hci_register_dev(struct hci_dev *hdev)
if (!hdev->open || !hdev->close || !hdev->destruct)
return -EINVAL;
/* 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;
write_lock_bh(&hci_dev_list_lock);
/* Find first available device id */
......@@ -1479,6 +1486,8 @@ int hci_register_dev(struct hci_dev *hdev)
hci_conn_hash_init(hdev);
INIT_LIST_HEAD(&hdev->mgmt_pending);
INIT_LIST_HEAD(&hdev->blacklist);
INIT_LIST_HEAD(&hdev->uuids);
......@@ -1492,8 +1501,9 @@ int hci_register_dev(struct hci_dev *hdev)
(unsigned long) hdev);
INIT_WORK(&hdev->power_on, hci_power_on);
INIT_WORK(&hdev->power_off, hci_power_off);
setup_timer(&hdev->off_timer, hci_auto_off, (unsigned long) hdev);
INIT_DELAYED_WORK(&hdev->power_off, hci_power_off);
INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off);
memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
......@@ -1502,10 +1512,14 @@ int hci_register_dev(struct hci_dev *hdev)
write_unlock_bh(&hci_dev_list_lock);
hdev->workqueue = create_singlethread_workqueue(hdev->name);
if (!hdev->workqueue)
goto nomem;
if (!hdev->workqueue) {
error = -ENOMEM;
goto err;
}
hci_register_sysfs(hdev);
error = hci_add_sysfs(hdev);
if (error < 0)
goto err_wqueue;
hdev->rfkill = rfkill_alloc(hdev->name, &hdev->dev,
RFKILL_TYPE_BLUETOOTH, &hci_rfkill_ops, hdev);
......@@ -1524,17 +1538,19 @@ int hci_register_dev(struct hci_dev *hdev)
return id;
nomem:
err_wqueue:
destroy_workqueue(hdev->workqueue);
err:
write_lock_bh(&hci_dev_list_lock);
list_del(&hdev->list);
write_unlock_bh(&hci_dev_list_lock);
return -ENOMEM;
return error;
}
EXPORT_SYMBOL(hci_register_dev);
/* Unregister HCI device */
int hci_unregister_dev(struct hci_dev *hdev)
void hci_unregister_dev(struct hci_dev *hdev)
{
int i;
......@@ -1550,8 +1566,15 @@ int hci_unregister_dev(struct hci_dev *hdev)
kfree_skb(hdev->reassembly[i]);
if (!test_bit(HCI_INIT, &hdev->flags) &&
!test_bit(HCI_SETUP, &hdev->flags))
mgmt_index_removed(hdev->id);
!test_bit(HCI_SETUP, &hdev->flags)) {
hci_dev_lock_bh(hdev);
mgmt_index_removed(hdev);
hci_dev_unlock_bh(hdev);
}
/* mgmt_index_removed should take care of emptying the
* pending list */
BUG_ON(!list_empty(&hdev->mgmt_pending));
hci_notify(hdev, HCI_DEV_UNREG);
......@@ -1560,9 +1583,8 @@ int hci_unregister_dev(struct hci_dev *hdev)
rfkill_destroy(hdev->rfkill);
}
hci_unregister_sysfs(hdev);
hci_del_sysfs(hdev);
hci_del_off_timer(hdev);
del_timer(&hdev->adv_timer);
destroy_workqueue(hdev->workqueue);
......@@ -1576,8 +1598,6 @@ int hci_unregister_dev(struct hci_dev *hdev)
hci_dev_unlock_bh(hdev);
__hci_dev_put(hdev);
return 0;
}
EXPORT_SYMBOL(hci_unregister_dev);
......@@ -1948,23 +1968,18 @@ static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
hdr->dlen = cpu_to_le16(len);
}
void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
struct sk_buff *skb, __u16 flags)
{
struct hci_dev *hdev = conn->hdev;
struct sk_buff *list;
BT_DBG("%s conn %p flags 0x%x", hdev->name, conn, flags);
skb->dev = (void *) hdev;
bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
hci_add_acl_hdr(skb, conn->handle, flags);
list = skb_shinfo(skb)->frag_list;
if (!list) {
/* Non fragmented */
BT_DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len);
skb_queue_tail(&conn->data_q, skb);
skb_queue_tail(queue, skb);
} else {
/* Fragmented */
BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
......@@ -1972,9 +1987,9 @@ void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
skb_shinfo(skb)->frag_list = NULL;
/* Queue all fragments atomically */
spin_lock_bh(&conn->data_q.lock);
spin_lock_bh(&queue->lock);
__skb_queue_tail(&conn->data_q, skb);
__skb_queue_tail(queue, skb);
flags &= ~ACL_START;
flags |= ACL_CONT;
......@@ -1987,11 +2002,25 @@ void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
BT_DBG("%s frag %p len %d", hdev->name, skb, skb->len);
__skb_queue_tail(&conn->data_q, skb);
__skb_queue_tail(queue, skb);
} while (list);
spin_unlock_bh(&conn->data_q.lock);
spin_unlock_bh(&queue->lock);
}
}
void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags)
{
struct hci_conn *conn = chan->conn;
struct hci_dev *hdev = conn->hdev;
BT_DBG("%s chan %p flags 0x%x", hdev->name, chan, flags);
skb->dev = (void *) hdev;
bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
hci_add_acl_hdr(skb, conn->handle, flags);
hci_queue_acl(conn, &chan->data_q, skb, flags);
tasklet_schedule(&hdev->tx_task);
}
......@@ -2026,16 +2055,12 @@ EXPORT_SYMBOL(hci_send_sco);
static inline 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;
struct hci_conn *conn = NULL, *c;
int num = 0, min = ~0;
struct list_head *p;
/* We don't have to lock device here. Connections are always
* added and removed with TX task disabled. */
list_for_each(p, &h->list) {
struct hci_conn *c;
c = list_entry(p, struct hci_conn, list);
list_for_each_entry(c, &h->list, list) {
if (c->type != type || skb_queue_empty(&c->data_q))
continue;
......@@ -2084,14 +2109,12 @@ static inline struct hci_conn *hci_low_sent(struct hci_dev *hdev, __u8 type, int
static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
{
struct hci_conn_hash *h = &hdev->conn_hash;
struct list_head *p;
struct hci_conn *c;
BT_ERR("%s link tx timeout", hdev->name);
/* Kill stalled connections */
list_for_each(p, &h->list) {
c = list_entry(p, struct hci_conn, list);
list_for_each_entry(c, &h->list, list) {
if (c->type == type && c->sent) {
BT_ERR("%s killing stalled connection %s",
hdev->name, batostr(&c->dst));
......@@ -2100,11 +2123,137 @@ static inline void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
}
}
static inline void hci_sched_acl(struct hci_dev *hdev)
static inline struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
int *quote)
{
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_chan *chan = NULL;
int num = 0, min = ~0, cur_prio = 0;
struct hci_conn *conn;
int cnt, q, conn_num = 0;
BT_DBG("%s", hdev->name);
list_for_each_entry(conn, &h->list, list) {
struct hci_chan_hash *ch;
struct hci_chan *tmp;
if (conn->type != type)
continue;
if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG)
continue;
conn_num++;
ch = &conn->chan_hash;
list_for_each_entry(tmp, &ch->list, list) {
struct sk_buff *skb;
if (skb_queue_empty(&tmp->data_q))
continue;
skb = skb_peek(&tmp->data_q);
if (skb->priority < cur_prio)
continue;
if (skb->priority > cur_prio) {
num = 0;
min = ~0;
cur_prio = skb->priority;
}
num++;
if (conn->sent < min) {
min = conn->sent;
chan = tmp;
}
}
if (hci_conn_num(hdev, type) == conn_num)
break;
}
if (!chan)
return NULL;
switch (chan->conn->type) {
case ACL_LINK:
cnt = hdev->acl_cnt;
break;
case SCO_LINK:
case ESCO_LINK:
cnt = hdev->sco_cnt;
break;
case LE_LINK:
cnt = hdev->le_mtu ? hdev->le_cnt : hdev->acl_cnt;
break;
default:
cnt = 0;
BT_ERR("Unknown link type");
}
q = cnt / num;
*quote = q ? q : 1;
BT_DBG("chan %p quote %d", chan, *quote);
return chan;
}
static void hci_prio_recalculate(struct hci_dev *hdev, __u8 type)
{
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_conn *conn;
int num = 0;
BT_DBG("%s", hdev->name);
list_for_each_entry(conn, &h->list, list) {
struct hci_chan_hash *ch;
struct hci_chan *chan;
if (conn->type != type)
continue;
if (conn->state != BT_CONNECTED && conn->state != BT_CONFIG)
continue;
num++;
ch = &conn->chan_hash;
list_for_each_entry(chan, &ch->list, list) {
struct sk_buff *skb;
if (chan->sent) {
chan->sent = 0;
continue;
}
if (skb_queue_empty(&chan->data_q))
continue;
skb = skb_peek(&chan->data_q);
if (skb->priority >= HCI_PRIO_MAX - 1)
continue;
skb->priority = HCI_PRIO_MAX - 1;
BT_DBG("chan %p skb %p promoted to %d", chan, skb,
skb->priority);
}
if (hci_conn_num(hdev, type) == num)
break;
}
}
static inline void hci_sched_acl(struct hci_dev *hdev)
{
struct hci_chan *chan;
struct sk_buff *skb;
int quote;
unsigned int cnt;
BT_DBG("%s", hdev->name);
......@@ -2118,19 +2267,35 @@ static inline void hci_sched_acl(struct hci_dev *hdev)
hci_link_tx_to(hdev, ACL_LINK);
}
while (hdev->acl_cnt && (conn = hci_low_sent(hdev, ACL_LINK, &quote))) {
while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
BT_DBG("skb %p len %d", skb, skb->len);
cnt = hdev->acl_cnt;
hci_conn_enter_active_mode(conn, bt_cb(skb)->force_active);
while (hdev->acl_cnt &&
(chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
u32 priority = (skb_peek(&chan->data_q))->priority;
while (quote-- && (skb = skb_peek(&chan->data_q))) {
BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
skb->len, skb->priority);
/* Stop if priority has changed */
if (skb->priority < priority)
break;
skb = skb_dequeue(&chan->data_q);
hci_conn_enter_active_mode(chan->conn,
bt_cb(skb)->force_active);
hci_send_frame(skb);
hdev->acl_last_tx = jiffies;
hdev->acl_cnt--;
conn->sent++;
chan->sent++;
chan->conn->sent++;
}
}
if (cnt != hdev->acl_cnt)
hci_prio_recalculate(hdev, ACL_LINK);
}
/* Schedule SCO */
......@@ -2182,9 +2347,9 @@ static inline void hci_sched_esco(struct hci_dev *hdev)
static inline void hci_sched_le(struct hci_dev *hdev)
{
struct hci_conn *conn;
struct hci_chan *chan;
struct sk_buff *skb;
int quote, cnt;
int quote, cnt, tmp;
BT_DBG("%s", hdev->name);
......@@ -2200,21 +2365,35 @@ static inline void hci_sched_le(struct hci_dev *hdev)
}
cnt = hdev->le_pkts ? hdev->le_cnt : hdev->acl_cnt;
while (cnt && (conn = hci_low_sent(hdev, LE_LINK, &quote))) {
while (quote-- && (skb = skb_dequeue(&conn->data_q))) {
BT_DBG("skb %p len %d", skb, skb->len);
tmp = cnt;
while (cnt && (chan = hci_chan_sent(hdev, LE_LINK, &quote))) {
u32 priority = (skb_peek(&chan->data_q))->priority;
while (quote-- && (skb = skb_peek(&chan->data_q))) {
BT_DBG("chan %p skb %p len %d priority %u", chan, skb,
skb->len, skb->priority);
/* Stop if priority has changed */
if (skb->priority < priority)
break;
skb = skb_dequeue(&chan->data_q);
hci_send_frame(skb);
hdev->le_last_tx = jiffies;
cnt--;
conn->sent++;
chan->sent++;
chan->conn->sent++;
}
}
if (hdev->le_pkts)
hdev->le_cnt = cnt;
else
hdev->acl_cnt = cnt;
if (cnt != tmp)
hci_prio_recalculate(hdev, LE_LINK);
}
static void hci_tx_task(unsigned long arg)
......@@ -2407,3 +2586,31 @@ static void hci_cmd_task(unsigned long arg)
}
}
}
int hci_do_inquiry(struct hci_dev *hdev, u8 length)
{
/* General inquiry access code (GIAC) */
u8 lap[3] = { 0x33, 0x8b, 0x9e };
struct hci_cp_inquiry cp;
BT_DBG("%s", hdev->name);
if (test_bit(HCI_INQUIRY, &hdev->flags))
return -EINPROGRESS;
memset(&cp, 0, sizeof(cp));
memcpy(&cp.lap, lap, sizeof(cp.lap));
cp.length = length;
return hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
}
int hci_cancel_inquiry(struct hci_dev *hdev)
{
BT_DBG("%s", hdev->name);
if (!test_bit(HCI_INQUIRY, &hdev->flags))
return -EPERM;
return hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
}
......@@ -58,9 +58,11 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb)
if (status)
return;
if (test_and_clear_bit(HCI_INQUIRY, &hdev->flags) &&
test_bit(HCI_MGMT, &hdev->flags))
mgmt_discovering(hdev->id, 0);
clear_bit(HCI_INQUIRY, &hdev->flags);
hci_dev_lock(hdev);
mgmt_discovering(hdev, 0);
hci_dev_unlock(hdev);
hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status);
......@@ -76,10 +78,6 @@ static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb)
if (status)
return;
if (test_and_clear_bit(HCI_INQUIRY, &hdev->flags) &&
test_bit(HCI_MGMT, &hdev->flags))
mgmt_discovering(hdev->id, 0);
hci_conn_check_pending(hdev);
}
......@@ -205,13 +203,15 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
if (!sent)
return;
if (test_bit(HCI_MGMT, &hdev->flags))
mgmt_set_local_name_complete(hdev->id, sent, status);
hci_dev_lock(hdev);
if (status)
return;
if (test_bit(HCI_MGMT, &hdev->flags))
mgmt_set_local_name_complete(hdev, sent, status);
if (status == 0)
memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH);
hci_dev_unlock(hdev);
}
static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb)
......@@ -274,7 +274,8 @@ static void hci_cc_write_encrypt_mode(struct hci_dev *hdev, struct sk_buff *skb)
static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
__u8 param, status = *((__u8 *) skb->data);
int old_pscan, old_iscan;
void *sent;
BT_DBG("%s status 0x%x", hdev->name, status);
......@@ -283,9 +284,15 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
if (!sent)
return;
if (!status) {
__u8 param = *((__u8 *) sent);
int old_pscan, old_iscan;
param = *((__u8 *) sent);
hci_dev_lock(hdev);
if (status != 0) {
mgmt_write_scan_failed(hdev, param, status);
hdev->discov_timeout = 0;
goto done;
}
old_pscan = test_and_clear_bit(HCI_PSCAN, &hdev->flags);
old_iscan = test_and_clear_bit(HCI_ISCAN, &hdev->flags);
......@@ -293,18 +300,24 @@ static void hci_cc_write_scan_enable(struct hci_dev *hdev, struct sk_buff *skb)
if (param & SCAN_INQUIRY) {
set_bit(HCI_ISCAN, &hdev->flags);
if (!old_iscan)
mgmt_discoverable(hdev->id, 1);
mgmt_discoverable(hdev, 1);
if (hdev->discov_timeout > 0) {
int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
queue_delayed_work(hdev->workqueue, &hdev->discov_off,
to);
}
} else if (old_iscan)
mgmt_discoverable(hdev->id, 0);
mgmt_discoverable(hdev, 0);
if (param & SCAN_PAGE) {
set_bit(HCI_PSCAN, &hdev->flags);
if (!old_pscan)
mgmt_connectable(hdev->id, 1);
mgmt_connectable(hdev, 1);
} else if (old_pscan)
mgmt_connectable(hdev->id, 0);
}
mgmt_connectable(hdev, 0);
done:
hci_dev_unlock(hdev);
hci_req_complete(hdev, HCI_OP_WRITE_SCAN_ENABLE, status);
}
......@@ -748,6 +761,30 @@ static void hci_cc_write_ca_timeout(struct hci_dev *hdev, struct sk_buff *skb)
hci_req_complete(hdev, HCI_OP_WRITE_CA_TIMEOUT, status);
}
static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_rp_read_local_amp_info *rp = (void *) skb->data;
BT_DBG("%s status 0x%x", hdev->name, rp->status);
if (rp->status)
return;
hdev->amp_status = rp->amp_status;
hdev->amp_total_bw = __le32_to_cpu(rp->total_bw);
hdev->amp_max_bw = __le32_to_cpu(rp->max_bw);
hdev->amp_min_latency = __le32_to_cpu(rp->min_latency);
hdev->amp_max_pdu = __le32_to_cpu(rp->max_pdu);
hdev->amp_type = rp->amp_type;
hdev->amp_pal_cap = __le16_to_cpu(rp->pal_cap);
hdev->amp_assoc_size = __le16_to_cpu(rp->max_assoc_size);
hdev->amp_be_flush_to = __le32_to_cpu(rp->be_flush_to);
hdev->amp_max_flush_to = __le32_to_cpu(rp->max_flush_to);
hci_req_complete(hdev, HCI_OP_READ_LOCAL_AMP_INFO, rp->status);
}
static void hci_cc_delete_stored_link_key(struct hci_dev *hdev,
struct sk_buff *skb)
{
......@@ -804,19 +841,24 @@ static void hci_cc_pin_code_reply(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s status 0x%x", hdev->name, rp->status);
hci_dev_lock(hdev);
if (test_bit(HCI_MGMT, &hdev->flags))
mgmt_pin_code_reply_complete(hdev->id, &rp->bdaddr, rp->status);
mgmt_pin_code_reply_complete(hdev, &rp->bdaddr, rp->status);
if (rp->status != 0)
return;
goto unlock;
cp = hci_sent_cmd_data(hdev, HCI_OP_PIN_CODE_REPLY);
if (!cp)
return;
goto unlock;
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
if (conn)
conn->pin_length = cp->pin_len;
unlock:
hci_dev_unlock(hdev);
}
static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
......@@ -825,10 +867,15 @@ static void hci_cc_pin_code_neg_reply(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s status 0x%x", hdev->name, rp->status);
hci_dev_lock(hdev);
if (test_bit(HCI_MGMT, &hdev->flags))
mgmt_pin_code_neg_reply_complete(hdev->id, &rp->bdaddr,
mgmt_pin_code_neg_reply_complete(hdev, &rp->bdaddr,
rp->status);
hci_dev_unlock(hdev);
}
static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
struct sk_buff *skb)
{
......@@ -855,9 +902,13 @@ static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s status 0x%x", hdev->name, rp->status);
hci_dev_lock(hdev);
if (test_bit(HCI_MGMT, &hdev->flags))
mgmt_user_confirm_reply_complete(hdev->id, &rp->bdaddr,
mgmt_user_confirm_reply_complete(hdev, &rp->bdaddr,
rp->status);
hci_dev_unlock(hdev);
}
static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
......@@ -867,9 +918,13 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev,
BT_DBG("%s status 0x%x", hdev->name, rp->status);
hci_dev_lock(hdev);
if (test_bit(HCI_MGMT, &hdev->flags))
mgmt_user_confirm_neg_reply_complete(hdev->id, &rp->bdaddr,
mgmt_user_confirm_neg_reply_complete(hdev, &rp->bdaddr,
rp->status);
hci_dev_unlock(hdev);
}
static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
......@@ -879,8 +934,10 @@ static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
BT_DBG("%s status 0x%x", hdev->name, rp->status);
mgmt_read_local_oob_data_reply_complete(hdev->id, rp->hash,
hci_dev_lock(hdev);
mgmt_read_local_oob_data_reply_complete(hdev, rp->hash,
rp->randomizer, rp->status);
hci_dev_unlock(hdev);
}
static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
......@@ -955,12 +1012,18 @@ static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
if (status) {
hci_req_complete(hdev, HCI_OP_INQUIRY, status);
hci_conn_check_pending(hdev);
hci_dev_lock(hdev);
if (test_bit(HCI_MGMT, &hdev->flags))
mgmt_inquiry_failed(hdev, status);
hci_dev_unlock(hdev);
return;
}
if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags) &&
test_bit(HCI_MGMT, &hdev->flags))
mgmt_discovering(hdev->id, 1);
set_bit(HCI_INQUIRY, &hdev->flags);
hci_dev_lock(hdev);
mgmt_discovering(hdev, 1);
hci_dev_unlock(hdev);
}
static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
......@@ -1339,13 +1402,16 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff
BT_DBG("%s status %d", hdev->name, status);
if (test_and_clear_bit(HCI_INQUIRY, &hdev->flags) &&
test_bit(HCI_MGMT, &hdev->flags))
mgmt_discovering(hdev->id, 0);
hci_req_complete(hdev, HCI_OP_INQUIRY, status);
hci_conn_check_pending(hdev);
if (!test_and_clear_bit(HCI_INQUIRY, &hdev->flags))
return;
hci_dev_lock(hdev);
mgmt_discovering(hdev, 0);
hci_dev_unlock(hdev);
}
static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *skb)
......@@ -1361,12 +1427,6 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
hci_dev_lock(hdev);
if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) {
if (test_bit(HCI_MGMT, &hdev->flags))
mgmt_discovering(hdev->id, 1);
}
for (; num_rsp; num_rsp--, info++) {
bacpy(&data.bdaddr, &info->bdaddr);
data.pscan_rep_mode = info->pscan_rep_mode;
......@@ -1377,8 +1437,8 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff *
data.rssi = 0x00;
data.ssp_mode = 0x00;
hci_inquiry_cache_update(hdev, &data);
mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class, 0,
NULL);
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
info->dev_class, 0, NULL);
}
hci_dev_unlock(hdev);
......@@ -1412,7 +1472,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
conn->state = BT_CONFIG;
hci_conn_hold(conn);
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
mgmt_connected(hdev->id, &ev->bdaddr, conn->type);
mgmt_connected(hdev, &ev->bdaddr, conn->type);
} else
conn->state = BT_CONNECTED;
......@@ -1444,7 +1504,8 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
} else {
conn->state = BT_CLOSED;
if (conn->type == ACL_LINK)
mgmt_connect_failed(hdev->id, &ev->bdaddr, ev->status);
mgmt_connect_failed(hdev, &ev->bdaddr, conn->type,
ev->status);
}
if (conn->type == ACL_LINK)
......@@ -1531,7 +1592,7 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
struct hci_cp_reject_conn_req cp;
bacpy(&cp.bdaddr, &ev->bdaddr);
cp.reason = 0x0f;
cp.reason = HCI_ERROR_REJ_BAD_ADDR;
hci_send_cmd(hdev, HCI_OP_REJECT_CONN_REQ, sizeof(cp), &cp);
}
}
......@@ -1544,7 +1605,9 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
BT_DBG("%s status %d", hdev->name, ev->status);
if (ev->status) {
mgmt_disconnect_failed(hdev->id);
hci_dev_lock(hdev);
mgmt_disconnect_failed(hdev);
hci_dev_unlock(hdev);
return;
}
......@@ -1557,7 +1620,7 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
conn->state = BT_CLOSED;
if (conn->type == ACL_LINK || conn->type == LE_LINK)
mgmt_disconnected(hdev->id, &conn->dst);
mgmt_disconnected(hdev, &conn->dst, conn->type);
hci_proto_disconn_cfm(conn, ev->reason);
hci_conn_del(conn);
......@@ -1588,7 +1651,7 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
conn->sec_level = conn->pending_sec_level;
}
} else {
mgmt_auth_failed(hdev->id, &conn->dst, ev->status);
mgmt_auth_failed(hdev, &conn->dst, ev->status);
}
clear_bit(HCI_CONN_AUTH_PEND, &conn->pend);
......@@ -1643,7 +1706,7 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb
hci_dev_lock(hdev);
if (ev->status == 0 && test_bit(HCI_MGMT, &hdev->flags))
mgmt_remote_name(hdev->id, &ev->bdaddr, ev->name);
mgmt_remote_name(hdev, &ev->bdaddr, ev->name);
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
if (!conn)
......@@ -1898,6 +1961,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk
hci_cc_write_ca_timeout(hdev, skb);
break;
case HCI_OP_READ_LOCAL_AMP_INFO:
hci_cc_read_local_amp_info(hdev, skb);
break;
case HCI_OP_DELETE_STORED_LINK_KEY:
hci_cc_delete_stored_link_key(hdev, skb);
break;
......@@ -2029,7 +2096,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
case HCI_OP_DISCONNECT:
if (ev->status != 0)
mgmt_disconnect_failed(hdev->id);
mgmt_disconnect_failed(hdev);
break;
case HCI_OP_LE_CREATE_CONN:
......@@ -2194,7 +2261,7 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff
else
secure = 0;
mgmt_pin_code_request(hdev->id, &ev->bdaddr, secure);
mgmt_pin_code_request(hdev, &ev->bdaddr, secure);
}
unlock:
......@@ -2363,12 +2430,6 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
hci_dev_lock(hdev);
if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) {
if (test_bit(HCI_MGMT, &hdev->flags))
mgmt_discovering(hdev->id, 1);
}
if ((skb->len - 1) / num_rsp != sizeof(struct inquiry_info_with_rssi)) {
struct inquiry_info_with_rssi_and_pscan_mode *info;
info = (void *) (skb->data + 1);
......@@ -2383,7 +2444,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
data.rssi = info->rssi;
data.ssp_mode = 0x00;
hci_inquiry_cache_update(hdev, &data);
mgmt_device_found(hdev->id, &info->bdaddr,
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
info->dev_class, info->rssi,
NULL);
}
......@@ -2400,7 +2461,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct
data.rssi = info->rssi;
data.ssp_mode = 0x00;
hci_inquiry_cache_update(hdev, &data);
mgmt_device_found(hdev->id, &info->bdaddr,
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
info->dev_class, info->rssi,
NULL);
}
......@@ -2531,12 +2592,6 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
if (!num_rsp)
return;
if (!test_and_set_bit(HCI_INQUIRY, &hdev->flags)) {
if (test_bit(HCI_MGMT, &hdev->flags))
mgmt_discovering(hdev->id, 1);
}
hci_dev_lock(hdev);
for (; num_rsp; num_rsp--, info++) {
......@@ -2549,8 +2604,8 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct
data.rssi = info->rssi;
data.ssp_mode = 0x01;
hci_inquiry_cache_update(hdev, &data);
mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class,
info->rssi, info->data);
mgmt_device_found(hdev, &info->bdaddr, ACL_LINK,
info->dev_class, info->rssi, info->data);
}
hci_dev_unlock(hdev);
......@@ -2614,7 +2669,7 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff
struct hci_cp_io_capability_neg_reply cp;
bacpy(&cp.bdaddr, &ev->bdaddr);
cp.reason = 0x18; /* Pairing not allowed */
cp.reason = HCI_ERROR_PAIRING_NOT_ALLOWED;
hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_NEG_REPLY,
sizeof(cp), &cp);
......@@ -2706,7 +2761,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev,
}
confirm:
mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey,
mgmt_user_confirm_request(hdev, &ev->bdaddr, ev->passkey,
confirm_hint);
unlock:
......@@ -2732,7 +2787,7 @@ static inline void hci_simple_pair_complete_evt(struct hci_dev *hdev, struct sk_
* event gets always produced as initiator and is also mapped to
* the mgmt_auth_failed event */
if (!test_bit(HCI_CONN_AUTH_PEND, &conn->pend) && ev->status != 0)
mgmt_auth_failed(hdev->id, &conn->dst, ev->status);
mgmt_auth_failed(hdev, &conn->dst, ev->status);
hci_conn_put(conn);
......@@ -2813,14 +2868,14 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
}
if (ev->status) {
mgmt_connect_failed(hdev->id, &ev->bdaddr, ev->status);
mgmt_connect_failed(hdev, &ev->bdaddr, conn->type, ev->status);
hci_proto_connect_cfm(conn, ev->status);
conn->state = BT_CLOSED;
hci_conn_del(conn);
goto unlock;
}
mgmt_connected(hdev->id, &ev->bdaddr, conn->type);
mgmt_connected(hdev, &ev->bdaddr, conn->type);
conn->sec_level = BT_SECURITY_LOW;
conn->handle = __le16_to_cpu(ev->handle);
......@@ -3104,5 +3159,5 @@ void hci_si_event(struct hci_dev *hdev, int type, int dlen, void *data)
kfree_skb(skb);
}
module_param(enable_le, bool, 0444);
module_param(enable_le, bool, 0644);
MODULE_PARM_DESC(enable_le, "Enable LE support");
......@@ -435,17 +435,12 @@ static const struct file_operations inquiry_cache_fops = {
static int blacklist_show(struct seq_file *f, void *p)
{
struct hci_dev *hdev = f->private;
struct list_head *l;
hci_dev_lock_bh(hdev);
list_for_each(l, &hdev->blacklist) {
struct bdaddr_list *b;
b = list_entry(l, struct bdaddr_list, list);
hci_dev_lock_bh(hdev);
list_for_each_entry(b, &hdev->blacklist, list)
seq_printf(f, "%s\n", batostr(&b->bdaddr));
}
hci_dev_unlock_bh(hdev);
......@@ -484,17 +479,12 @@ static void print_bt_uuid(struct seq_file *f, u8 *uuid)
static int uuids_show(struct seq_file *f, void *p)
{
struct hci_dev *hdev = f->private;
struct list_head *l;
hci_dev_lock_bh(hdev);
list_for_each(l, &hdev->uuids) {
struct bt_uuid *uuid;
uuid = list_entry(l, struct bt_uuid, list);
hci_dev_lock_bh(hdev);
list_for_each_entry(uuid, &hdev->uuids, list)
print_bt_uuid(f, uuid->uuid);
}
hci_dev_unlock_bh(hdev);
......@@ -542,22 +532,28 @@ static int auto_accept_delay_get(void *data, u64 *val)
DEFINE_SIMPLE_ATTRIBUTE(auto_accept_delay_fops, auto_accept_delay_get,
auto_accept_delay_set, "%llu\n");
int hci_register_sysfs(struct hci_dev *hdev)
void hci_init_sysfs(struct hci_dev *hdev)
{
struct device *dev = &hdev->dev;
dev->type = &bt_host;
dev->class = bt_class;
dev_set_drvdata(dev, hdev);
device_initialize(dev);
}
int hci_add_sysfs(struct hci_dev *hdev)
{
struct device *dev = &hdev->dev;
int err;
BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
dev->type = &bt_host;
dev->class = bt_class;
dev->parent = hdev->parent;
dev_set_name(dev, "%s", hdev->name);
dev_set_drvdata(dev, hdev);
err = device_register(dev);
err = device_add(dev);
if (err < 0)
return err;
......@@ -581,7 +577,7 @@ int hci_register_sysfs(struct hci_dev *hdev)
return 0;
}
void hci_unregister_sysfs(struct hci_dev *hdev)
void hci_del_sysfs(struct hci_dev *hdev)
{
BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
......
......@@ -81,24 +81,20 @@ static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 };
static struct hidp_session *__hidp_get_session(bdaddr_t *bdaddr)
{
struct hidp_session *session;
struct list_head *p;
BT_DBG("");
list_for_each(p, &hidp_session_list) {
session = list_entry(p, struct hidp_session, list);
list_for_each_entry(session, &hidp_session_list, list) {
if (!bacmp(bdaddr, &session->bdaddr))
return session;
}
return NULL;
}
static void __hidp_link_session(struct hidp_session *session)
{
__module_get(THIS_MODULE);
list_add(&session->list, &hidp_session_list);
hci_conn_hold_device(session->conn);
}
static void __hidp_unlink_session(struct hidp_session *session)
......@@ -106,7 +102,6 @@ static void __hidp_unlink_session(struct hidp_session *session)
hci_conn_put_device(session->conn);
list_del(&session->list);
module_put(THIS_MODULE);
}
static void __hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci)
......@@ -255,6 +250,9 @@ static int __hidp_send_ctrl_message(struct hidp_session *session,
BT_DBG("session %p data %p size %d", session, data, size);
if (atomic_read(&session->terminate))
return -EIO;
skb = alloc_skb(size + 1, GFP_ATOMIC);
if (!skb) {
BT_ERR("Can't allocate memory for new frame");
......@@ -329,6 +327,7 @@ static int hidp_get_raw_report(struct hid_device *hid,
struct sk_buff *skb;
size_t len;
int numbered_reports = hid->report_enum[report_type].numbered;
int ret;
switch (report_type) {
case HID_FEATURE_REPORT:
......@@ -352,8 +351,9 @@ static int hidp_get_raw_report(struct hid_device *hid,
session->waiting_report_number = numbered_reports ? report_number : -1;
set_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
data[0] = report_number;
if (hidp_send_ctrl_message(hid->driver_data, report_type, data, 1))
goto err_eio;
ret = hidp_send_ctrl_message(hid->driver_data, report_type, data, 1);
if (ret)
goto err;
/* Wait for the return of the report. The returned report
gets put in session->report_return. */
......@@ -365,11 +365,13 @@ static int hidp_get_raw_report(struct hid_device *hid,
5*HZ);
if (res == 0) {
/* timeout */
goto err_eio;
ret = -EIO;
goto err;
}
if (res < 0) {
/* signal */
goto err_restartsys;
ret = -ERESTARTSYS;
goto err;
}
}
......@@ -390,14 +392,10 @@ static int hidp_get_raw_report(struct hid_device *hid,
return len;
err_restartsys:
clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
mutex_unlock(&session->report_mutex);
return -ERESTARTSYS;
err_eio:
err:
clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
mutex_unlock(&session->report_mutex);
return -EIO;
return ret;
}
static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count,
......@@ -422,11 +420,10 @@ static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, s
/* Set up our wait, and send the report request to the device. */
set_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
if (hidp_send_ctrl_message(hid->driver_data, report_type,
data, count)) {
ret = -ENOMEM;
ret = hidp_send_ctrl_message(hid->driver_data, report_type, data,
count);
if (ret)
goto err;
}
/* Wait for the ACK from the device. */
while (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) {
......@@ -496,10 +493,9 @@ static void hidp_process_handshake(struct hidp_session *session,
case HIDP_HSHK_ERR_INVALID_REPORT_ID:
case HIDP_HSHK_ERR_UNSUPPORTED_REQUEST:
case HIDP_HSHK_ERR_INVALID_PARAMETER:
if (test_bit(HIDP_WAITING_FOR_RETURN, &session->flags)) {
clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
if (test_and_clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags))
wake_up_interruptible(&session->report_queue);
}
/* FIXME: Call into SET_ GET_ handlers here */
break;
......@@ -520,10 +516,8 @@ static void hidp_process_handshake(struct hidp_session *session,
}
/* Wake up the waiting thread. */
if (test_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags)) {
clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
if (test_and_clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags))
wake_up_interruptible(&session->report_queue);
}
}
static void hidp_process_hid_control(struct hidp_session *session,
......@@ -663,25 +657,32 @@ static int hidp_send_frame(struct socket *sock, unsigned char *data, int len)
return kernel_sendmsg(sock, &msg, &iv, 1, len);
}
static void hidp_process_transmit(struct hidp_session *session)
static void hidp_process_intr_transmit(struct hidp_session *session)
{
struct sk_buff *skb;
BT_DBG("session %p", session);
while ((skb = skb_dequeue(&session->ctrl_transmit))) {
if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) {
skb_queue_head(&session->ctrl_transmit, skb);
while ((skb = skb_dequeue(&session->intr_transmit))) {
if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) {
skb_queue_head(&session->intr_transmit, skb);
break;
}
hidp_set_timer(session);
kfree_skb(skb);
}
}
while ((skb = skb_dequeue(&session->intr_transmit))) {
if (hidp_send_frame(session->intr_sock, skb->data, skb->len) < 0) {
skb_queue_head(&session->intr_transmit, skb);
static void hidp_process_ctrl_transmit(struct hidp_session *session)
{
struct sk_buff *skb;
BT_DBG("session %p", session);
while ((skb = skb_dequeue(&session->ctrl_transmit))) {
if (hidp_send_frame(session->ctrl_sock, skb->data, skb->len) < 0) {
skb_queue_head(&session->ctrl_transmit, skb);
break;
}
......@@ -700,6 +701,7 @@ static int hidp_session(void *arg)
BT_DBG("session %p", session);
__module_get(THIS_MODULE);
set_user_nice(current, -15);
init_waitqueue_entry(&ctrl_wait, current);
......@@ -714,23 +716,25 @@ static int hidp_session(void *arg)
intr_sk->sk_state != BT_CONNECTED)
break;
while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
skb_orphan(skb);
if (!skb_linearize(skb))
hidp_recv_ctrl_frame(session, skb);
hidp_recv_intr_frame(session, skb);
else
kfree_skb(skb);
}
while ((skb = skb_dequeue(&intr_sk->sk_receive_queue))) {
hidp_process_intr_transmit(session);
while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) {
skb_orphan(skb);
if (!skb_linearize(skb))
hidp_recv_intr_frame(session, skb);
hidp_recv_ctrl_frame(session, skb);
else
kfree_skb(skb);
}
hidp_process_transmit(session);
hidp_process_ctrl_transmit(session);
schedule();
set_current_state(TASK_INTERRUPTIBLE);
......@@ -739,6 +743,10 @@ static int hidp_session(void *arg)
remove_wait_queue(sk_sleep(intr_sk), &intr_wait);
remove_wait_queue(sk_sleep(ctrl_sk), &ctrl_wait);
clear_bit(HIDP_WAITING_FOR_SEND_ACK, &session->flags);
clear_bit(HIDP_WAITING_FOR_RETURN, &session->flags);
wake_up_interruptible(&session->report_queue);
down_write(&hidp_session_sem);
hidp_del_timer(session);
......@@ -772,34 +780,37 @@ static int hidp_session(void *arg)
kfree(session->rd_data);
kfree(session);
module_put_and_exit(0);
return 0;
}
static struct device *hidp_get_device(struct hidp_session *session)
static struct hci_conn *hidp_get_connection(struct hidp_session *session)
{
bdaddr_t *src = &bt_sk(session->ctrl_sock->sk)->src;
bdaddr_t *dst = &bt_sk(session->ctrl_sock->sk)->dst;
struct device *device = NULL;
struct hci_conn *conn;
struct hci_dev *hdev;
hdev = hci_get_route(dst, src);
if (!hdev)
return NULL;
session->conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
if (session->conn)
device = &session->conn->dev;
hci_dev_lock_bh(hdev);
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
if (conn)
hci_conn_hold_device(conn);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
return device;
return conn;
}
static int hidp_setup_input(struct hidp_session *session,
struct hidp_connadd_req *req)
{
struct input_dev *input;
int err, i;
int i;
input = input_allocate_device();
if (!input)
......@@ -842,17 +853,10 @@ static int hidp_setup_input(struct hidp_session *session,
input->relbit[0] |= BIT_MASK(REL_WHEEL);
}
input->dev.parent = hidp_get_device(session);
input->dev.parent = &session->conn->dev;
input->event = hidp_input_event;
err = input_register_device(input);
if (err < 0) {
input_free_device(input);
session->input = NULL;
return err;
}
return 0;
}
......@@ -949,7 +953,7 @@ static int hidp_setup_hid(struct hidp_session *session,
strncpy(hid->phys, batostr(&bt_sk(session->ctrl_sock->sk)->src), 64);
strncpy(hid->uniq, batostr(&bt_sk(session->ctrl_sock->sk)->dst), 64);
hid->dev.parent = hidp_get_device(session);
hid->dev.parent = &session->conn->dev;
hid->ll_driver = &hidp_hid_driver;
hid->hid_get_raw_report = hidp_get_raw_report;
......@@ -976,18 +980,20 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
bacmp(&bt_sk(ctrl_sock->sk)->dst, &bt_sk(intr_sock->sk)->dst))
return -ENOTUNIQ;
session = kzalloc(sizeof(struct hidp_session), GFP_KERNEL);
if (!session)
return -ENOMEM;
BT_DBG("rd_data %p rd_size %d", req->rd_data, req->rd_size);
down_write(&hidp_session_sem);
s = __hidp_get_session(&bt_sk(ctrl_sock->sk)->dst);
if (s && s->state == BT_CONNECTED) {
err = -EEXIST;
goto failed;
up_write(&hidp_session_sem);
return -EEXIST;
}
session = kzalloc(sizeof(struct hidp_session), GFP_KERNEL);
if (!session) {
up_write(&hidp_session_sem);
return -ENOMEM;
}
bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst);
......@@ -1003,6 +1009,12 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
session->intr_sock = intr_sock;
session->state = BT_CONNECTED;
session->conn = hidp_get_connection(session);
if (!session->conn) {
err = -ENOTCONN;
goto failed;
}
setup_timer(&session->timer, hidp_idle_timeout, (unsigned long)session);
skb_queue_head_init(&session->ctrl_transmit);
......@@ -1015,9 +1027,11 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
session->flags = req->flags & (1 << HIDP_BLUETOOTH_VENDOR_ID);
session->idle_to = req->idle_to;
__hidp_link_session(session);
if (req->rd_size > 0) {
err = hidp_setup_hid(session, req);
if (err && err != -ENODEV)
if (err)
goto purge;
}
......@@ -1027,8 +1041,6 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
goto purge;
}
__hidp_link_session(session);
hidp_set_timer(session);
if (session->hid) {
......@@ -1054,7 +1066,11 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
!session->waiting_for_startup);
}
if (session->hid)
err = hid_add_device(session->hid);
else
err = input_register_device(session->input);
if (err < 0) {
atomic_inc(&session->terminate);
wake_up_process(session->task);
......@@ -1077,8 +1093,6 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
unlink:
hidp_del_timer(session);
__hidp_unlink_session(session);
if (session->input) {
input_unregister_device(session->input);
session->input = NULL;
......@@ -1093,6 +1107,8 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock,
session->rd_data = NULL;
purge:
__hidp_unlink_session(session);
skb_queue_purge(&session->ctrl_transmit);
skb_queue_purge(&session->intr_transmit);
......@@ -1134,19 +1150,16 @@ int hidp_del_connection(struct hidp_conndel_req *req)
int hidp_get_connlist(struct hidp_connlist_req *req)
{
struct list_head *p;
struct hidp_session *session;
int err = 0, n = 0;
BT_DBG("");
down_read(&hidp_session_sem);
list_for_each(p, &hidp_session_list) {
struct hidp_session *session;
list_for_each_entry(session, &hidp_session_list, list) {
struct hidp_conninfo ci;
session = list_entry(p, struct hidp_session, list);
__hidp_copy_session(session, &ci);
if (copy_to_user(req->ci, &ci, sizeof(ci))) {
......
......@@ -57,9 +57,10 @@
#include <net/bluetooth/smp.h>
int disable_ertm;
int enable_hs;
static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
static u8 l2cap_fixed_chan[8] = { 0x02, };
static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP, };
static LIST_HEAD(chan_list);
static DEFINE_RWLOCK(chan_list_lock);
......@@ -219,7 +220,7 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
static void l2cap_set_timer(struct l2cap_chan *chan, struct timer_list *timer, long timeout)
{
BT_DBG("chan %p state %d timeout %ld", chan->sk, chan->state, timeout);
BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout);
if (!mod_timer(timer, jiffies + msecs_to_jiffies(timeout)))
chan_hold(chan);
......@@ -293,6 +294,8 @@ struct l2cap_chan *l2cap_chan_create(struct sock *sk)
atomic_set(&chan->refcnt, 1);
BT_DBG("sk %p chan %p", sk, chan);
return chan;
}
......@@ -310,7 +313,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
chan->psm, chan->dcid);
conn->disc_reason = 0x13;
conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
chan->conn = conn;
......@@ -337,6 +340,13 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
chan->omtu = L2CAP_DEFAULT_MTU;
}
chan->local_id = L2CAP_BESTEFFORT_ID;
chan->local_stype = L2CAP_SERV_BESTEFFORT;
chan->local_msdu = L2CAP_DEFAULT_MAX_SDU_SIZE;
chan->local_sdu_itime = L2CAP_DEFAULT_SDU_ITIME;
chan->local_acc_lat = L2CAP_DEFAULT_ACC_LAT;
chan->local_flush_to = L2CAP_DEFAULT_FLUSH_TO;
chan_hold(chan);
list_add(&chan->list, &conn->chan_l);
......@@ -556,34 +566,58 @@ static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
flags = ACL_START;
bt_cb(skb)->force_active = BT_POWER_FORCE_ACTIVE_ON;
skb->priority = HCI_PRIO_MAX;
hci_send_acl(conn->hchan, skb, flags);
}
static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
{
struct hci_conn *hcon = chan->conn->hcon;
u16 flags;
BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,
skb->priority);
if (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
lmp_no_flush_capable(hcon->hdev))
flags = ACL_START_NO_FLUSH;
else
flags = ACL_START;
hci_send_acl(conn->hcon, skb, flags);
bt_cb(skb)->force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
hci_send_acl(chan->conn->hchan, skb, flags);
}
static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
static inline void l2cap_send_sframe(struct l2cap_chan *chan, u32 control)
{
struct sk_buff *skb;
struct l2cap_hdr *lh;
struct l2cap_conn *conn = chan->conn;
int count, hlen = L2CAP_HDR_SIZE + 2;
u8 flags;
int count, hlen;
if (chan->state != BT_CONNECTED)
return;
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
hlen = L2CAP_EXT_HDR_SIZE;
else
hlen = L2CAP_ENH_HDR_SIZE;
if (chan->fcs == L2CAP_FCS_CRC16)
hlen += 2;
hlen += L2CAP_FCS_SIZE;
BT_DBG("chan %p, control 0x%2.2x", chan, control);
BT_DBG("chan %p, control 0x%8.8x", chan, control);
count = min_t(unsigned int, conn->mtu, hlen);
control |= L2CAP_CTRL_FRAME_TYPE;
control |= __set_sframe(chan);
if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
control |= L2CAP_CTRL_FINAL;
control |= __set_ctrl_final(chan);
if (test_and_clear_bit(CONN_SEND_PBIT, &chan->conn_state))
control |= L2CAP_CTRL_POLL;
control |= __set_ctrl_poll(chan);
skb = bt_skb_alloc(count, GFP_ATOMIC);
if (!skb)
......@@ -592,32 +626,27 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control)
lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
lh->len = cpu_to_le16(hlen - L2CAP_HDR_SIZE);
lh->cid = cpu_to_le16(chan->dcid);
put_unaligned_le16(control, skb_put(skb, 2));
__put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
if (chan->fcs == L2CAP_FCS_CRC16) {
u16 fcs = crc16(0, (u8 *)lh, count - 2);
put_unaligned_le16(fcs, skb_put(skb, 2));
u16 fcs = crc16(0, (u8 *)lh, count - L2CAP_FCS_SIZE);
put_unaligned_le16(fcs, skb_put(skb, L2CAP_FCS_SIZE));
}
if (lmp_no_flush_capable(conn->hcon->hdev))
flags = ACL_START_NO_FLUSH;
else
flags = ACL_START;
bt_cb(skb)->force_active = chan->force_active;
hci_send_acl(chan->conn->hcon, skb, flags);
skb->priority = HCI_PRIO_MAX;
l2cap_do_send(chan, skb);
}
static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control)
static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u32 control)
{
if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
control |= L2CAP_SUPER_RCV_NOT_READY;
control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
set_bit(CONN_RNR_SENT, &chan->conn_state);
} else
control |= L2CAP_SUPER_RCV_READY;
control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
control |= __set_reqseq(chan, chan->buffer_seq);
l2cap_send_sframe(chan, control);
}
......@@ -947,7 +976,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
list_for_each_entry(chan, &conn->chan_l, list) {
struct sock *sk = chan->sk;
if (chan->force_reliable)
if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
sk->sk_err = err;
}
......@@ -986,6 +1015,8 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
chan->ops->close(chan->data);
}
hci_chan_del(conn->hchan);
if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
del_timer_sync(&conn->info_timer);
......@@ -1008,18 +1039,26 @@ static void security_timeout(unsigned long arg)
static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
{
struct l2cap_conn *conn = hcon->l2cap_data;
struct hci_chan *hchan;
if (conn || status)
return conn;
hchan = hci_chan_create(hcon);
if (!hchan)
return NULL;
conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
if (!conn)
if (!conn) {
hci_chan_del(hchan);
return NULL;
}
hcon->l2cap_data = conn;
conn->hcon = hcon;
conn->hchan = hchan;
BT_DBG("hcon %p conn %p", hcon, conn);
BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
conn->mtu = hcon->hdev->le_mtu;
......@@ -1043,7 +1082,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
setup_timer(&conn->info_timer, l2cap_info_timeout,
(unsigned long) conn);
conn->disc_reason = 0x13;
conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
return conn;
}
......@@ -1245,47 +1284,35 @@ static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
__clear_retrans_timer(chan);
}
static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
{
struct hci_conn *hcon = chan->conn->hcon;
u16 flags;
BT_DBG("chan %p, skb %p len %d", chan, skb, skb->len);
if (!chan->flushable && lmp_no_flush_capable(hcon->hdev))
flags = ACL_START_NO_FLUSH;
else
flags = ACL_START;
bt_cb(skb)->force_active = chan->force_active;
hci_send_acl(hcon, skb, flags);
}
static void l2cap_streaming_send(struct l2cap_chan *chan)
{
struct sk_buff *skb;
u16 control, fcs;
u32 control;
u16 fcs;
while ((skb = skb_dequeue(&chan->tx_q))) {
control = get_unaligned_le16(skb->data + L2CAP_HDR_SIZE);
control |= chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT;
put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE);
control = __get_control(chan, skb->data + L2CAP_HDR_SIZE);
control |= __set_txseq(chan, chan->next_tx_seq);
__put_control(chan, control, skb->data + L2CAP_HDR_SIZE);
if (chan->fcs == L2CAP_FCS_CRC16) {
fcs = crc16(0, (u8 *)skb->data, skb->len - 2);
put_unaligned_le16(fcs, skb->data + skb->len - 2);
fcs = crc16(0, (u8 *)skb->data,
skb->len - L2CAP_FCS_SIZE);
put_unaligned_le16(fcs,
skb->data + skb->len - L2CAP_FCS_SIZE);
}
l2cap_do_send(chan, skb);
chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
}
}
static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u16 tx_seq)
{
struct sk_buff *skb, *tx_skb;
u16 control, fcs;
u16 fcs;
u32 control;
skb = skb_peek(&chan->tx_q);
if (!skb)
......@@ -1308,20 +1335,23 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
tx_skb = skb_clone(skb, GFP_ATOMIC);
bt_cb(skb)->retries++;
control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
control &= L2CAP_CTRL_SAR;
control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
control &= __get_sar_mask(chan);
if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
control |= L2CAP_CTRL_FINAL;
control |= __set_ctrl_final(chan);
control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
| (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
control |= __set_reqseq(chan, chan->buffer_seq);
control |= __set_txseq(chan, tx_seq);
put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
__put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
if (chan->fcs == L2CAP_FCS_CRC16) {
fcs = crc16(0, (u8 *)tx_skb->data, tx_skb->len - 2);
put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2);
fcs = crc16(0, (u8 *)tx_skb->data,
tx_skb->len - L2CAP_FCS_SIZE);
put_unaligned_le16(fcs,
tx_skb->data + tx_skb->len - L2CAP_FCS_SIZE);
}
l2cap_do_send(chan, tx_skb);
......@@ -1330,7 +1360,8 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq)
static int l2cap_ertm_send(struct l2cap_chan *chan)
{
struct sk_buff *skb, *tx_skb;
u16 control, fcs;
u16 fcs;
u32 control;
int nsent = 0;
if (chan->state != BT_CONNECTED)
......@@ -1348,20 +1379,22 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
bt_cb(skb)->retries++;
control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE);
control &= L2CAP_CTRL_SAR;
control = __get_control(chan, tx_skb->data + L2CAP_HDR_SIZE);
control &= __get_sar_mask(chan);
if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state))
control |= L2CAP_CTRL_FINAL;
control |= __set_ctrl_final(chan);
control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT)
| (chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT);
put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE);
control |= __set_reqseq(chan, chan->buffer_seq);
control |= __set_txseq(chan, chan->next_tx_seq);
__put_control(chan, control, tx_skb->data + L2CAP_HDR_SIZE);
if (chan->fcs == L2CAP_FCS_CRC16) {
fcs = crc16(0, (u8 *)skb->data, tx_skb->len - 2);
put_unaligned_le16(fcs, skb->data + tx_skb->len - 2);
fcs = crc16(0, (u8 *)skb->data,
tx_skb->len - L2CAP_FCS_SIZE);
put_unaligned_le16(fcs, skb->data +
tx_skb->len - L2CAP_FCS_SIZE);
}
l2cap_do_send(chan, tx_skb);
......@@ -1369,7 +1402,8 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
__set_retrans_timer(chan);
bt_cb(skb)->tx_seq = chan->next_tx_seq;
chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
chan->next_tx_seq = __next_seq(chan, chan->next_tx_seq);
if (bt_cb(skb)->retries == 1)
chan->unacked_frames++;
......@@ -1401,12 +1435,12 @@ static int l2cap_retransmit_frames(struct l2cap_chan *chan)
static void l2cap_send_ack(struct l2cap_chan *chan)
{
u16 control = 0;
u32 control = 0;
control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
control |= __set_reqseq(chan, chan->buffer_seq);
if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
control |= L2CAP_SUPER_RCV_NOT_READY;
control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
set_bit(CONN_RNR_SENT, &chan->conn_state);
l2cap_send_sframe(chan, control);
return;
......@@ -1415,20 +1449,20 @@ static void l2cap_send_ack(struct l2cap_chan *chan)
if (l2cap_ertm_send(chan) > 0)
return;
control |= L2CAP_SUPER_RCV_READY;
control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
l2cap_send_sframe(chan, control);
}
static void l2cap_send_srejtail(struct l2cap_chan *chan)
{
struct srej_list *tail;
u16 control;
u32 control;
control = L2CAP_SUPER_SELECT_REJECT;
control |= L2CAP_CTRL_FINAL;
control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
control |= __set_ctrl_final(chan);
tail = list_entry((&chan->srej_l)->prev, struct srej_list, list);
control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
control |= __set_reqseq(chan, tail->tx_seq);
l2cap_send_sframe(chan, control);
}
......@@ -1456,6 +1490,8 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in
if (memcpy_fromiovec(skb_put(*frag, count), msg->msg_iov, count))
return -EFAULT;
(*frag)->priority = skb->priority;
sent += count;
len -= count;
......@@ -1465,15 +1501,17 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in
return sent;
}
static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan,
struct msghdr *msg, size_t len,
u32 priority)
{
struct sock *sk = chan->sk;
struct l2cap_conn *conn = chan->conn;
struct sk_buff *skb;
int err, count, hlen = L2CAP_HDR_SIZE + 2;
int err, count, hlen = L2CAP_HDR_SIZE + L2CAP_PSMLEN_SIZE;
struct l2cap_hdr *lh;
BT_DBG("sk %p len %d", sk, (int)len);
BT_DBG("sk %p len %d priority %u", sk, (int)len, priority);
count = min_t(unsigned int, (conn->mtu - hlen), len);
skb = bt_skb_send_alloc(sk, count + hlen,
......@@ -1481,6 +1519,8 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct
if (!skb)
return ERR_PTR(err);
skb->priority = priority;
/* Create L2CAP header */
lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
lh->cid = cpu_to_le16(chan->dcid);
......@@ -1495,7 +1535,9 @@ static struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct
return skb;
}
static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan,
struct msghdr *msg, size_t len,
u32 priority)
{
struct sock *sk = chan->sk;
struct l2cap_conn *conn = chan->conn;
......@@ -1511,6 +1553,8 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct ms
if (!skb)
return ERR_PTR(err);
skb->priority = priority;
/* Create L2CAP header */
lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
lh->cid = cpu_to_le16(chan->dcid);
......@@ -1526,12 +1570,12 @@ static struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct ms
static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
struct msghdr *msg, size_t len,
u16 control, u16 sdulen)
u32 control, u16 sdulen)
{
struct sock *sk = chan->sk;
struct l2cap_conn *conn = chan->conn;
struct sk_buff *skb;
int err, count, hlen = L2CAP_HDR_SIZE + 2;
int err, count, hlen;
struct l2cap_hdr *lh;
BT_DBG("sk %p len %d", sk, (int)len);
......@@ -1539,11 +1583,16 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
if (!conn)
return ERR_PTR(-ENOTCONN);
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
hlen = L2CAP_EXT_HDR_SIZE;
else
hlen = L2CAP_ENH_HDR_SIZE;
if (sdulen)
hlen += 2;
hlen += L2CAP_SDULEN_SIZE;
if (chan->fcs == L2CAP_FCS_CRC16)
hlen += 2;
hlen += L2CAP_FCS_SIZE;
count = min_t(unsigned int, (conn->mtu - hlen), len);
skb = bt_skb_send_alloc(sk, count + hlen,
......@@ -1555,9 +1604,11 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
lh->cid = cpu_to_le16(chan->dcid);
lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE));
put_unaligned_le16(control, skb_put(skb, 2));
__put_control(chan, control, skb_put(skb, __ctrl_size(chan)));
if (sdulen)
put_unaligned_le16(sdulen, skb_put(skb, 2));
put_unaligned_le16(sdulen, skb_put(skb, L2CAP_SDULEN_SIZE));
err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb);
if (unlikely(err < 0)) {
......@@ -1566,7 +1617,7 @@ static struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan,
}
if (chan->fcs == L2CAP_FCS_CRC16)
put_unaligned_le16(0, skb_put(skb, 2));
put_unaligned_le16(0, skb_put(skb, L2CAP_FCS_SIZE));
bt_cb(skb)->retries = 0;
return skb;
......@@ -1576,11 +1627,11 @@ static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, si
{
struct sk_buff *skb;
struct sk_buff_head sar_queue;
u16 control;
u32 control;
size_t size = 0;
skb_queue_head_init(&sar_queue);
control = L2CAP_SDU_START;
control = __set_ctrl_sar(chan, L2CAP_SAR_START);
skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len);
if (IS_ERR(skb))
return PTR_ERR(skb);
......@@ -1593,10 +1644,10 @@ static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, si
size_t buflen;
if (len > chan->remote_mps) {
control = L2CAP_SDU_CONTINUE;
control = __set_ctrl_sar(chan, L2CAP_SAR_CONTINUE);
buflen = chan->remote_mps;
} else {
control = L2CAP_SDU_END;
control = __set_ctrl_sar(chan, L2CAP_SAR_END);
buflen = len;
}
......@@ -1617,15 +1668,16 @@ static int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, si
return size;
}
int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
u32 priority)
{
struct sk_buff *skb;
u16 control;
u32 control;
int err;
/* Connectionless channel */
if (chan->chan_type == L2CAP_CHAN_CONN_LESS) {
skb = l2cap_create_connless_pdu(chan, msg, len);
skb = l2cap_create_connless_pdu(chan, msg, len, priority);
if (IS_ERR(skb))
return PTR_ERR(skb);
......@@ -1640,7 +1692,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
return -EMSGSIZE;
/* Create a basic PDU */
skb = l2cap_create_basic_pdu(chan, msg, len);
skb = l2cap_create_basic_pdu(chan, msg, len, priority);
if (IS_ERR(skb))
return PTR_ERR(skb);
......@@ -1652,7 +1704,7 @@ int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len)
case L2CAP_MODE_STREAMING:
/* Entire SDU fits into one PDU */
if (len <= chan->remote_mps) {
control = L2CAP_SDU_UNSEGMENTED;
control = __set_ctrl_sar(chan, L2CAP_SAR_UNSEGMENTED);
skb = l2cap_create_iframe_pdu(chan, msg, len, control,
0);
if (IS_ERR(skb))
......@@ -1850,6 +1902,37 @@ static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val)
*ptr += L2CAP_CONF_OPT_SIZE + len;
}
static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
{
struct l2cap_conf_efs efs;
switch(chan->mode) {
case L2CAP_MODE_ERTM:
efs.id = chan->local_id;
efs.stype = chan->local_stype;
efs.msdu = cpu_to_le16(chan->local_msdu);
efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
efs.acc_lat = cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
efs.flush_to = cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
break;
case L2CAP_MODE_STREAMING:
efs.id = 1;
efs.stype = L2CAP_SERV_BESTEFFORT;
efs.msdu = cpu_to_le16(chan->local_msdu);
efs.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
efs.acc_lat = 0;
efs.flush_to = 0;
break;
default:
return;
}
l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
(unsigned long) &efs);
}
static void l2cap_ack_timeout(unsigned long arg)
{
struct l2cap_chan *chan = (void *) arg;
......@@ -1896,11 +1979,36 @@ static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
}
}
static inline bool __l2cap_ews_supported(struct l2cap_chan *chan)
{
return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_WINDOW;
}
static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
{
return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
}
static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
{
if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
__l2cap_ews_supported(chan)) {
/* use extended control field */
set_bit(FLAG_EXT_CTRL, &chan->flags);
chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
} else {
chan->tx_win = min_t(u16, chan->tx_win,
L2CAP_DEFAULT_TX_WINDOW);
chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
}
}
static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
{
struct l2cap_conf_req *req = data;
struct l2cap_conf_rfc rfc = { .mode = chan->mode };
void *ptr = req->data;
u16 size;
BT_DBG("chan %p", chan);
......@@ -1913,6 +2021,9 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state))
break;
if (__l2cap_efs_supported(chan))
set_bit(FLAG_EFS_ENABLE, &chan->flags);
/* fall through */
default:
chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask);
......@@ -1942,17 +2053,27 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
case L2CAP_MODE_ERTM:
rfc.mode = L2CAP_MODE_ERTM;
rfc.txwin_size = chan->tx_win;
rfc.max_transmit = chan->max_tx;
rfc.retrans_timeout = 0;
rfc.monitor_timeout = 0;
rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
L2CAP_EXT_HDR_SIZE -
L2CAP_SDULEN_SIZE -
L2CAP_FCS_SIZE);
rfc.max_pdu_size = cpu_to_le16(size);
l2cap_txwin_setup(chan);
rfc.txwin_size = min_t(u16, chan->tx_win,
L2CAP_DEFAULT_TX_WINDOW);
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
(unsigned long) &rfc);
if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
l2cap_add_opt_efs(&ptr, chan);
if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
break;
......@@ -1961,6 +2082,10 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
chan->fcs = L2CAP_FCS_NONE;
l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
}
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
chan->tx_win);
break;
case L2CAP_MODE_STREAMING:
......@@ -1969,13 +2094,19 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data)
rfc.max_transmit = 0;
rfc.retrans_timeout = 0;
rfc.monitor_timeout = 0;
rfc.max_pdu_size = cpu_to_le16(L2CAP_DEFAULT_MAX_PDU_SIZE);
if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10)
rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
L2CAP_EXT_HDR_SIZE -
L2CAP_SDULEN_SIZE -
L2CAP_FCS_SIZE);
rfc.max_pdu_size = cpu_to_le16(size);
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
(unsigned long) &rfc);
if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
l2cap_add_opt_efs(&ptr, chan);
if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS))
break;
......@@ -2002,8 +2133,11 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
int type, hint, olen;
unsigned long val;
struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC };
struct l2cap_conf_efs efs;
u8 remote_efs = 0;
u16 mtu = L2CAP_DEFAULT_MTU;
u16 result = L2CAP_CONF_SUCCESS;
u16 size;
BT_DBG("chan %p", chan);
......@@ -2033,7 +2167,22 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
case L2CAP_CONF_FCS:
if (val == L2CAP_FCS_NONE)
set_bit(CONF_NO_FCS_RECV, &chan->conf_state);
break;
case L2CAP_CONF_EFS:
remote_efs = 1;
if (olen == sizeof(efs))
memcpy(&efs, (void *) val, olen);
break;
case L2CAP_CONF_EWS:
if (!enable_hs)
return -ECONNREFUSED;
set_bit(FLAG_EXT_CTRL, &chan->flags);
set_bit(CONF_EWS_RECV, &chan->conf_state);
chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
chan->remote_tx_win = val;
break;
default:
......@@ -2058,6 +2207,13 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
break;
}
if (remote_efs) {
if (__l2cap_efs_supported(chan))
set_bit(FLAG_EFS_ENABLE, &chan->flags);
else
return -ECONNREFUSED;
}
if (chan->mode != rfc.mode)
return -ECONNREFUSED;
......@@ -2076,7 +2232,6 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
sizeof(rfc), (unsigned long) &rfc);
}
if (result == L2CAP_CONF_SUCCESS) {
/* Configure output options and let the other side know
* which ones we don't like. */
......@@ -2089,6 +2244,26 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
}
l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu);
if (remote_efs) {
if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
efs.stype != L2CAP_SERV_NOTRAFIC &&
efs.stype != chan->local_stype) {
result = L2CAP_CONF_UNACCEPT;
if (chan->num_conf_req >= 1)
return -ECONNREFUSED;
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
sizeof(efs),
(unsigned long) &efs);
} else {
/* Send PENDING Conf Rsp */
result = L2CAP_CONF_PENDING;
set_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
}
}
switch (rfc.mode) {
case L2CAP_MODE_BASIC:
chan->fcs = L2CAP_FCS_NONE;
......@@ -2096,13 +2271,20 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
break;
case L2CAP_MODE_ERTM:
if (!test_bit(CONF_EWS_RECV, &chan->conf_state))
chan->remote_tx_win = rfc.txwin_size;
chan->remote_max_tx = rfc.max_transmit;
else
rfc.txwin_size = L2CAP_DEFAULT_TX_WINDOW;
if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
chan->remote_max_tx = rfc.max_transmit;
chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
chan->conn->mtu -
L2CAP_EXT_HDR_SIZE -
L2CAP_SDULEN_SIZE -
L2CAP_FCS_SIZE);
rfc.max_pdu_size = cpu_to_le16(size);
chan->remote_mps = size;
rfc.retrans_timeout =
le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO);
......@@ -2114,13 +2296,29 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
sizeof(rfc), (unsigned long) &rfc);
if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
chan->remote_id = efs.id;
chan->remote_stype = efs.stype;
chan->remote_msdu = le16_to_cpu(efs.msdu);
chan->remote_flush_to =
le32_to_cpu(efs.flush_to);
chan->remote_acc_lat =
le32_to_cpu(efs.acc_lat);
chan->remote_sdu_itime =
le32_to_cpu(efs.sdu_itime);
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
sizeof(efs), (unsigned long) &efs);
}
break;
case L2CAP_MODE_STREAMING:
if (le16_to_cpu(rfc.max_pdu_size) > chan->conn->mtu - 10)
rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10);
chan->remote_mps = le16_to_cpu(rfc.max_pdu_size);
size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
chan->conn->mtu -
L2CAP_EXT_HDR_SIZE -
L2CAP_SDULEN_SIZE -
L2CAP_FCS_SIZE);
rfc.max_pdu_size = cpu_to_le16(size);
chan->remote_mps = size;
set_bit(CONF_MODE_DONE, &chan->conf_state);
......@@ -2153,6 +2351,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
int type, olen;
unsigned long val;
struct l2cap_conf_rfc rfc;
struct l2cap_conf_efs efs;
BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data);
......@@ -2188,6 +2387,26 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
sizeof(rfc), (unsigned long) &rfc);
break;
case L2CAP_CONF_EWS:
chan->tx_win = min_t(u16, val,
L2CAP_DEFAULT_EXT_WINDOW);
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
chan->tx_win);
break;
case L2CAP_CONF_EFS:
if (olen == sizeof(efs))
memcpy(&efs, (void *)val, olen);
if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
efs.stype != L2CAP_SERV_NOTRAFIC &&
efs.stype != chan->local_stype)
return -ECONNREFUSED;
l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
sizeof(efs), (unsigned long) &efs);
break;
}
}
......@@ -2196,13 +2415,23 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
chan->mode = rfc.mode;
if (*result == L2CAP_CONF_SUCCESS) {
if (*result == L2CAP_CONF_SUCCESS || *result == L2CAP_CONF_PENDING) {
switch (rfc.mode) {
case L2CAP_MODE_ERTM:
chan->retrans_timeout = le16_to_cpu(rfc.retrans_timeout);
chan->monitor_timeout = le16_to_cpu(rfc.monitor_timeout);
chan->mps = le16_to_cpu(rfc.max_pdu_size);
if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
chan->local_msdu = le16_to_cpu(efs.msdu);
chan->local_sdu_itime =
le32_to_cpu(efs.sdu_itime);
chan->local_acc_lat = le32_to_cpu(efs.acc_lat);
chan->local_flush_to =
le32_to_cpu(efs.flush_to);
}
break;
case L2CAP_MODE_STREAMING:
chan->mps = le16_to_cpu(rfc.max_pdu_size);
}
......@@ -2330,7 +2559,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
/* Check if the ACL is secure enough (if not SDP) */
if (psm != cpu_to_le16(0x0001) &&
!hci_conn_check_link_mode(conn->hcon)) {
conn->disc_reason = 0x05;
conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
result = L2CAP_CR_SEC_BLOCK;
goto response;
}
......@@ -2602,6 +2831,21 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
chan->num_conf_req++;
}
/* Got Conf Rsp PENDING from remote side and asume we sent
Conf Rsp PENDING in the code above */
if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) &&
test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
/* check compatibility */
clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
l2cap_build_conf_rsp(chan, rsp,
L2CAP_CONF_SUCCESS, 0x0000), rsp);
}
unlock:
bh_unlock_sock(sk);
return 0;
......@@ -2631,8 +2875,33 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
switch (result) {
case L2CAP_CONF_SUCCESS:
l2cap_conf_rfc_get(chan, rsp->data, len);
clear_bit(CONF_REM_CONF_PEND, &chan->conf_state);
break;
case L2CAP_CONF_PENDING:
set_bit(CONF_REM_CONF_PEND, &chan->conf_state);
if (test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
char buf[64];
len = l2cap_parse_conf_rsp(chan, rsp->data, len,
buf, &result);
if (len < 0) {
l2cap_send_disconn_req(conn, chan, ECONNRESET);
goto done;
}
/* check compatibility */
clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
l2cap_build_conf_rsp(chan, buf,
L2CAP_CONF_SUCCESS, 0x0000), buf);
}
goto done;
case L2CAP_CONF_UNACCEPT:
if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) {
char req[64];
......@@ -2782,15 +3051,25 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm
if (!disable_ertm)
feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
| L2CAP_FEAT_FCS;
if (enable_hs)
feat_mask |= L2CAP_FEAT_EXT_FLOW
| L2CAP_FEAT_EXT_WINDOW;
put_unaligned_le32(feat_mask, rsp->data);
l2cap_send_cmd(conn, cmd->ident,
L2CAP_INFO_RSP, sizeof(buf), buf);
} else if (type == L2CAP_IT_FIXED_CHAN) {
u8 buf[12];
struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
if (enable_hs)
l2cap_fixed_chan[0] |= L2CAP_FC_A2MP;
else
l2cap_fixed_chan[0] &= ~L2CAP_FC_A2MP;
rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
memcpy(buf + 4, l2cap_fixed_chan, 8);
memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
l2cap_send_cmd(conn, cmd->ident,
L2CAP_INFO_RSP, sizeof(buf), buf);
} else {
......@@ -2857,6 +3136,165 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
return 0;
}
static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len,
void *data)
{
struct l2cap_create_chan_req *req = data;
struct l2cap_create_chan_rsp rsp;
u16 psm, scid;
if (cmd_len != sizeof(*req))
return -EPROTO;
if (!enable_hs)
return -EINVAL;
psm = le16_to_cpu(req->psm);
scid = le16_to_cpu(req->scid);
BT_DBG("psm %d, scid %d, amp_id %d", psm, scid, req->amp_id);
/* Placeholder: Always reject */
rsp.dcid = 0;
rsp.scid = cpu_to_le16(scid);
rsp.result = L2CAP_CR_NO_MEM;
rsp.status = L2CAP_CS_NO_INFO;
l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
sizeof(rsp), &rsp);
return 0;
}
static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, void *data)
{
BT_DBG("conn %p", conn);
return l2cap_connect_rsp(conn, cmd, data);
}
static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
u16 icid, u16 result)
{
struct l2cap_move_chan_rsp rsp;
BT_DBG("icid %d, result %d", icid, result);
rsp.icid = cpu_to_le16(icid);
rsp.result = cpu_to_le16(result);
l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp);
}
static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn,
struct l2cap_chan *chan, u16 icid, u16 result)
{
struct l2cap_move_chan_cfm cfm;
u8 ident;
BT_DBG("icid %d, result %d", icid, result);
ident = l2cap_get_ident(conn);
if (chan)
chan->ident = ident;
cfm.icid = cpu_to_le16(icid);
cfm.result = cpu_to_le16(result);
l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm);
}
static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
u16 icid)
{
struct l2cap_move_chan_cfm_rsp rsp;
BT_DBG("icid %d", icid);
rsp.icid = cpu_to_le16(icid);
l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
}
static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
{
struct l2cap_move_chan_req *req = data;
u16 icid = 0;
u16 result = L2CAP_MR_NOT_ALLOWED;
if (cmd_len != sizeof(*req))
return -EPROTO;
icid = le16_to_cpu(req->icid);
BT_DBG("icid %d, dest_amp_id %d", icid, req->dest_amp_id);
if (!enable_hs)
return -EINVAL;
/* Placeholder: Always refuse */
l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result);
return 0;
}
static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
{
struct l2cap_move_chan_rsp *rsp = data;
u16 icid, result;
if (cmd_len != sizeof(*rsp))
return -EPROTO;
icid = le16_to_cpu(rsp->icid);
result = le16_to_cpu(rsp->result);
BT_DBG("icid %d, result %d", icid, result);
/* Placeholder: Always unconfirmed */
l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED);
return 0;
}
static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
{
struct l2cap_move_chan_cfm *cfm = data;
u16 icid, result;
if (cmd_len != sizeof(*cfm))
return -EPROTO;
icid = le16_to_cpu(cfm->icid);
result = le16_to_cpu(cfm->result);
BT_DBG("icid %d, result %d", icid, result);
l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
return 0;
}
static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
struct l2cap_cmd_hdr *cmd, u16 cmd_len, void *data)
{
struct l2cap_move_chan_cfm_rsp *rsp = data;
u16 icid;
if (cmd_len != sizeof(*rsp))
return -EPROTO;
icid = le16_to_cpu(rsp->icid);
BT_DBG("icid %d", icid);
return 0;
}
static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
u16 to_multiplier)
{
......@@ -2969,6 +3407,30 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
err = l2cap_information_rsp(conn, cmd, data);
break;
case L2CAP_CREATE_CHAN_REQ:
err = l2cap_create_channel_req(conn, cmd, cmd_len, data);
break;
case L2CAP_CREATE_CHAN_RSP:
err = l2cap_create_channel_rsp(conn, cmd, data);
break;
case L2CAP_MOVE_CHAN_REQ:
err = l2cap_move_channel_req(conn, cmd, cmd_len, data);
break;
case L2CAP_MOVE_CHAN_RSP:
err = l2cap_move_channel_rsp(conn, cmd, cmd_len, data);
break;
case L2CAP_MOVE_CHAN_CFM:
err = l2cap_move_channel_confirm(conn, cmd, cmd_len, data);
break;
case L2CAP_MOVE_CHAN_CFM_RSP:
err = l2cap_move_channel_confirm_rsp(conn, cmd, cmd_len, data);
break;
default:
BT_ERR("Unknown BR/EDR signaling command 0x%2.2x", cmd->code);
err = -EINVAL;
......@@ -3047,10 +3509,15 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
{
u16 our_fcs, rcv_fcs;
int hdr_size = L2CAP_HDR_SIZE + 2;
int hdr_size;
if (test_bit(FLAG_EXT_CTRL, &chan->flags))
hdr_size = L2CAP_EXT_HDR_SIZE;
else
hdr_size = L2CAP_ENH_HDR_SIZE;
if (chan->fcs == L2CAP_FCS_CRC16) {
skb_trim(skb, skb->len - 2);
skb_trim(skb, skb->len - L2CAP_FCS_SIZE);
rcv_fcs = get_unaligned_le16(skb->data + skb->len);
our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size);
......@@ -3062,14 +3529,14 @@ static int l2cap_check_fcs(struct l2cap_chan *chan, struct sk_buff *skb)
static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
{
u16 control = 0;
u32 control = 0;
chan->frames_sent = 0;
control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
control |= __set_reqseq(chan, chan->buffer_seq);
if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
control |= L2CAP_SUPER_RCV_NOT_READY;
control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
l2cap_send_sframe(chan, control);
set_bit(CONN_RNR_SENT, &chan->conn_state);
}
......@@ -3081,12 +3548,12 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
if (!test_bit(CONN_LOCAL_BUSY, &chan->conn_state) &&
chan->frames_sent == 0) {
control |= L2CAP_SUPER_RCV_READY;
control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
l2cap_send_sframe(chan, control);
}
}
static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u8 tx_seq, u8 sar)
static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u16 tx_seq, u8 sar)
{
struct sk_buff *next_skb;
int tx_seq_offset, next_tx_seq_offset;
......@@ -3100,18 +3567,14 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb,
return 0;
}
tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
if (tx_seq_offset < 0)
tx_seq_offset += 64;
tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
do {
if (bt_cb(next_skb)->tx_seq == tx_seq)
return -EINVAL;
next_tx_seq_offset = (bt_cb(next_skb)->tx_seq -
chan->buffer_seq) % 64;
if (next_tx_seq_offset < 0)
next_tx_seq_offset += 64;
next_tx_seq_offset = __seq_offset(chan,
bt_cb(next_skb)->tx_seq, chan->buffer_seq);
if (next_tx_seq_offset > tx_seq_offset) {
__skb_queue_before(&chan->srej_q, next_skb, skb);
......@@ -3147,24 +3610,24 @@ static void append_skb_frag(struct sk_buff *skb,
skb->truesize += new_frag->truesize;
}
static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control)
static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u32 control)
{
int err = -EINVAL;
switch (control & L2CAP_CTRL_SAR) {
case L2CAP_SDU_UNSEGMENTED:
switch (__get_ctrl_sar(chan, control)) {
case L2CAP_SAR_UNSEGMENTED:
if (chan->sdu)
break;
err = chan->ops->recv(chan->data, skb);
break;
case L2CAP_SDU_START:
case L2CAP_SAR_START:
if (chan->sdu)
break;
chan->sdu_len = get_unaligned_le16(skb->data);
skb_pull(skb, 2);
skb_pull(skb, L2CAP_SDULEN_SIZE);
if (chan->sdu_len > chan->imtu) {
err = -EMSGSIZE;
......@@ -3181,7 +3644,7 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u1
err = 0;
break;
case L2CAP_SDU_CONTINUE:
case L2CAP_SAR_CONTINUE:
if (!chan->sdu)
break;
......@@ -3195,7 +3658,7 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u1
err = 0;
break;
case L2CAP_SDU_END:
case L2CAP_SAR_END:
if (!chan->sdu)
break;
......@@ -3230,14 +3693,14 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u1
static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
{
u16 control;
u32 control;
BT_DBG("chan %p, Enter local busy", chan);
set_bit(CONN_LOCAL_BUSY, &chan->conn_state);
control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
control |= L2CAP_SUPER_RCV_NOT_READY;
control = __set_reqseq(chan, chan->buffer_seq);
control |= __set_ctrl_super(chan, L2CAP_SUPER_RNR);
l2cap_send_sframe(chan, control);
set_bit(CONN_RNR_SENT, &chan->conn_state);
......@@ -3247,13 +3710,14 @@ static void l2cap_ertm_enter_local_busy(struct l2cap_chan *chan)
static void l2cap_ertm_exit_local_busy(struct l2cap_chan *chan)
{
u16 control;
u32 control;
if (!test_bit(CONN_RNR_SENT, &chan->conn_state))
goto done;
control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT;
control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL;
control = __set_reqseq(chan, chan->buffer_seq);
control |= __set_ctrl_poll(chan);
control |= __set_ctrl_super(chan, L2CAP_SUPER_RR);
l2cap_send_sframe(chan, control);
chan->retry_count = 1;
......@@ -3279,10 +3743,10 @@ void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
}
}
static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
static void l2cap_check_srej_gap(struct l2cap_chan *chan, u16 tx_seq)
{
struct sk_buff *skb;
u16 control;
u32 control;
while ((skb = skb_peek(&chan->srej_q)) &&
!test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
......@@ -3292,7 +3756,7 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
break;
skb = skb_dequeue(&chan->srej_q);
control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT;
control = __set_ctrl_sar(chan, bt_cb(skb)->sar);
err = l2cap_reassemble_sdu(chan, skb, control);
if (err < 0) {
......@@ -3300,16 +3764,15 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq)
break;
}
chan->buffer_seq_srej =
(chan->buffer_seq_srej + 1) % 64;
tx_seq = (tx_seq + 1) % 64;
chan->buffer_seq_srej = __next_seq(chan, chan->buffer_seq_srej);
tx_seq = __next_seq(chan, tx_seq);
}
}
static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq)
static void l2cap_resend_srejframe(struct l2cap_chan *chan, u16 tx_seq)
{
struct srej_list *l, *tmp;
u16 control;
u32 control;
list_for_each_entry_safe(l, tmp, &chan->srej_l, list) {
if (l->tx_seq == tx_seq) {
......@@ -3317,45 +3780,48 @@ static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq)
kfree(l);
return;
}
control = L2CAP_SUPER_SELECT_REJECT;
control |= l->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
control |= __set_reqseq(chan, l->tx_seq);
l2cap_send_sframe(chan, control);
list_del(&l->list);
list_add_tail(&l->list, &chan->srej_l);
}
}
static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq)
static void l2cap_send_srejframe(struct l2cap_chan *chan, u16 tx_seq)
{
struct srej_list *new;
u16 control;
u32 control;
while (tx_seq != chan->expected_tx_seq) {
control = L2CAP_SUPER_SELECT_REJECT;
control |= chan->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT;
control = __set_ctrl_super(chan, L2CAP_SUPER_SREJ);
control |= __set_reqseq(chan, chan->expected_tx_seq);
l2cap_send_sframe(chan, control);
new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC);
new->tx_seq = chan->expected_tx_seq;
chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
list_add_tail(&new->list, &chan->srej_l);
}
chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
}
static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb)
static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
{
u8 tx_seq = __get_txseq(rx_control);
u8 req_seq = __get_reqseq(rx_control);
u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT;
u16 tx_seq = __get_txseq(chan, rx_control);
u16 req_seq = __get_reqseq(chan, rx_control);
u8 sar = __get_ctrl_sar(chan, rx_control);
int tx_seq_offset, expected_tx_seq_offset;
int num_to_ack = (chan->tx_win/6) + 1;
int err = 0;
BT_DBG("chan %p len %d tx_seq %d rx_control 0x%4.4x", chan, skb->len,
BT_DBG("chan %p len %d tx_seq %d rx_control 0x%8.8x", chan, skb->len,
tx_seq, rx_control);
if (L2CAP_CTRL_FINAL & rx_control &&
if (__is_ctrl_final(chan, rx_control) &&
test_bit(CONN_WAIT_F, &chan->conn_state)) {
__clear_monitor_timer(chan);
if (chan->unacked_frames > 0)
......@@ -3366,9 +3832,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
chan->expected_ack_seq = req_seq;
l2cap_drop_acked_frames(chan);
tx_seq_offset = (tx_seq - chan->buffer_seq) % 64;
if (tx_seq_offset < 0)
tx_seq_offset += 64;
tx_seq_offset = __seq_offset(chan, tx_seq, chan->buffer_seq);
/* invalid tx_seq */
if (tx_seq_offset >= chan->tx_win) {
......@@ -3416,10 +3880,8 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
l2cap_send_srejframe(chan, tx_seq);
}
} else {
expected_tx_seq_offset =
(chan->expected_tx_seq - chan->buffer_seq) % 64;
if (expected_tx_seq_offset < 0)
expected_tx_seq_offset += 64;
expected_tx_seq_offset = __seq_offset(chan,
chan->expected_tx_seq, chan->buffer_seq);
/* duplicated tx_seq */
if (tx_seq_offset < expected_tx_seq_offset)
......@@ -3444,7 +3906,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
return 0;
expected:
chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64;
chan->expected_tx_seq = __next_seq(chan, chan->expected_tx_seq);
if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
bt_cb(skb)->tx_seq = tx_seq;
......@@ -3454,13 +3916,14 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
}
err = l2cap_reassemble_sdu(chan, skb, rx_control);
chan->buffer_seq = (chan->buffer_seq + 1) % 64;
chan->buffer_seq = __next_seq(chan, chan->buffer_seq);
if (err < 0) {
l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
return err;
}
if (rx_control & L2CAP_CTRL_FINAL) {
if (__is_ctrl_final(chan, rx_control)) {
if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
l2cap_retransmit_frames(chan);
}
......@@ -3478,15 +3941,15 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont
return 0;
}
static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_control)
static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u32 rx_control)
{
BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, __get_reqseq(rx_control),
rx_control);
BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan,
__get_reqseq(chan, rx_control), rx_control);
chan->expected_ack_seq = __get_reqseq(rx_control);
chan->expected_ack_seq = __get_reqseq(chan, rx_control);
l2cap_drop_acked_frames(chan);
if (rx_control & L2CAP_CTRL_POLL) {
if (__is_ctrl_poll(chan, rx_control)) {
set_bit(CONN_SEND_FBIT, &chan->conn_state);
if (test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state) &&
......@@ -3499,7 +3962,7 @@ static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_co
l2cap_send_i_or_rr_or_rnr(chan);
}
} else if (rx_control & L2CAP_CTRL_FINAL) {
} else if (__is_ctrl_final(chan, rx_control)) {
clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
......@@ -3518,18 +3981,18 @@ static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_co
}
}
static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_control)
static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u32 rx_control)
{
u8 tx_seq = __get_reqseq(rx_control);
u16 tx_seq = __get_reqseq(chan, rx_control);
BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
chan->expected_ack_seq = tx_seq;
l2cap_drop_acked_frames(chan);
if (rx_control & L2CAP_CTRL_FINAL) {
if (__is_ctrl_final(chan, rx_control)) {
if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state))
l2cap_retransmit_frames(chan);
} else {
......@@ -3539,15 +4002,15 @@ static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_c
set_bit(CONN_REJ_ACT, &chan->conn_state);
}
}
static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_control)
static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u32 rx_control)
{
u8 tx_seq = __get_reqseq(rx_control);
u16 tx_seq = __get_reqseq(chan, rx_control);
BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
if (rx_control & L2CAP_CTRL_POLL) {
if (__is_ctrl_poll(chan, rx_control)) {
chan->expected_ack_seq = tx_seq;
l2cap_drop_acked_frames(chan);
......@@ -3560,7 +4023,7 @@ static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_
chan->srej_save_reqseq = tx_seq;
set_bit(CONN_SREJ_ACT, &chan->conn_state);
}
} else if (rx_control & L2CAP_CTRL_FINAL) {
} else if (__is_ctrl_final(chan, rx_control)) {
if (test_bit(CONN_SREJ_ACT, &chan->conn_state) &&
chan->srej_save_reqseq == tx_seq)
clear_bit(CONN_SREJ_ACT, &chan->conn_state);
......@@ -3575,37 +4038,39 @@ static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_
}
}
static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_control)
static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u32 rx_control)
{
u8 tx_seq = __get_reqseq(rx_control);
u16 tx_seq = __get_reqseq(chan, rx_control);
BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control);
BT_DBG("chan %p, req_seq %d ctrl 0x%8.8x", chan, tx_seq, rx_control);
set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
chan->expected_ack_seq = tx_seq;
l2cap_drop_acked_frames(chan);
if (rx_control & L2CAP_CTRL_POLL)
if (__is_ctrl_poll(chan, rx_control))
set_bit(CONN_SEND_FBIT, &chan->conn_state);
if (!test_bit(CONN_SREJ_SENT, &chan->conn_state)) {
__clear_retrans_timer(chan);
if (rx_control & L2CAP_CTRL_POLL)
if (__is_ctrl_poll(chan, rx_control))
l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL);
return;
}
if (rx_control & L2CAP_CTRL_POLL)
if (__is_ctrl_poll(chan, rx_control)) {
l2cap_send_srejtail(chan);
else
l2cap_send_sframe(chan, L2CAP_SUPER_RCV_READY);
} else {
rx_control = __set_ctrl_super(chan, L2CAP_SUPER_RR);
l2cap_send_sframe(chan, rx_control);
}
}
static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb)
static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u32 rx_control, struct sk_buff *skb)
{
BT_DBG("chan %p rx_control 0x%4.4x len %d", chan, rx_control, skb->len);
BT_DBG("chan %p rx_control 0x%8.8x len %d", chan, rx_control, skb->len);
if (L2CAP_CTRL_FINAL & rx_control &&
if (__is_ctrl_final(chan, rx_control) &&
test_bit(CONN_WAIT_F, &chan->conn_state)) {
__clear_monitor_timer(chan);
if (chan->unacked_frames > 0)
......@@ -3613,20 +4078,20 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_cont
clear_bit(CONN_WAIT_F, &chan->conn_state);
}
switch (rx_control & L2CAP_CTRL_SUPERVISE) {
case L2CAP_SUPER_RCV_READY:
switch (__get_ctrl_super(chan, rx_control)) {
case L2CAP_SUPER_RR:
l2cap_data_channel_rrframe(chan, rx_control);
break;
case L2CAP_SUPER_REJECT:
case L2CAP_SUPER_REJ:
l2cap_data_channel_rejframe(chan, rx_control);
break;
case L2CAP_SUPER_SELECT_REJECT:
case L2CAP_SUPER_SREJ:
l2cap_data_channel_srejframe(chan, rx_control);
break;
case L2CAP_SUPER_RCV_NOT_READY:
case L2CAP_SUPER_RNR:
l2cap_data_channel_rnrframe(chan, rx_control);
break;
}
......@@ -3638,12 +4103,12 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_cont
static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
{
struct l2cap_chan *chan = l2cap_pi(sk)->chan;
u16 control;
u8 req_seq;
u32 control;
u16 req_seq;
int len, next_tx_seq_offset, req_seq_offset;
control = get_unaligned_le16(skb->data);
skb_pull(skb, 2);
control = __get_control(chan, skb->data);
skb_pull(skb, __ctrl_size(chan));
len = skb->len;
/*
......@@ -3654,26 +4119,23 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
if (l2cap_check_fcs(chan, skb))
goto drop;
if (__is_sar_start(control) && __is_iframe(control))
len -= 2;
if (__is_sar_start(chan, control) && !__is_sframe(chan, control))
len -= L2CAP_SDULEN_SIZE;
if (chan->fcs == L2CAP_FCS_CRC16)
len -= 2;
len -= L2CAP_FCS_SIZE;
if (len > chan->mps) {
l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
goto drop;
}
req_seq = __get_reqseq(control);
req_seq_offset = (req_seq - chan->expected_ack_seq) % 64;
if (req_seq_offset < 0)
req_seq_offset += 64;
req_seq = __get_reqseq(chan, control);
req_seq_offset = __seq_offset(chan, req_seq, chan->expected_ack_seq);
next_tx_seq_offset =
(chan->next_tx_seq - chan->expected_ack_seq) % 64;
if (next_tx_seq_offset < 0)
next_tx_seq_offset += 64;
next_tx_seq_offset = __seq_offset(chan, chan->next_tx_seq,
chan->expected_ack_seq);
/* check for invalid req-seq */
if (req_seq_offset > next_tx_seq_offset) {
......@@ -3681,7 +4143,7 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb)
goto drop;
}
if (__is_iframe(control)) {
if (!__is_sframe(chan, control)) {
if (len < 0) {
l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
goto drop;
......@@ -3709,8 +4171,8 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
{
struct l2cap_chan *chan;
struct sock *sk = NULL;
u16 control;
u8 tx_seq;
u32 control;
u16 tx_seq;
int len;
chan = l2cap_get_chan_by_scid(conn, cid);
......@@ -3751,23 +4213,23 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
goto done;
case L2CAP_MODE_STREAMING:
control = get_unaligned_le16(skb->data);
skb_pull(skb, 2);
control = __get_control(chan, skb->data);
skb_pull(skb, __ctrl_size(chan));
len = skb->len;
if (l2cap_check_fcs(chan, skb))
goto drop;
if (__is_sar_start(control))
len -= 2;
if (__is_sar_start(chan, control))
len -= L2CAP_SDULEN_SIZE;
if (chan->fcs == L2CAP_FCS_CRC16)
len -= 2;
len -= L2CAP_FCS_SIZE;
if (len > chan->mps || len < 0 || __is_sframe(control))
if (len > chan->mps || len < 0 || __is_sframe(chan, control))
goto drop;
tx_seq = __get_txseq(control);
tx_seq = __get_txseq(chan, control);
if (chan->expected_tx_seq != tx_seq) {
/* Frame(s) missing - must discard partial SDU */
......@@ -3779,7 +4241,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk
/* TODO: Notify userland of missing data */
}
chan->expected_tx_seq = (tx_seq + 1) % 64;
chan->expected_tx_seq = __next_seq(chan, tx_seq);
if (l2cap_reassemble_sdu(chan, skb, control) == -EMSGSIZE)
l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
......@@ -3933,12 +4395,12 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
lm1 |= HCI_LM_ACCEPT;
if (c->role_switch)
if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
lm1 |= HCI_LM_MASTER;
exact++;
} else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
lm2 |= HCI_LM_ACCEPT;
if (c->role_switch)
if (test_bit(FLAG_ROLE_SWITCH, &c->flags))
lm2 |= HCI_LM_MASTER;
}
}
......@@ -3973,7 +4435,7 @@ static int l2cap_disconn_ind(struct hci_conn *hcon)
BT_DBG("hcon %p", hcon);
if ((hcon->type != ACL_LINK && hcon->type != LE_LINK) || !conn)
return 0x13;
return HCI_ERROR_REMOTE_USER_TERM;
return conn->disc_reason;
}
......@@ -4306,3 +4768,6 @@ void l2cap_exit(void)
module_param(disable_ertm, bool, 0644);
MODULE_PARM_DESC(disable_ertm, "Disable enhanced retransmission mode");
module_param(enable_hs, bool, 0644);
MODULE_PARM_DESC(enable_hs, "Enable High Speed");
......@@ -333,7 +333,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
opts.mode = chan->mode;
opts.fcs = chan->fcs;
opts.max_tx = chan->max_tx;
opts.txwin_size = (__u16)chan->tx_win;
opts.txwin_size = chan->tx_win;
len = min_t(unsigned int, len, sizeof(opts));
if (copy_to_user(optval, (char *) &opts, len))
......@@ -358,10 +358,10 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
break;
}
if (chan->role_switch)
if (test_bit(FLAG_ROLE_SWITCH, &chan->flags))
opt |= L2CAP_LM_MASTER;
if (chan->force_reliable)
if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
opt |= L2CAP_LM_RELIABLE;
if (put_user(opt, (u32 __user *) optval))
......@@ -448,7 +448,8 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
break;
case BT_FLUSHABLE:
if (put_user(chan->flushable, (u32 __user *) optval))
if (put_user(test_bit(FLAG_FLUSHABLE, &chan->flags),
(u32 __user *) optval))
err = -EFAULT;
break;
......@@ -460,7 +461,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
break;
}
pwr.force_active = chan->force_active;
pwr.force_active = test_bit(FLAG_FORCE_ACTIVE, &chan->flags);
len = min_t(unsigned int, len, sizeof(pwr));
if (copy_to_user(optval, (char *) &pwr, len))
......@@ -468,6 +469,16 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
break;
case BT_CHANNEL_POLICY:
if (!enable_hs) {
err = -ENOPROTOOPT;
break;
}
if (put_user(chan->chan_policy, (u32 __user *) optval))
err = -EFAULT;
break;
default:
err = -ENOPROTOOPT;
break;
......@@ -502,7 +513,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
opts.mode = chan->mode;
opts.fcs = chan->fcs;
opts.max_tx = chan->max_tx;
opts.txwin_size = (__u16)chan->tx_win;
opts.txwin_size = chan->tx_win;
len = min_t(unsigned int, sizeof(opts), optlen);
if (copy_from_user((char *) &opts, optval, len)) {
......@@ -510,7 +521,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
break;
}
if (opts.txwin_size > L2CAP_DEFAULT_TX_WINDOW) {
if (opts.txwin_size > L2CAP_DEFAULT_EXT_WINDOW) {
err = -EINVAL;
break;
}
......@@ -534,7 +545,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
chan->omtu = opts.omtu;
chan->fcs = opts.fcs;
chan->max_tx = opts.max_tx;
chan->tx_win = (__u8)opts.txwin_size;
chan->tx_win = opts.txwin_size;
break;
case L2CAP_LM:
......@@ -550,8 +561,15 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
if (opt & L2CAP_LM_SECURE)
chan->sec_level = BT_SECURITY_HIGH;
chan->role_switch = (opt & L2CAP_LM_MASTER);
chan->force_reliable = (opt & L2CAP_LM_RELIABLE);
if (opt & L2CAP_LM_MASTER)
set_bit(FLAG_ROLE_SWITCH, &chan->flags);
else
clear_bit(FLAG_ROLE_SWITCH, &chan->flags);
if (opt & L2CAP_LM_RELIABLE)
set_bit(FLAG_FORCE_RELIABLE, &chan->flags);
else
clear_bit(FLAG_FORCE_RELIABLE, &chan->flags);
break;
default:
......@@ -657,7 +675,10 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
}
}
chan->flushable = opt;
if (opt)
set_bit(FLAG_FLUSHABLE, &chan->flags);
else
clear_bit(FLAG_FLUSHABLE, &chan->flags);
break;
case BT_POWER:
......@@ -674,7 +695,36 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
err = -EFAULT;
break;
}
chan->force_active = pwr.force_active;
if (pwr.force_active)
set_bit(FLAG_FORCE_ACTIVE, &chan->flags);
else
clear_bit(FLAG_FORCE_ACTIVE, &chan->flags);
break;
case BT_CHANNEL_POLICY:
if (!enable_hs) {
err = -ENOPROTOOPT;
break;
}
if (get_user(opt, (u32 __user *) optval)) {
err = -EFAULT;
break;
}
if (opt > BT_CHANNEL_POLICY_AMP_PREFERRED) {
err = -EINVAL;
break;
}
if (chan->mode != L2CAP_MODE_ERTM &&
chan->mode != L2CAP_MODE_STREAMING) {
err = -EOPNOTSUPP;
break;
}
chan->chan_policy = (u8) opt;
break;
default:
......@@ -708,7 +758,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
return -ENOTCONN;
}
err = l2cap_chan_send(chan, msg, len);
err = l2cap_chan_send(chan, msg, len, sk->sk_priority);
release_sock(sk);
return err;
......@@ -930,11 +980,9 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
chan->fcs = pchan->fcs;
chan->max_tx = pchan->max_tx;
chan->tx_win = pchan->tx_win;
chan->tx_win_max = pchan->tx_win_max;
chan->sec_level = pchan->sec_level;
chan->role_switch = pchan->role_switch;
chan->force_reliable = pchan->force_reliable;
chan->flushable = pchan->flushable;
chan->force_active = pchan->force_active;
chan->flags = pchan->flags;
security_sk_clone(parent, sk);
} else {
......@@ -963,12 +1011,10 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
chan->max_tx = L2CAP_DEFAULT_MAX_TX;
chan->fcs = L2CAP_FCS_CRC16;
chan->tx_win = L2CAP_DEFAULT_TX_WINDOW;
chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
chan->sec_level = BT_SECURITY_LOW;
chan->role_switch = 0;
chan->force_reliable = 0;
chan->flushable = BT_FLUSHABLE_OFF;
chan->force_active = BT_POWER_FORCE_ACTIVE_ON;
chan->flags = 0;
set_bit(FLAG_FORCE_ACTIVE, &chan->flags);
}
/* Default config options */
......
......@@ -32,22 +32,23 @@
#define MGMT_VERSION 0
#define MGMT_REVISION 1
#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
struct pending_cmd {
struct list_head list;
__u16 opcode;
u16 opcode;
int index;
void *param;
struct sock *sk;
void *user_data;
};
static LIST_HEAD(cmd_list);
static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
{
struct sk_buff *skb;
struct mgmt_hdr *hdr;
struct mgmt_ev_cmd_status *ev;
int err;
BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
......@@ -65,10 +66,11 @@ static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
ev->status = status;
put_unaligned_le16(cmd, &ev->opcode);
if (sock_queue_rcv_skb(sk, skb) < 0)
err = sock_queue_rcv_skb(sk, skb);
if (err < 0)
kfree_skb(skb);
return 0;
return err;
}
static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
......@@ -77,6 +79,7 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
struct sk_buff *skb;
struct mgmt_hdr *hdr;
struct mgmt_ev_cmd_complete *ev;
int err;
BT_DBG("sock %p", sk);
......@@ -96,10 +99,11 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
if (rp)
memcpy(ev->data, rp, rp_len);
if (sock_queue_rcv_skb(sk, skb) < 0)
err = sock_queue_rcv_skb(sk, skb);
if (err < 0)
kfree_skb(skb);
return 0;
return err;;
}
static int read_version(struct sock *sk)
......@@ -119,6 +123,7 @@ static int read_index_list(struct sock *sk)
{
struct mgmt_rp_read_index_list *rp;
struct list_head *p;
struct hci_dev *d;
size_t rp_len;
u16 count;
int i, err;
......@@ -142,10 +147,9 @@ static int read_index_list(struct sock *sk)
put_unaligned_le16(count, &rp->num_controllers);
i = 0;
list_for_each(p, &hci_dev_list) {
struct hci_dev *d = list_entry(p, struct hci_dev, list);
hci_del_off_timer(d);
list_for_each_entry(d, &hci_dev_list, list) {
if (test_and_clear_bit(HCI_AUTO_OFF, &d->flags))
cancel_delayed_work(&d->power_off);
if (test_bit(HCI_SETUP, &d->flags))
continue;
......@@ -175,7 +179,8 @@ static int read_controller_info(struct sock *sk, u16 index)
if (!hdev)
return cmd_status(sk, index, MGMT_OP_READ_INFO, ENODEV);
hci_del_off_timer(hdev);
if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
cancel_delayed_work_sync(&hdev->power_off);
hci_dev_lock_bh(hdev);
......@@ -220,7 +225,8 @@ static void mgmt_pending_free(struct pending_cmd *cmd)
}
static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
u16 index, void *data, u16 len)
struct hci_dev *hdev,
void *data, u16 len)
{
struct pending_cmd *cmd;
......@@ -229,7 +235,7 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
return NULL;
cmd->opcode = opcode;
cmd->index = index;
cmd->index = hdev->id;
cmd->param = kmalloc(len, GFP_ATOMIC);
if (!cmd->param) {
......@@ -243,47 +249,35 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
cmd->sk = sk;
sock_hold(sk);
list_add(&cmd->list, &cmd_list);
list_add(&cmd->list, &hdev->mgmt_pending);
return cmd;
}
static void mgmt_pending_foreach(u16 opcode, int index,
static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
void (*cb)(struct pending_cmd *cmd, void *data),
void *data)
{
struct list_head *p, *n;
list_for_each_safe(p, n, &cmd_list) {
list_for_each_safe(p, n, &hdev->mgmt_pending) {
struct pending_cmd *cmd;
cmd = list_entry(p, struct pending_cmd, list);
if (cmd->opcode != opcode)
continue;
if (index >= 0 && cmd->index != index)
if (opcode > 0 && cmd->opcode != opcode)
continue;
cb(cmd, data);
}
}
static struct pending_cmd *mgmt_pending_find(u16 opcode, int index)
static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
{
struct list_head *p;
list_for_each(p, &cmd_list) {
struct pending_cmd *cmd;
cmd = list_entry(p, struct pending_cmd, list);
if (cmd->opcode != opcode)
continue;
if (index >= 0 && cmd->index != index)
continue;
list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
if (cmd->opcode == opcode)
return cmd;
}
......@@ -322,12 +316,12 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
goto failed;
}
if (mgmt_pending_find(MGMT_OP_SET_POWERED, index)) {
if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
err = cmd_status(sk, index, MGMT_OP_SET_POWERED, EBUSY);
goto failed;
}
cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, index, data, len);
cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
if (!cmd) {
err = -ENOMEM;
goto failed;
......@@ -336,7 +330,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
if (cp->val)
queue_work(hdev->workqueue, &hdev->power_on);
else
queue_work(hdev->workqueue, &hdev->power_off);
queue_work(hdev->workqueue, &hdev->power_off.work);
err = 0;
......@@ -349,7 +343,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
u16 len)
{
struct mgmt_mode *cp;
struct mgmt_cp_set_discoverable *cp;
struct hci_dev *hdev;
struct pending_cmd *cmd;
u8 scan;
......@@ -373,8 +367,8 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
goto failed;
}
if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, EBUSY);
goto failed;
}
......@@ -385,7 +379,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
goto failed;
}
cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, index, data, len);
cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
if (!cmd) {
err = -ENOMEM;
goto failed;
......@@ -395,11 +389,16 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
if (cp->val)
scan |= SCAN_INQUIRY;
else
cancel_delayed_work(&hdev->discov_off);
err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
if (err < 0)
mgmt_pending_remove(cmd);
if (cp->val)
hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
failed:
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
......@@ -434,8 +433,8 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
goto failed;
}
if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, index) ||
mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, index)) {
if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, EBUSY);
goto failed;
}
......@@ -445,7 +444,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
goto failed;
}
cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, index, data, len);
cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
if (!cmd) {
err = -ENOMEM;
goto failed;
......@@ -467,8 +466,8 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
return err;
}
static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
struct sock *skip_sk)
static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
u16 data_len, struct sock *skip_sk)
{
struct sk_buff *skb;
struct mgmt_hdr *hdr;
......@@ -481,7 +480,10 @@ static int mgmt_event(u16 event, u16 index, void *data, u16 data_len,
hdr = (void *) skb_put(skb, sizeof(*hdr));
hdr->opcode = cpu_to_le16(event);
hdr->index = cpu_to_le16(index);
if (hdev)
hdr->index = cpu_to_le16(hdev->id);
else
hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
hdr->len = cpu_to_le16(data_len);
if (data)
......@@ -533,7 +535,7 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
ev.val = cp->val;
err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk);
err = mgmt_event(MGMT_EV_PAIRABLE, hdev, &ev, sizeof(ev), sk);
failed:
hci_dev_unlock_bh(hdev);
......@@ -586,7 +588,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
u16 eir_len = 0;
u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
int i, truncated = 0;
struct list_head *p;
struct bt_uuid *uuid;
size_t name_len;
name_len = strlen(hdev->dev_name);
......@@ -611,8 +613,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
memset(uuid16_list, 0, sizeof(uuid16_list));
/* Group all UUID16 types */
list_for_each(p, &hdev->uuids) {
struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
list_for_each_entry(uuid, &hdev->uuids, list) {
u16 uuid16;
uuid16 = get_uuid16(uuid->uuid);
......@@ -688,14 +689,11 @@ static int update_eir(struct hci_dev *hdev)
static u8 get_service_classes(struct hci_dev *hdev)
{
struct list_head *p;
struct bt_uuid *uuid;
u8 val = 0;
list_for_each(p, &hdev->uuids) {
struct bt_uuid *uuid = list_entry(p, struct bt_uuid, list);
list_for_each_entry(uuid, &hdev->uuids, list)
val |= uuid->svc_hint;
}
return val;
}
......@@ -894,6 +892,9 @@ static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
if (err == 0)
err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
0);
else
cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, -err);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
......@@ -901,30 +902,32 @@ static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
return err;
}
static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
u16 len)
{
struct hci_dev *hdev;
struct mgmt_cp_load_keys *cp;
struct mgmt_cp_load_link_keys *cp;
u16 key_count, expected_len;
int i;
cp = (void *) data;
if (len < sizeof(*cp))
return -EINVAL;
return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, EINVAL);
key_count = get_unaligned_le16(&cp->key_count);
expected_len = sizeof(*cp) + key_count * sizeof(struct mgmt_key_info);
expected_len = sizeof(*cp) + key_count *
sizeof(struct mgmt_link_key_info);
if (expected_len != len) {
BT_ERR("load_keys: expected %u bytes, got %u bytes",
BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
len, expected_len);
return -EINVAL;
return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, EINVAL);
}
hdev = hci_dev_get(index);
if (!hdev)
return cmd_status(sk, index, MGMT_OP_LOAD_KEYS, ENODEV);
return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS, ENODEV);
BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
key_count);
......@@ -941,7 +944,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
for (i = 0; i < key_count; i++) {
struct mgmt_key_info *key = &cp->keys[i];
struct mgmt_link_key_info *key = &cp->keys[i];
hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
key->pin_len);
......@@ -953,27 +956,28 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len)
return 0;
}
static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len)
static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
u16 len)
{
struct hci_dev *hdev;
struct mgmt_cp_remove_key *cp;
struct mgmt_cp_remove_keys *cp;
struct hci_conn *conn;
int err;
cp = (void *) data;
if (len != sizeof(*cp))
return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, EINVAL);
return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, EINVAL);
hdev = hci_dev_get(index);
if (!hdev)
return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV);
return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, ENODEV);
hci_dev_lock_bh(hdev);
err = hci_remove_link_key(hdev, &cp->bdaddr);
if (err < 0) {
err = cmd_status(sk, index, MGMT_OP_REMOVE_KEY, -err);
err = cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, -err);
goto unlock;
}
......@@ -1025,7 +1029,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
goto failed;
}
if (mgmt_pending_find(MGMT_OP_DISCONNECT, index)) {
if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
err = cmd_status(sk, index, MGMT_OP_DISCONNECT, EBUSY);
goto failed;
}
......@@ -1039,7 +1043,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
goto failed;
}
cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, index, data, len);
cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
if (!cmd) {
err = -ENOMEM;
goto failed;
......@@ -1059,10 +1063,23 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
return err;
}
static u8 link_to_mgmt(u8 link_type)
{
switch (link_type) {
case LE_LINK:
return MGMT_ADDR_LE;
case ACL_LINK:
return MGMT_ADDR_BREDR;
default:
return MGMT_ADDR_INVALID;
}
}
static int get_connections(struct sock *sk, u16 index)
{
struct mgmt_rp_get_connections *rp;
struct hci_dev *hdev;
struct hci_conn *c;
struct list_head *p;
size_t rp_len;
u16 count;
......@@ -1081,7 +1098,7 @@ static int get_connections(struct sock *sk, u16 index)
count++;
}
rp_len = sizeof(*rp) + (count * sizeof(bdaddr_t));
rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
rp = kmalloc(rp_len, GFP_ATOMIC);
if (!rp) {
err = -ENOMEM;
......@@ -1091,12 +1108,17 @@ static int get_connections(struct sock *sk, u16 index)
put_unaligned_le16(count, &rp->conn_count);
i = 0;
list_for_each(p, &hdev->conn_hash.list) {
struct hci_conn *c = list_entry(p, struct hci_conn, list);
bacpy(&rp->conn[i++], &c->dst);
list_for_each_entry(c, &hdev->conn_hash.list, list) {
bacpy(&rp->addr[i].bdaddr, &c->dst);
rp->addr[i].type = link_to_mgmt(c->type);
if (rp->addr[i].type == MGMT_ADDR_INVALID)
continue;
i++;
}
/* Recalculate length in case of filtered SCO connections, etc */
rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
unlock:
......@@ -1112,7 +1134,7 @@ static int send_pin_code_neg_reply(struct sock *sk, u16 index,
struct pending_cmd *cmd;
int err;
cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, index, cp,
cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
sizeof(*cp));
if (!cmd)
return -ENOMEM;
......@@ -1173,7 +1195,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
goto failed;
}
cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, index, data, len);
cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
if (!cmd) {
err = -ENOMEM;
goto failed;
......@@ -1264,19 +1286,12 @@ static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
{
struct hci_dev *hdev = conn->hdev;
struct list_head *p;
list_for_each(p, &cmd_list) {
struct pending_cmd *cmd;
cmd = list_entry(p, struct pending_cmd, list);
list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
continue;
if (cmd->index != hdev->id)
continue;
if (cmd->user_data != conn)
continue;
......@@ -1309,16 +1324,19 @@ static void pairing_complete(struct pending_cmd *cmd, u8 status)
static void pairing_complete_cb(struct hci_conn *conn, u8 status)
{
struct pending_cmd *cmd;
struct hci_dev *hdev = conn->hdev;
BT_DBG("status %u", status);
hci_dev_lock_bh(hdev);
cmd = find_pairing(conn);
if (!cmd) {
if (!cmd)
BT_DBG("Unable to find a pending command");
return;
}
else
pairing_complete(cmd, status);
hci_dev_unlock_bh(hdev);
}
static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
......@@ -1369,7 +1387,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
goto unlock;
}
cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, index, data, len);
cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
if (!cmd) {
err = -ENOMEM;
hci_conn_put(conn);
......@@ -1431,7 +1449,7 @@ static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
goto failed;
}
cmd = mgmt_pending_add(sk, mgmt_op, index, data, len);
cmd = mgmt_pending_add(sk, mgmt_op, hdev, data, len);
if (!cmd) {
err = -ENOMEM;
goto failed;
......@@ -1468,7 +1486,7 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
hci_dev_lock_bh(hdev);
cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len);
cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
if (!cmd) {
err = -ENOMEM;
goto failed;
......@@ -1514,12 +1532,12 @@ static int read_local_oob_data(struct sock *sk, u16 index)
goto unlock;
}
if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) {
if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, EBUSY);
goto unlock;
}
cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, index, NULL, 0);
cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
if (!cmd) {
err = -ENOMEM;
goto unlock;
......@@ -1606,8 +1624,6 @@ static int remove_remote_oob_data(struct sock *sk, u16 index,
static int start_discovery(struct sock *sk, u16 index)
{
u8 lap[3] = { 0x33, 0x8b, 0x9e };
struct hci_cp_inquiry cp;
struct pending_cmd *cmd;
struct hci_dev *hdev;
int err;
......@@ -1620,18 +1636,18 @@ static int start_discovery(struct sock *sk, u16 index)
hci_dev_lock_bh(hdev);
cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, NULL, 0);
if (!test_bit(HCI_UP, &hdev->flags)) {
err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENETDOWN);
goto failed;
}
cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
if (!cmd) {
err = -ENOMEM;
goto failed;
}
memset(&cp, 0, sizeof(cp));
memcpy(&cp.lap, lap, 3);
cp.length = 0x08;
cp.num_rsp = 0x00;
err = hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
if (err < 0)
mgmt_pending_remove(cmd);
......@@ -1656,13 +1672,13 @@ static int stop_discovery(struct sock *sk, u16 index)
hci_dev_lock_bh(hdev);
cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0);
cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
if (!cmd) {
err = -ENOMEM;
goto failed;
}
err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
err = hci_cancel_inquiry(hdev);
if (err < 0)
mgmt_pending_remove(cmd);
......@@ -1677,7 +1693,6 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
u16 len)
{
struct hci_dev *hdev;
struct pending_cmd *cmd;
struct mgmt_cp_block_device *cp = (void *) data;
int err;
......@@ -1694,23 +1709,13 @@ static int block_device(struct sock *sk, u16 index, unsigned char *data,
hci_dev_lock_bh(hdev);
cmd = mgmt_pending_add(sk, MGMT_OP_BLOCK_DEVICE, index, NULL, 0);
if (!cmd) {
err = -ENOMEM;
goto failed;
}
err = hci_blacklist_add(hdev, &cp->bdaddr);
if (err < 0)
err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE, -err);
else
err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
NULL, 0);
mgmt_pending_remove(cmd);
failed:
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
......@@ -1721,7 +1726,6 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
u16 len)
{
struct hci_dev *hdev;
struct pending_cmd *cmd;
struct mgmt_cp_unblock_device *cp = (void *) data;
int err;
......@@ -1738,12 +1742,6 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
hci_dev_lock_bh(hdev);
cmd = mgmt_pending_add(sk, MGMT_OP_UNBLOCK_DEVICE, index, NULL, 0);
if (!cmd) {
err = -ENOMEM;
goto failed;
}
err = hci_blacklist_del(hdev, &cp->bdaddr);
if (err < 0)
......@@ -1752,9 +1750,6 @@ static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
NULL, 0);
mgmt_pending_remove(cmd);
failed:
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
......@@ -1882,11 +1877,11 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
case MGMT_OP_SET_SERVICE_CACHE:
err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
break;
case MGMT_OP_LOAD_KEYS:
err = load_keys(sk, index, buf + sizeof(*hdr), len);
case MGMT_OP_LOAD_LINK_KEYS:
err = load_link_keys(sk, index, buf + sizeof(*hdr), len);
break;
case MGMT_OP_REMOVE_KEY:
err = remove_key(sk, index, buf + sizeof(*hdr), len);
case MGMT_OP_REMOVE_KEYS:
err = remove_keys(sk, index, buf + sizeof(*hdr), len);
break;
case MGMT_OP_DISCONNECT:
err = disconnect(sk, index, buf + sizeof(*hdr), len);
......@@ -1957,14 +1952,26 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
return err;
}
int mgmt_index_added(u16 index)
static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
{
return mgmt_event(MGMT_EV_INDEX_ADDED, index, NULL, 0, NULL);
u8 *status = data;
cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
mgmt_pending_remove(cmd);
}
int mgmt_index_removed(u16 index)
int mgmt_index_added(struct hci_dev *hdev)
{
return mgmt_event(MGMT_EV_INDEX_REMOVED, index, NULL, 0, NULL);
return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
}
int mgmt_index_removed(struct hci_dev *hdev)
{
u8 status = ENODEV;
mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
}
struct cmd_lookup {
......@@ -1992,17 +1999,22 @@ static void mode_rsp(struct pending_cmd *cmd, void *data)
mgmt_pending_free(cmd);
}
int mgmt_powered(u16 index, u8 powered)
int mgmt_powered(struct hci_dev *hdev, u8 powered)
{
struct mgmt_mode ev;
struct cmd_lookup match = { powered, NULL };
int ret;
mgmt_pending_foreach(MGMT_OP_SET_POWERED, index, mode_rsp, &match);
mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, mode_rsp, &match);
if (!powered) {
u8 status = ENETDOWN;
mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
}
ev.val = powered;
ret = mgmt_event(MGMT_EV_POWERED, index, &ev, sizeof(ev), match.sk);
ret = mgmt_event(MGMT_EV_POWERED, hdev, &ev, sizeof(ev), match.sk);
if (match.sk)
sock_put(match.sk);
......@@ -2010,17 +2022,17 @@ int mgmt_powered(u16 index, u8 powered)
return ret;
}
int mgmt_discoverable(u16 index, u8 discoverable)
int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
{
struct mgmt_mode ev;
struct cmd_lookup match = { discoverable, NULL };
int ret;
mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, index, mode_rsp, &match);
mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, mode_rsp, &match);
ev.val = discoverable;
ret = mgmt_event(MGMT_EV_DISCOVERABLE, index, &ev, sizeof(ev),
ret = mgmt_event(MGMT_EV_DISCOVERABLE, hdev, &ev, sizeof(ev),
match.sk);
if (match.sk)
......@@ -2029,17 +2041,17 @@ int mgmt_discoverable(u16 index, u8 discoverable)
return ret;
}
int mgmt_connectable(u16 index, u8 connectable)
int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
{
struct mgmt_mode ev;
struct cmd_lookup match = { connectable, NULL };
int ret;
mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, index, mode_rsp, &match);
mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, mode_rsp, &match);
ev.val = connectable;
ret = mgmt_event(MGMT_EV_CONNECTABLE, index, &ev, sizeof(ev), match.sk);
ret = mgmt_event(MGMT_EV_CONNECTABLE, hdev, &ev, sizeof(ev), match.sk);
if (match.sk)
sock_put(match.sk);
......@@ -2047,9 +2059,23 @@ int mgmt_connectable(u16 index, u8 connectable)
return ret;
}
int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
{
if (scan & SCAN_PAGE)
mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
cmd_status_rsp, &status);
if (scan & SCAN_INQUIRY)
mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
cmd_status_rsp, &status);
return 0;
}
int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
u8 persistent)
{
struct mgmt_ev_new_key ev;
struct mgmt_ev_new_link_key ev;
memset(&ev, 0, sizeof(ev));
......@@ -2059,17 +2085,17 @@ int mgmt_new_key(u16 index, struct link_key *key, u8 persistent)
memcpy(ev.key.val, key->val, 16);
ev.key.pin_len = key->pin_len;
return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL);
return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
}
int mgmt_connected(u16 index, bdaddr_t *bdaddr, u8 link_type)
int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type)
{
struct mgmt_ev_connected ev;
struct mgmt_addr_info ev;
bacpy(&ev.bdaddr, bdaddr);
ev.link_type = link_type;
ev.type = link_to_mgmt(link_type);
return mgmt_event(MGMT_EV_CONNECTED, index, &ev, sizeof(ev), NULL);
return mgmt_event(MGMT_EV_CONNECTED, hdev, &ev, sizeof(ev), NULL);
}
static void disconnect_rsp(struct pending_cmd *cmd, void *data)
......@@ -2088,17 +2114,18 @@ static void disconnect_rsp(struct pending_cmd *cmd, void *data)
mgmt_pending_remove(cmd);
}
int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
{
struct mgmt_ev_disconnected ev;
struct mgmt_addr_info ev;
struct sock *sk = NULL;
int err;
mgmt_pending_foreach(MGMT_OP_DISCONNECT, index, disconnect_rsp, &sk);
mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
bacpy(&ev.bdaddr, bdaddr);
ev.type = link_to_mgmt(type);
err = mgmt_event(MGMT_EV_DISCONNECTED, index, &ev, sizeof(ev), sk);
err = mgmt_event(MGMT_EV_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
if (sk)
sock_put(sk);
......@@ -2106,57 +2133,60 @@ int mgmt_disconnected(u16 index, bdaddr_t *bdaddr)
return err;
}
int mgmt_disconnect_failed(u16 index)
int mgmt_disconnect_failed(struct hci_dev *hdev)
{
struct pending_cmd *cmd;
int err;
cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, index);
cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
if (!cmd)
return -ENOENT;
err = cmd_status(cmd->sk, index, MGMT_OP_DISCONNECT, EIO);
err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT, EIO);
mgmt_pending_remove(cmd);
return err;
}
int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status)
int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
u8 status)
{
struct mgmt_ev_connect_failed ev;
bacpy(&ev.bdaddr, bdaddr);
bacpy(&ev.addr.bdaddr, bdaddr);
ev.addr.type = link_to_mgmt(type);
ev.status = status;
return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL);
return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
}
int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr, u8 secure)
int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
{
struct mgmt_ev_pin_code_request ev;
bacpy(&ev.bdaddr, bdaddr);
ev.secure = secure;
return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, index, &ev, sizeof(ev),
return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
NULL);
}
int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 status)
{
struct pending_cmd *cmd;
struct mgmt_rp_pin_code_reply rp;
int err;
cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, index);
cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
if (!cmd)
return -ENOENT;
bacpy(&rp.bdaddr, bdaddr);
rp.status = status;
err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_REPLY, &rp,
err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
sizeof(rp));
mgmt_pending_remove(cmd);
......@@ -2164,20 +2194,21 @@ int mgmt_pin_code_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
return err;
}
int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 status)
{
struct pending_cmd *cmd;
struct mgmt_rp_pin_code_reply rp;
int err;
cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, index);
cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
if (!cmd)
return -ENOENT;
bacpy(&rp.bdaddr, bdaddr);
rp.status = status;
err = cmd_complete(cmd->sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
sizeof(rp));
mgmt_pending_remove(cmd);
......@@ -2185,97 +2216,93 @@ int mgmt_pin_code_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
return err;
}
int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value,
u8 confirm_hint)
int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
__le32 value, u8 confirm_hint)
{
struct mgmt_ev_user_confirm_request ev;
BT_DBG("hci%u", index);
BT_DBG("%s", hdev->name);
bacpy(&ev.bdaddr, bdaddr);
ev.confirm_hint = confirm_hint;
put_unaligned_le32(value, &ev.value);
return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, index, &ev, sizeof(ev),
return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
NULL);
}
static int confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status,
u8 opcode)
static int confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 status, u8 opcode)
{
struct pending_cmd *cmd;
struct mgmt_rp_user_confirm_reply rp;
int err;
cmd = mgmt_pending_find(opcode, index);
cmd = mgmt_pending_find(opcode, hdev);
if (!cmd)
return -ENOENT;
bacpy(&rp.bdaddr, bdaddr);
rp.status = status;
err = cmd_complete(cmd->sk, index, opcode, &rp, sizeof(rp));
err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
mgmt_pending_remove(cmd);
return err;
}
int mgmt_user_confirm_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
u8 status)
{
return confirm_reply_complete(index, bdaddr, status,
return confirm_reply_complete(hdev, bdaddr, status,
MGMT_OP_USER_CONFIRM_REPLY);
}
int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, u8 status)
int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
bdaddr_t *bdaddr, u8 status)
{
return confirm_reply_complete(index, bdaddr, status,
return confirm_reply_complete(hdev, bdaddr, status,
MGMT_OP_USER_CONFIRM_NEG_REPLY);
}
int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status)
int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
{
struct mgmt_ev_auth_failed ev;
bacpy(&ev.bdaddr, bdaddr);
ev.status = status;
return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL);
return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
}
int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
{
struct pending_cmd *cmd;
struct hci_dev *hdev;
struct mgmt_cp_set_local_name ev;
int err;
memset(&ev, 0, sizeof(ev));
memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, index);
cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
if (!cmd)
goto send_event;
if (status) {
err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO);
err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
EIO);
goto failed;
}
hdev = hci_dev_get(index);
if (hdev) {
hci_dev_lock_bh(hdev);
update_eir(hdev);
hci_dev_unlock_bh(hdev);
hci_dev_put(hdev);
}
err = cmd_complete(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, &ev,
err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
sizeof(ev));
if (err < 0)
goto failed;
send_event:
err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, index, &ev, sizeof(ev),
err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
cmd ? cmd->sk : NULL);
failed:
......@@ -2284,28 +2311,29 @@ int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status)
return err;
}
int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
u8 status)
int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
u8 *randomizer, u8 status)
{
struct pending_cmd *cmd;
int err;
BT_DBG("hci%u status %u", index, status);
BT_DBG("%s status %u", hdev->name, status);
cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index);
cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
if (!cmd)
return -ENOENT;
if (status) {
err = cmd_status(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
EIO);
err = cmd_status(cmd->sk, hdev->id,
MGMT_OP_READ_LOCAL_OOB_DATA, EIO);
} else {
struct mgmt_rp_read_local_oob_data rp;
memcpy(rp.hash, hash, sizeof(rp.hash));
memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
err = cmd_complete(cmd->sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
err = cmd_complete(cmd->sk, hdev->id,
MGMT_OP_READ_LOCAL_OOB_DATA,
&rp, sizeof(rp));
}
......@@ -2314,14 +2342,15 @@ int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer,
return err;
}
int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
u8 *eir)
int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type,
u8 *dev_class, s8 rssi, u8 *eir)
{
struct mgmt_ev_device_found ev;
memset(&ev, 0, sizeof(ev));
bacpy(&ev.bdaddr, bdaddr);
bacpy(&ev.addr.bdaddr, bdaddr);
ev.addr.type = link_to_mgmt(type);
ev.rssi = rssi;
if (eir)
......@@ -2330,10 +2359,10 @@ int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi,
if (dev_class)
memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL);
return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
}
int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name)
{
struct mgmt_ev_remote_name ev;
......@@ -2342,37 +2371,64 @@ int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name)
bacpy(&ev.bdaddr, bdaddr);
memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL);
return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL);
}
int mgmt_discovering(u16 index, u8 discovering)
int mgmt_inquiry_failed(struct hci_dev *hdev, u8 status)
{
return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering,
struct pending_cmd *cmd;
int err;
cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
if (!cmd)
return -ENOENT;
err = cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
mgmt_pending_remove(cmd);
return err;
}
int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
{
struct pending_cmd *cmd;
if (discovering)
cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
else
cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
if (cmd != NULL) {
cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
mgmt_pending_remove(cmd);
}
return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
sizeof(discovering), NULL);
}
int mgmt_device_blocked(u16 index, bdaddr_t *bdaddr)
int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
{
struct pending_cmd *cmd;
struct mgmt_ev_device_blocked ev;
cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, index);
cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
bacpy(&ev.bdaddr, bdaddr);
return mgmt_event(MGMT_EV_DEVICE_BLOCKED, index, &ev, sizeof(ev),
return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
cmd ? cmd->sk : NULL);
}
int mgmt_device_unblocked(u16 index, bdaddr_t *bdaddr)
int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
{
struct pending_cmd *cmd;
struct mgmt_ev_device_unblocked ev;
cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, index);
cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
bacpy(&ev.bdaddr, bdaddr);
return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, index, &ev, sizeof(ev),
return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
cmd ? cmd->sk : NULL);
}
......@@ -65,7 +65,8 @@ static DEFINE_MUTEX(rfcomm_mutex);
static LIST_HEAD(session_list);
static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len);
static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len,
u32 priority);
static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci);
static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci);
static int rfcomm_queue_disc(struct rfcomm_dlc *d);
......@@ -377,13 +378,11 @@ static void rfcomm_dlc_unlink(struct rfcomm_dlc *d)
static struct rfcomm_dlc *rfcomm_dlc_get(struct rfcomm_session *s, u8 dlci)
{
struct rfcomm_dlc *d;
struct list_head *p;
list_for_each(p, &s->dlcs) {
d = list_entry(p, struct rfcomm_dlc, list);
list_for_each_entry(d, &s->dlcs, list)
if (d->dlci == dlci)
return d;
}
return NULL;
}
......@@ -749,19 +748,34 @@ void rfcomm_session_getaddr(struct rfcomm_session *s, bdaddr_t *src, bdaddr_t *d
}
/* ---- RFCOMM frame sending ---- */
static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len)
static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len,
u32 priority)
{
struct socket *sock = s->sock;
struct sock *sk = sock->sk;
struct kvec iv = { data, len };
struct msghdr msg;
BT_DBG("session %p len %d", s, len);
BT_DBG("session %p len %d priority %u", s, len, priority);
if (sk->sk_priority != priority) {
lock_sock(sk);
sk->sk_priority = priority;
release_sock(sk);
}
memset(&msg, 0, sizeof(msg));
return kernel_sendmsg(sock, &msg, &iv, 1, len);
}
static int rfcomm_send_cmd(struct rfcomm_session *s, struct rfcomm_cmd *cmd)
{
BT_DBG("%p cmd %u", s, cmd->ctrl);
return rfcomm_send_frame(s, (void *) cmd, sizeof(*cmd), HCI_PRIO_MAX);
}
static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci)
{
struct rfcomm_cmd cmd;
......@@ -773,7 +787,7 @@ static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci)
cmd.len = __len8(0);
cmd.fcs = __fcs2((u8 *) &cmd);
return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
return rfcomm_send_cmd(s, &cmd);
}
static int rfcomm_send_ua(struct rfcomm_session *s, u8 dlci)
......@@ -787,7 +801,7 @@ static int rfcomm_send_ua(struct rfcomm_session *s, u8 dlci)
cmd.len = __len8(0);
cmd.fcs = __fcs2((u8 *) &cmd);
return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
return rfcomm_send_cmd(s, &cmd);
}
static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci)
......@@ -801,7 +815,7 @@ static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci)
cmd.len = __len8(0);
cmd.fcs = __fcs2((u8 *) &cmd);
return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
return rfcomm_send_cmd(s, &cmd);
}
static int rfcomm_queue_disc(struct rfcomm_dlc *d)
......@@ -815,6 +829,8 @@ static int rfcomm_queue_disc(struct rfcomm_dlc *d)
if (!skb)
return -ENOMEM;
skb->priority = HCI_PRIO_MAX;
cmd = (void *) __skb_put(skb, sizeof(*cmd));
cmd->addr = d->addr;
cmd->ctrl = __ctrl(RFCOMM_DISC, 1);
......@@ -837,7 +853,7 @@ static int rfcomm_send_dm(struct rfcomm_session *s, u8 dlci)
cmd.len = __len8(0);
cmd.fcs = __fcs2((u8 *) &cmd);
return rfcomm_send_frame(s, (void *) &cmd, sizeof(cmd));
return rfcomm_send_cmd(s, &cmd);
}
static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type)
......@@ -862,7 +878,7 @@ static int rfcomm_send_nsc(struct rfcomm_session *s, int cr, u8 type)
*ptr = __fcs(buf); ptr++;
return rfcomm_send_frame(s, buf, ptr - buf);
return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
}
static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d)
......@@ -904,7 +920,7 @@ static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d
*ptr = __fcs(buf); ptr++;
return rfcomm_send_frame(s, buf, ptr - buf);
return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
}
int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
......@@ -942,7 +958,7 @@ int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
*ptr = __fcs(buf); ptr++;
return rfcomm_send_frame(s, buf, ptr - buf);
return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
}
static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status)
......@@ -969,7 +985,7 @@ static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status)
*ptr = __fcs(buf); ptr++;
return rfcomm_send_frame(s, buf, ptr - buf);
return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
}
static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig)
......@@ -996,7 +1012,7 @@ static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig
*ptr = __fcs(buf); ptr++;
return rfcomm_send_frame(s, buf, ptr - buf);
return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
}
static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr)
......@@ -1018,7 +1034,7 @@ static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr)
*ptr = __fcs(buf); ptr++;
return rfcomm_send_frame(s, buf, ptr - buf);
return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
}
static int rfcomm_send_fcon(struct rfcomm_session *s, int cr)
......@@ -1040,7 +1056,7 @@ static int rfcomm_send_fcon(struct rfcomm_session *s, int cr)
*ptr = __fcs(buf); ptr++;
return rfcomm_send_frame(s, buf, ptr - buf);
return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
}
static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len)
......@@ -1091,7 +1107,7 @@ static int rfcomm_send_credits(struct rfcomm_session *s, u8 addr, u8 credits)
*ptr = __fcs(buf); ptr++;
return rfcomm_send_frame(s, buf, ptr - buf);
return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
}
static void rfcomm_make_uih(struct sk_buff *skb, u8 addr)
......@@ -1769,7 +1785,8 @@ static inline int rfcomm_process_tx(struct rfcomm_dlc *d)
return skb_queue_len(&d->tx_queue);
while (d->tx_credits && (skb = skb_dequeue(&d->tx_queue))) {
err = rfcomm_send_frame(d->session, skb->data, skb->len);
err = rfcomm_send_frame(d->session, skb->data, skb->len,
skb->priority);
if (err < 0) {
skb_queue_head(&d->tx_queue, skb);
break;
......@@ -2120,15 +2137,13 @@ static struct hci_cb rfcomm_cb = {
static int rfcomm_dlc_debugfs_show(struct seq_file *f, void *x)
{
struct rfcomm_session *s;
struct list_head *pp, *p;
rfcomm_lock();
list_for_each(p, &session_list) {
s = list_entry(p, struct rfcomm_session, list);
list_for_each(pp, &s->dlcs) {
list_for_each_entry(s, &session_list, list) {
struct rfcomm_dlc *d;
list_for_each_entry(d, &s->dlcs, list) {
struct sock *sk = s->sock->sk;
struct rfcomm_dlc *d = list_entry(pp, struct rfcomm_dlc, list);
seq_printf(f, "%s %s %ld %d %d %d %d\n",
batostr(&bt_sk(sk)->src),
......
......@@ -600,6 +600,8 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
break;
}
skb->priority = sk->sk_priority;
err = rfcomm_dlc_send(d, skb);
if (err < 0) {
kfree_skb(skb);
......
......@@ -34,6 +34,7 @@
#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>
......@@ -65,7 +66,7 @@ struct rfcomm_dev {
struct rfcomm_dlc *dlc;
struct tty_struct *tty;
wait_queue_head_t wait;
struct tasklet_struct wakeup_task;
struct work_struct wakeup_task;
struct device *tty_dev;
......@@ -81,7 +82,7 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb);
static void rfcomm_dev_state_change(struct rfcomm_dlc *dlc, int err);
static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig);
static void rfcomm_tty_wakeup(unsigned long arg);
static void rfcomm_tty_wakeup(struct work_struct *work);
/* ---- Device functions ---- */
static void rfcomm_dev_destruct(struct rfcomm_dev *dev)
......@@ -133,13 +134,10 @@ static inline void rfcomm_dev_put(struct rfcomm_dev *dev)
static struct rfcomm_dev *__rfcomm_dev_get(int id)
{
struct rfcomm_dev *dev;
struct list_head *p;
list_for_each(p, &rfcomm_dev_list) {
dev = list_entry(p, struct rfcomm_dev, list);
list_for_each_entry(dev, &rfcomm_dev_list, list)
if (dev->id == id)
return dev;
}
return NULL;
}
......@@ -197,7 +195,7 @@ static DEVICE_ATTR(channel, S_IRUGO, show_channel, NULL);
static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
{
struct rfcomm_dev *dev;
struct rfcomm_dev *dev, *entry;
struct list_head *head = &rfcomm_dev_list, *p;
int err = 0;
......@@ -212,8 +210,8 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
if (req->dev_id < 0) {
dev->id = 0;
list_for_each(p, &rfcomm_dev_list) {
if (list_entry(p, struct rfcomm_dev, list)->id != dev->id)
list_for_each_entry(entry, &rfcomm_dev_list, list) {
if (entry->id != dev->id)
break;
dev->id++;
......@@ -222,9 +220,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
} else {
dev->id = req->dev_id;
list_for_each(p, &rfcomm_dev_list) {
struct rfcomm_dev *entry = list_entry(p, struct rfcomm_dev, list);
list_for_each_entry(entry, &rfcomm_dev_list, list) {
if (entry->id == dev->id) {
err = -EADDRINUSE;
goto out;
......@@ -257,7 +253,7 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc)
atomic_set(&dev->opened, 0);
init_waitqueue_head(&dev->wait);
tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev);
INIT_WORK(&dev->wakeup_task, rfcomm_tty_wakeup);
skb_queue_head_init(&dev->pending);
......@@ -351,7 +347,7 @@ static void rfcomm_wfree(struct sk_buff *skb)
struct rfcomm_dev *dev = (void *) skb->sk;
atomic_sub(skb->truesize, &dev->wmem_alloc);
if (test_bit(RFCOMM_TTY_ATTACHED, &dev->flags))
tasklet_schedule(&dev->wakeup_task);
queue_work(system_nrt_wq, &dev->wakeup_task);
rfcomm_dev_put(dev);
}
......@@ -455,9 +451,9 @@ static int rfcomm_release_dev(void __user *arg)
static int rfcomm_get_dev_list(void __user *arg)
{
struct rfcomm_dev *dev;
struct rfcomm_dev_list_req *dl;
struct rfcomm_dev_info *di;
struct list_head *p;
int n = 0, size, err;
u16 dev_num;
......@@ -479,8 +475,7 @@ static int rfcomm_get_dev_list(void __user *arg)
read_lock_bh(&rfcomm_dev_lock);
list_for_each(p, &rfcomm_dev_list) {
struct rfcomm_dev *dev = list_entry(p, struct rfcomm_dev, list);
list_for_each_entry(dev, &rfcomm_dev_list, list) {
if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags))
continue;
(di + n)->id = dev->id;
......@@ -635,9 +630,10 @@ static void rfcomm_dev_modem_status(struct rfcomm_dlc *dlc, u8 v24_sig)
}
/* ---- TTY functions ---- */
static void rfcomm_tty_wakeup(unsigned long arg)
static void rfcomm_tty_wakeup(struct work_struct *work)
{
struct rfcomm_dev *dev = (void *) arg;
struct rfcomm_dev *dev = container_of(work, struct rfcomm_dev,
wakeup_task);
struct tty_struct *tty = dev->tty;
if (!tty)
return;
......@@ -762,7 +758,7 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
rfcomm_dlc_close(dev->dlc, 0);
clear_bit(RFCOMM_TTY_ATTACHED, &dev->flags);
tasklet_kill(&dev->wakeup_task);
cancel_work_sync(&dev->wakeup_task);
rfcomm_dlc_lock(dev->dlc);
tty->driver_data = NULL;
......@@ -1155,9 +1151,11 @@ static const struct tty_operations rfcomm_ops = {
int __init rfcomm_init_ttys(void)
{
int error;
rfcomm_tty_driver = alloc_tty_driver(RFCOMM_TTY_PORTS);
if (!rfcomm_tty_driver)
return -1;
return -ENOMEM;
rfcomm_tty_driver->owner = THIS_MODULE;
rfcomm_tty_driver->driver_name = "rfcomm";
......@@ -1172,10 +1170,11 @@ int __init rfcomm_init_ttys(void)
rfcomm_tty_driver->init_termios.c_lflag &= ~ICANON;
tty_set_operations(rfcomm_tty_driver, &rfcomm_ops);
if (tty_register_driver(rfcomm_tty_driver)) {
error = tty_register_driver(rfcomm_tty_driver);
if (error) {
BT_ERR("Can't register RFCOMM TTY driver");
put_tty_driver(rfcomm_tty_driver);
return -1;
return error;
}
BT_INFO("RFCOMM TTY layer initialized");
......
......@@ -181,7 +181,8 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
if (!skb)
return;
hci_send_acl(conn->hcon, skb, 0);
skb->priority = HCI_PRIO_MAX;
hci_send_acl(conn->hchan, skb, 0);
mod_timer(&conn->security_timer, jiffies +
msecs_to_jiffies(SMP_TIMEOUT));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment