Commit bc27d5f1 authored by John W. Linville's avatar John W. Linville
parents ddffeb8c f706adfe
...@@ -492,7 +492,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card) ...@@ -492,7 +492,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
{ {
u16 buf_len = 0; u16 buf_len = 0;
int ret, buf_block_len, blksz; int ret, num_blocks, blksz;
struct sk_buff *skb = NULL; struct sk_buff *skb = NULL;
u32 type; u32 type;
u8 *payload = NULL; u8 *payload = NULL;
...@@ -514,18 +514,17 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) ...@@ -514,18 +514,17 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
} }
blksz = SDIO_BLOCK_SIZE; blksz = SDIO_BLOCK_SIZE;
buf_block_len = (buf_len + blksz - 1) / blksz; num_blocks = DIV_ROUND_UP(buf_len, blksz);
if (buf_len <= SDIO_HEADER_LEN if (buf_len <= SDIO_HEADER_LEN
|| (buf_block_len * blksz) > ALLOC_BUF_SIZE) { || (num_blocks * blksz) > ALLOC_BUF_SIZE) {
BT_ERR("invalid packet length: %d", buf_len); BT_ERR("invalid packet length: %d", buf_len);
ret = -EINVAL; ret = -EINVAL;
goto exit; goto exit;
} }
/* Allocate buffer */ /* Allocate buffer */
skb = bt_skb_alloc(buf_block_len * blksz + BTSDIO_DMA_ALIGN, skb = bt_skb_alloc(num_blocks * blksz + BTSDIO_DMA_ALIGN, GFP_ATOMIC);
GFP_ATOMIC);
if (skb == NULL) { if (skb == NULL) {
BT_ERR("No free skb"); BT_ERR("No free skb");
goto exit; goto exit;
...@@ -541,7 +540,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) ...@@ -541,7 +540,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
payload = skb->data; payload = skb->data;
ret = sdio_readsb(card->func, payload, card->ioport, ret = sdio_readsb(card->func, payload, card->ioport,
buf_block_len * blksz); num_blocks * blksz);
if (ret < 0) { if (ret < 0) {
BT_ERR("readsb failed: %d", ret); BT_ERR("readsb failed: %d", ret);
ret = -EIO; ret = -EIO;
...@@ -553,7 +552,16 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) ...@@ -553,7 +552,16 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
*/ */
buf_len = payload[0]; buf_len = payload[0];
buf_len |= (u16) payload[1] << 8; buf_len |= payload[1] << 8;
buf_len |= payload[2] << 16;
if (buf_len > blksz * num_blocks) {
BT_ERR("Skip incorrect packet: hdrlen %d buffer %d",
buf_len, blksz * num_blocks);
ret = -EIO;
goto exit;
}
type = payload[3]; type = payload[3];
switch (type) { switch (type) {
...@@ -589,8 +597,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) ...@@ -589,8 +597,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
default: default:
BT_ERR("Unknown packet type:%d", type); BT_ERR("Unknown packet type:%d", type);
print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, payload, BT_ERR("hex: %*ph", blksz * num_blocks, payload);
blksz * buf_block_len);
kfree_skb(skb); kfree_skb(skb);
skb = NULL; skb = NULL;
...@@ -849,8 +856,7 @@ static int btmrvl_sdio_host_to_card(struct btmrvl_private *priv, ...@@ -849,8 +856,7 @@ static int btmrvl_sdio_host_to_card(struct btmrvl_private *priv,
if (ret < 0) { if (ret < 0) {
i++; i++;
BT_ERR("i=%d writesb failed: %d", i, ret); BT_ERR("i=%d writesb failed: %d", i, ret);
print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, BT_ERR("hex: %*ph", nb, payload);
payload, nb);
ret = -EIO; ret = -EIO;
if (i > MAX_WRITE_IOMEM_RETRY) if (i > MAX_WRITE_IOMEM_RETRY)
goto exit; goto exit;
......
...@@ -19,13 +19,25 @@ ...@@ -19,13 +19,25 @@
#define A2MP_FEAT_EXT 0x8000 #define A2MP_FEAT_EXT 0x8000
enum amp_mgr_state {
READ_LOC_AMP_INFO,
READ_LOC_AMP_ASSOC,
READ_LOC_AMP_ASSOC_FINAL,
};
struct amp_mgr { struct amp_mgr {
struct list_head list;
struct l2cap_conn *l2cap_conn; struct l2cap_conn *l2cap_conn;
struct l2cap_chan *a2mp_chan; struct l2cap_chan *a2mp_chan;
struct l2cap_chan *bredr_chan;
struct kref kref; struct kref kref;
__u8 ident; __u8 ident;
__u8 handle; __u8 handle;
enum amp_mgr_state state;
unsigned long flags; unsigned long flags;
struct list_head amp_ctrls;
struct mutex amp_ctrls_lock;
}; };
struct a2mp_cmd { struct a2mp_cmd {
...@@ -118,9 +130,19 @@ struct a2mp_physlink_rsp { ...@@ -118,9 +130,19 @@ struct a2mp_physlink_rsp {
#define A2MP_STATUS_PHYS_LINK_EXISTS 0x05 #define A2MP_STATUS_PHYS_LINK_EXISTS 0x05
#define A2MP_STATUS_SECURITY_VIOLATION 0x06 #define A2MP_STATUS_SECURITY_VIOLATION 0x06
void amp_mgr_get(struct amp_mgr *mgr); extern struct list_head amp_mgr_list;
extern struct mutex amp_mgr_list_lock;
struct amp_mgr *amp_mgr_get(struct amp_mgr *mgr);
int amp_mgr_put(struct amp_mgr *mgr); int amp_mgr_put(struct amp_mgr *mgr);
u8 __next_ident(struct amp_mgr *mgr);
struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn, struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
struct sk_buff *skb); struct sk_buff *skb);
struct amp_mgr *amp_mgr_lookup_by_state(u8 state);
void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data);
void a2mp_discover_amp(struct l2cap_chan *chan);
void a2mp_send_getinfo_rsp(struct hci_dev *hdev);
void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status);
void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status);
#endif /* __A2MP_H */ #endif /* __A2MP_H */
/*
Copyright (c) 2011,2012 Intel Corp.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 and
only version 2 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#ifndef __AMP_H
#define __AMP_H
struct amp_ctrl {
struct list_head list;
struct kref kref;
__u8 id;
__u16 assoc_len_so_far;
__u16 assoc_rem_len;
__u16 assoc_len;
__u8 *assoc;
};
int amp_ctrl_put(struct amp_ctrl *ctrl);
void amp_ctrl_get(struct amp_ctrl *ctrl);
struct amp_ctrl *amp_ctrl_add(struct amp_mgr *mgr, u8 id);
struct amp_ctrl *amp_ctrl_lookup(struct amp_mgr *mgr, u8 id);
void amp_ctrl_list_flush(struct amp_mgr *mgr);
struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr,
u8 remote_id, bool out);
int phylink_gen_key(struct hci_conn *hcon, u8 *data, u8 *len, u8 *type);
void amp_read_loc_info(struct hci_dev *hdev, struct amp_mgr *mgr);
void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle);
void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr);
void amp_read_loc_assoc_final_data(struct hci_dev *hdev,
struct hci_conn *hcon);
void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
struct hci_conn *hcon);
void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
struct hci_conn *hcon);
void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle);
void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle);
#endif /* __AMP_H */
...@@ -180,7 +180,6 @@ static inline void bacpy(bdaddr_t *dst, bdaddr_t *src) ...@@ -180,7 +180,6 @@ static inline void bacpy(bdaddr_t *dst, bdaddr_t *src)
} }
void baswap(bdaddr_t *dst, bdaddr_t *src); void baswap(bdaddr_t *dst, bdaddr_t *src);
char *batostr(bdaddr_t *ba);
/* Common socket structures and functions */ /* Common socket structures and functions */
......
...@@ -33,6 +33,8 @@ ...@@ -33,6 +33,8 @@
#define HCI_LINK_KEY_SIZE 16 #define HCI_LINK_KEY_SIZE 16
#define HCI_AMP_LINK_KEY_SIZE (2 * HCI_LINK_KEY_SIZE) #define HCI_AMP_LINK_KEY_SIZE (2 * HCI_LINK_KEY_SIZE)
#define HCI_MAX_AMP_ASSOC_SIZE 672
/* HCI dev events */ /* HCI dev events */
#define HCI_DEV_REG 1 #define HCI_DEV_REG 1
#define HCI_DEV_UNREG 2 #define HCI_DEV_UNREG 2
...@@ -196,6 +198,7 @@ enum { ...@@ -196,6 +198,7 @@ enum {
#define ACL_START_NO_FLUSH 0x00 #define ACL_START_NO_FLUSH 0x00
#define ACL_CONT 0x01 #define ACL_CONT 0x01
#define ACL_START 0x02 #define ACL_START 0x02
#define ACL_COMPLETE 0x03
#define ACL_ACTIVE_BCAST 0x04 #define ACL_ACTIVE_BCAST 0x04
#define ACL_PICO_BCAST 0x08 #define ACL_PICO_BCAST 0x08
...@@ -205,6 +208,7 @@ enum { ...@@ -205,6 +208,7 @@ enum {
#define ESCO_LINK 0x02 #define ESCO_LINK 0x02
/* Low Energy links do not have defined link type. Use invented one */ /* Low Energy links do not have defined link type. Use invented one */
#define LE_LINK 0x80 #define LE_LINK 0x80
#define AMP_LINK 0x81
/* LMP features */ /* LMP features */
#define LMP_3SLOT 0x01 #define LMP_3SLOT 0x01
...@@ -556,12 +560,46 @@ struct hci_cp_accept_phy_link { ...@@ -556,12 +560,46 @@ struct hci_cp_accept_phy_link {
__u8 key[HCI_AMP_LINK_KEY_SIZE]; __u8 key[HCI_AMP_LINK_KEY_SIZE];
} __packed; } __packed;
#define HCI_OP_DISCONN_PHY_LINK 0x0437 #define HCI_OP_DISCONN_PHY_LINK 0x0437
struct hci_cp_disconn_phy_link { struct hci_cp_disconn_phy_link {
__u8 phy_handle; __u8 phy_handle;
__u8 reason; __u8 reason;
} __packed; } __packed;
struct ext_flow_spec {
__u8 id;
__u8 stype;
__le16 msdu;
__le32 sdu_itime;
__le32 acc_lat;
__le32 flush_to;
} __packed;
#define HCI_OP_CREATE_LOGICAL_LINK 0x0438
#define HCI_OP_ACCEPT_LOGICAL_LINK 0x0439
struct hci_cp_create_accept_logical_link {
__u8 phy_handle;
struct ext_flow_spec tx_flow_spec;
struct ext_flow_spec rx_flow_spec;
} __packed;
#define HCI_OP_DISCONN_LOGICAL_LINK 0x043a
struct hci_cp_disconn_logical_link {
__le16 log_handle;
} __packed;
#define HCI_OP_LOGICAL_LINK_CANCEL 0x043b
struct hci_cp_logical_link_cancel {
__u8 phy_handle;
__u8 flow_spec_id;
} __packed;
struct hci_rp_logical_link_cancel {
__u8 status;
__u8 phy_handle;
__u8 flow_spec_id;
} __packed;
#define HCI_OP_SNIFF_MODE 0x0803 #define HCI_OP_SNIFF_MODE 0x0803
struct hci_cp_sniff_mode { struct hci_cp_sniff_mode {
__le16 handle; __le16 handle;
......
...@@ -73,6 +73,7 @@ struct discovery_state { ...@@ -73,6 +73,7 @@ struct discovery_state {
struct hci_conn_hash { struct hci_conn_hash {
struct list_head list; struct list_head list;
unsigned int acl_num; unsigned int acl_num;
unsigned int amp_num;
unsigned int sco_num; unsigned int sco_num;
unsigned int le_num; unsigned int le_num;
}; };
...@@ -124,6 +125,14 @@ struct le_scan_params { ...@@ -124,6 +125,14 @@ struct le_scan_params {
#define HCI_MAX_SHORT_NAME_LENGTH 10 #define HCI_MAX_SHORT_NAME_LENGTH 10
struct amp_assoc {
__u16 len;
__u16 offset;
__u16 rem_len;
__u16 len_so_far;
__u8 data[HCI_MAX_AMP_ASSOC_SIZE];
};
#define NUM_REASSEMBLY 4 #define NUM_REASSEMBLY 4
struct hci_dev { struct hci_dev {
struct list_head list; struct list_head list;
...@@ -177,6 +186,8 @@ struct hci_dev { ...@@ -177,6 +186,8 @@ struct hci_dev {
__u32 amp_max_flush_to; __u32 amp_max_flush_to;
__u32 amp_be_flush_to; __u32 amp_be_flush_to;
struct amp_assoc loc_assoc;
__u8 flow_ctl_mode; __u8 flow_ctl_mode;
unsigned int auto_accept_delay; unsigned int auto_accept_delay;
...@@ -252,8 +263,6 @@ struct hci_dev { ...@@ -252,8 +263,6 @@ struct hci_dev {
struct sk_buff_head driver_init; struct sk_buff_head driver_init;
void *core_data;
atomic_t promisc; atomic_t promisc;
struct dentry *debugfs; struct dentry *debugfs;
...@@ -277,6 +286,8 @@ struct hci_dev { ...@@ -277,6 +286,8 @@ struct hci_dev {
int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg); int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg);
}; };
#define HCI_PHY_HANDLE(handle) (handle & 0xff)
struct hci_conn { struct hci_conn {
struct list_head list; struct list_head list;
...@@ -310,6 +321,7 @@ struct hci_conn { ...@@ -310,6 +321,7 @@ struct hci_conn {
__u8 remote_cap; __u8 remote_cap;
__u8 remote_auth; __u8 remote_auth;
__u8 remote_id;
bool flush_key; bool flush_key;
unsigned int sent; unsigned int sent;
...@@ -339,7 +351,7 @@ struct hci_conn { ...@@ -339,7 +351,7 @@ struct hci_conn {
struct hci_chan { struct hci_chan {
struct list_head list; struct list_head list;
__u16 handle;
struct hci_conn *conn; struct hci_conn *conn;
struct sk_buff_head data_q; struct sk_buff_head data_q;
unsigned int sent; unsigned int sent;
...@@ -438,6 +450,9 @@ static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c) ...@@ -438,6 +450,9 @@ static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
case ACL_LINK: case ACL_LINK:
h->acl_num++; h->acl_num++;
break; break;
case AMP_LINK:
h->amp_num++;
break;
case LE_LINK: case LE_LINK:
h->le_num++; h->le_num++;
break; break;
...@@ -459,6 +474,9 @@ static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c) ...@@ -459,6 +474,9 @@ static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
case ACL_LINK: case ACL_LINK:
h->acl_num--; h->acl_num--;
break; break;
case AMP_LINK:
h->amp_num--;
break;
case LE_LINK: case LE_LINK:
h->le_num--; h->le_num--;
break; break;
...@@ -475,6 +493,8 @@ static inline unsigned int hci_conn_num(struct hci_dev *hdev, __u8 type) ...@@ -475,6 +493,8 @@ static inline unsigned int hci_conn_num(struct hci_dev *hdev, __u8 type)
switch (type) { switch (type) {
case ACL_LINK: case ACL_LINK:
return h->acl_num; return h->acl_num;
case AMP_LINK:
return h->amp_num;
case LE_LINK: case LE_LINK:
return h->le_num; return h->le_num;
case SCO_LINK: case SCO_LINK:
...@@ -556,6 +576,7 @@ void hci_conn_check_pending(struct hci_dev *hdev); ...@@ -556,6 +576,7 @@ void hci_conn_check_pending(struct hci_dev *hdev);
struct hci_chan *hci_chan_create(struct hci_conn *conn); struct hci_chan *hci_chan_create(struct hci_conn *conn);
void hci_chan_del(struct hci_chan *chan); void hci_chan_del(struct hci_chan *chan);
void hci_chan_list_flush(struct hci_conn *conn); void hci_chan_list_flush(struct hci_conn *conn);
struct hci_chan *hci_chan_lookup_handle(struct hci_dev *hdev, __u16 handle);
struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
__u8 dst_type, __u8 sec_level, __u8 auth_type); __u8 dst_type, __u8 sec_level, __u8 auth_type);
...@@ -584,7 +605,10 @@ static inline void hci_conn_put(struct hci_conn *conn) ...@@ -584,7 +605,10 @@ static inline void hci_conn_put(struct hci_conn *conn)
if (atomic_dec_and_test(&conn->refcnt)) { if (atomic_dec_and_test(&conn->refcnt)) {
unsigned long timeo; unsigned long timeo;
if (conn->type == ACL_LINK || conn->type == LE_LINK) {
switch (conn->type) {
case ACL_LINK:
case LE_LINK:
del_timer(&conn->idle_timer); del_timer(&conn->idle_timer);
if (conn->state == BT_CONNECTED) { if (conn->state == BT_CONNECTED) {
timeo = conn->disc_timeout; timeo = conn->disc_timeout;
...@@ -593,12 +617,20 @@ static inline void hci_conn_put(struct hci_conn *conn) ...@@ -593,12 +617,20 @@ static inline void hci_conn_put(struct hci_conn *conn)
} else { } else {
timeo = msecs_to_jiffies(10); timeo = msecs_to_jiffies(10);
} }
} else { break;
case AMP_LINK:
timeo = conn->disc_timeout;
break;
default:
timeo = msecs_to_jiffies(10); timeo = msecs_to_jiffies(10);
break;
} }
cancel_delayed_work(&conn->disc_work); cancel_delayed_work(&conn->disc_work);
queue_delayed_work(conn->hdev->workqueue, queue_delayed_work(conn->hdev->workqueue,
&conn->disc_work, timeo); &conn->disc_work, timeo);
} }
} }
...@@ -789,6 +821,10 @@ static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason) ...@@ -789,6 +821,10 @@ static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason)
sco_disconn_cfm(conn, reason); sco_disconn_cfm(conn, reason);
break; break;
/* L2CAP would be handled for BREDR chan */
case AMP_LINK:
break;
default: default:
BT_ERR("unknown link type %d", conn->type); BT_ERR("unknown link type %d", conn->type);
break; break;
......
...@@ -32,13 +32,14 @@ ...@@ -32,13 +32,14 @@
/* L2CAP defaults */ /* L2CAP defaults */
#define L2CAP_DEFAULT_MTU 672 #define L2CAP_DEFAULT_MTU 672
#define L2CAP_DEFAULT_MIN_MTU 48 #define L2CAP_DEFAULT_MIN_MTU 48
#define L2CAP_DEFAULT_FLUSH_TO 0xffff #define L2CAP_DEFAULT_FLUSH_TO 0xFFFF
#define L2CAP_EFS_DEFAULT_FLUSH_TO 0xFFFFFFFF
#define L2CAP_DEFAULT_TX_WINDOW 63 #define L2CAP_DEFAULT_TX_WINDOW 63
#define L2CAP_DEFAULT_EXT_WINDOW 0x3FFF #define L2CAP_DEFAULT_EXT_WINDOW 0x3FFF
#define L2CAP_DEFAULT_MAX_TX 3 #define L2CAP_DEFAULT_MAX_TX 3
#define L2CAP_DEFAULT_RETRANS_TO 2000 /* 2 seconds */ #define L2CAP_DEFAULT_RETRANS_TO 2000 /* 2 seconds */
#define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */ #define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */
#define L2CAP_DEFAULT_MAX_PDU_SIZE 1009 /* Sized for 3-DH5 packet */ #define L2CAP_DEFAULT_MAX_PDU_SIZE 1492 /* Sized for AMP packet */
#define L2CAP_DEFAULT_ACK_TO 200 #define L2CAP_DEFAULT_ACK_TO 200
#define L2CAP_DEFAULT_MAX_SDU_SIZE 0xFFFF #define L2CAP_DEFAULT_MAX_SDU_SIZE 0xFFFF
#define L2CAP_DEFAULT_SDU_ITIME 0xFFFFFFFF #define L2CAP_DEFAULT_SDU_ITIME 0xFFFFFFFF
...@@ -508,6 +509,8 @@ struct l2cap_chan { ...@@ -508,6 +509,8 @@ struct l2cap_chan {
__u32 remote_acc_lat; __u32 remote_acc_lat;
__u32 remote_flush_to; __u32 remote_flush_to;
__u8 ctrl_id;
struct delayed_work chan_timer; struct delayed_work chan_timer;
struct delayed_work retrans_timer; struct delayed_work retrans_timer;
struct delayed_work monitor_timer; struct delayed_work monitor_timer;
...@@ -538,6 +541,7 @@ struct l2cap_ops { ...@@ -538,6 +541,7 @@ struct l2cap_ops {
void (*state_change) (struct l2cap_chan *chan, void (*state_change) (struct l2cap_chan *chan,
int state); int state);
void (*ready) (struct l2cap_chan *chan); void (*ready) (struct l2cap_chan *chan);
void (*defer) (struct l2cap_chan *chan);
struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan, struct sk_buff *(*alloc_skb) (struct l2cap_chan *chan,
unsigned long len, int nb); unsigned long len, int nb);
}; };
...@@ -745,6 +749,10 @@ static inline void l2cap_chan_no_ready(struct l2cap_chan *chan) ...@@ -745,6 +749,10 @@ static inline void l2cap_chan_no_ready(struct l2cap_chan *chan)
{ {
} }
static inline void l2cap_chan_no_defer(struct l2cap_chan *chan)
{
}
extern bool disable_ertm; extern bool disable_ertm;
int l2cap_init_sockets(void); int l2cap_init_sockets(void);
...@@ -767,6 +775,8 @@ int l2cap_chan_check_security(struct l2cap_chan *chan); ...@@ -767,6 +775,8 @@ int l2cap_chan_check_security(struct l2cap_chan *chan);
void l2cap_chan_set_defaults(struct l2cap_chan *chan); void l2cap_chan_set_defaults(struct l2cap_chan *chan);
int l2cap_ertm_init(struct l2cap_chan *chan); int l2cap_ertm_init(struct l2cap_chan *chan);
void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan); void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
void l2cap_chan_del(struct l2cap_chan *chan, int err); void l2cap_chan_del(struct l2cap_chan *chan, int err);
void l2cap_send_conn_req(struct l2cap_chan *chan);
#endif /* __L2CAP_H */ #endif /* __L2CAP_H */
...@@ -11,6 +11,7 @@ menuconfig BT ...@@ -11,6 +11,7 @@ menuconfig BT
select CRYPTO_BLKCIPHER select CRYPTO_BLKCIPHER
select CRYPTO_AES select CRYPTO_AES
select CRYPTO_ECB select CRYPTO_ECB
select CRYPTO_SHA256
help help
Bluetooth is low-cost, low-power, short-range wireless technology. Bluetooth is low-cost, low-power, short-range wireless technology.
It was designed as a replacement for cables and other short-range It was designed as a replacement for cables and other short-range
......
...@@ -10,4 +10,4 @@ obj-$(CONFIG_BT_HIDP) += hidp/ ...@@ -10,4 +10,4 @@ obj-$(CONFIG_BT_HIDP) += hidp/
bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \ bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \ hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
a2mp.o a2mp.o amp.o
This diff is collapsed.
...@@ -569,7 +569,6 @@ static int bt_seq_show(struct seq_file *seq, void *v) ...@@ -569,7 +569,6 @@ static int bt_seq_show(struct seq_file *seq, void *v)
{ {
struct bt_seq_state *s = seq->private; struct bt_seq_state *s = seq->private;
struct bt_sock_list *l = s->l; struct bt_sock_list *l = s->l;
bdaddr_t src_baswapped, dst_baswapped;
if (v == SEQ_START_TOKEN) { if (v == SEQ_START_TOKEN) {
seq_puts(seq ,"sk RefCnt Rmem Wmem User Inode Src Dst Parent"); seq_puts(seq ,"sk RefCnt Rmem Wmem User Inode Src Dst Parent");
...@@ -583,18 +582,17 @@ static int bt_seq_show(struct seq_file *seq, void *v) ...@@ -583,18 +582,17 @@ static int bt_seq_show(struct seq_file *seq, void *v)
} else { } else {
struct sock *sk = sk_entry(v); struct sock *sk = sk_entry(v);
struct bt_sock *bt = bt_sk(sk); struct bt_sock *bt = bt_sk(sk);
baswap(&src_baswapped, &bt->src);
baswap(&dst_baswapped, &bt->dst);
seq_printf(seq, "%pK %-6d %-6u %-6u %-6u %-6lu %pM %pM %-6lu", seq_printf(seq,
"%pK %-6d %-6u %-6u %-6u %-6lu %pMR %pMR %-6lu",
sk, sk,
atomic_read(&sk->sk_refcnt), atomic_read(&sk->sk_refcnt),
sk_rmem_alloc_get(sk), sk_rmem_alloc_get(sk),
sk_wmem_alloc_get(sk), sk_wmem_alloc_get(sk),
from_kuid(seq_user_ns(seq), sock_i_uid(sk)), from_kuid(seq_user_ns(seq), sock_i_uid(sk)),
sock_i_ino(sk), sock_i_ino(sk),
&src_baswapped, &bt->src,
&dst_baswapped, &bt->dst,
bt->parent? sock_i_ino(bt->parent): 0LU); bt->parent? sock_i_ino(bt->parent): 0LU);
if (l->custom_seq_show) { if (l->custom_seq_show) {
......
/*
Copyright (c) 2011,2012 Intel Corp.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 and
only version 2 as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/a2mp.h>
#include <net/bluetooth/amp.h>
#include <crypto/hash.h>
/* Remote AMP Controllers interface */
void amp_ctrl_get(struct amp_ctrl *ctrl)
{
BT_DBG("ctrl %p orig refcnt %d", ctrl,
atomic_read(&ctrl->kref.refcount));
kref_get(&ctrl->kref);
}
static void amp_ctrl_destroy(struct kref *kref)
{
struct amp_ctrl *ctrl = container_of(kref, struct amp_ctrl, kref);
BT_DBG("ctrl %p", ctrl);
kfree(ctrl->assoc);
kfree(ctrl);
}
int amp_ctrl_put(struct amp_ctrl *ctrl)
{
BT_DBG("ctrl %p orig refcnt %d", ctrl,
atomic_read(&ctrl->kref.refcount));
return kref_put(&ctrl->kref, &amp_ctrl_destroy);
}
struct amp_ctrl *amp_ctrl_add(struct amp_mgr *mgr, u8 id)
{
struct amp_ctrl *ctrl;
ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
if (!ctrl)
return NULL;
kref_init(&ctrl->kref);
ctrl->id = id;
mutex_lock(&mgr->amp_ctrls_lock);
list_add(&ctrl->list, &mgr->amp_ctrls);
mutex_unlock(&mgr->amp_ctrls_lock);
BT_DBG("mgr %p ctrl %p", mgr, ctrl);
return ctrl;
}
void amp_ctrl_list_flush(struct amp_mgr *mgr)
{
struct amp_ctrl *ctrl, *n;
BT_DBG("mgr %p", mgr);
mutex_lock(&mgr->amp_ctrls_lock);
list_for_each_entry_safe(ctrl, n, &mgr->amp_ctrls, list) {
list_del(&ctrl->list);
amp_ctrl_put(ctrl);
}
mutex_unlock(&mgr->amp_ctrls_lock);
}
struct amp_ctrl *amp_ctrl_lookup(struct amp_mgr *mgr, u8 id)
{
struct amp_ctrl *ctrl;
BT_DBG("mgr %p id %d", mgr, id);
mutex_lock(&mgr->amp_ctrls_lock);
list_for_each_entry(ctrl, &mgr->amp_ctrls, list) {
if (ctrl->id == id) {
amp_ctrl_get(ctrl);
mutex_unlock(&mgr->amp_ctrls_lock);
return ctrl;
}
}
mutex_unlock(&mgr->amp_ctrls_lock);
return NULL;
}
/* Physical Link interface */
static u8 __next_handle(struct amp_mgr *mgr)
{
if (++mgr->handle == 0)
mgr->handle = 1;
return mgr->handle;
}
struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr,
u8 remote_id, bool out)
{
bdaddr_t *dst = mgr->l2cap_conn->dst;
struct hci_conn *hcon;
hcon = hci_conn_add(hdev, AMP_LINK, dst);
if (!hcon)
return NULL;
BT_DBG("hcon %p dst %pMR", hcon, dst);
hcon->state = BT_CONNECT;
hcon->attempt++;
hcon->handle = __next_handle(mgr);
hcon->remote_id = remote_id;
hcon->amp_mgr = amp_mgr_get(mgr);
hcon->out = out;
return hcon;
}
/* AMP crypto key generation interface */
static int hmac_sha256(u8 *key, u8 ksize, char *plaintext, u8 psize, u8 *output)
{
int ret = 0;
struct crypto_shash *tfm;
if (!ksize)
return -EINVAL;
tfm = crypto_alloc_shash("hmac(sha256)", 0, 0);
if (IS_ERR(tfm)) {
BT_DBG("crypto_alloc_ahash failed: err %ld", PTR_ERR(tfm));
return PTR_ERR(tfm);
}
ret = crypto_shash_setkey(tfm, key, ksize);
if (ret) {
BT_DBG("crypto_ahash_setkey failed: err %d", ret);
} else {
struct {
struct shash_desc shash;
char ctx[crypto_shash_descsize(tfm)];
} desc;
desc.shash.tfm = tfm;
desc.shash.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
ret = crypto_shash_digest(&desc.shash, plaintext, psize,
output);
}
crypto_free_shash(tfm);
return ret;
}
int phylink_gen_key(struct hci_conn *conn, u8 *data, u8 *len, u8 *type)
{
struct hci_dev *hdev = conn->hdev;
struct link_key *key;
u8 keybuf[HCI_AMP_LINK_KEY_SIZE];
u8 gamp_key[HCI_AMP_LINK_KEY_SIZE];
int err;
if (!hci_conn_check_link_mode(conn))
return -EACCES;
BT_DBG("conn %p key_type %d", conn, conn->key_type);
/* Legacy key */
if (conn->key_type < 3) {
BT_ERR("Legacy key type %d", conn->key_type);
return -EACCES;
}
*type = conn->key_type;
*len = HCI_AMP_LINK_KEY_SIZE;
key = hci_find_link_key(hdev, &conn->dst);
if (!key) {
BT_DBG("No Link key for conn %p dst %pMR", conn, &conn->dst);
return -EACCES;
}
/* BR/EDR Link Key concatenated together with itself */
memcpy(&keybuf[0], key->val, HCI_LINK_KEY_SIZE);
memcpy(&keybuf[HCI_LINK_KEY_SIZE], key->val, HCI_LINK_KEY_SIZE);
/* Derive Generic AMP Link Key (gamp) */
err = hmac_sha256(keybuf, HCI_AMP_LINK_KEY_SIZE, "gamp", 4, gamp_key);
if (err) {
BT_ERR("Could not derive Generic AMP Key: err %d", err);
return err;
}
if (conn->key_type == HCI_LK_DEBUG_COMBINATION) {
BT_DBG("Use Generic AMP Key (gamp)");
memcpy(data, gamp_key, HCI_AMP_LINK_KEY_SIZE);
return err;
}
/* Derive Dedicated AMP Link Key: "802b" is 802.11 PAL keyID */
return hmac_sha256(gamp_key, HCI_AMP_LINK_KEY_SIZE, "802b", 4, data);
}
void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle)
{
struct hci_cp_read_local_amp_assoc cp;
struct amp_assoc *loc_assoc = &hdev->loc_assoc;
BT_DBG("%s handle %d", hdev->name, phy_handle);
cp.phy_handle = phy_handle;
cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
cp.len_so_far = cpu_to_le16(loc_assoc->offset);
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
}
void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr)
{
struct hci_cp_read_local_amp_assoc cp;
memset(&hdev->loc_assoc, 0, sizeof(struct amp_assoc));
memset(&cp, 0, sizeof(cp));
cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
mgr->state = READ_LOC_AMP_ASSOC;
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
}
void amp_read_loc_assoc_final_data(struct hci_dev *hdev,
struct hci_conn *hcon)
{
struct hci_cp_read_local_amp_assoc cp;
struct amp_mgr *mgr = hcon->amp_mgr;
cp.phy_handle = hcon->handle;
cp.len_so_far = cpu_to_le16(0);
cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
mgr->state = READ_LOC_AMP_ASSOC_FINAL;
/* Read Local AMP Assoc final link information data */
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
}
/* Write AMP Assoc data fragments, returns true with last fragment written*/
static bool amp_write_rem_assoc_frag(struct hci_dev *hdev,
struct hci_conn *hcon)
{
struct hci_cp_write_remote_amp_assoc *cp;
struct amp_mgr *mgr = hcon->amp_mgr;
struct amp_ctrl *ctrl;
u16 frag_len, len;
ctrl = amp_ctrl_lookup(mgr, hcon->remote_id);
if (!ctrl)
return false;
if (!ctrl->assoc_rem_len) {
BT_DBG("all fragments are written");
ctrl->assoc_rem_len = ctrl->assoc_len;
ctrl->assoc_len_so_far = 0;
amp_ctrl_put(ctrl);
return true;
}
frag_len = min_t(u16, 248, ctrl->assoc_rem_len);
len = frag_len + sizeof(*cp);
cp = kzalloc(len, GFP_KERNEL);
if (!cp) {
amp_ctrl_put(ctrl);
return false;
}
BT_DBG("hcon %p ctrl %p frag_len %u assoc_len %u rem_len %u",
hcon, ctrl, frag_len, ctrl->assoc_len, ctrl->assoc_rem_len);
cp->phy_handle = hcon->handle;
cp->len_so_far = cpu_to_le16(ctrl->assoc_len_so_far);
cp->rem_len = cpu_to_le16(ctrl->assoc_rem_len);
memcpy(cp->frag, ctrl->assoc, frag_len);
ctrl->assoc_len_so_far += frag_len;
ctrl->assoc_rem_len -= frag_len;
amp_ctrl_put(ctrl);
hci_send_cmd(hdev, HCI_OP_WRITE_REMOTE_AMP_ASSOC, len, cp);
kfree(cp);
return false;
}
void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle)
{
struct hci_conn *hcon;
BT_DBG("%s phy handle 0x%2.2x", hdev->name, handle);
hcon = hci_conn_hash_lookup_handle(hdev, handle);
if (!hcon)
return;
amp_write_rem_assoc_frag(hdev, hcon);
}
void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle)
{
struct hci_conn *hcon;
BT_DBG("%s phy handle 0x%2.2x", hdev->name, handle);
hcon = hci_conn_hash_lookup_handle(hdev, handle);
if (!hcon)
return;
BT_DBG("%s phy handle 0x%2.2x hcon %p", hdev->name, handle, hcon);
amp_write_rem_assoc_frag(hdev, hcon);
}
void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
struct hci_conn *hcon)
{
struct hci_cp_create_phy_link cp;
cp.phy_handle = hcon->handle;
BT_DBG("%s hcon %p phy handle 0x%2.2x", hdev->name, hcon,
hcon->handle);
if (phylink_gen_key(mgr->l2cap_conn->hcon, cp.key, &cp.key_len,
&cp.key_type)) {
BT_DBG("Cannot create link key");
return;
}
hci_send_cmd(hdev, HCI_OP_CREATE_PHY_LINK, sizeof(cp), &cp);
}
void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
struct hci_conn *hcon)
{
struct hci_cp_accept_phy_link cp;
cp.phy_handle = hcon->handle;
BT_DBG("%s hcon %p phy handle 0x%2.2x", hdev->name, hcon,
hcon->handle);
if (phylink_gen_key(mgr->l2cap_conn->hcon, cp.key, &cp.key_len,
&cp.key_type)) {
BT_DBG("Cannot create link key");
return;
}
hci_send_cmd(hdev, HCI_OP_ACCEPT_PHY_LINK, sizeof(cp), &cp);
}
...@@ -182,8 +182,7 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len) ...@@ -182,8 +182,7 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
a2 = data; a2 = data;
data += ETH_ALEN; data += ETH_ALEN;
BT_DBG("mc filter %s -> %s", BT_DBG("mc filter %pMR -> %pMR", a1, a2);
batostr((void *) a1), batostr((void *) a2));
/* Iterate from a1 to a2 */ /* Iterate from a1 to a2 */
set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter); set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
......
...@@ -353,7 +353,7 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock) ...@@ -353,7 +353,7 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
BT_DBG("mtu %d", session->mtu); BT_DBG("mtu %d", session->mtu);
sprintf(session->name, "%s", batostr(&bt_sk(sock->sk)->dst)); sprintf(session->name, "%pMR", &bt_sk(sock->sk)->dst);
session->sock = sock; session->sock = sock;
session->state = BT_CONFIG; session->state = BT_CONFIG;
......
...@@ -130,6 +130,20 @@ void hci_acl_disconn(struct hci_conn *conn, __u8 reason) ...@@ -130,6 +130,20 @@ void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp); hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp);
} }
static void hci_amp_disconn(struct hci_conn *conn, __u8 reason)
{
struct hci_cp_disconn_phy_link cp;
BT_DBG("hcon %p", conn);
conn->state = BT_DISCONN;
cp.phy_handle = HCI_PHY_HANDLE(conn->handle);
cp.reason = reason;
hci_send_cmd(conn->hdev, HCI_OP_DISCONN_PHY_LINK,
sizeof(cp), &cp);
}
static void hci_add_sco(struct hci_conn *conn, __u16 handle) static void hci_add_sco(struct hci_conn *conn, __u16 handle)
{ {
struct hci_dev *hdev = conn->hdev; struct hci_dev *hdev = conn->hdev;
...@@ -230,11 +244,24 @@ void hci_sco_setup(struct hci_conn *conn, __u8 status) ...@@ -230,11 +244,24 @@ void hci_sco_setup(struct hci_conn *conn, __u8 status)
} }
} }
static void hci_conn_disconnect(struct hci_conn *conn)
{
__u8 reason = hci_proto_disconn_ind(conn);
switch (conn->type) {
case ACL_LINK:
hci_acl_disconn(conn, reason);
break;
case AMP_LINK:
hci_amp_disconn(conn, reason);
break;
}
}
static void hci_conn_timeout(struct work_struct *work) static void hci_conn_timeout(struct work_struct *work)
{ {
struct hci_conn *conn = container_of(work, struct hci_conn, struct hci_conn *conn = container_of(work, struct hci_conn,
disc_work.work); disc_work.work);
__u8 reason;
BT_DBG("hcon %p state %s", conn, state_to_string(conn->state)); BT_DBG("hcon %p state %s", conn, state_to_string(conn->state));
...@@ -253,8 +280,7 @@ static void hci_conn_timeout(struct work_struct *work) ...@@ -253,8 +280,7 @@ static void hci_conn_timeout(struct work_struct *work)
break; break;
case BT_CONFIG: case BT_CONFIG:
case BT_CONNECTED: case BT_CONNECTED:
reason = hci_proto_disconn_ind(conn); hci_conn_disconnect(conn);
hci_acl_disconn(conn, reason);
break; break;
default: default:
conn->state = BT_CLOSED; conn->state = BT_CLOSED;
...@@ -320,7 +346,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) ...@@ -320,7 +346,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
{ {
struct hci_conn *conn; struct hci_conn *conn;
BT_DBG("%s dst %s", hdev->name, batostr(dst)); BT_DBG("%s dst %pMR", hdev->name, dst);
conn = kzalloc(sizeof(struct hci_conn), GFP_KERNEL); conn = kzalloc(sizeof(struct hci_conn), GFP_KERNEL);
if (!conn) if (!conn)
...@@ -437,7 +463,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src) ...@@ -437,7 +463,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
int use_src = bacmp(src, BDADDR_ANY); int use_src = bacmp(src, BDADDR_ANY);
struct hci_dev *hdev = NULL, *d; struct hci_dev *hdev = NULL, *d;
BT_DBG("%s -> %s", batostr(src), batostr(dst)); BT_DBG("%pMR -> %pMR", src, dst);
read_lock(&hci_dev_list_lock); read_lock(&hci_dev_list_lock);
...@@ -567,7 +593,7 @@ static struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, ...@@ -567,7 +593,7 @@ static struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type,
struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
__u8 dst_type, __u8 sec_level, __u8 auth_type) __u8 dst_type, __u8 sec_level, __u8 auth_type)
{ {
BT_DBG("%s dst %s type 0x%x", hdev->name, batostr(dst), type); BT_DBG("%s dst %pMR type 0x%x", hdev->name, dst, type);
switch (type) { switch (type) {
case LE_LINK: case LE_LINK:
...@@ -963,3 +989,35 @@ void hci_chan_list_flush(struct hci_conn *conn) ...@@ -963,3 +989,35 @@ void hci_chan_list_flush(struct hci_conn *conn)
list_for_each_entry_safe(chan, n, &conn->chan_list, list) list_for_each_entry_safe(chan, n, &conn->chan_list, list)
hci_chan_del(chan); hci_chan_del(chan);
} }
static struct hci_chan *__hci_chan_lookup_handle(struct hci_conn *hcon,
__u16 handle)
{
struct hci_chan *hchan;
list_for_each_entry(hchan, &hcon->chan_list, list) {
if (hchan->handle == handle)
return hchan;
}
return NULL;
}
struct hci_chan *hci_chan_lookup_handle(struct hci_dev *hdev, __u16 handle)
{
struct hci_conn_hash *h = &hdev->conn_hash;
struct hci_conn *hcon;
struct hci_chan *hchan = NULL;
rcu_read_lock();
list_for_each_entry_rcu(hcon, &h->list, list) {
hchan = __hci_chan_lookup_handle(hcon, handle);
if (hchan)
break;
}
rcu_read_unlock();
return hchan;
}
...@@ -405,7 +405,7 @@ struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, ...@@ -405,7 +405,7 @@ struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev,
struct discovery_state *cache = &hdev->discovery; struct discovery_state *cache = &hdev->discovery;
struct inquiry_entry *e; struct inquiry_entry *e;
BT_DBG("cache %p, %s", cache, batostr(bdaddr)); BT_DBG("cache %p, %pMR", cache, bdaddr);
list_for_each_entry(e, &cache->all, all) { list_for_each_entry(e, &cache->all, all) {
if (!bacmp(&e->data.bdaddr, bdaddr)) if (!bacmp(&e->data.bdaddr, bdaddr))
...@@ -421,7 +421,7 @@ struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev, ...@@ -421,7 +421,7 @@ struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev,
struct discovery_state *cache = &hdev->discovery; struct discovery_state *cache = &hdev->discovery;
struct inquiry_entry *e; struct inquiry_entry *e;
BT_DBG("cache %p, %s", cache, batostr(bdaddr)); BT_DBG("cache %p, %pMR", cache, bdaddr);
list_for_each_entry(e, &cache->unknown, list) { list_for_each_entry(e, &cache->unknown, list) {
if (!bacmp(&e->data.bdaddr, bdaddr)) if (!bacmp(&e->data.bdaddr, bdaddr))
...@@ -438,7 +438,7 @@ struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev, ...@@ -438,7 +438,7 @@ struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev,
struct discovery_state *cache = &hdev->discovery; struct discovery_state *cache = &hdev->discovery;
struct inquiry_entry *e; struct inquiry_entry *e;
BT_DBG("cache %p bdaddr %s state %d", cache, batostr(bdaddr), state); BT_DBG("cache %p bdaddr %pMR state %d", cache, bdaddr, state);
list_for_each_entry(e, &cache->resolve, list) { list_for_each_entry(e, &cache->resolve, list) {
if (!bacmp(bdaddr, BDADDR_ANY) && e->name_state == state) if (!bacmp(bdaddr, BDADDR_ANY) && e->name_state == state)
...@@ -475,7 +475,7 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data, ...@@ -475,7 +475,7 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
struct discovery_state *cache = &hdev->discovery; struct discovery_state *cache = &hdev->discovery;
struct inquiry_entry *ie; struct inquiry_entry *ie;
BT_DBG("cache %p, %s", cache, batostr(&data->bdaddr)); BT_DBG("cache %p, %pMR", cache, &data->bdaddr);
if (ssp) if (ssp)
*ssp = data->ssp_mode; *ssp = data->ssp_mode;
...@@ -1259,7 +1259,7 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, ...@@ -1259,7 +1259,7 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
list_add(&key->list, &hdev->link_keys); list_add(&key->list, &hdev->link_keys);
} }
BT_DBG("%s key for %s type %u", hdev->name, batostr(bdaddr), type); BT_DBG("%s key for %pMR type %u", hdev->name, bdaddr, type);
/* Some buggy controller combinations generate a changed /* Some buggy controller combinations generate a changed
* combination key for legacy pairing even when there's no * combination key for legacy pairing even when there's no
...@@ -1338,7 +1338,7 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) ...@@ -1338,7 +1338,7 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
if (!key) if (!key)
return -ENOENT; return -ENOENT;
BT_DBG("%s removing %s", hdev->name, batostr(bdaddr)); BT_DBG("%s removing %pMR", hdev->name, bdaddr);
list_del(&key->list); list_del(&key->list);
kfree(key); kfree(key);
...@@ -1354,7 +1354,7 @@ int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr) ...@@ -1354,7 +1354,7 @@ int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr)
if (bacmp(bdaddr, &k->bdaddr)) if (bacmp(bdaddr, &k->bdaddr))
continue; continue;
BT_DBG("%s removing %s", hdev->name, batostr(bdaddr)); BT_DBG("%s removing %pMR", hdev->name, bdaddr);
list_del(&k->list); list_del(&k->list);
kfree(k); kfree(k);
...@@ -1401,7 +1401,7 @@ int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr) ...@@ -1401,7 +1401,7 @@ int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr)
if (!data) if (!data)
return -ENOENT; return -ENOENT;
BT_DBG("%s removing %s", hdev->name, batostr(bdaddr)); BT_DBG("%s removing %pMR", hdev->name, bdaddr);
list_del(&data->list); list_del(&data->list);
kfree(data); kfree(data);
...@@ -1440,7 +1440,7 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, ...@@ -1440,7 +1440,7 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
memcpy(data->hash, hash, sizeof(data->hash)); memcpy(data->hash, hash, sizeof(data->hash));
memcpy(data->randomizer, randomizer, sizeof(data->randomizer)); memcpy(data->randomizer, randomizer, sizeof(data->randomizer));
BT_DBG("%s for %s", hdev->name, batostr(bdaddr)); BT_DBG("%s for %pMR", hdev->name, bdaddr);
return 0; return 0;
} }
...@@ -2153,9 +2153,10 @@ static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags) ...@@ -2153,9 +2153,10 @@ static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
hdr->dlen = cpu_to_le16(len); hdr->dlen = cpu_to_le16(len);
} }
static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue, static void hci_queue_acl(struct hci_chan *chan, struct sk_buff_head *queue,
struct sk_buff *skb, __u16 flags) struct sk_buff *skb, __u16 flags)
{ {
struct hci_conn *conn = chan->conn;
struct hci_dev *hdev = conn->hdev; struct hci_dev *hdev = conn->hdev;
struct sk_buff *list; struct sk_buff *list;
...@@ -2163,7 +2164,18 @@ static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue, ...@@ -2163,7 +2164,18 @@ static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
skb->data_len = 0; skb->data_len = 0;
bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT; bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
hci_add_acl_hdr(skb, conn->handle, flags);
switch (hdev->dev_type) {
case HCI_BREDR:
hci_add_acl_hdr(skb, conn->handle, flags);
break;
case HCI_AMP:
hci_add_acl_hdr(skb, chan->handle, flags);
break;
default:
BT_ERR("%s unknown dev_type %d", hdev->name, hdev->dev_type);
return;
}
list = skb_shinfo(skb)->frag_list; list = skb_shinfo(skb)->frag_list;
if (!list) { if (!list) {
...@@ -2202,14 +2214,13 @@ static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue, ...@@ -2202,14 +2214,13 @@ static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags) void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags)
{ {
struct hci_conn *conn = chan->conn; struct hci_dev *hdev = chan->conn->hdev;
struct hci_dev *hdev = conn->hdev;
BT_DBG("%s chan %p flags 0x%4.4x", hdev->name, chan, flags); BT_DBG("%s chan %p flags 0x%4.4x", hdev->name, chan, flags);
skb->dev = (void *) hdev; skb->dev = (void *) hdev;
hci_queue_acl(conn, &chan->data_q, skb, flags); hci_queue_acl(chan, &chan->data_q, skb, flags);
queue_work(hdev->workqueue, &hdev->tx_work); queue_work(hdev->workqueue, &hdev->tx_work);
} }
...@@ -2311,8 +2322,8 @@ static void hci_link_tx_to(struct hci_dev *hdev, __u8 type) ...@@ -2311,8 +2322,8 @@ static void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
/* Kill stalled connections */ /* Kill stalled connections */
list_for_each_entry_rcu(c, &h->list, list) { list_for_each_entry_rcu(c, &h->list, list) {
if (c->type == type && c->sent) { if (c->type == type && c->sent) {
BT_ERR("%s killing stalled connection %s", BT_ERR("%s killing stalled connection %pMR",
hdev->name, batostr(&c->dst)); hdev->name, &c->dst);
hci_acl_disconn(c, HCI_ERROR_REMOTE_USER_TERM); hci_acl_disconn(c, HCI_ERROR_REMOTE_USER_TERM);
} }
} }
...@@ -2381,6 +2392,9 @@ static struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type, ...@@ -2381,6 +2392,9 @@ static struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
case ACL_LINK: case ACL_LINK:
cnt = hdev->acl_cnt; cnt = hdev->acl_cnt;
break; break;
case AMP_LINK:
cnt = hdev->block_cnt;
break;
case SCO_LINK: case SCO_LINK:
case ESCO_LINK: case ESCO_LINK:
cnt = hdev->sco_cnt; cnt = hdev->sco_cnt;
...@@ -2510,11 +2524,19 @@ static void hci_sched_acl_blk(struct hci_dev *hdev) ...@@ -2510,11 +2524,19 @@ static void hci_sched_acl_blk(struct hci_dev *hdev)
struct hci_chan *chan; struct hci_chan *chan;
struct sk_buff *skb; struct sk_buff *skb;
int quote; int quote;
u8 type;
__check_timeout(hdev, cnt); __check_timeout(hdev, cnt);
BT_DBG("%s", hdev->name);
if (hdev->dev_type == HCI_AMP)
type = AMP_LINK;
else
type = ACL_LINK;
while (hdev->block_cnt > 0 && while (hdev->block_cnt > 0 &&
(chan = hci_chan_sent(hdev, ACL_LINK, &quote))) { (chan = hci_chan_sent(hdev, type, &quote))) {
u32 priority = (skb_peek(&chan->data_q))->priority; u32 priority = (skb_peek(&chan->data_q))->priority;
while (quote > 0 && (skb = skb_peek(&chan->data_q))) { while (quote > 0 && (skb = skb_peek(&chan->data_q))) {
int blocks; int blocks;
...@@ -2547,14 +2569,19 @@ static void hci_sched_acl_blk(struct hci_dev *hdev) ...@@ -2547,14 +2569,19 @@ static void hci_sched_acl_blk(struct hci_dev *hdev)
} }
if (cnt != hdev->block_cnt) if (cnt != hdev->block_cnt)
hci_prio_recalculate(hdev, ACL_LINK); hci_prio_recalculate(hdev, type);
} }
static void hci_sched_acl(struct hci_dev *hdev) static void hci_sched_acl(struct hci_dev *hdev)
{ {
BT_DBG("%s", hdev->name); BT_DBG("%s", hdev->name);
if (!hci_conn_num(hdev, ACL_LINK)) /* No ACL link over BR/EDR controller */
if (!hci_conn_num(hdev, ACL_LINK) && hdev->dev_type == HCI_BREDR)
return;
/* No AMP link over AMP controller */
if (!hci_conn_num(hdev, AMP_LINK) && hdev->dev_type == HCI_AMP)
return; return;
switch (hdev->flow_ctl_mode) { switch (hdev->flow_ctl_mode) {
......
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
#include <net/bluetooth/bluetooth.h> #include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h> #include <net/bluetooth/hci_core.h>
#include <net/bluetooth/mgmt.h> #include <net/bluetooth/mgmt.h>
#include <net/bluetooth/a2mp.h>
#include <net/bluetooth/amp.h>
/* Handle HCI Event packets */ /* Handle HCI Event packets */
...@@ -846,7 +848,7 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev, ...@@ -846,7 +848,7 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status); BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
if (rp->status) if (rp->status)
return; goto a2mp_rsp;
hdev->amp_status = rp->amp_status; hdev->amp_status = rp->amp_status;
hdev->amp_total_bw = __le32_to_cpu(rp->total_bw); hdev->amp_total_bw = __le32_to_cpu(rp->total_bw);
...@@ -860,6 +862,46 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev, ...@@ -860,6 +862,46 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
hdev->amp_max_flush_to = __le32_to_cpu(rp->max_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); hci_req_complete(hdev, HCI_OP_READ_LOCAL_AMP_INFO, rp->status);
a2mp_rsp:
a2mp_send_getinfo_rsp(hdev);
}
static void hci_cc_read_local_amp_assoc(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_rp_read_local_amp_assoc *rp = (void *) skb->data;
struct amp_assoc *assoc = &hdev->loc_assoc;
size_t rem_len, frag_len;
BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
if (rp->status)
goto a2mp_rsp;
frag_len = skb->len - sizeof(*rp);
rem_len = __le16_to_cpu(rp->rem_len);
if (rem_len > frag_len) {
BT_DBG("frag_len %zu rem_len %zu", frag_len, rem_len);
memcpy(assoc->data + assoc->offset, rp->frag, frag_len);
assoc->offset += frag_len;
/* Read other fragments */
amp_read_loc_assoc_frag(hdev, rp->phy_handle);
return;
}
memcpy(assoc->data + assoc->offset, rp->frag, rem_len);
assoc->len = assoc->offset + rem_len;
assoc->offset = 0;
a2mp_rsp:
/* Send A2MP Rsp when all fragments are received */
a2mp_send_getampassoc_rsp(hdev, rp->status);
a2mp_send_create_phy_link_req(hdev, rp->status);
} }
static void hci_cc_delete_stored_link_key(struct hci_dev *hdev, static void hci_cc_delete_stored_link_key(struct hci_dev *hdev,
...@@ -1174,6 +1216,20 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev, ...@@ -1174,6 +1216,20 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
hci_req_complete(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, status); hci_req_complete(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, status);
} }
static void hci_cc_write_remote_amp_assoc(struct hci_dev *hdev,
struct sk_buff *skb)
{
struct hci_rp_write_remote_amp_assoc *rp = (void *) skb->data;
BT_DBG("%s status 0x%2.2x phy_handle 0x%2.2x",
hdev->name, rp->status, rp->phy_handle);
if (rp->status)
return;
amp_write_rem_assoc_continue(hdev, rp->phy_handle);
}
static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
{ {
BT_DBG("%s status 0x%2.2x", hdev->name, status); BT_DBG("%s status 0x%2.2x", hdev->name, status);
...@@ -1210,7 +1266,7 @@ static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) ...@@ -1210,7 +1266,7 @@ static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
BT_DBG("%s bdaddr %s hcon %p", hdev->name, batostr(&cp->bdaddr), conn); BT_DBG("%s bdaddr %pMR hcon %p", hdev->name, &cp->bdaddr, conn);
if (status) { if (status) {
if (conn && conn->state == BT_CONNECT) { if (conn && conn->state == BT_CONNECT) {
...@@ -1639,8 +1695,7 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status) ...@@ -1639,8 +1695,7 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
return; return;
} }
BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&conn->dst), BT_DBG("%s bdaddr %pMR conn %p", hdev->name, &conn->dst, conn);
conn);
conn->state = BT_CLOSED; conn->state = BT_CLOSED;
mgmt_connect_failed(hdev, &conn->dst, conn->type, mgmt_connect_failed(hdev, &conn->dst, conn->type,
...@@ -1657,6 +1712,38 @@ static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status) ...@@ -1657,6 +1712,38 @@ static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
BT_DBG("%s status 0x%2.2x", hdev->name, status); BT_DBG("%s status 0x%2.2x", hdev->name, status);
} }
static void hci_cs_create_phylink(struct hci_dev *hdev, u8 status)
{
struct hci_cp_create_phy_link *cp;
BT_DBG("%s status 0x%2.2x", hdev->name, status);
if (status)
return;
cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_PHY_LINK);
if (!cp)
return;
amp_write_remote_assoc(hdev, cp->phy_handle);
}
static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status)
{
struct hci_cp_accept_phy_link *cp;
BT_DBG("%s status 0x%2.2x", hdev->name, status);
if (status)
return;
cp = hci_sent_cmd_data(hdev, HCI_OP_ACCEPT_PHY_LINK);
if (!cp)
return;
amp_write_remote_assoc(hdev, cp->phy_handle);
}
static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
__u8 status = *((__u8 *) skb->data); __u8 status = *((__u8 *) skb->data);
...@@ -1822,7 +1909,7 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -1822,7 +1909,7 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
struct hci_ev_conn_request *ev = (void *) skb->data; struct hci_ev_conn_request *ev = (void *) skb->data;
int mask = hdev->link_mode; int mask = hdev->link_mode;
BT_DBG("%s bdaddr %s type 0x%x", hdev->name, batostr(&ev->bdaddr), BT_DBG("%s bdaddr %pMR type 0x%x", hdev->name, &ev->bdaddr,
ev->link_type); ev->link_type);
mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type); mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);
...@@ -2314,6 +2401,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -2314,6 +2401,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cc_read_local_amp_info(hdev, skb); hci_cc_read_local_amp_info(hdev, skb);
break; break;
case HCI_OP_READ_LOCAL_AMP_ASSOC:
hci_cc_read_local_amp_assoc(hdev, skb);
break;
case HCI_OP_DELETE_STORED_LINK_KEY: case HCI_OP_DELETE_STORED_LINK_KEY:
hci_cc_delete_stored_link_key(hdev, skb); hci_cc_delete_stored_link_key(hdev, skb);
break; break;
...@@ -2386,6 +2477,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -2386,6 +2477,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cc_write_le_host_supported(hdev, skb); hci_cc_write_le_host_supported(hdev, skb);
break; break;
case HCI_OP_WRITE_REMOTE_AMP_ASSOC:
hci_cc_write_remote_amp_assoc(hdev, skb);
break;
default: default:
BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode); BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);
break; break;
...@@ -2467,6 +2562,14 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -2467,6 +2562,14 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cs_le_start_enc(hdev, ev->status); hci_cs_le_start_enc(hdev, ev->status);
break; break;
case HCI_OP_CREATE_PHY_LINK:
hci_cs_create_phylink(hdev, ev->status);
break;
case HCI_OP_ACCEPT_PHY_LINK:
hci_cs_accept_phylink(hdev, ev->status);
break;
default: default:
BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode); BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);
break; break;
...@@ -2574,6 +2677,27 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -2574,6 +2677,27 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
queue_work(hdev->workqueue, &hdev->tx_work); queue_work(hdev->workqueue, &hdev->tx_work);
} }
static struct hci_conn *__hci_conn_lookup_handle(struct hci_dev *hdev,
__u16 handle)
{
struct hci_chan *chan;
switch (hdev->dev_type) {
case HCI_BREDR:
return hci_conn_hash_lookup_handle(hdev, handle);
case HCI_AMP:
chan = hci_chan_lookup_handle(hdev, handle);
if (chan)
return chan->conn;
break;
default:
BT_ERR("%s unknown dev_type %d", hdev->name, hdev->dev_type);
break;
}
return NULL;
}
static void hci_num_comp_blocks_evt(struct hci_dev *hdev, struct sk_buff *skb) static void hci_num_comp_blocks_evt(struct hci_dev *hdev, struct sk_buff *skb)
{ {
struct hci_ev_num_comp_blocks *ev = (void *) skb->data; struct hci_ev_num_comp_blocks *ev = (void *) skb->data;
...@@ -2595,13 +2719,13 @@ static void hci_num_comp_blocks_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -2595,13 +2719,13 @@ static void hci_num_comp_blocks_evt(struct hci_dev *hdev, struct sk_buff *skb)
for (i = 0; i < ev->num_hndl; i++) { for (i = 0; i < ev->num_hndl; i++) {
struct hci_comp_blocks_info *info = &ev->handles[i]; struct hci_comp_blocks_info *info = &ev->handles[i];
struct hci_conn *conn; struct hci_conn *conn = NULL;
__u16 handle, block_count; __u16 handle, block_count;
handle = __le16_to_cpu(info->handle); handle = __le16_to_cpu(info->handle);
block_count = __le16_to_cpu(info->blocks); block_count = __le16_to_cpu(info->blocks);
conn = hci_conn_hash_lookup_handle(hdev, handle); conn = __hci_conn_lookup_handle(hdev, handle);
if (!conn) if (!conn)
continue; continue;
...@@ -2609,6 +2733,7 @@ static void hci_num_comp_blocks_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -2609,6 +2733,7 @@ static void hci_num_comp_blocks_evt(struct hci_dev *hdev, struct sk_buff *skb)
switch (conn->type) { switch (conn->type) {
case ACL_LINK: case ACL_LINK:
case AMP_LINK:
hdev->block_cnt += block_count; hdev->block_cnt += block_count;
if (hdev->block_cnt > hdev->num_blocks) if (hdev->block_cnt > hdev->num_blocks)
hdev->block_cnt = hdev->num_blocks; hdev->block_cnt = hdev->num_blocks;
...@@ -2705,13 +2830,13 @@ static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -2705,13 +2830,13 @@ static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
key = hci_find_link_key(hdev, &ev->bdaddr); key = hci_find_link_key(hdev, &ev->bdaddr);
if (!key) { if (!key) {
BT_DBG("%s link key not found for %s", hdev->name, BT_DBG("%s link key not found for %pMR", hdev->name,
batostr(&ev->bdaddr)); &ev->bdaddr);
goto not_found; goto not_found;
} }
BT_DBG("%s found key type %u for %s", hdev->name, key->type, BT_DBG("%s found key type %u for %pMR", hdev->name, key->type,
batostr(&ev->bdaddr)); &ev->bdaddr);
if (!test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags) && if (!test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags) &&
key->type == HCI_LK_DEBUG_COMBINATION) { key->type == HCI_LK_DEBUG_COMBINATION) {
...@@ -3558,6 +3683,22 @@ static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -3558,6 +3683,22 @@ static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
} }
} }
static void hci_chan_selected_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
struct hci_ev_channel_selected *ev = (void *) skb->data;
struct hci_conn *hcon;
BT_DBG("%s handle 0x%2.2x", hdev->name, ev->phy_handle);
skb_pull(skb, sizeof(*ev));
hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle);
if (!hcon)
return;
amp_read_loc_assoc_final_data(hdev, hcon);
}
void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
{ {
struct hci_event_hdr *hdr = (void *) skb->data; struct hci_event_hdr *hdr = (void *) skb->data;
...@@ -3722,6 +3863,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) ...@@ -3722,6 +3863,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
hci_le_meta_evt(hdev, skb); hci_le_meta_evt(hdev, skb);
break; break;
case HCI_EV_CHANNEL_SELECTED:
hci_chan_selected_evt(hdev, skb);
break;
case HCI_EV_REMOTE_OOB_DATA_REQUEST: case HCI_EV_REMOTE_OOB_DATA_REQUEST:
hci_remote_oob_data_request_evt(hdev, skb); hci_remote_oob_data_request_evt(hdev, skb);
break; break;
......
...@@ -38,7 +38,7 @@ static ssize_t show_link_address(struct device *dev, ...@@ -38,7 +38,7 @@ static ssize_t show_link_address(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct hci_conn *conn = to_hci_conn(dev); struct hci_conn *conn = to_hci_conn(dev);
return sprintf(buf, "%s\n", batostr(&conn->dst)); return sprintf(buf, "%pMR\n", &conn->dst);
} }
static ssize_t show_link_features(struct device *dev, static ssize_t show_link_features(struct device *dev,
...@@ -224,7 +224,7 @@ static ssize_t show_address(struct device *dev, ...@@ -224,7 +224,7 @@ static ssize_t show_address(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct hci_dev *hdev = to_hci_dev(dev); struct hci_dev *hdev = to_hci_dev(dev);
return sprintf(buf, "%s\n", batostr(&hdev->bdaddr)); return sprintf(buf, "%pMR\n", &hdev->bdaddr);
} }
static ssize_t show_features(struct device *dev, static ssize_t show_features(struct device *dev,
...@@ -406,8 +406,8 @@ static int inquiry_cache_show(struct seq_file *f, void *p) ...@@ -406,8 +406,8 @@ static int inquiry_cache_show(struct seq_file *f, void *p)
list_for_each_entry(e, &cache->all, all) { list_for_each_entry(e, &cache->all, all) {
struct inquiry_data *data = &e->data; struct inquiry_data *data = &e->data;
seq_printf(f, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n", seq_printf(f, "%pMR %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n",
batostr(&data->bdaddr), &data->bdaddr,
data->pscan_rep_mode, data->pscan_period_mode, data->pscan_rep_mode, data->pscan_period_mode,
data->pscan_mode, data->dev_class[2], data->pscan_mode, data->dev_class[2],
data->dev_class[1], data->dev_class[0], data->dev_class[1], data->dev_class[0],
...@@ -440,7 +440,7 @@ static int blacklist_show(struct seq_file *f, void *p) ...@@ -440,7 +440,7 @@ static int blacklist_show(struct seq_file *f, void *p)
hci_dev_lock(hdev); hci_dev_lock(hdev);
list_for_each_entry(b, &hdev->blacklist, list) list_for_each_entry(b, &hdev->blacklist, list)
seq_printf(f, "%s\n", batostr(&b->bdaddr)); seq_printf(f, "%pMR\n", &b->bdaddr);
hci_dev_unlock(hdev); hci_dev_unlock(hdev);
......
...@@ -932,8 +932,12 @@ static int hidp_setup_hid(struct hidp_session *session, ...@@ -932,8 +932,12 @@ static int hidp_setup_hid(struct hidp_session *session,
hid->country = req->country; hid->country = req->country;
strncpy(hid->name, req->name, 128); strncpy(hid->name, req->name, 128);
strncpy(hid->phys, batostr(&bt_sk(session->ctrl_sock->sk)->src), 64);
strncpy(hid->uniq, batostr(&bt_sk(session->ctrl_sock->sk)->dst), 64); snprintf(hid->phys, sizeof(hid->phys), "%pMR",
&bt_sk(session->ctrl_sock->sk)->src);
snprintf(hid->uniq, sizeof(hid->uniq), "%pMR",
&bt_sk(session->ctrl_sock->sk)->dst);
hid->dev.parent = &session->conn->dev; hid->dev.parent = &session->conn->dev;
hid->ll_driver = &hidp_hid_driver; hid->ll_driver = &hidp_hid_driver;
......
This diff is collapsed.
This diff is collapsed.
...@@ -41,20 +41,6 @@ void baswap(bdaddr_t *dst, bdaddr_t *src) ...@@ -41,20 +41,6 @@ void baswap(bdaddr_t *dst, bdaddr_t *src)
} }
EXPORT_SYMBOL(baswap); EXPORT_SYMBOL(baswap);
char *batostr(bdaddr_t *ba)
{
static char str[2][18];
static int i = 1;
i ^= 1;
sprintf(str[i], "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
ba->b[5], ba->b[4], ba->b[3],
ba->b[2], ba->b[1], ba->b[0]);
return str[i];
}
EXPORT_SYMBOL(batostr);
/* Bluetooth error codes to Unix errno mapping */ /* Bluetooth error codes to Unix errno mapping */
int bt_to_errno(__u16 code) int bt_to_errno(__u16 code)
{ {
......
...@@ -3125,6 +3125,9 @@ int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, ...@@ -3125,6 +3125,9 @@ int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
struct pending_cmd *cmd; struct pending_cmd *cmd;
int err; int err;
mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
hdev);
cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev); cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
if (!cmd) if (!cmd)
return -ENOENT; return -ENOENT;
...@@ -3137,8 +3140,6 @@ int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, ...@@ -3137,8 +3140,6 @@ int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
mgmt_pending_remove(cmd); mgmt_pending_remove(cmd);
mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
hdev);
return err; return err;
} }
......
...@@ -377,8 +377,8 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst, ...@@ -377,8 +377,8 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst,
int err = 0; int err = 0;
u8 dlci; u8 dlci;
BT_DBG("dlc %p state %ld %s %s channel %d", BT_DBG("dlc %p state %ld %pMR -> %pMR channel %d",
d, d->state, batostr(src), batostr(dst), channel); d, d->state, src, dst, channel);
if (channel < 1 || channel > 30) if (channel < 1 || channel > 30)
return -EINVAL; return -EINVAL;
...@@ -676,7 +676,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, ...@@ -676,7 +676,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
struct socket *sock; struct socket *sock;
struct sock *sk; struct sock *sk;
BT_DBG("%s %s", batostr(src), batostr(dst)); BT_DBG("%pMR -> %pMR", src, dst);
*err = rfcomm_l2sock_create(&sock); *err = rfcomm_l2sock_create(&sock);
if (*err < 0) if (*err < 0)
...@@ -709,7 +709,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, ...@@ -709,7 +709,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
bacpy(&addr.l2_bdaddr, dst); bacpy(&addr.l2_bdaddr, dst);
addr.l2_family = AF_BLUETOOTH; addr.l2_family = AF_BLUETOOTH;
addr.l2_psm = cpu_to_le16(RFCOMM_PSM); addr.l2_psm = __constant_cpu_to_le16(RFCOMM_PSM);
addr.l2_cid = 0; addr.l2_cid = 0;
*err = kernel_connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK); *err = kernel_connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK);
if (*err == 0 || *err == -EINPROGRESS) if (*err == 0 || *err == -EINPROGRESS)
...@@ -1987,7 +1987,7 @@ static int rfcomm_add_listener(bdaddr_t *ba) ...@@ -1987,7 +1987,7 @@ static int rfcomm_add_listener(bdaddr_t *ba)
/* Bind socket */ /* Bind socket */
bacpy(&addr.l2_bdaddr, ba); bacpy(&addr.l2_bdaddr, ba);
addr.l2_family = AF_BLUETOOTH; addr.l2_family = AF_BLUETOOTH;
addr.l2_psm = cpu_to_le16(RFCOMM_PSM); addr.l2_psm = __constant_cpu_to_le16(RFCOMM_PSM);
addr.l2_cid = 0; addr.l2_cid = 0;
err = kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr)); err = kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr));
if (err < 0) { if (err < 0) {
...@@ -2125,11 +2125,10 @@ static int rfcomm_dlc_debugfs_show(struct seq_file *f, void *x) ...@@ -2125,11 +2125,10 @@ static int rfcomm_dlc_debugfs_show(struct seq_file *f, void *x)
list_for_each_entry(d, &s->dlcs, list) { list_for_each_entry(d, &s->dlcs, list) {
struct sock *sk = s->sock->sk; struct sock *sk = s->sock->sk;
seq_printf(f, "%s %s %ld %d %d %d %d\n", seq_printf(f, "%pMR %pMR %ld %d %d %d %d\n",
batostr(&bt_sk(sk)->src), &bt_sk(sk)->src, &bt_sk(sk)->dst,
batostr(&bt_sk(sk)->dst), d->state, d->dlci, d->mtu,
d->state, d->dlci, d->mtu, d->rx_credits, d->tx_credits);
d->rx_credits, d->tx_credits);
} }
} }
......
...@@ -334,7 +334,7 @@ static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr ...@@ -334,7 +334,7 @@ static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
int err = 0; int err = 0;
BT_DBG("sk %p %s", sk, batostr(&sa->rc_bdaddr)); BT_DBG("sk %p %pMR", sk, &sa->rc_bdaddr);
if (!addr || addr->sa_family != AF_BLUETOOTH) if (!addr || addr->sa_family != AF_BLUETOOTH)
return -EINVAL; return -EINVAL;
...@@ -975,10 +975,9 @@ static int rfcomm_sock_debugfs_show(struct seq_file *f, void *p) ...@@ -975,10 +975,9 @@ static int rfcomm_sock_debugfs_show(struct seq_file *f, void *p)
read_lock(&rfcomm_sk_list.lock); read_lock(&rfcomm_sk_list.lock);
sk_for_each(sk, node, &rfcomm_sk_list.head) { sk_for_each(sk, node, &rfcomm_sk_list.head) {
seq_printf(f, "%s %s %d %d\n", seq_printf(f, "%pMR %pMR %d %d\n",
batostr(&bt_sk(sk)->src), &bt_sk(sk)->src, &bt_sk(sk)->dst,
batostr(&bt_sk(sk)->dst), sk->sk_state, rfcomm_pi(sk)->channel);
sk->sk_state, rfcomm_pi(sk)->channel);
} }
read_unlock(&rfcomm_sk_list.lock); read_unlock(&rfcomm_sk_list.lock);
......
...@@ -166,7 +166,7 @@ static struct device *rfcomm_get_device(struct rfcomm_dev *dev) ...@@ -166,7 +166,7 @@ static struct device *rfcomm_get_device(struct rfcomm_dev *dev)
static ssize_t show_address(struct device *tty_dev, struct device_attribute *attr, char *buf) static ssize_t show_address(struct device *tty_dev, struct device_attribute *attr, char *buf)
{ {
struct rfcomm_dev *dev = dev_get_drvdata(tty_dev); struct rfcomm_dev *dev = dev_get_drvdata(tty_dev);
return sprintf(buf, "%s\n", batostr(&dev->dst)); return sprintf(buf, "%pMR\n", &dev->dst);
} }
static ssize_t show_channel(struct device *tty_dev, struct device_attribute *attr, char *buf) static ssize_t show_channel(struct device *tty_dev, struct device_attribute *attr, char *buf)
...@@ -663,8 +663,8 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) ...@@ -663,8 +663,8 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
if (!dev) if (!dev)
return -ENODEV; return -ENODEV;
BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst), BT_DBG("dev %p dst %pMR channel %d opened %d", dev, &dev->dst,
dev->channel, dev->port.count); dev->channel, dev->port.count);
spin_lock_irqsave(&dev->port.lock, flags); spin_lock_irqsave(&dev->port.lock, flags);
if (++dev->port.count > 1) { if (++dev->port.count > 1) {
......
...@@ -172,7 +172,7 @@ static int sco_connect(struct sock *sk) ...@@ -172,7 +172,7 @@ static int sco_connect(struct sock *sk)
struct hci_dev *hdev; struct hci_dev *hdev;
int err, type; int err, type;
BT_DBG("%s -> %s", batostr(src), batostr(dst)); BT_DBG("%pMR -> %pMR", src, dst);
hdev = hci_get_route(dst, src); hdev = hci_get_route(dst, src);
if (!hdev) if (!hdev)
...@@ -460,7 +460,7 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le ...@@ -460,7 +460,7 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
int err = 0; int err = 0;
BT_DBG("sk %p %s", sk, batostr(&sa->sco_bdaddr)); BT_DBG("sk %p %pMR", sk, &sa->sco_bdaddr);
if (!addr || addr->sa_family != AF_BLUETOOTH) if (!addr || addr->sa_family != AF_BLUETOOTH)
return -EINVAL; return -EINVAL;
...@@ -893,7 +893,7 @@ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr) ...@@ -893,7 +893,7 @@ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
struct hlist_node *node; struct hlist_node *node;
int lm = 0; int lm = 0;
BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr)); BT_DBG("hdev %s, bdaddr %pMR", hdev->name, bdaddr);
/* Find listening sockets */ /* Find listening sockets */
read_lock(&sco_sk_list.lock); read_lock(&sco_sk_list.lock);
...@@ -914,7 +914,7 @@ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr) ...@@ -914,7 +914,7 @@ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
void sco_connect_cfm(struct hci_conn *hcon, __u8 status) void sco_connect_cfm(struct hci_conn *hcon, __u8 status)
{ {
BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status); BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status);
if (!status) { if (!status) {
struct sco_conn *conn; struct sco_conn *conn;
...@@ -959,8 +959,8 @@ static int sco_debugfs_show(struct seq_file *f, void *p) ...@@ -959,8 +959,8 @@ static int sco_debugfs_show(struct seq_file *f, void *p)
read_lock(&sco_sk_list.lock); read_lock(&sco_sk_list.lock);
sk_for_each(sk, node, &sco_sk_list.head) { sk_for_each(sk, node, &sco_sk_list.head) {
seq_printf(f, "%s %s %d\n", batostr(&bt_sk(sk)->src), seq_printf(f, "%pMR %pMR %d\n", &bt_sk(sk)->src,
batostr(&bt_sk(sk)->dst), sk->sk_state); &bt_sk(sk)->dst, sk->sk_state);
} }
read_unlock(&sco_sk_list.lock); read_unlock(&sco_sk_list.lock);
......
...@@ -165,7 +165,7 @@ static struct sk_buff *smp_build_cmd(struct l2cap_conn *conn, u8 code, ...@@ -165,7 +165,7 @@ static struct sk_buff *smp_build_cmd(struct l2cap_conn *conn, u8 code,
lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
lh->len = cpu_to_le16(sizeof(code) + dlen); lh->len = cpu_to_le16(sizeof(code) + dlen);
lh->cid = cpu_to_le16(L2CAP_CID_SMP); lh->cid = __constant_cpu_to_le16(L2CAP_CID_SMP);
memcpy(skb_put(skb, sizeof(code)), &code, sizeof(code)); memcpy(skb_put(skb, sizeof(code)), &code, sizeof(code));
......
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