From f0681a68dd3a32699891cd1de93459aee5af7728 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 16 Mar 2011 21:06:52 -0300 Subject: Bluetooth: remove unnecessary function declaration hci_notify() doesn't need declaration first. Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_core.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index b372fb8bcdcf..c20cbe5ff6db 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -56,7 +56,6 @@ static void hci_cmd_task(unsigned long arg); static void hci_rx_task(unsigned long arg); static void hci_tx_task(unsigned long arg); -static void hci_notify(struct hci_dev *hdev, int event); static DEFINE_RWLOCK(hci_task_lock); -- cgit v1.2.3 From 1f6c6378c59f3ddac9ed89a68ccefe2611300c09 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 16 Mar 2011 14:29:35 +0200 Subject: Bluetooth: Add define for the maximum name length on HCI level This patch adds a clear define for the maximum device name length in HCI messages and thereby avoids magic numbers in the code. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci.h | 8 +++++--- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_event.c | 4 ++-- net/bluetooth/hci_sysfs.c | 6 +++--- 4 files changed, 11 insertions(+), 9 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index ec6acf2f1c0b..1cd031cd1c4d 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -535,15 +535,17 @@ struct hci_cp_delete_stored_link_key { __u8 delete_all; } __packed; +#define HCI_MAX_NAME_LENGTH 248 + #define HCI_OP_WRITE_LOCAL_NAME 0x0c13 struct hci_cp_write_local_name { - __u8 name[248]; + __u8 name[HCI_MAX_NAME_LENGTH]; } __packed; #define HCI_OP_READ_LOCAL_NAME 0x0c14 struct hci_rp_read_local_name { __u8 status; - __u8 name[248]; + __u8 name[HCI_MAX_NAME_LENGTH]; } __packed; #define HCI_OP_WRITE_CA_TIMEOUT 0x0c16 @@ -745,7 +747,7 @@ struct hci_ev_auth_complete { struct hci_ev_remote_name { __u8 status; bdaddr_t bdaddr; - __u8 name[248]; + __u8 name[HCI_MAX_NAME_LENGTH]; } __packed; #define HCI_EV_ENCRYPT_CHANGE 0x08 diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 441dadbf6a89..9aabb14982dd 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -94,7 +94,7 @@ struct hci_dev { __u8 bus; __u8 dev_type; bdaddr_t bdaddr; - __u8 dev_name[248]; + __u8 dev_name[HCI_MAX_NAME_LENGTH]; __u8 dev_class[3]; __u8 major_class; __u8 minor_class; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 3fbfa50c2bff..91ef52673ed3 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -200,7 +200,7 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) if (!sent) return; - memcpy(hdev->dev_name, sent, 248); + memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH); } static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb) @@ -212,7 +212,7 @@ static void hci_cc_read_local_name(struct hci_dev *hdev, struct sk_buff *skb) if (rp->status) return; - memcpy(hdev->dev_name, rp->name, 248); + memcpy(hdev->dev_name, rp->name, HCI_MAX_NAME_LENGTH); } static void hci_cc_write_auth_enable(struct hci_dev *hdev, struct sk_buff *skb) diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 3c838a65a75a..e54421693eb8 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -216,13 +216,13 @@ static ssize_t show_type(struct device *dev, struct device_attribute *attr, char static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf) { struct hci_dev *hdev = dev_get_drvdata(dev); - char name[249]; + char name[HCI_MAX_NAME_LENGTH + 1]; int i; - for (i = 0; i < 248; i++) + for (i = 0; i < HCI_MAX_NAME_LENGTH; i++) name[i] = hdev->dev_name[i]; - name[248] = '\0'; + name[HCI_MAX_NAME_LENGTH] = '\0'; return sprintf(buf, "%s\n", name); } -- cgit v1.2.3 From dc4fe30b8675033e538e2dea50be8af9c75f1b6a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 16 Mar 2011 14:29:36 +0200 Subject: Bluetooth: mgmt: Add local name information to read_info reply This patch adds the name of the adapter to the reply of the read_info management command. The management messages reserve 249 bytes for the name instead of 248 (like in the HCI spec) so that there is always a guarantee that it is nul-terminated. That way it can safely be passed onto string manipulation functions. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/mgmt.h | 5 +++++ net/bluetooth/mgmt.c | 4 ++++ 2 files changed, 9 insertions(+) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 5fabfa886b3e..7d0749bed090 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -41,6 +41,10 @@ struct mgmt_rp_read_index_list { __le16 index[0]; } __packed; +/* Reserve one extra byte for names in management messages so that they + * are always guaranteed to be nul-terminated */ +#define MGMT_MAX_NAME_LENGTH (HCI_MAX_NAME_LENGTH + 1) + #define MGMT_OP_READ_INFO 0x0004 struct mgmt_rp_read_info { __u8 type; @@ -55,6 +59,7 @@ struct mgmt_rp_read_info { __u16 manufacturer; __u8 hci_ver; __u16 hci_rev; + __u8 name[MGMT_MAX_NAME_LENGTH]; } __packed; struct mgmt_mode { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 0054c74e27b7..ffdb2f4e8635 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -183,6 +183,8 @@ static int read_controller_info(struct sock *sk, u16 index) set_bit(HCI_MGMT, &hdev->flags); + memset(&rp, 0, sizeof(rp)); + rp.type = hdev->dev_type; rp.powered = test_bit(HCI_UP, &hdev->flags); @@ -204,6 +206,8 @@ static int read_controller_info(struct sock *sk, u16 index) rp.hci_ver = hdev->hci_ver; put_unaligned_le16(hdev->hci_rev, &rp.hci_rev); + memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name)); + hci_dev_unlock_bh(hdev); hci_dev_put(hdev); -- cgit v1.2.3 From b312b161ecb833b1bce5c4a97853f4a4f40c7901 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 16 Mar 2011 14:29:37 +0200 Subject: Bluetooth: mgmt: Add support for setting the local name This patch adds a new set_local_name management command as well as a local_name_changed management event. With these user space can both change the local name as well as monitor changes to it by others. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 1 + include/net/bluetooth/mgmt.h | 10 ++++++ net/bluetooth/hci_event.c | 9 +++-- net/bluetooth/mgmt.c | 75 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 92 insertions(+), 3 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 9aabb14982dd..3912c7ab717c 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -767,6 +767,7 @@ 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, 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); /* HCI info for socket */ #define hci_pi(sk) ((struct hci_pinfo *) sk) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 7d0749bed090..89e7c82c4784 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -172,6 +172,11 @@ struct mgmt_rp_user_confirm_reply { #define MGMT_OP_USER_CONFIRM_NEG_REPLY 0x0016 +#define MGMT_OP_SET_LOCAL_NAME 0x0017 +struct mgmt_cp_set_local_name { + __u8 name[MGMT_MAX_NAME_LENGTH]; +} __packed; + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; @@ -239,3 +244,8 @@ struct mgmt_ev_auth_failed { bdaddr_t bdaddr; __u8 status; } __packed; + +#define MGMT_EV_LOCAL_NAME_CHANGED 0x0011 +struct mgmt_ev_local_name_changed { + __u8 name[MGMT_MAX_NAME_LENGTH]; +} __packed; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 91ef52673ed3..0def3e1fe5ef 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -193,13 +193,16 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s status 0x%x", hdev->name, status); - if (status) - return; - sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_LOCAL_NAME); if (!sent) return; + if (test_bit(HCI_MGMT, &hdev->flags)) + mgmt_set_local_name_complete(hdev->id, sent, status); + + if (status) + return; + memcpy(hdev->dev_name, sent, HCI_MAX_NAME_LENGTH); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index ffdb2f4e8635..f7ce78235590 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1256,6 +1256,45 @@ failed: return err; } +static int set_local_name(struct sock *sk, u16 index, unsigned char *data, + u16 len) +{ + struct mgmt_cp_set_local_name *mgmt_cp = (void *) data; + struct hci_cp_write_local_name hci_cp; + struct hci_dev *hdev; + struct pending_cmd *cmd; + int err; + + BT_DBG(""); + + if (len != sizeof(*mgmt_cp)) + return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, EINVAL); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV); + + hci_dev_lock_bh(hdev); + + cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len); + if (!cmd) { + err = -ENOMEM; + goto failed; + } + + memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name)); + err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp), + &hci_cp); + if (err < 0) + mgmt_pending_remove(cmd); + +failed: + hci_dev_unlock_bh(hdev); + hci_dev_put(hdev); + + return err; +} + int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) { unsigned char *buf; @@ -1351,6 +1390,9 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_USER_CONFIRM_NEG_REPLY: err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0); break; + case MGMT_OP_SET_LOCAL_NAME: + err = set_local_name(sk, index, buf + sizeof(*hdr), len); + break; default: BT_DBG("Unknown op %u", opcode); err = cmd_status(sk, index, opcode, 0x01); @@ -1647,3 +1689,36 @@ int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status) return mgmt_event(MGMT_EV_AUTH_FAILED, index, &ev, sizeof(ev), NULL); } + +int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status) +{ + struct pending_cmd *cmd; + 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); + if (!cmd) + goto send_event; + + if (status) { + err = cmd_status(cmd->sk, index, MGMT_OP_SET_LOCAL_NAME, EIO); + goto failed; + } + + err = cmd_complete(cmd->sk, index, 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), + cmd ? cmd->sk : NULL); + +failed: + if (cmd) + mgmt_pending_remove(cmd); + return err; +} -- cgit v1.2.3 From 2c6d1a2eec5c49793c6760546d05515ce1b76881 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 23 Mar 2011 14:38:32 -0300 Subject: Bluetooth: Improve error message on wrong link type Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index c9f9cecca527..b5a1ce06e1c0 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2670,7 +2670,8 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, if (err) { struct l2cap_cmd_rej rej; - BT_DBG("error %d", err); + + BT_ERR("Wrong link type (%d)", err); /* FIXME: Map err to a valid reason */ rej.reason = cpu_to_le16(0); -- cgit v1.2.3 From a3d9bd4c00f13defd4c0fdcf8b47f8764a69e54d Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Mon, 21 Mar 2011 14:19:57 +0100 Subject: Bluetooth: Opencode macros in bnep/core.c BNEP_RX_TYPES and INCA macros have only one user each and don't provide any benefits compared to opencoding them. Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan --- net/bluetooth/bnep/core.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index 03d4d1245d58..940b4e129741 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -187,6 +187,8 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len) n /= (ETH_ALEN * 2); if (n > 0) { + int i; + s->mc_filter = 0; /* Always send broadcast */ @@ -202,12 +204,14 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len) BT_DBG("mc filter %s -> %s", batostr((void *) a1), batostr((void *) a2)); - #define INCA(a) { int i = 5; while (i >=0 && ++a[i--] == 0); } - /* Iterate from a1 to a2 */ set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter); while (memcmp(a1, a2, 6) < 0 && s->mc_filter != ~0LL) { - INCA(a1); + /* Increment a1 */ + i = 5; + while (i >= 0 && ++a1[i--] == 0) + ; + set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter); } } @@ -302,7 +306,6 @@ static u8 __bnep_rx_hlen[] = { ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_ONLY */ ETH_ALEN + 2 /* BNEP_COMPRESSED_DST_ONLY */ }; -#define BNEP_RX_TYPES (sizeof(__bnep_rx_hlen) - 1) static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) { @@ -314,7 +317,7 @@ static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) type = *(u8 *) skb->data; skb_pull(skb, 1); - if ((type & BNEP_TYPE_MASK) > BNEP_RX_TYPES) + if ((type & BNEP_TYPE_MASK) >= sizeof(__bnep_rx_hlen)) goto badframe; if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) { -- cgit v1.2.3 From 3aad75a128e2f2b8da31de1df4b9b9b4a8f65c66 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Mon, 21 Mar 2011 14:19:58 +0100 Subject: Bluetooth: Fix checkpatch errors and some code style issues in bnep Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan --- net/bluetooth/bnep/bnep.h | 146 +++++++++++++++++++++++----------------------- net/bluetooth/bnep/core.c | 37 +++++++----- 2 files changed, 94 insertions(+), 89 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/bnep/bnep.h b/net/bluetooth/bnep/bnep.h index 70672544db86..d768e0434ed8 100644 --- a/net/bluetooth/bnep/bnep.h +++ b/net/bluetooth/bnep/bnep.h @@ -23,88 +23,88 @@ #include #include -// Limits -#define BNEP_MAX_PROTO_FILTERS 5 -#define BNEP_MAX_MULTICAST_FILTERS 20 - -// UUIDs -#define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB -#define BNEP_UUID16 0x02 -#define BNEP_UUID32 0x04 -#define BNEP_UUID128 0x16 - -#define BNEP_SVC_PANU 0x1115 -#define BNEP_SVC_NAP 0x1116 -#define BNEP_SVC_GN 0x1117 - -// Packet types -#define BNEP_GENERAL 0x00 -#define BNEP_CONTROL 0x01 -#define BNEP_COMPRESSED 0x02 -#define BNEP_COMPRESSED_SRC_ONLY 0x03 -#define BNEP_COMPRESSED_DST_ONLY 0x04 - -// Control types -#define BNEP_CMD_NOT_UNDERSTOOD 0x00 -#define BNEP_SETUP_CONN_REQ 0x01 -#define BNEP_SETUP_CONN_RSP 0x02 -#define BNEP_FILTER_NET_TYPE_SET 0x03 -#define BNEP_FILTER_NET_TYPE_RSP 0x04 -#define BNEP_FILTER_MULTI_ADDR_SET 0x05 -#define BNEP_FILTER_MULTI_ADDR_RSP 0x06 - -// Extension types -#define BNEP_EXT_CONTROL 0x00 - -// Response messages -#define BNEP_SUCCESS 0x00 - -#define BNEP_CONN_INVALID_DST 0x01 -#define BNEP_CONN_INVALID_SRC 0x02 -#define BNEP_CONN_INVALID_SVC 0x03 -#define BNEP_CONN_NOT_ALLOWED 0x04 - -#define BNEP_FILTER_UNSUPPORTED_REQ 0x01 -#define BNEP_FILTER_INVALID_RANGE 0x02 -#define BNEP_FILTER_INVALID_MCADDR 0x02 -#define BNEP_FILTER_LIMIT_REACHED 0x03 -#define BNEP_FILTER_DENIED_SECURITY 0x04 - -// L2CAP settings -#define BNEP_MTU 1691 -#define BNEP_PSM 0x0f -#define BNEP_FLUSH_TO 0xffff -#define BNEP_CONNECT_TO 15 -#define BNEP_FILTER_TO 15 - -// Headers -#define BNEP_TYPE_MASK 0x7f -#define BNEP_EXT_HEADER 0x80 +/* Limits */ +#define BNEP_MAX_PROTO_FILTERS 5 +#define BNEP_MAX_MULTICAST_FILTERS 20 + +/* UUIDs */ +#define BNEP_BASE_UUID 0x0000000000001000800000805F9B34FB +#define BNEP_UUID16 0x02 +#define BNEP_UUID32 0x04 +#define BNEP_UUID128 0x16 + +#define BNEP_SVC_PANU 0x1115 +#define BNEP_SVC_NAP 0x1116 +#define BNEP_SVC_GN 0x1117 + +/* Packet types */ +#define BNEP_GENERAL 0x00 +#define BNEP_CONTROL 0x01 +#define BNEP_COMPRESSED 0x02 +#define BNEP_COMPRESSED_SRC_ONLY 0x03 +#define BNEP_COMPRESSED_DST_ONLY 0x04 + +/* Control types */ +#define BNEP_CMD_NOT_UNDERSTOOD 0x00 +#define BNEP_SETUP_CONN_REQ 0x01 +#define BNEP_SETUP_CONN_RSP 0x02 +#define BNEP_FILTER_NET_TYPE_SET 0x03 +#define BNEP_FILTER_NET_TYPE_RSP 0x04 +#define BNEP_FILTER_MULTI_ADDR_SET 0x05 +#define BNEP_FILTER_MULTI_ADDR_RSP 0x06 + +/* Extension types */ +#define BNEP_EXT_CONTROL 0x00 + +/* Response messages */ +#define BNEP_SUCCESS 0x00 + +#define BNEP_CONN_INVALID_DST 0x01 +#define BNEP_CONN_INVALID_SRC 0x02 +#define BNEP_CONN_INVALID_SVC 0x03 +#define BNEP_CONN_NOT_ALLOWED 0x04 + +#define BNEP_FILTER_UNSUPPORTED_REQ 0x01 +#define BNEP_FILTER_INVALID_RANGE 0x02 +#define BNEP_FILTER_INVALID_MCADDR 0x02 +#define BNEP_FILTER_LIMIT_REACHED 0x03 +#define BNEP_FILTER_DENIED_SECURITY 0x04 + +/* L2CAP settings */ +#define BNEP_MTU 1691 +#define BNEP_PSM 0x0f +#define BNEP_FLUSH_TO 0xffff +#define BNEP_CONNECT_TO 15 +#define BNEP_FILTER_TO 15 + +/* Headers */ +#define BNEP_TYPE_MASK 0x7f +#define BNEP_EXT_HEADER 0x80 struct bnep_setup_conn_req { - __u8 type; - __u8 ctrl; - __u8 uuid_size; - __u8 service[0]; + __u8 type; + __u8 ctrl; + __u8 uuid_size; + __u8 service[0]; } __packed; struct bnep_set_filter_req { - __u8 type; - __u8 ctrl; + __u8 type; + __u8 ctrl; __be16 len; - __u8 list[0]; + __u8 list[0]; } __packed; struct bnep_control_rsp { - __u8 type; - __u8 ctrl; + __u8 type; + __u8 ctrl; __be16 resp; } __packed; struct bnep_ext_hdr { - __u8 type; - __u8 len; - __u8 data[0]; + __u8 type; + __u8 len; + __u8 data[0]; } __packed; /* BNEP ioctl defines */ @@ -114,10 +114,10 @@ struct bnep_ext_hdr { #define BNEPGETCONNINFO _IOR('B', 211, int) struct bnep_connadd_req { - int sock; // Connected socket + int sock; /* Connected socket */ __u32 flags; __u16 role; - char device[16]; // Name of the Ethernet device + char device[16]; /* Name of the Ethernet device */ }; struct bnep_conndel_req { @@ -148,7 +148,7 @@ int bnep_del_connection(struct bnep_conndel_req *req); int bnep_get_connlist(struct bnep_connlist_req *req); int bnep_get_conninfo(struct bnep_conninfo *ci); -// BNEP sessions +/* BNEP sessions */ struct bnep_session { struct list_head list; @@ -173,7 +173,7 @@ void bnep_sock_cleanup(void); static inline int bnep_mc_hash(__u8 *addr) { - return (crc32_be(~0, addr, ETH_ALEN) >> 26); + return crc32_be(~0, addr, ETH_ALEN) >> 26; } #endif diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index 940b4e129741..0a2e76bde542 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -131,7 +131,8 @@ static int bnep_ctrl_set_netfilter(struct bnep_session *s, __be16 *data, int len return -EILSEQ; n = get_unaligned_be16(data); - data++; len -= 2; + data++; + len -= 2; if (len < n) return -EILSEQ; @@ -176,7 +177,8 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len) return -EILSEQ; n = get_unaligned_be16(data); - data += 2; len -= 2; + data += 2; + len -= 2; if (len < n) return -EILSEQ; @@ -198,8 +200,10 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len) for (; n > 0; n--) { u8 a1[6], *a2; - memcpy(a1, data, ETH_ALEN); data += ETH_ALEN; - a2 = data; data += ETH_ALEN; + memcpy(a1, data, ETH_ALEN); + data += ETH_ALEN; + a2 = data; + data += ETH_ALEN; BT_DBG("mc filter %s -> %s", batostr((void *) a1), batostr((void *) a2)); @@ -231,7 +235,8 @@ static int bnep_rx_control(struct bnep_session *s, void *data, int len) u8 cmd = *(u8 *)data; int err = 0; - data++; len--; + data++; + len--; switch (cmd) { case BNEP_CMD_NOT_UNDERSTOOD: @@ -315,7 +320,8 @@ static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) dev->stats.rx_bytes += skb->len; - type = *(u8 *) skb->data; skb_pull(skb, 1); + type = *(u8 *) skb->data; + skb_pull(skb, 1); if ((type & BNEP_TYPE_MASK) >= sizeof(__bnep_rx_hlen)) goto badframe; @@ -370,14 +376,14 @@ static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) case BNEP_COMPRESSED_DST_ONLY: memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb), - ETH_ALEN); + ETH_ALEN); memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source, - ETH_ALEN + 2); + ETH_ALEN + 2); break; case BNEP_GENERAL: memcpy(__skb_put(nskb, ETH_ALEN * 2), skb_mac_header(skb), - ETH_ALEN * 2); + ETH_ALEN * 2); put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2)); break; } @@ -481,7 +487,7 @@ static int bnep_session(void *arg) while (!atomic_read(&s->killed)) { set_current_state(TASK_INTERRUPTIBLE); - // RX + /* RX */ while ((skb = skb_dequeue(&sk->sk_receive_queue))) { skb_orphan(skb); bnep_rx_frame(s, skb); @@ -490,7 +496,7 @@ static int bnep_session(void *arg) if (sk->sk_state != BT_CONNECTED) break; - // TX + /* TX */ while ((skb = skb_dequeue(&sk->sk_write_queue))) if (bnep_tx_frame(s, skb)) break; @@ -558,8 +564,8 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) /* session struct allocated as private part of net_device */ dev = alloc_netdev(sizeof(struct bnep_session), - (*req->device) ? req->device : "bnep%d", - bnep_net_setup); + (*req->device) ? req->device : "bnep%d", + bnep_net_setup); if (!dev) return -ENOMEM; @@ -574,7 +580,7 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) s = netdev_priv(dev); /* This is rx header therefore addresses are swapped. - * ie eh.h_dest is our local address. */ + * ie. eh.h_dest is our local address. */ memcpy(s->eh.h_dest, &src, ETH_ALEN); memcpy(s->eh.h_source, &dst, ETH_ALEN); memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN); @@ -600,9 +606,8 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) SET_NETDEV_DEVTYPE(dev, &bnep_type); err = register_netdev(dev); - if (err) { + if (err) goto failed; - } __bnep_link_session(s); -- cgit v1.2.3 From 8c20aa9ffc5a5ef52b6148e905671a8d12b40c87 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Mon, 21 Mar 2011 14:19:59 +0100 Subject: Bluetooth: Use #include instead of As warned by checkpatch.pl, use #include instead of Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan --- net/bluetooth/bnep/sock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c index d935da71ab3b..17800b1d28ea 100644 --- a/net/bluetooth/bnep/sock.c +++ b/net/bluetooth/bnep/sock.c @@ -39,10 +39,10 @@ #include #include #include +#include #include #include -#include #include "bnep.h" -- cgit v1.2.3 From 17f09a7e4ec5dd6a0d96498da6bf78762fba4468 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Mon, 21 Mar 2011 14:20:01 +0100 Subject: Bluetooth: Fix checkpatch errors, code style issues and typos in hidp Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hidp/core.c | 37 ++++++++++++++++++++----------------- net/bluetooth/hidp/hidp.h | 4 ++-- net/bluetooth/hidp/sock.c | 7 ++++--- 3 files changed, 26 insertions(+), 22 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index 5ec12971af6b..a1472b75d628 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -55,22 +55,24 @@ static DECLARE_RWSEM(hidp_session_sem); static LIST_HEAD(hidp_session_list); static unsigned char hidp_keycode[256] = { - 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, - 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 2, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, 14, 15, 57, 12, 13, 26, - 27, 43, 43, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64, - 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106, - 105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, - 72, 73, 82, 83, 86,127,116,117,183,184,185,186,187,188,189,190, - 191,192,193,194,134,138,130,132,128,129,131,137,133,135,136,113, - 115,114, 0, 0, 0,121, 0, 89, 93,124, 92, 94, 95, 0, 0, 0, - 122,123, 90, 91, 85, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113, - 150,158,159,128,136,177,178,176,142,152,173,140 + 0, 0, 0, 0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, + 37, 38, 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, + 21, 44, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 28, 1, + 14, 15, 57, 12, 13, 26, 27, 43, 43, 39, 40, 41, 51, 52, + 53, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 87, 88, + 99, 70, 119, 110, 102, 104, 111, 107, 109, 106, 105, 108, 103, 69, + 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71, 72, 73, + 82, 83, 86, 127, 116, 117, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 134, 138, 130, 132, 128, 129, 131, 137, 133, 135, + 136, 113, 115, 114, 0, 0, 0, 121, 0, 89, 93, 124, 92, 94, + 95, 0, 0, 0, 122, 123, 90, 91, 85, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 29, 42, 56, 125, 97, 54, 100, 126, 164, 166, 165, 163, 161, 115, + 114, 113, 150, 158, 159, 128, 136, 177, 178, 176, 142, 152, 173, 140 }; static unsigned char hidp_mkeyspat[] = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }; @@ -721,7 +723,8 @@ static int hidp_session(void *arg) while (!atomic_read(&session->terminate)) { set_current_state(TASK_INTERRUPTIBLE); - if (ctrl_sk->sk_state != BT_CONNECTED || intr_sk->sk_state != BT_CONNECTED) + if (ctrl_sk->sk_state != BT_CONNECTED || + intr_sk->sk_state != BT_CONNECTED) break; while ((skb = skb_dequeue(&ctrl_sk->sk_receive_queue))) { diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h index 13de5fa03480..b412e7152eec 100644 --- a/net/bluetooth/hidp/hidp.h +++ b/net/bluetooth/hidp/hidp.h @@ -84,8 +84,8 @@ #define HIDP_WAITING_FOR_SEND_ACK 11 struct hidp_connadd_req { - int ctrl_sock; // Connected control socket - int intr_sock; // Connteted interrupt socket + int ctrl_sock; /* Connected control socket */ + int intr_sock; /* Connected interrupt socket */ __u16 parser; __u16 rd_size; __u8 __user *rd_data; diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c index 250dfd46237d..178ac7f127ad 100644 --- a/net/bluetooth/hidp/sock.c +++ b/net/bluetooth/hidp/sock.c @@ -85,7 +85,8 @@ static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long return err; } - if (csock->sk->sk_state != BT_CONNECTED || isock->sk->sk_state != BT_CONNECTED) { + if (csock->sk->sk_state != BT_CONNECTED || + isock->sk->sk_state != BT_CONNECTED) { sockfd_put(csock); sockfd_put(isock); return -EBADFD; @@ -140,8 +141,8 @@ static int hidp_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long #ifdef CONFIG_COMPAT struct compat_hidp_connadd_req { - int ctrl_sock; // Connected control socket - int intr_sock; // Connteted interrupt socket + int ctrl_sock; /* Connected control socket */ + int intr_sock; /* Connected interrupt socket */ __u16 parser; __u16 rd_size; compat_uptr_t rd_data; -- cgit v1.2.3 From 58aac468be411f2a9b4a28f2ed8e6e2a0db04267 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Mon, 21 Mar 2011 14:20:03 +0100 Subject: Bluetooth: Do not use assignments in IF conditions Fix checkpatch warnings concerning assignments in if conditions. Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan --- net/bluetooth/cmtp/core.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c index 964ea9126f9f..16aa6bd039ba 100644 --- a/net/bluetooth/cmtp/core.c +++ b/net/bluetooth/cmtp/core.c @@ -235,9 +235,12 @@ static void cmtp_process_transmit(struct cmtp_session *session) size = min_t(uint, ((tail < 258) ? (tail - 2) : (tail - 3)), skb->len); - if ((scb->id < 0) && ((scb->id = cmtp_alloc_block_id(session)) < 0)) { - skb_queue_head(&session->transmit, skb); - break; + if (scb->id < 0) { + scb->id = cmtp_alloc_block_id(session); + if (scb->id < 0) { + skb_queue_head(&session->transmit, skb); + break; + } } if (size < 256) { -- cgit v1.2.3 From ffd13320aa96e07f3048ebdcc603aaf38bed0c47 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Mon, 21 Mar 2011 14:20:04 +0100 Subject: Bluetooth: Use #include instead of As warned by checkpatch.pl, use #include instead of Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan --- net/bluetooth/cmtp/sock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c index 7ea1979a8e4f..3f2dd5c25ae5 100644 --- a/net/bluetooth/cmtp/sock.c +++ b/net/bluetooth/cmtp/sock.c @@ -34,12 +34,12 @@ #include #include #include +#include #include #include #include -#include #include "cmtp.h" -- cgit v1.2.3 From e0e185efbad442a659657c152a9cd9b3fdcb43f2 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Mon, 21 Mar 2011 14:20:05 +0100 Subject: Bluetooth: Fix checkpatch error in cmtp.h Do not use C99 // comments. Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan --- net/bluetooth/cmtp/cmtp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/cmtp/cmtp.h b/net/bluetooth/cmtp/cmtp.h index 785e79e953c5..c6f78f89415c 100644 --- a/net/bluetooth/cmtp/cmtp.h +++ b/net/bluetooth/cmtp/cmtp.h @@ -37,7 +37,7 @@ #define CMTP_LOOPBACK 0 struct cmtp_connadd_req { - int sock; // Connected socket + int sock; /* Connected socket */ __u32 flags; }; -- cgit v1.2.3 From c68fb7ff29622a7db8264f939f94e37330c27080 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Tue, 22 Mar 2011 13:12:19 +0100 Subject: Bluetooth: Rename cmd to param in pending_cmd This field holds not whole command but only command specific parameters. Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan --- net/bluetooth/mgmt.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f7ce78235590..d0c01230bba9 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -36,7 +36,7 @@ struct pending_cmd { struct list_head list; __u16 opcode; int index; - void *cmd; + void *param; struct sock *sk; void *user_data; }; @@ -217,7 +217,7 @@ static int read_controller_info(struct sock *sk, u16 index) static void mgmt_pending_free(struct pending_cmd *cmd) { sock_put(cmd->sk); - kfree(cmd->cmd); + kfree(cmd->param); kfree(cmd); } @@ -233,13 +233,13 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode, cmd->opcode = opcode; cmd->index = index; - cmd->cmd = kmalloc(len, GFP_ATOMIC); - if (!cmd->cmd) { + cmd->param = kmalloc(len, GFP_ATOMIC); + if (!cmd->param) { kfree(cmd); return NULL; } - memcpy(cmd->cmd, data, len); + memcpy(cmd->param, data, len); cmd->sk = sk; sock_hold(sk); @@ -1426,7 +1426,7 @@ struct cmd_lookup { static void mode_rsp(struct pending_cmd *cmd, void *data) { - struct mgmt_mode *cp = cmd->cmd; + struct mgmt_mode *cp = cmd->param; struct cmd_lookup *match = data; if (cp->val != match->val) @@ -1525,7 +1525,7 @@ int mgmt_connected(u16 index, bdaddr_t *bdaddr) static void disconnect_rsp(struct pending_cmd *cmd, void *data) { - struct mgmt_cp_disconnect *cp = cmd->cmd; + struct mgmt_cp_disconnect *cp = cmd->param; struct sock **sk = data; struct mgmt_rp_disconnect rp; -- cgit v1.2.3 From 8fce6357a9e72c4c9c846f9951895954bfb34ad1 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Tue, 22 Mar 2011 13:12:20 +0100 Subject: Bluetooth: Allow for NULL data in mgmt_pending_add Since index is in mgmt_hdr it is possible to have mgmt command with no parameters that still needs to add itself to pending list. Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan --- net/bluetooth/mgmt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index d0c01230bba9..93f0f04c8bcd 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -239,7 +239,8 @@ static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode, return NULL; } - memcpy(cmd->param, data, len); + if (data) + memcpy(cmd->param, data, len); cmd->sk = sk; sock_hold(sk); -- cgit v1.2.3 From c35938b2f56547ee77b5a038fe0db394aeac59bb Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Tue, 22 Mar 2011 13:12:21 +0100 Subject: Bluetooth: Add read_local_oob_data management command This patch adds a command to read local OOB data to the managment interface. The command maps directly to the Read Local OOB Data HCI command. Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci.h | 7 ++++ include/net/bluetooth/hci_core.h | 2 + include/net/bluetooth/mgmt.h | 6 +++ net/bluetooth/hci_event.c | 15 ++++++++ net/bluetooth/mgmt.c | 83 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 113 insertions(+) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 1cd031cd1c4d..ac4de1afe046 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -613,6 +613,13 @@ struct hci_cp_write_ssp_mode { __u8 mode; } __packed; +#define HCI_OP_READ_LOCAL_OOB_DATA 0x0c57 +struct hci_rp_read_local_oob_data { + __u8 status; + __u8 hash[16]; + __u8 randomizer[16]; +} __packed; + #define HCI_OP_READ_INQ_RSP_TX_POWER 0x0c58 #define HCI_OP_READ_LOCAL_VERSION 0x1001 diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 3912c7ab717c..fd9b8a31e5b0 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -768,6 +768,8 @@ int mgmt_user_confirm_neg_reply_complete(u16 index, bdaddr_t *bdaddr, 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, + u8 status); /* HCI info for socket */ #define hci_pi(sk) ((struct hci_pinfo *) sk) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 89e7c82c4784..6ebb1265c36e 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -177,6 +177,12 @@ struct mgmt_cp_set_local_name { __u8 name[MGMT_MAX_NAME_LENGTH]; } __packed; +#define MGMT_OP_READ_LOCAL_OOB_DATA 0x0018 +struct mgmt_rp_read_local_oob_data { + __u8 hash[16]; + __u8 randomizer[16]; +} __packed; + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 0def3e1fe5ef..582ef60a8bc0 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -822,6 +822,17 @@ static void hci_cc_user_confirm_neg_reply(struct hci_dev *hdev, rp->status); } +static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev, + struct sk_buff *skb) +{ + struct hci_rp_read_local_oob_data *rp = (void *) skb->data; + + BT_DBG("%s status 0x%x", hdev->name, rp->status); + + mgmt_read_local_oob_data_reply_complete(hdev->id, rp->hash, + rp->randomizer, rp->status); +} + static inline void hci_cs_inquiry(struct hci_dev *hdev, __u8 status) { BT_DBG("%s status 0x%x", hdev->name, status); @@ -1752,6 +1763,10 @@ static inline void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *sk hci_cc_pin_code_neg_reply(hdev, skb); break; + case HCI_OP_READ_LOCAL_OOB_DATA: + hci_cc_read_local_oob_data_reply(hdev, skb); + break; + case HCI_OP_LE_READ_BUFFER_SIZE: hci_cc_le_read_buffer_size(hdev, skb); break; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 93f0f04c8bcd..33b1f7400dab 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1296,6 +1296,55 @@ failed: return err; } +static int read_local_oob_data(struct sock *sk, u16 index) +{ + struct hci_dev *hdev; + struct pending_cmd *cmd; + int err; + + BT_DBG("hci%u", index); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, + ENODEV); + + hci_dev_lock_bh(hdev); + + if (!test_bit(HCI_UP, &hdev->flags)) { + err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, + ENETDOWN); + goto unlock; + } + + if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) { + err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, + EOPNOTSUPP); + goto unlock; + } + + if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index)) { + 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); + if (!cmd) { + err = -ENOMEM; + goto unlock; + } + + err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL); + if (err < 0) + mgmt_pending_remove(cmd); + +unlock: + hci_dev_unlock_bh(hdev); + hci_dev_put(hdev); + + return err; +} + int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) { unsigned char *buf; @@ -1394,6 +1443,10 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_SET_LOCAL_NAME: err = set_local_name(sk, index, buf + sizeof(*hdr), len); break; + case MGMT_OP_READ_LOCAL_OOB_DATA: + err = read_local_oob_data(sk, index); + break; + default: BT_DBG("Unknown op %u", opcode); err = cmd_status(sk, index, opcode, 0x01); @@ -1723,3 +1776,33 @@ failed: mgmt_pending_remove(cmd); return err; } + +int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer, + u8 status) +{ + struct pending_cmd *cmd; + int err; + + BT_DBG("hci%u status %u", index, status); + + cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, index); + if (!cmd) + return -ENOENT; + + if (status) { + err = cmd_status(cmd->sk, index, 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, + &rp, sizeof(rp)); + } + + mgmt_pending_remove(cmd); + + return err; +} -- cgit v1.2.3 From 2763eda6ccaf126633bb3180f440c8f3589f0679 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Tue, 22 Mar 2011 13:12:22 +0100 Subject: Bluetooth: Add add/remove_remote_oob_data management commands This patch adds commands to add and remove remote OOB data to the managment interface. Remote data is stored in kernel and can be used by corresponding HCI commands and events when needed. Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci.h | 17 +++++++++ include/net/bluetooth/hci_core.h | 16 +++++++++ include/net/bluetooth/mgmt.h | 12 +++++++ net/bluetooth/hci_core.c | 67 +++++++++++++++++++++++++++++++++++ net/bluetooth/hci_event.c | 35 +++++++++++++++++++ net/bluetooth/mgmt.c | 75 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 222 insertions(+) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index ac4de1afe046..b989a8c3e01a 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -426,6 +426,18 @@ struct hci_rp_user_confirm_reply { #define HCI_OP_USER_CONFIRM_NEG_REPLY 0x042d +#define HCI_OP_REMOTE_OOB_DATA_REPLY 0x0430 +struct hci_cp_remote_oob_data_reply { + bdaddr_t bdaddr; + __u8 hash[16]; + __u8 randomizer[16]; +} __packed; + +#define HCI_OP_REMOTE_OOB_DATA_NEG_REPLY 0x0433 +struct hci_cp_remote_oob_data_neg_reply { + bdaddr_t bdaddr; +} __packed; + #define HCI_OP_IO_CAPABILITY_NEG_REPLY 0x0434 struct hci_cp_io_capability_neg_reply { bdaddr_t bdaddr; @@ -962,6 +974,11 @@ struct hci_ev_user_confirm_req { __le32 passkey; } __packed; +#define HCI_EV_REMOTE_OOB_DATA_REQUEST 0x35 +struct hci_ev_remote_oob_data_request { + bdaddr_t bdaddr; +} __packed; + #define HCI_EV_SIMPLE_PAIR_COMPLETE 0x36 struct hci_ev_simple_pair_complete { __u8 status; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index fd9b8a31e5b0..87bff518b54b 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -82,6 +82,13 @@ struct link_key { u8 pin_len; }; +struct oob_data { + struct list_head list; + bdaddr_t bdaddr; + u8 hash[16]; + u8 randomizer[16]; +}; + #define NUM_REASSEMBLY 4 struct hci_dev { struct list_head list; @@ -169,6 +176,8 @@ struct hci_dev { struct list_head link_keys; + struct list_head remote_oob_data; + struct hci_dev_stats stat; struct sk_buff_head driver_init; @@ -505,6 +514,13 @@ int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, u8 *key, u8 type, u8 pin_len); int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); +int hci_remote_oob_data_clear(struct hci_dev *hdev); +struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev, + bdaddr_t *bdaddr); +int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, + u8 *randomizer); +int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr); + void hci_del_off_timer(struct hci_dev *hdev); void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 6ebb1265c36e..1a6283f9fee8 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -183,6 +183,18 @@ struct mgmt_rp_read_local_oob_data { __u8 randomizer[16]; } __packed; +#define MGMT_OP_ADD_REMOTE_OOB_DATA 0x0019 +struct mgmt_cp_add_remote_oob_data { + bdaddr_t bdaddr; + __u8 hash[16]; + __u8 randomizer[16]; +} __packed; + +#define MGMT_OP_REMOVE_REMOTE_OOB_DATA 0x001A +struct mgmt_cp_remove_remote_oob_data { + bdaddr_t bdaddr; +} __packed; + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index c20cbe5ff6db..675f0a1832ee 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1076,6 +1076,70 @@ static void hci_cmd_timer(unsigned long arg) tasklet_schedule(&hdev->cmd_task); } +struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev, + bdaddr_t *bdaddr) +{ + struct oob_data *data; + + list_for_each_entry(data, &hdev->remote_oob_data, list) + if (bacmp(bdaddr, &data->bdaddr) == 0) + return data; + + return NULL; +} + +int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr) +{ + struct oob_data *data; + + data = hci_find_remote_oob_data(hdev, bdaddr); + if (!data) + return -ENOENT; + + BT_DBG("%s removing %s", hdev->name, batostr(bdaddr)); + + list_del(&data->list); + kfree(data); + + return 0; +} + +int hci_remote_oob_data_clear(struct hci_dev *hdev) +{ + struct oob_data *data, *n; + + list_for_each_entry_safe(data, n, &hdev->remote_oob_data, list) { + list_del(&data->list); + kfree(data); + } + + return 0; +} + +int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash, + u8 *randomizer) +{ + struct oob_data *data; + + data = hci_find_remote_oob_data(hdev, bdaddr); + + if (!data) { + data = kmalloc(sizeof(*data), GFP_ATOMIC); + if (!data) + return -ENOMEM; + + bacpy(&data->bdaddr, bdaddr); + list_add(&data->list, &hdev->remote_oob_data); + } + + memcpy(data->hash, hash, sizeof(data->hash)); + memcpy(data->randomizer, randomizer, sizeof(data->randomizer)); + + BT_DBG("%s for %s", hdev->name, batostr(bdaddr)); + + return 0; +} + /* Register HCI device */ int hci_register_dev(struct hci_dev *hdev) { @@ -1140,6 +1204,8 @@ int hci_register_dev(struct hci_dev *hdev) INIT_LIST_HEAD(&hdev->link_keys); + INIT_LIST_HEAD(&hdev->remote_oob_data); + 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); @@ -1219,6 +1285,7 @@ int hci_unregister_dev(struct hci_dev *hdev) hci_blacklist_clear(hdev); hci_uuids_clear(hdev); hci_link_keys_clear(hdev); + hci_remote_oob_data_clear(hdev); hci_dev_unlock_bh(hdev); __hci_dev_put(hdev); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 582ef60a8bc0..e0aaf3053667 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2471,6 +2471,37 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_ hci_dev_unlock(hdev); } +static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev, + struct sk_buff *skb) +{ + struct hci_ev_remote_oob_data_request *ev = (void *) skb->data; + struct oob_data *data; + + BT_DBG("%s", hdev->name); + + hci_dev_lock(hdev); + + data = hci_find_remote_oob_data(hdev, &ev->bdaddr); + if (data) { + struct hci_cp_remote_oob_data_reply cp; + + bacpy(&cp.bdaddr, &ev->bdaddr); + memcpy(cp.hash, data->hash, sizeof(cp.hash)); + memcpy(cp.randomizer, data->randomizer, sizeof(cp.randomizer)); + + hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_REPLY, sizeof(cp), + &cp); + } else { + struct hci_cp_remote_oob_data_neg_reply cp; + + bacpy(&cp.bdaddr, &ev->bdaddr); + hci_send_cmd(hdev, HCI_OP_REMOTE_OOB_DATA_NEG_REPLY, sizeof(cp), + &cp); + } + + hci_dev_unlock(hdev); +} + static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_le_conn_complete *ev = (void *) skb->data; @@ -2673,6 +2704,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb) hci_le_meta_evt(hdev, skb); break; + case HCI_EV_REMOTE_OOB_DATA_REQUEST: + hci_remote_oob_data_request_evt(hdev, skb); + break; + default: BT_DBG("%s event 0x%x", hdev->name, event); break; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 33b1f7400dab..a42dc8ca0a6f 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1345,6 +1345,74 @@ unlock: return err; } +static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data, + u16 len) +{ + struct hci_dev *hdev; + struct mgmt_cp_add_remote_oob_data *cp = (void *) data; + int err; + + BT_DBG("hci%u ", index); + + if (len != sizeof(*cp)) + return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, + EINVAL); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, + ENODEV); + + hci_dev_lock_bh(hdev); + + err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash, + cp->randomizer); + if (err < 0) + err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, -err); + else + err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL, + 0); + + hci_dev_unlock_bh(hdev); + hci_dev_put(hdev); + + return err; +} + +static int remove_remote_oob_data(struct sock *sk, u16 index, + unsigned char *data, u16 len) +{ + struct hci_dev *hdev; + struct mgmt_cp_remove_remote_oob_data *cp = (void *) data; + int err; + + BT_DBG("hci%u ", index); + + if (len != sizeof(*cp)) + return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, + EINVAL); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, + ENODEV); + + hci_dev_lock_bh(hdev); + + err = hci_remove_remote_oob_data(hdev, &cp->bdaddr); + if (err < 0) + err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, + -err); + else + err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, + NULL, 0); + + hci_dev_unlock_bh(hdev); + hci_dev_put(hdev); + + return err; +} + int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) { unsigned char *buf; @@ -1446,6 +1514,13 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) case MGMT_OP_READ_LOCAL_OOB_DATA: err = read_local_oob_data(sk, index); break; + case MGMT_OP_ADD_REMOTE_OOB_DATA: + err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len); + break; + case MGMT_OP_REMOVE_REMOTE_OOB_DATA: + err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr), + len); + break; default: BT_DBG("Unknown op %u", opcode); -- cgit v1.2.3 From ce85ee13e6b5d078f4a6c3b02ba7cd0fa140c552 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Tue, 22 Mar 2011 13:12:23 +0100 Subject: Bluetooth: Enable support for out of band association model If remote side reports oob availability or we are pairing initiator use oob data for pairing if available. Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_event.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e0aaf3053667..da4c662dbc30 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2371,9 +2371,14 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff bacpy(&cp.bdaddr, &ev->bdaddr); cp.capability = conn->io_capability; - cp.oob_data = 0; cp.authentication = hci_get_auth_req(conn); + if ((conn->out == 0x01 || conn->remote_oob == 0x01) && + hci_find_remote_oob_data(hdev, &conn->dst)) + cp.oob_data = 0x01; + else + cp.oob_data = 0x00; + hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_REPLY, sizeof(cp), &cp); } else { -- cgit v1.2.3 From d1010240fa9aac93da56a683c1295e759ee69d10 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 25 Mar 2011 00:39:48 -0300 Subject: Bluetooth: Move bt_accept_enqueue() to outside __l2cap_chan_add bt_accept_enqueue() is not really a channel action, so do it outside. This patch is part of a set of patches to create an struct l2cap_chan to have a clear separation between the struct sock and the L2CAP channel stuff. Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_core.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index b5a1ce06e1c0..bf09f6027bd2 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -169,7 +169,7 @@ static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk) __sock_put(sk); } -static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) +static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk) { struct l2cap_chan_list *l = &conn->chan_list; @@ -204,9 +204,6 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so } __l2cap_chan_link(l, sk); - - if (parent) - bt_accept_enqueue(parent, sk); } /* Delete channel. @@ -652,7 +649,9 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) bacpy(&bt_sk(sk)->src, conn->src); bacpy(&bt_sk(sk)->dst, conn->dst); - __l2cap_chan_add(conn, sk, parent); + bt_accept_enqueue(parent, sk); + + __l2cap_chan_add(conn, sk); l2cap_sock_set_timer(sk, sk->sk_sndtimeo); @@ -793,11 +792,11 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) kfree(conn); } -static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent) +static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk) { struct l2cap_chan_list *l = &conn->chan_list; write_lock_bh(&l->lock); - __l2cap_chan_add(conn, sk, parent); + __l2cap_chan_add(conn, sk); write_unlock_bh(&l->lock); } @@ -876,7 +875,7 @@ int l2cap_do_connect(struct sock *sk) /* Update source addr of the socket */ bacpy(src, conn->src); - l2cap_chan_add(conn, sk, NULL); + l2cap_chan_add(conn, sk); sk->sk_state = BT_CONNECT; l2cap_sock_set_timer(sk, sk->sk_sndtimeo); @@ -2030,7 +2029,9 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd l2cap_pi(sk)->psm = psm; l2cap_pi(sk)->dcid = scid; - __l2cap_chan_add(conn, sk, parent); + bt_accept_enqueue(parent, sk); + + __l2cap_chan_add(conn, sk); dcid = l2cap_pi(sk)->scid; l2cap_sock_set_timer(sk, sk->sk_sndtimeo); -- cgit v1.2.3 From e90165be9a4d6a1e8fa632fcae00a5294abd3981 Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Fri, 25 Mar 2011 11:31:41 +0200 Subject: Bluetooth: check L2CAP info_rsp ident and state Information requests/responses are unbound to L2CAP channel. Patch fixes issue arising when two devices connects at the same time to each other. This way we do not process out of the context messages. We are safe dropping info_rsp since info_timer is left running. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_core.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index bf09f6027bd2..033c83be3524 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2461,6 +2461,11 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm BT_DBG("type 0x%4.4x result 0x%2.2x", type, result); + /* L2CAP Info req/rsp are unbound to channels, add extra checks */ + if (cmd->ident != conn->info_ident || + conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) + return 0; + del_timer(&conn->info_timer); if (result != L2CAP_IR_SUCCESS) { -- cgit v1.2.3 From 80a1e1dbf62a08984d4c1bfb5a4bca38c3e1664f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Mon, 28 Mar 2011 14:07:23 +0300 Subject: Bluetooth: Add local Extended Inquiry Response (EIR) support This patch adds automated creation of the local EIR data based on what 16-bit UUIDs are registered and what the device name is. This should cover the majority use cases, however things like 32/128-bit UUIDs, TX power and Device ID will need to be added later to be on par with what bluetoothd is capable of doing (without the Management interface). Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci.h | 8 ++ include/net/bluetooth/hci_core.h | 1 + net/bluetooth/mgmt.c | 163 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 172 insertions(+) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index b989a8c3e01a..6846ec02dcb0 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -614,6 +614,14 @@ struct hci_cp_host_buffer_size { #define HCI_OP_WRITE_INQUIRY_MODE 0x0c45 +#define HCI_MAX_EIR_LENGTH 240 + +#define HCI_OP_WRITE_EIR 0x0c52 +struct hci_cp_write_eir { + uint8_t fec; + uint8_t data[HCI_MAX_EIR_LENGTH]; +} __packed; + #define HCI_OP_READ_SSP_MODE 0x0c55 struct hci_rp_read_ssp_mode { __u8 status; diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 87bff518b54b..3b2f09df279a 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -102,6 +102,7 @@ struct hci_dev { __u8 dev_type; bdaddr_t bdaddr; __u8 dev_name[HCI_MAX_NAME_LENGTH]; + __u8 eir[HCI_MAX_EIR_LENGTH]; __u8 dev_class[3]; __u8 major_class; __u8 minor_class; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a42dc8ca0a6f..62055c9a8084 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -544,6 +544,150 @@ failed: return err; } +#define EIR_FLAGS 0x01 /* flags */ +#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */ +#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */ +#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */ +#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */ +#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */ +#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */ +#define EIR_NAME_SHORT 0x08 /* shortened local name */ +#define EIR_NAME_COMPLETE 0x09 /* complete local name */ +#define EIR_TX_POWER 0x0A /* transmit power level */ +#define EIR_DEVICE_ID 0x10 /* device ID */ + +#define PNP_INFO_SVCLASS_ID 0x1200 + +static u8 bluetooth_base_uuid[] = { + 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80, + 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static u16 get_uuid16(u8 *uuid128) +{ + u32 val; + int i; + + for (i = 0; i < 12; i++) { + if (bluetooth_base_uuid[i] != uuid128[i]) + return 0; + } + + memcpy(&val, &uuid128[12], 4); + + val = le32_to_cpu(val); + if (val > 0xffff) + return 0; + + return (u16) val; +} + +static void create_eir(struct hci_dev *hdev, u8 *data) +{ + u8 *ptr = data; + u16 eir_len = 0; + u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)]; + int i, truncated = 0; + struct list_head *p; + size_t name_len; + + name_len = strlen(hdev->dev_name); + + if (name_len > 0) { + /* EIR Data type */ + if (name_len > 48) { + name_len = 48; + ptr[1] = EIR_NAME_SHORT; + } else + ptr[1] = EIR_NAME_COMPLETE; + + /* EIR Data length */ + ptr[0] = name_len + 1; + + memcpy(ptr + 2, hdev->dev_name, name_len); + + eir_len += (name_len + 2); + ptr += (name_len + 2); + } + + 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); + u16 uuid16; + + uuid16 = get_uuid16(uuid->uuid); + if (uuid16 == 0) + return; + + if (uuid16 < 0x1100) + continue; + + if (uuid16 == PNP_INFO_SVCLASS_ID) + continue; + + /* Stop if not enough space to put next UUID */ + if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) { + truncated = 1; + break; + } + + /* Check for duplicates */ + for (i = 0; uuid16_list[i] != 0; i++) + if (uuid16_list[i] == uuid16) + break; + + if (uuid16_list[i] == 0) { + uuid16_list[i] = uuid16; + eir_len += sizeof(u16); + } + } + + if (uuid16_list[0] != 0) { + u8 *length = ptr; + + /* EIR Data type */ + ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL; + + ptr += 2; + eir_len += 2; + + for (i = 0; uuid16_list[i] != 0; i++) { + *ptr++ = (uuid16_list[i] & 0x00ff); + *ptr++ = (uuid16_list[i] & 0xff00) >> 8; + } + + /* EIR Data length */ + *length = (i * sizeof(u16)) + 1; + } +} + +static int update_eir(struct hci_dev *hdev) +{ + struct hci_cp_write_eir cp; + + if (!(hdev->features[6] & LMP_EXT_INQ)) + return 0; + + if (hdev->ssp_mode == 0) + return 0; + + if (test_bit(HCI_SERVICE_CACHE, &hdev->flags)) + return 0; + + memset(&cp, 0, sizeof(cp)); + + create_eir(hdev, cp.data); + + if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0) + return 0; + + memcpy(hdev->eir, cp.data, sizeof(cp.data)); + + return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp); +} + static u8 get_service_classes(struct hci_dev *hdev) { struct list_head *p; @@ -612,6 +756,10 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) if (err < 0) goto failed; + err = update_eir(hdev); + if (err < 0) + goto failed; + err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0); failed: @@ -668,6 +816,10 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) if (err < 0) goto unlock; + err = update_eir(hdev); + if (err < 0) + goto unlock; + err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0); unlock: @@ -737,6 +889,8 @@ static int set_service_cache(struct sock *sk, u16 index, unsigned char *data, } else { clear_bit(HCI_SERVICE_CACHE, &hdev->flags); err = update_class(hdev); + if (err == 0) + err = update_eir(hdev); } if (err == 0) @@ -1822,6 +1976,7 @@ int mgmt_auth_failed(u16 index, bdaddr_t *bdaddr, u8 status) int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status) { struct pending_cmd *cmd; + struct hci_dev *hdev; struct mgmt_cp_set_local_name ev; int err; @@ -1837,6 +1992,14 @@ int mgmt_set_local_name_complete(u16 index, u8 *name, u8 status) 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, sizeof(ev)); if (err < 0) -- cgit v1.2.3 From 23e9fde2b344c22c5176c7fd37b52c3776ef5aba Mon Sep 17 00:00:00 2001 From: Suraj Sumangala Date: Wed, 9 Mar 2011 14:44:05 +0530 Subject: Bluetooth: Increment unacked_frames count only the first transmit This patch lets 'l2cap_pinfo.unacked_frames' be incremented only the first time a frame is transmitted. Previously it was being incremented for retransmitted packets too resulting the value to cross the transmit window size. Signed-off-by: Suraj Sumangala Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index c9f9cecca527..ca27f3a41536 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1116,7 +1116,9 @@ int l2cap_ertm_send(struct sock *sk) bt_cb(skb)->tx_seq = pi->next_tx_seq; pi->next_tx_seq = (pi->next_tx_seq + 1) % 64; - pi->unacked_frames++; + if (bt_cb(skb)->retries == 1) + pi->unacked_frames++; + pi->frames_sent++; if (skb_queue_is_last(TX_QUEUE(sk), skb)) -- cgit v1.2.3 From 105721328f0fa53e772592eaca17ee0023f0cc87 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 16 Mar 2011 15:36:29 -0300 Subject: Bluetooth: Fix HCI_RESET command synchronization We can't send new commands before a cmd_complete for the HCI_RESET command shows up. Reported-by: Mikko Vinni Reported-by: Justin P. Mattock Reported-by: Ed Tomlinson Signed-off-by: Gustavo F. Padovan Tested-by: Justin P. Mattock Tested-by: Mikko Vinni Tested-by: Ed Tomlinson --- include/net/bluetooth/hci.h | 2 ++ net/bluetooth/hci_core.c | 6 +++++- net/bluetooth/hci_event.c | 4 +++- 3 files changed, 10 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index ec6acf2f1c0b..2c0d309c7381 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -84,6 +84,8 @@ enum { HCI_SERVICE_CACHE, HCI_LINK_KEYS, HCI_DEBUG_KEYS, + + HCI_RESET, }; /* HCI ioctl defines */ diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index b372fb8bcdcf..92b48e257b89 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -186,6 +186,7 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt) BT_DBG("%s %ld", hdev->name, opt); /* Reset device */ + set_bit(HCI_RESET, &hdev->flags); hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL); } @@ -213,8 +214,10 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) /* Mandatory initialization */ /* Reset */ - if (!test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) + if (!test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) { + set_bit(HCI_RESET, &hdev->flags); hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL); + } /* Read Local Supported Features */ hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL); @@ -1074,6 +1077,7 @@ static void hci_cmd_timer(unsigned long arg) BT_ERR("%s command tx timeout", hdev->name); atomic_set(&hdev->cmd_cnt, 1); + clear_bit(HCI_RESET, &hdev->flags); tasklet_schedule(&hdev->cmd_task); } diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 3fbfa50c2bff..cebe7588469f 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -183,6 +183,8 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb) BT_DBG("%s status 0x%x", hdev->name, status); + clear_bit(HCI_RESET, &hdev->flags); + hci_req_complete(hdev, HCI_OP_RESET, status); } @@ -1847,7 +1849,7 @@ static inline void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb) if (ev->opcode != HCI_OP_NOP) del_timer(&hdev->cmd_timer); - if (ev->ncmd) { + if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) { atomic_set(&hdev->cmd_cnt, 1); if (!skb_queue_empty(&hdev->cmd_q)) tasklet_schedule(&hdev->cmd_task); -- cgit v1.2.3 From 08ba53824a7fb224085a0ff73eab213cab0197e9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 16 Mar 2011 14:29:34 +0200 Subject: Bluetooth: Fix missing hci_dev_lock_bh in user_confirm_reply The code was correctly calling _unlock at the end of the function but there was no actual _lock call anywhere. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan --- net/bluetooth/mgmt.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 0054c74e27b7..4476d8e3c0f2 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1230,6 +1230,8 @@ static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, mgmt_op, ENODEV); + hci_dev_lock_bh(hdev); + if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, mgmt_op, ENETDOWN); goto failed; -- cgit v1.2.3 From 34bd0273b631742e8d929c80e90cb7782105d8da Mon Sep 17 00:00:00 2001 From: Andrei Emeltchenko Date: Thu, 24 Mar 2011 17:16:08 +0200 Subject: Bluetooth: delete hanging L2CAP channel Sometimes L2CAP connection remains hanging. Make sure that L2CAP channel is deleted. Signed-off-by: Andrei Emeltchenko Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_sock.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index fc85e7ae33c7..f77308e63e58 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -923,8 +923,9 @@ void __l2cap_sock_close(struct sock *sk, int reason) rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); l2cap_send_cmd(conn, l2cap_pi(sk)->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); - } else - l2cap_chan_del(sk, reason); + } + + l2cap_chan_del(sk, reason); break; case BT_CONNECT: -- cgit v1.2.3 From 6f5ef998b7b0b1bf1471654bf6176a5419197128 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Thu, 24 Mar 2011 20:16:42 +0100 Subject: Bluetooth: Fix warning with hci_cmd_timer After we made debugobjects working again, we got the following: WARNING: at lib/debugobjects.c:262 debug_print_object+0x8e/0xb0() Hardware name: System Product Name ODEBUG: free active (active state 0) object type: timer_list hint: hci_cmd_timer+0x0/0x60 Pid: 2125, comm: dmsetup Tainted: G W 2.6.38-06707-gc62b389 #110375 Call Trace: [] warn_slowpath_common+0x7a/0xb0 [] warn_slowpath_fmt+0x46/0x50 [] debug_print_object+0x8e/0xb0 [] ? hci_cmd_timer+0x0/0x60 [] debug_check_no_obj_freed+0x125/0x230 [] ? check_object+0xb3/0x2b0 [] kfree+0x150/0x190 [] ? bt_host_release+0x16/0x20 [] bt_host_release+0x16/0x20 [] device_release+0x27/0xa0 [] kobject_release+0x4c/0xa0 [] ? kobject_release+0x0/0xa0 [] kref_put+0x36/0x70 [] kobject_put+0x27/0x60 [] put_device+0x17/0x20 [] hci_free_dev+0x29/0x30 [] vhci_release+0x36/0x70 [] fput+0xd6/0x1f0 [] filp_close+0x66/0x90 [] sys_close+0x99/0xf0 [] system_call_fastpath+0x16/0x1b That timer was introduced with commit 6bd32326cda(Bluetooth: Use proper timer for hci command timout) Timer seems to be running when the thing is closed. Removing the timer unconditionally fixes the problem. And yes, it needs to be fixed before the HCI_UP check. Signed-off-by: Thomas Gleixner Tested-by: Ingo Molnar Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 92b48e257b89..2216620ff296 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -587,6 +587,9 @@ static int hci_dev_do_close(struct hci_dev *hdev) hci_req_cancel(hdev, ENODEV); hci_req_lock(hdev); + /* Stop timer, it might be running */ + del_timer_sync(&hdev->cmd_timer); + if (!test_and_clear_bit(HCI_UP, &hdev->flags)) { hci_req_unlock(hdev); return 0; @@ -626,7 +629,6 @@ static int hci_dev_do_close(struct hci_dev *hdev) /* Drop last sent command */ if (hdev->sent_cmd) { - del_timer_sync(&hdev->cmd_timer); kfree_skb(hdev->sent_cmd); hdev->sent_cmd = NULL; } -- cgit v1.2.3 From 1e429f3842b5c9b5967a250f4daf78f92436268c Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 4 Apr 2011 18:25:14 -0300 Subject: Bluetooth: Remove gfp_mask param from hci_reassembly() It is unnecessary, once we are always in interrupt context. Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_core.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index decd60198f31..a80bc1cdb35b 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1341,7 +1341,7 @@ int hci_recv_frame(struct sk_buff *skb) EXPORT_SYMBOL(hci_recv_frame); static int hci_reassembly(struct hci_dev *hdev, int type, void *data, - int count, __u8 index, gfp_t gfp_mask) + int count, __u8 index) { int len = 0; int hlen = 0; @@ -1371,7 +1371,7 @@ static int hci_reassembly(struct hci_dev *hdev, int type, void *data, break; } - skb = bt_skb_alloc(len, gfp_mask); + skb = bt_skb_alloc(len, GFP_ATOMIC); if (!skb) return -ENOMEM; @@ -1457,8 +1457,7 @@ int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count) return -EILSEQ; while (count) { - rem = hci_reassembly(hdev, type, data, count, - type - 1, GFP_ATOMIC); + rem = hci_reassembly(hdev, type, data, count, type - 1); if (rem < 0) return rem; @@ -1492,8 +1491,8 @@ int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count) } else type = bt_cb(skb)->pkt_type; - rem = hci_reassembly(hdev, type, data, - count, STREAM_REASSEMBLY, GFP_ATOMIC); + rem = hci_reassembly(hdev, type, data, count, + STREAM_REASSEMBLY); if (rem < 0) return rem; -- cgit v1.2.3 From e17acd40f6006d0a0e0b1b3f7359ba4d543011c6 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 30 Mar 2011 23:57:16 +0300 Subject: Bluetooth: Add mgmt_device_found event This patch adds a device_found event to the Management interface. For now the event only maps to BR/EDR inquiry result HCI events, but in the future the plan is to also use it for the LE device discovery process. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 2 ++ include/net/bluetooth/mgmt.h | 8 ++++++++ net/bluetooth/hci_event.c | 22 ++++++++++++++-------- net/bluetooth/mgmt.c | 17 +++++++++++++++++ 4 files changed, 41 insertions(+), 8 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 3b2f09df279a..2a88fc82429b 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -787,6 +787,8 @@ 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, u8 status); +int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi, + u8 *eir); /* HCI info for socket */ #define hci_pi(sk) ((struct hci_pinfo *) sk) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 1a6283f9fee8..864d0cbd2d57 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -267,3 +267,11 @@ struct mgmt_ev_auth_failed { struct mgmt_ev_local_name_changed { __u8 name[MGMT_MAX_NAME_LENGTH]; } __packed; + +#define MGMT_EV_DEVICE_FOUND 0x0012 +struct mgmt_ev_device_found { + bdaddr_t bdaddr; + __u8 dev_class[3]; + __s8 rssi; + __u8 eir[HCI_MAX_EIR_LENGTH]; +} __packed; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 833797e9654b..d04011c06be0 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1228,7 +1228,7 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * hci_dev_lock(hdev); - for (; num_rsp; num_rsp--) { + for (; num_rsp; num_rsp--, info++) { bacpy(&data.bdaddr, &info->bdaddr); data.pscan_rep_mode = info->pscan_rep_mode; data.pscan_period_mode = info->pscan_period_mode; @@ -1237,8 +1237,9 @@ static inline void hci_inquiry_result_evt(struct hci_dev *hdev, struct sk_buff * data.clock_offset = info->clock_offset; data.rssi = 0x00; data.ssp_mode = 0x00; - info++; hci_inquiry_cache_update(hdev, &data); + mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class, 0, + NULL); } hci_dev_unlock(hdev); @@ -2158,7 +2159,7 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct struct inquiry_info_with_rssi_and_pscan_mode *info; info = (void *) (skb->data + 1); - for (; num_rsp; num_rsp--) { + for (; num_rsp; num_rsp--, info++) { bacpy(&data.bdaddr, &info->bdaddr); data.pscan_rep_mode = info->pscan_rep_mode; data.pscan_period_mode = info->pscan_period_mode; @@ -2167,13 +2168,15 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct data.clock_offset = info->clock_offset; data.rssi = info->rssi; data.ssp_mode = 0x00; - info++; hci_inquiry_cache_update(hdev, &data); + mgmt_device_found(hdev->id, &info->bdaddr, + info->dev_class, info->rssi, + NULL); } } else { struct inquiry_info_with_rssi *info = (void *) (skb->data + 1); - for (; num_rsp; num_rsp--) { + for (; num_rsp; num_rsp--, info++) { bacpy(&data.bdaddr, &info->bdaddr); data.pscan_rep_mode = info->pscan_rep_mode; data.pscan_period_mode = info->pscan_period_mode; @@ -2182,8 +2185,10 @@ static inline void hci_inquiry_result_with_rssi_evt(struct hci_dev *hdev, struct data.clock_offset = info->clock_offset; data.rssi = info->rssi; data.ssp_mode = 0x00; - info++; hci_inquiry_cache_update(hdev, &data); + mgmt_device_found(hdev->id, &info->bdaddr, + info->dev_class, info->rssi, + NULL); } } @@ -2314,7 +2319,7 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct hci_dev_lock(hdev); - for (; num_rsp; num_rsp--) { + for (; num_rsp; num_rsp--, info++) { bacpy(&data.bdaddr, &info->bdaddr); data.pscan_rep_mode = info->pscan_rep_mode; data.pscan_period_mode = info->pscan_period_mode; @@ -2323,8 +2328,9 @@ static inline void hci_extended_inquiry_result_evt(struct hci_dev *hdev, struct data.clock_offset = info->clock_offset; data.rssi = info->rssi; data.ssp_mode = 0x01; - info++; hci_inquiry_cache_update(hdev, &data); + mgmt_device_found(hdev->id, &info->bdaddr, info->dev_class, + info->rssi, info->data); } hci_dev_unlock(hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f87691e04dca..86fb50215485 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2046,3 +2046,20 @@ 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) +{ + struct mgmt_ev_device_found ev; + + memset(&ev, 0, sizeof(ev)); + + bacpy(&ev.bdaddr, bdaddr); + memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class)); + ev.rssi = rssi; + + if (eir) + memcpy(ev.eir, eir, sizeof(ev.eir)); + + return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL); +} -- cgit v1.2.3 From a88a9652d25a63ce10b6a5fe680d0ad8f33b9c9b Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 30 Mar 2011 13:18:12 +0300 Subject: Bluetooth: Add mgmt_remote_name event This patch adds a new remote_name event to the Management interface which is sent every time the name of a remote device is resolved (over BR/EDR). Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 1 + include/net/bluetooth/mgmt.h | 6 ++++++ net/bluetooth/hci_event.c | 3 +++ net/bluetooth/mgmt.c | 12 ++++++++++++ 4 files changed, 22 insertions(+) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 2a88fc82429b..4093133c1283 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -789,6 +789,7 @@ int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer, 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); /* HCI info for socket */ #define hci_pi(sk) ((struct hci_pinfo *) sk) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 864d0cbd2d57..6b6ff92ab499 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -275,3 +275,9 @@ struct mgmt_ev_device_found { __s8 rssi; __u8 eir[HCI_MAX_EIR_LENGTH]; } __packed; + +#define MGMT_EV_REMOTE_NAME 0x0013 +struct mgmt_ev_remote_name { + bdaddr_t bdaddr; + __u8 name[MGMT_MAX_NAME_LENGTH]; +} __packed; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d04011c06be0..7a3398d9cd65 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1497,6 +1497,9 @@ 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); + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); if (conn && hci_outgoing_auth_needed(hdev, conn)) { struct hci_cp_auth_requested cp; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 86fb50215485..9a61320c5f2e 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2063,3 +2063,15 @@ int mgmt_device_found(u16 index, bdaddr_t *bdaddr, u8 *dev_class, s8 rssi, return mgmt_event(MGMT_EV_DEVICE_FOUND, index, &ev, sizeof(ev), NULL); } + +int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name) +{ + struct mgmt_ev_remote_name ev; + + memset(&ev, 0, sizeof(ev)); + + bacpy(&ev.bdaddr, bdaddr); + memcpy(ev.name, name, HCI_MAX_NAME_LENGTH); + + return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL); +} -- cgit v1.2.3 From aabf6f897e44bdf3e237ada04aa8f88d77d75cac Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Tue, 5 Apr 2011 15:37:45 +0200 Subject: Bluetooth: Use kthread API in hidp kernel_thread() is a low-level implementation detail and EXPORT_SYMBOL(kernel_thread) is scheduled for removal. Use the API instead. Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hidp/core.c | 53 +++++++++++++++++++++-------------------------- net/bluetooth/hidp/hidp.h | 2 +- 2 files changed, 25 insertions(+), 30 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index a1472b75d628..ae6ebc6c3481 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -463,8 +464,7 @@ static void hidp_idle_timeout(unsigned long arg) { struct hidp_session *session = (struct hidp_session *) arg; - atomic_inc(&session->terminate); - hidp_schedule(session); + kthread_stop(session->task); } static void hidp_set_timer(struct hidp_session *session) @@ -535,9 +535,7 @@ static void hidp_process_hid_control(struct hidp_session *session, skb_queue_purge(&session->ctrl_transmit); skb_queue_purge(&session->intr_transmit); - /* Kill session thread */ - atomic_inc(&session->terminate); - hidp_schedule(session); + kthread_stop(session->task); } } @@ -696,22 +694,10 @@ static int hidp_session(void *arg) struct sock *ctrl_sk = session->ctrl_sock->sk; struct sock *intr_sk = session->intr_sock->sk; struct sk_buff *skb; - int vendor = 0x0000, product = 0x0000; wait_queue_t ctrl_wait, intr_wait; BT_DBG("session %p", session); - if (session->input) { - vendor = session->input->id.vendor; - product = session->input->id.product; - } - - if (session->hid) { - vendor = session->hid->vendor; - product = session->hid->product; - } - - daemonize("khidpd_%04x%04x", vendor, product); set_user_nice(current, -15); init_waitqueue_entry(&ctrl_wait, current); @@ -720,7 +706,7 @@ static int hidp_session(void *arg) add_wait_queue(sk_sleep(intr_sk), &intr_wait); session->waiting_for_startup = 0; wake_up_interruptible(&session->startup_queue); - while (!atomic_read(&session->terminate)) { + while (!kthread_should_stop()) { set_current_state(TASK_INTERRUPTIBLE); if (ctrl_sk->sk_state != BT_CONNECTED || @@ -968,6 +954,7 @@ fault: int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock) { struct hidp_session *session, *s; + int vendor, product; int err; BT_DBG(""); @@ -1029,9 +1016,24 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, hidp_set_timer(session); - err = kernel_thread(hidp_session, session, CLONE_KERNEL); - if (err < 0) + if (session->hid) { + vendor = session->hid->vendor; + product = session->hid->product; + } else if (session->input) { + vendor = session->input->id.vendor; + product = session->input->id.product; + } else { + vendor = 0x0000; + product = 0x0000; + } + + session->task = kthread_run(hidp_session, session, "khidpd_%04x%04x", + vendor, product); + if (IS_ERR(session->task)) { + err = PTR_ERR(session->task); goto unlink; + } + while (session->waiting_for_startup) { wait_event_interruptible(session->startup_queue, !session->waiting_for_startup); @@ -1056,8 +1058,7 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, err_add_device: hid_destroy_device(session->hid); session->hid = NULL; - atomic_inc(&session->terminate); - hidp_schedule(session); + kthread_stop(session->task); unlink: hidp_del_timer(session); @@ -1108,13 +1109,7 @@ int hidp_del_connection(struct hidp_conndel_req *req) skb_queue_purge(&session->ctrl_transmit); skb_queue_purge(&session->intr_transmit); - /* Wakeup user-space polling for socket errors */ - session->intr_sock->sk->sk_err = EUNATCH; - session->ctrl_sock->sk->sk_err = EUNATCH; - - /* Kill session thread */ - atomic_inc(&session->terminate); - hidp_schedule(session); + kthread_stop(session->task); } } else err = -ENOENT; diff --git a/net/bluetooth/hidp/hidp.h b/net/bluetooth/hidp/hidp.h index b412e7152eec..12822cde4b49 100644 --- a/net/bluetooth/hidp/hidp.h +++ b/net/bluetooth/hidp/hidp.h @@ -142,7 +142,7 @@ struct hidp_session { uint ctrl_mtu; uint intr_mtu; - atomic_t terminate; + struct task_struct *task; unsigned char keys[8]; unsigned char leds; -- cgit v1.2.3 From f4d7cd4a4c25cb4a5c30a675d4cc0052c93b925a Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Mon, 21 Mar 2011 14:20:00 +0100 Subject: Bluetooth: Use kthread API in bnep kernel_thread() is a low-level implementation detail and EXPORT_SYMBOL(kernel_thread) is scheduled for removal. Use the API instead. Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan --- net/bluetooth/bnep/bnep.h | 2 +- net/bluetooth/bnep/core.c | 21 ++++++++------------- 2 files changed, 9 insertions(+), 14 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/bnep/bnep.h b/net/bluetooth/bnep/bnep.h index d768e0434ed8..8e6c06158f8e 100644 --- a/net/bluetooth/bnep/bnep.h +++ b/net/bluetooth/bnep/bnep.h @@ -155,7 +155,7 @@ struct bnep_session { unsigned int role; unsigned long state; unsigned long flags; - atomic_t killed; + struct task_struct *task; struct ethhdr eh; struct msghdr msg; diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index 0a2e76bde542..ca39fcf010ce 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -479,12 +480,11 @@ static int bnep_session(void *arg) BT_DBG(""); - daemonize("kbnepd %s", dev->name); set_user_nice(current, -15); init_waitqueue_entry(&wait, current); add_wait_queue(sk_sleep(sk), &wait); - while (!atomic_read(&s->killed)) { + while (!kthread_should_stop()) { set_current_state(TASK_INTERRUPTIBLE); /* RX */ @@ -611,11 +611,12 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) __bnep_link_session(s); - err = kernel_thread(bnep_session, s, CLONE_KERNEL); - if (err < 0) { + s->task = kthread_run(bnep_session, s, "kbnepd %s", dev->name); + if (IS_ERR(s->task)) { /* Session thread start failed, gotta cleanup. */ unregister_netdev(dev); __bnep_unlink_session(s); + err = PTR_ERR(s->task); goto failed; } @@ -639,15 +640,9 @@ int bnep_del_connection(struct bnep_conndel_req *req) down_read(&bnep_session_sem); s = __bnep_get_session(req->dst); - if (s) { - /* Wakeup user-space which is polling for socket errors. - * This is temporary hack until we have shutdown in L2CAP */ - s->sock->sk->sk_err = EUNATCH; - - /* Kill session thread */ - atomic_inc(&s->killed); - wake_up_interruptible(sk_sleep(s->sock->sk)); - } else + if (s) + kthread_stop(s->task); + else err = -ENOENT; up_read(&bnep_session_sem); -- cgit v1.2.3 From fada4ac33992b1f953d95584e36f6ca7860aea40 Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Mon, 21 Mar 2011 14:20:06 +0100 Subject: Bluetooth: Use kthread API in cmtp kernel_thread() is a low-level implementation detail and EXPORT_SYMBOL(kernel_thread) is scheduled for removal. Use the API instead. Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan --- net/bluetooth/cmtp/capi.c | 6 +++--- net/bluetooth/cmtp/cmtp.h | 9 +-------- net/bluetooth/cmtp/core.c | 16 +++++++++------- 3 files changed, 13 insertions(+), 18 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c index 67cff810c77d..744233cba244 100644 --- a/net/bluetooth/cmtp/capi.c +++ b/net/bluetooth/cmtp/capi.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -143,7 +144,7 @@ static void cmtp_send_capimsg(struct cmtp_session *session, struct sk_buff *skb) skb_queue_tail(&session->transmit, skb); - cmtp_schedule(session); + wake_up_interruptible(sk_sleep(session->sock->sk)); } static void cmtp_send_interopmsg(struct cmtp_session *session, @@ -386,8 +387,7 @@ static void cmtp_reset_ctr(struct capi_ctr *ctrl) capi_ctr_down(ctrl); - atomic_inc(&session->terminate); - cmtp_schedule(session); + kthread_stop(session->task); } static void cmtp_register_appl(struct capi_ctr *ctrl, __u16 appl, capi_register_params *rp) diff --git a/net/bluetooth/cmtp/cmtp.h b/net/bluetooth/cmtp/cmtp.h index c6f78f89415c..db43b54ac9af 100644 --- a/net/bluetooth/cmtp/cmtp.h +++ b/net/bluetooth/cmtp/cmtp.h @@ -81,7 +81,7 @@ struct cmtp_session { char name[BTNAMSIZ]; - atomic_t terminate; + struct task_struct *task; wait_queue_head_t wait; @@ -121,13 +121,6 @@ void cmtp_detach_device(struct cmtp_session *session); void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb); -static inline void cmtp_schedule(struct cmtp_session *session) -{ - struct sock *sk = session->sock->sk; - - wake_up_interruptible(sk_sleep(sk)); -} - /* CMTP init defines */ int cmtp_init_sockets(void); void cmtp_cleanup_sockets(void); diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c index 16aa6bd039ba..cce99b0919f5 100644 --- a/net/bluetooth/cmtp/core.c +++ b/net/bluetooth/cmtp/core.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -287,12 +288,11 @@ static int cmtp_session(void *arg) BT_DBG("session %p", session); - daemonize("kcmtpd_ctr_%d", session->num); set_user_nice(current, -15); init_waitqueue_entry(&wait, current); add_wait_queue(sk_sleep(sk), &wait); - while (!atomic_read(&session->terminate)) { + while (!kthread_should_stop()) { set_current_state(TASK_INTERRUPTIBLE); if (sk->sk_state != BT_CONNECTED) @@ -370,9 +370,12 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock) __cmtp_link_session(session); - err = kernel_thread(cmtp_session, session, CLONE_KERNEL); - if (err < 0) + session->task = kthread_run(cmtp_session, session, "kcmtpd_ctr_%d", + session->num); + if (IS_ERR(session->task)) { + err = PTR_ERR(session->task); goto unlink; + } if (!(session->flags & (1 << CMTP_LOOPBACK))) { err = cmtp_attach_device(session); @@ -409,9 +412,8 @@ int cmtp_del_connection(struct cmtp_conndel_req *req) /* Flush the transmit queue */ skb_queue_purge(&session->transmit); - /* Kill session thread */ - atomic_inc(&session->terminate); - cmtp_schedule(session); + /* Stop session thread */ + kthread_stop(session->task); } else err = -ENOENT; -- cgit v1.2.3 From 1322901da5094cecd9826ec3aaade83f6452cc45 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 4 Apr 2011 19:06:05 -0300 Subject: Bluetooth: Don't use spin_lock_bh in user context spin_lock() and spin_unlock() are more apropiated for user context. Signed-off-by: Gustavo F. Padovan --- net/bluetooth/mgmt.c | 88 ++++++++++++++++++++++++++-------------------------- 1 file changed, 44 insertions(+), 44 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9a61320c5f2e..c32238163b72 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -179,7 +179,7 @@ static int read_controller_info(struct sock *sk, u16 index) hci_del_off_timer(hdev); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); set_bit(HCI_MGMT, &hdev->flags); @@ -208,7 +208,7 @@ static int read_controller_info(struct sock *sk, u16 index) memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name)); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp)); @@ -316,7 +316,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) if (!hdev) return cmd_status(sk, index, MGMT_OP_SET_POWERED, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); up = test_bit(HCI_UP, &hdev->flags); if ((cp->val && up) || (!cp->val && !up)) { @@ -343,7 +343,7 @@ static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len) err = 0; failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; } @@ -368,7 +368,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE, ENETDOWN); @@ -403,7 +403,7 @@ static int set_discoverable(struct sock *sk, u16 index, unsigned char *data, mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -429,7 +429,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE, ENETDOWN); @@ -463,7 +463,7 @@ static int set_connectable(struct sock *sk, u16 index, unsigned char *data, mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -522,7 +522,7 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (cp->val) set_bit(HCI_PAIRABLE, &hdev->flags); @@ -538,7 +538,7 @@ static int set_pairable(struct sock *sk, u16 index, unsigned char *data, err = mgmt_event(MGMT_EV_PAIRABLE, index, &ev, sizeof(ev), sk); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -739,7 +739,7 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) if (!hdev) return cmd_status(sk, index, MGMT_OP_ADD_UUID, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC); if (!uuid) { @@ -763,7 +763,7 @@ static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -788,7 +788,7 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) if (!hdev) return cmd_status(sk, index, MGMT_OP_REMOVE_UUID, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) { err = hci_uuids_clear(hdev); @@ -823,7 +823,7 @@ static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len) err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0); unlock: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -847,7 +847,7 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); hdev->major_class = cp->major; hdev->minor_class = cp->minor; @@ -857,7 +857,7 @@ static int set_dev_class(struct sock *sk, u16 index, unsigned char *data, if (err == 0) err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -879,7 +879,7 @@ static int set_service_cache(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); BT_DBG("hci%u enable %d", index, cp->enable); @@ -897,7 +897,7 @@ static int set_service_cache(struct sock *sk, u16 index, unsigned char *data, err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL, 0); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -931,7 +931,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len) BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys, key_count); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); hci_link_keys_clear(hdev); @@ -949,7 +949,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len) key->pin_len); } - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return 0; @@ -971,7 +971,7 @@ static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len) if (!hdev) return cmd_status(sk, index, MGMT_OP_REMOVE_KEY, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); err = hci_remove_link_key(hdev, &cp->bdaddr); if (err < 0) { @@ -994,7 +994,7 @@ static int remove_key(struct sock *sk, u16 index, unsigned char *data, u16 len) } unlock: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1020,7 +1020,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len) if (!hdev) return cmd_status(sk, index, MGMT_OP_DISCONNECT, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENETDOWN); @@ -1052,7 +1052,7 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len) mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1073,7 +1073,7 @@ static int get_connections(struct sock *sk, u16 index) if (!hdev) return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); count = 0; list_for_each(p, &hdev->conn_hash.list) { @@ -1104,7 +1104,7 @@ static int get_connections(struct sock *sk, u16 index) unlock: kfree(rp); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; } @@ -1129,7 +1129,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY, ENETDOWN); @@ -1151,7 +1151,7 @@ static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data, mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1178,7 +1178,7 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY, @@ -1199,7 +1199,7 @@ static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data, mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1222,14 +1222,14 @@ static int set_io_capability(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); hdev->io_capability = cp->io_capability; BT_DBG("%s IO capability set to 0x%02x", hdev->name, hdev->io_capability); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0); @@ -1315,7 +1315,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) if (!hdev) return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (cp->io_cap == 0x03) { sec_level = BT_SECURITY_MEDIUM; @@ -1357,7 +1357,7 @@ static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len) err = 0; unlock: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1389,7 +1389,7 @@ static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, mgmt_op, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, mgmt_op, ENETDOWN); @@ -1407,7 +1407,7 @@ static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data, mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1431,7 +1431,7 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data, if (!hdev) return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, index, data, len); if (!cmd) { @@ -1446,7 +1446,7 @@ static int set_local_name(struct sock *sk, u16 index, unsigned char *data, mgmt_pending_remove(cmd); failed: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1465,7 +1465,7 @@ static int read_local_oob_data(struct sock *sk, u16 index) return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); if (!test_bit(HCI_UP, &hdev->flags)) { err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA, @@ -1495,7 +1495,7 @@ static int read_local_oob_data(struct sock *sk, u16 index) mgmt_pending_remove(cmd); unlock: - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1519,7 +1519,7 @@ static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data, return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash, cp->randomizer); @@ -1529,7 +1529,7 @@ static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data, err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL, 0); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; @@ -1553,7 +1553,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, ENODEV); - hci_dev_lock_bh(hdev); + hci_dev_lock(hdev); err = hci_remove_remote_oob_data(hdev, &cp->bdaddr); if (err < 0) @@ -1563,7 +1563,7 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, NULL, 0); - hci_dev_unlock_bh(hdev); + hci_dev_unlock(hdev); hci_dev_put(hdev); return err; -- cgit v1.2.3 From e63a15ec0f25c0f97e8f6247b97ac9b30968b6b3 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 4 Apr 2011 18:56:53 -0300 Subject: Bluetooth: Use GFP_KERNEL in user context The allocation in mgmt_control() code are in user context and not locked by any spinlock, so it's not recommended the use of GFP_ATOMIC there. Signed-off-by: Gustavo F. Padovan --- net/bluetooth/mgmt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c32238163b72..c304688252b8 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1581,7 +1581,7 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) if (msglen < sizeof(*hdr)) return -EINVAL; - buf = kmalloc(msglen, GFP_ATOMIC); + buf = kmalloc(msglen, GFP_KERNEL); if (!buf) return -ENOMEM; -- cgit v1.2.3 From db940cb0db7c69a217661ecd49e1e6b0d680a6cc Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Sat, 2 Apr 2011 14:19:41 +0300 Subject: Bluetooth: convert net/bluetooth/ to kstrtox Convert from strict_strto*() interfaces to kstrto*() interfaces. Signed-off-by: Alexey Dobriyan Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_sysfs.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index e54421693eb8..8775933ea837 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -277,10 +277,12 @@ static ssize_t show_idle_timeout(struct device *dev, struct device_attribute *at static ssize_t store_idle_timeout(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct hci_dev *hdev = dev_get_drvdata(dev); - unsigned long val; + unsigned int val; + int rv; - if (strict_strtoul(buf, 0, &val) < 0) - return -EINVAL; + rv = kstrtouint(buf, 0, &val); + if (rv < 0) + return rv; if (val != 0 && (val < 500 || val > 3600000)) return -EINVAL; @@ -299,15 +301,14 @@ static ssize_t show_sniff_max_interval(struct device *dev, struct device_attribu static ssize_t store_sniff_max_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct hci_dev *hdev = dev_get_drvdata(dev); - unsigned long val; - - if (strict_strtoul(buf, 0, &val) < 0) - return -EINVAL; + u16 val; + int rv; - if (val < 0x0002 || val > 0xFFFE || val % 2) - return -EINVAL; + rv = kstrtou16(buf, 0, &val); + if (rv < 0) + return rv; - if (val < hdev->sniff_min_interval) + if (val == 0 || val % 2 || val < hdev->sniff_min_interval) return -EINVAL; hdev->sniff_max_interval = val; @@ -324,15 +325,14 @@ static ssize_t show_sniff_min_interval(struct device *dev, struct device_attribu static ssize_t store_sniff_min_interval(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct hci_dev *hdev = dev_get_drvdata(dev); - unsigned long val; + u16 val; + int rv; - if (strict_strtoul(buf, 0, &val) < 0) - return -EINVAL; - - if (val < 0x0002 || val > 0xFFFE || val % 2) - return -EINVAL; + rv = kstrtou16(buf, 0, &val); + if (rv < 0) + return rv; - if (val > hdev->sniff_max_interval) + if (val == 0 || val % 2 || val > hdev->sniff_max_interval) return -EINVAL; hdev->sniff_min_interval = val; -- cgit v1.2.3 From 48454079c2d4b9ee65c570a22c5fdfe1827996a4 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 25 Mar 2011 00:22:30 -0300 Subject: Bluetooth: Create struct l2cap_chan struct l2cap_chan cames to create a clear separation between what properties and data belongs to the L2CAP channel and what belongs to the socket. By now we just fold the struct sock * in struct l2cap_chan as all the channel info is struct l2cap_pinfo today. In the next commits we will see a move of channel stuff to struct l2cap_chan. Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 18 ++- net/bluetooth/l2cap_core.c | 247 +++++++++++++++++++++++++++--------------- net/bluetooth/l2cap_sock.c | 6 +- 3 files changed, 175 insertions(+), 96 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 2b9ca0d5c4a0..6378bcc94e2b 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -276,9 +276,16 @@ struct l2cap_conn_param_update_rsp { #define L2CAP_CONN_PARAM_ACCEPTED 0x0000 #define L2CAP_CONN_PARAM_REJECTED 0x0001 -/* ----- L2CAP connections ----- */ +/* ----- L2CAP channels and connections ----- */ + +struct l2cap_chan { + struct sock *sk; + struct l2cap_chan *next_c; + struct l2cap_chan *prev_c; +}; + struct l2cap_chan_list { - struct sock *head; + struct l2cap_chan *head; rwlock_t lock; }; @@ -317,7 +324,7 @@ struct sock_del_list { #define L2CAP_INFO_FEAT_MASK_REQ_SENT 0x04 #define L2CAP_INFO_FEAT_MASK_REQ_DONE 0x08 -/* ----- L2CAP channel and socket info ----- */ +/* ----- L2CAP socket info ----- */ #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk) #define TX_QUEUE(sk) (&l2cap_pi(sk)->tx_queue) #define SREJ_QUEUE(sk) (&l2cap_pi(sk)->srej_queue) @@ -389,8 +396,7 @@ struct l2cap_pinfo { struct work_struct busy_work; struct srej_list srej_l; struct l2cap_conn *conn; - struct sock *next_c; - struct sock *prev_c; + struct l2cap_chan *chan; }; #define L2CAP_CONF_REQ_SENT 0x01 @@ -471,7 +477,7 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent); struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio); void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err); -void l2cap_chan_del(struct sock *sk, int err); +void l2cap_chan_del(struct l2cap_chan *chan, int err); int l2cap_do_connect(struct sock *sk); #endif /* __L2CAP_H */ diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index c3cebed205cc..e49d8f7b80a5 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -74,58 +74,58 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb); /* ---- L2CAP channels ---- */ -static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid) +static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid) { - struct sock *s; - for (s = l->head; s; s = l2cap_pi(s)->next_c) { - if (l2cap_pi(s)->dcid == cid) + struct l2cap_chan *c; + for (c = l->head; c; c = c->next_c) { + if (l2cap_pi(c->sk)->dcid == cid) break; } - return s; + return c; } -static struct sock *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid) +static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid) { - struct sock *s; - for (s = l->head; s; s = l2cap_pi(s)->next_c) { - if (l2cap_pi(s)->scid == cid) + struct l2cap_chan *c; + for (c = l->head; c; c = c->next_c) { + if (l2cap_pi(c->sk)->scid == cid) break; } - return s; + return c; } /* Find channel with given SCID. * Returns locked socket */ -static inline struct sock *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid) +static inline struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid) { - struct sock *s; + struct l2cap_chan *c; read_lock(&l->lock); - s = __l2cap_get_chan_by_scid(l, cid); - if (s) - bh_lock_sock(s); + c = __l2cap_get_chan_by_scid(l, cid); + if (c) + bh_lock_sock(c->sk); read_unlock(&l->lock); - return s; + return c; } -static struct sock *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident) +static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident) { - struct sock *s; - for (s = l->head; s; s = l2cap_pi(s)->next_c) { - if (l2cap_pi(s)->ident == ident) + struct l2cap_chan *c; + for (c = l->head; c; c = c->next_c) { + if (l2cap_pi(c->sk)->ident == ident) break; } - return s; + return c; } -static inline struct sock *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident) +static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident) { - struct sock *s; + struct l2cap_chan *c; read_lock(&l->lock); - s = __l2cap_get_chan_by_ident(l, ident); - if (s) - bh_lock_sock(s); + c = __l2cap_get_chan_by_ident(l, ident); + if (c) + bh_lock_sock(c->sk); read_unlock(&l->lock); - return s; + return c; } static u16 l2cap_alloc_cid(struct l2cap_chan_list *l) @@ -140,38 +140,52 @@ static u16 l2cap_alloc_cid(struct l2cap_chan_list *l) return 0; } -static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct sock *sk) +static struct l2cap_chan *l2cap_chan_alloc(struct sock *sk) +{ + struct l2cap_chan *chan; + + chan = kzalloc(sizeof(*chan), GFP_ATOMIC); + if (!chan) + return NULL; + + chan->sk = sk; + + return chan; +} + +static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct l2cap_chan *chan) { - sock_hold(sk); + sock_hold(chan->sk); if (l->head) - l2cap_pi(l->head)->prev_c = sk; + l->head->prev_c = chan; - l2cap_pi(sk)->next_c = l->head; - l2cap_pi(sk)->prev_c = NULL; - l->head = sk; + chan->next_c = l->head; + chan->prev_c = NULL; + l->head = chan; } -static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct sock *sk) +static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct l2cap_chan *chan) { - struct sock *next = l2cap_pi(sk)->next_c, *prev = l2cap_pi(sk)->prev_c; + struct l2cap_chan *next = chan->next_c, *prev = chan->prev_c; write_lock_bh(&l->lock); - if (sk == l->head) + if (chan == l->head) l->head = next; if (next) - l2cap_pi(next)->prev_c = prev; + next->prev_c = prev; if (prev) - l2cap_pi(prev)->next_c = next; + prev->next_c = next; write_unlock_bh(&l->lock); - __sock_put(sk); + __sock_put(chan->sk); } -static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk) +static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { struct l2cap_chan_list *l = &conn->chan_list; + struct sock *sk = chan->sk; BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid); @@ -203,13 +217,14 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk) l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; } - __l2cap_chan_link(l, sk); + __l2cap_chan_link(l, chan); } /* Delete channel. * Must be called on the locked socket. */ -void l2cap_chan_del(struct sock *sk, int err) +void l2cap_chan_del(struct l2cap_chan *chan, int err) { + struct sock *sk = chan->sk; struct l2cap_conn *conn = l2cap_pi(sk)->conn; struct sock *parent = bt_sk(sk)->parent; @@ -219,7 +234,7 @@ void l2cap_chan_del(struct sock *sk, int err) if (conn) { /* Unlink from channel list */ - l2cap_chan_unlink(&conn->chan_list, sk); + l2cap_chan_unlink(&conn->chan_list, chan); l2cap_pi(sk)->conn = NULL; hci_conn_put(conn->hcon); } @@ -253,6 +268,8 @@ void l2cap_chan_del(struct sock *sk, int err) kfree(l); } } + + kfree(chan); } static inline u8 l2cap_get_auth_type(struct sock *sk) @@ -487,7 +504,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) { struct l2cap_chan_list *l = &conn->chan_list; struct sock_del_list del, *tmp1, *tmp2; - struct sock *sk; + struct l2cap_chan *chan; BT_DBG("conn %p", conn); @@ -495,7 +512,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn) read_lock(&l->lock); - for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { + for (chan = l->head; chan; chan = chan->next_c) { + struct sock *sk = chan->sk; bh_lock_sock(sk); if (sk->sk_type != SOCK_SEQPACKET && @@ -622,6 +640,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) { struct l2cap_chan_list *list = &conn->chan_list; struct sock *parent, *uninitialized_var(sk); + struct l2cap_chan *chan; BT_DBG(""); @@ -641,6 +660,12 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) if (!sk) goto clean; + chan = l2cap_chan_alloc(sk); + if (!chan) { + l2cap_sock_kill(sk); + goto clean; + } + write_lock_bh(&list->lock); hci_conn_hold(conn->hcon); @@ -651,7 +676,9 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) bt_accept_enqueue(parent, sk); - __l2cap_chan_add(conn, sk); + __l2cap_chan_add(conn, chan); + + l2cap_pi(sk)->chan = chan; l2cap_sock_set_timer(sk, sk->sk_sndtimeo); @@ -667,7 +694,7 @@ clean: static void l2cap_conn_ready(struct l2cap_conn *conn) { struct l2cap_chan_list *l = &conn->chan_list; - struct sock *sk; + struct l2cap_chan *chan; BT_DBG("conn %p", conn); @@ -676,7 +703,8 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) read_lock(&l->lock); - for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { + for (chan = l->head; chan; chan = chan->next_c) { + struct sock *sk = chan->sk; bh_lock_sock(sk); if (conn->hcon->type == LE_LINK) { @@ -703,13 +731,14 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) { struct l2cap_chan_list *l = &conn->chan_list; - struct sock *sk; + struct l2cap_chan *chan; BT_DBG("conn %p", conn); read_lock(&l->lock); - for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { + for (chan = l->head; chan; chan = chan->next_c) { + struct sock *sk = chan->sk; if (l2cap_pi(sk)->force_reliable) sk->sk_err = err; } @@ -768,6 +797,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) static void l2cap_conn_del(struct hci_conn *hcon, int err) { struct l2cap_conn *conn = hcon->l2cap_data; + struct l2cap_chan *chan; struct sock *sk; if (!conn) @@ -778,9 +808,10 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) kfree_skb(conn->rx_skb); /* Kill channels */ - while ((sk = conn->chan_list.head)) { + while ((chan = conn->chan_list.head)) { + sk = chan->sk; bh_lock_sock(sk); - l2cap_chan_del(sk, err); + l2cap_chan_del(chan, err); bh_unlock_sock(sk); l2cap_sock_kill(sk); } @@ -792,11 +823,11 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) kfree(conn); } -static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk) +static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { struct l2cap_chan_list *l = &conn->chan_list; write_lock_bh(&l->lock); - __l2cap_chan_add(conn, sk); + __l2cap_chan_add(conn, chan); write_unlock_bh(&l->lock); } @@ -837,6 +868,7 @@ int l2cap_do_connect(struct sock *sk) bdaddr_t *src = &bt_sk(sk)->src; bdaddr_t *dst = &bt_sk(sk)->dst; struct l2cap_conn *conn; + struct l2cap_chan *chan; struct hci_conn *hcon; struct hci_dev *hdev; __u8 auth_type; @@ -872,10 +904,19 @@ int l2cap_do_connect(struct sock *sk) goto done; } + chan = l2cap_chan_alloc(sk); + if (!chan) { + hci_conn_put(hcon); + err = -ENOMEM; + goto done; + } + /* Update source addr of the socket */ bacpy(src, conn->src); - l2cap_chan_add(conn, sk); + l2cap_chan_add(conn, chan); + + l2cap_pi(sk)->chan = chan; sk->sk_state = BT_CONNECT; l2cap_sock_set_timer(sk, sk->sk_sndtimeo); @@ -1387,12 +1428,13 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) { struct l2cap_chan_list *l = &conn->chan_list; struct sk_buff *nskb; - struct sock *sk; + struct l2cap_chan *chan; BT_DBG("conn %p", conn); read_lock(&l->lock); - for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { + for (chan = l->head; chan; chan = chan->next_c) { + struct sock *sk = chan->sk; if (sk->sk_type != SOCK_RAW) continue; @@ -1976,6 +2018,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd struct l2cap_chan_list *list = &conn->chan_list; struct l2cap_conn_req *req = (struct l2cap_conn_req *) data; struct l2cap_conn_rsp rsp; + struct l2cap_chan *chan; struct sock *parent, *sk = NULL; int result, status = L2CAP_CS_NO_INFO; @@ -2013,6 +2056,12 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd if (!sk) goto response; + chan = l2cap_chan_alloc(sk); + if (!chan) { + l2cap_sock_kill(sk); + goto response; + } + write_lock_bh(&list->lock); /* Check if we already have channel with that dcid */ @@ -2033,7 +2082,10 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd bt_accept_enqueue(parent, sk); - __l2cap_chan_add(conn, sk); + __l2cap_chan_add(conn, chan); + + l2cap_pi(sk)->chan = chan; + dcid = l2cap_pi(sk)->scid; l2cap_sock_set_timer(sk, sk->sk_sndtimeo); @@ -2105,6 +2157,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd { struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data; u16 scid, dcid, result, status; + struct l2cap_chan *chan; struct sock *sk; u8 req[128]; @@ -2116,15 +2169,17 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status); if (scid) { - sk = l2cap_get_chan_by_scid(&conn->chan_list, scid); - if (!sk) + chan = l2cap_get_chan_by_scid(&conn->chan_list, scid); + if (!chan) return -EFAULT; } else { - sk = l2cap_get_chan_by_ident(&conn->chan_list, cmd->ident); - if (!sk) + chan = l2cap_get_chan_by_ident(&conn->chan_list, cmd->ident); + if (!chan) return -EFAULT; } + sk = chan->sk; + switch (result) { case L2CAP_CR_SUCCESS: sk->sk_state = BT_CONFIG; @@ -2155,7 +2210,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd break; } - l2cap_chan_del(sk, ECONNREFUSED); + l2cap_chan_del(chan, ECONNREFUSED); break; } @@ -2179,6 +2234,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr struct l2cap_conf_req *req = (struct l2cap_conf_req *) data; u16 dcid, flags; u8 rsp[64]; + struct l2cap_chan *chan; struct sock *sk; int len; @@ -2187,10 +2243,12 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags); - sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid); - if (!sk) + chan = l2cap_get_chan_by_scid(&conn->chan_list, dcid); + if (!chan) return -ENOENT; + sk = chan->sk; + if (sk->sk_state != BT_CONFIG) { struct l2cap_cmd_rej rej; @@ -2269,6 +2327,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr { struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data; u16 scid, flags, result; + struct l2cap_chan *chan; struct sock *sk; int len = cmd->len - sizeof(*rsp); @@ -2279,10 +2338,12 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result); - sk = l2cap_get_chan_by_scid(&conn->chan_list, scid); - if (!sk) + chan = l2cap_get_chan_by_scid(&conn->chan_list, scid); + if (!chan) return 0; + sk = chan->sk; + switch (result) { case L2CAP_CONF_SUCCESS: l2cap_conf_rfc_get(sk, rsp->data, len); @@ -2349,6 +2410,7 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data; struct l2cap_disconn_rsp rsp; u16 dcid, scid; + struct l2cap_chan *chan; struct sock *sk; scid = __le16_to_cpu(req->scid); @@ -2356,10 +2418,12 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid); - sk = l2cap_get_chan_by_scid(&conn->chan_list, dcid); - if (!sk) + chan = l2cap_get_chan_by_scid(&conn->chan_list, dcid); + if (!chan) return 0; + sk = chan->sk; + rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp); @@ -2375,7 +2439,7 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd return 0; } - l2cap_chan_del(sk, ECONNRESET); + l2cap_chan_del(chan, ECONNRESET); bh_unlock_sock(sk); l2cap_sock_kill(sk); @@ -2386,6 +2450,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd { struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data; u16 dcid, scid; + struct l2cap_chan *chan; struct sock *sk; scid = __le16_to_cpu(rsp->scid); @@ -2393,10 +2458,12 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid); - sk = l2cap_get_chan_by_scid(&conn->chan_list, scid); - if (!sk) + chan = l2cap_get_chan_by_scid(&conn->chan_list, scid); + if (!chan) return 0; + sk = chan->sk; + /* don't delete l2cap channel if sk is owned by user */ if (sock_owned_by_user(sk)) { sk->sk_state = BT_DISCONN; @@ -2406,7 +2473,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd return 0; } - l2cap_chan_del(sk, 0); + l2cap_chan_del(chan, 0); bh_unlock_sock(sk); l2cap_sock_kill(sk); @@ -3538,18 +3605,20 @@ drop: static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb) { + struct l2cap_chan *chan; struct sock *sk; struct l2cap_pinfo *pi; u16 control; u8 tx_seq; int len; - sk = l2cap_get_chan_by_scid(&conn->chan_list, cid); - if (!sk) { + chan = l2cap_get_chan_by_scid(&conn->chan_list, cid); + if (!chan) { BT_DBG("unknown cid 0x%4.4x", cid); goto drop; } + sk = chan->sk; pi = l2cap_pi(sk); BT_DBG("sk %p, len %d", sk, skb->len); @@ -3788,7 +3857,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) { struct l2cap_chan_list *l; struct l2cap_conn *conn = hcon->l2cap_data; - struct sock *sk; + struct l2cap_chan *chan; if (!conn) return 0; @@ -3799,7 +3868,8 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) read_lock(&l->lock); - for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { + for (chan = l->head; chan; chan = chan->next_c) { + struct sock *sk = chan->sk; bh_lock_sock(sk); if (l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND) { @@ -3872,7 +3942,7 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl if (!(flags & ACL_CONT)) { struct l2cap_hdr *hdr; - struct sock *sk; + struct l2cap_chan *chan; u16 cid; int len; @@ -3910,18 +3980,21 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl goto drop; } - sk = l2cap_get_chan_by_scid(&conn->chan_list, cid); + chan = l2cap_get_chan_by_scid(&conn->chan_list, cid); - if (sk && l2cap_pi(sk)->imtu < len - L2CAP_HDR_SIZE) { - BT_ERR("Frame exceeding recv MTU (len %d, MTU %d)", - len, l2cap_pi(sk)->imtu); - bh_unlock_sock(sk); - l2cap_conn_unreliable(conn, ECOMM); - goto drop; - } + if (chan && chan->sk) { + struct sock *sk = chan->sk; - if (sk) + if (l2cap_pi(sk)->imtu < len - L2CAP_HDR_SIZE) { + BT_ERR("Frame exceeding recv MTU (len %d, " + "MTU %d)", len, + l2cap_pi(sk)->imtu); + bh_unlock_sock(sk); + l2cap_conn_unreliable(conn, ECOMM); + goto drop; + } bh_unlock_sock(sk); + } /* Allocate skb for the complete frame (with header) */ conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index f77308e63e58..7df81181a119 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -902,7 +902,7 @@ void __l2cap_sock_close(struct sock *sk, int reason) l2cap_sock_set_timer(sk, sk->sk_sndtimeo); l2cap_send_disconn_req(conn, sk, reason); } else - l2cap_chan_del(sk, reason); + l2cap_chan_del(l2cap_pi(sk)->chan, reason); break; case BT_CONNECT2: @@ -925,12 +925,12 @@ void __l2cap_sock_close(struct sock *sk, int reason) L2CAP_CONN_RSP, sizeof(rsp), &rsp); } - l2cap_chan_del(sk, reason); + l2cap_chan_del(l2cap_pi(sk)->chan, reason); break; case BT_CONNECT: case BT_DISCONN: - l2cap_chan_del(sk, reason); + l2cap_chan_del(l2cap_pi(sk)->chan, reason); break; default: -- cgit v1.2.3 From baa7e1fa6d2870462bd744df1c6ddbd497fe86d6 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 31 Mar 2011 16:17:41 -0300 Subject: Bluetooth: Use struct list_head for L2CAP channels list Use a well known Kernel API is always a good idea than implement your own list. In the future we might use RCU on this list. Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 12 +-- net/bluetooth/l2cap_core.c | 188 +++++++++++++++++++----------------------- 2 files changed, 88 insertions(+), 112 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 6378bcc94e2b..ddf4bc56a5b5 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -277,16 +277,9 @@ struct l2cap_conn_param_update_rsp { #define L2CAP_CONN_PARAM_REJECTED 0x0001 /* ----- L2CAP channels and connections ----- */ - struct l2cap_chan { struct sock *sk; - struct l2cap_chan *next_c; - struct l2cap_chan *prev_c; -}; - -struct l2cap_chan_list { - struct l2cap_chan *head; - rwlock_t lock; + struct list_head list; }; struct l2cap_conn { @@ -312,7 +305,8 @@ struct l2cap_conn { __u8 disc_reason; - struct l2cap_chan_list chan_list; + struct list_head chan_l; + rwlock_t chan_lock; }; struct sock_del_list { diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index e49d8f7b80a5..0dbbaf394c13 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -74,66 +74,75 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb); /* ---- L2CAP channels ---- */ -static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid) +static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid) { struct l2cap_chan *c; - for (c = l->head; c; c = c->next_c) { - if (l2cap_pi(c->sk)->dcid == cid) - break; + + list_for_each_entry(c, &conn->chan_l, list) { + struct sock *s = c->sk; + if (l2cap_pi(s)->dcid == cid) + return c; } - return c; + return NULL; + } -static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid) +static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) { struct l2cap_chan *c; - for (c = l->head; c; c = c->next_c) { - if (l2cap_pi(c->sk)->scid == cid) - break; + + list_for_each_entry(c, &conn->chan_l, list) { + struct sock *s = c->sk; + if (l2cap_pi(s)->scid == cid) + return c; } - return c; + return NULL; } /* Find channel with given SCID. * Returns locked socket */ -static inline struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_chan_list *l, u16 cid) +static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid) { struct l2cap_chan *c; - read_lock(&l->lock); - c = __l2cap_get_chan_by_scid(l, cid); + + read_lock(&conn->chan_lock); + c = __l2cap_get_chan_by_scid(conn, cid); if (c) bh_lock_sock(c->sk); - read_unlock(&l->lock); + read_unlock(&conn->chan_lock); return c; } -static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident) +static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident) { struct l2cap_chan *c; - for (c = l->head; c; c = c->next_c) { - if (l2cap_pi(c->sk)->ident == ident) - break; + + list_for_each_entry(c, &conn->chan_l, list) { + struct sock *s = c->sk; + if (l2cap_pi(s)->ident == ident) + return c; } - return c; + return NULL; } -static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_chan_list *l, u8 ident) +static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident) { struct l2cap_chan *c; - read_lock(&l->lock); - c = __l2cap_get_chan_by_ident(l, ident); + + read_lock(&conn->chan_lock); + c = __l2cap_get_chan_by_ident(conn, ident); if (c) bh_lock_sock(c->sk); - read_unlock(&l->lock); + read_unlock(&conn->chan_lock); return c; } -static u16 l2cap_alloc_cid(struct l2cap_chan_list *l) +static u16 l2cap_alloc_cid(struct l2cap_conn *conn) { u16 cid = L2CAP_CID_DYN_START; for (; cid < L2CAP_CID_DYN_END; cid++) { - if (!__l2cap_get_chan_by_scid(l, cid)) + if (!__l2cap_get_chan_by_scid(conn, cid)) return cid; } @@ -153,38 +162,8 @@ static struct l2cap_chan *l2cap_chan_alloc(struct sock *sk) return chan; } -static inline void __l2cap_chan_link(struct l2cap_chan_list *l, struct l2cap_chan *chan) -{ - sock_hold(chan->sk); - - if (l->head) - l->head->prev_c = chan; - - chan->next_c = l->head; - chan->prev_c = NULL; - l->head = chan; -} - -static inline void l2cap_chan_unlink(struct l2cap_chan_list *l, struct l2cap_chan *chan) -{ - struct l2cap_chan *next = chan->next_c, *prev = chan->prev_c; - - write_lock_bh(&l->lock); - if (chan == l->head) - l->head = next; - - if (next) - next->prev_c = prev; - if (prev) - prev->next_c = next; - write_unlock_bh(&l->lock); - - __sock_put(chan->sk); -} - static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { - struct l2cap_chan_list *l = &conn->chan_list; struct sock *sk = chan->sk; BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, @@ -202,7 +181,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) l2cap_pi(sk)->dcid = L2CAP_CID_LE_DATA; } else { /* Alloc CID for connection-oriented socket */ - l2cap_pi(sk)->scid = l2cap_alloc_cid(l); + l2cap_pi(sk)->scid = l2cap_alloc_cid(conn); l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; } } else if (sk->sk_type == SOCK_DGRAM) { @@ -217,7 +196,9 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; } - __l2cap_chan_link(l, chan); + sock_hold(sk); + + list_add(&chan->list, &conn->chan_l); } /* Delete channel. @@ -233,8 +214,12 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) BT_DBG("sk %p, conn %p, err %d", sk, conn, err); if (conn) { - /* Unlink from channel list */ - l2cap_chan_unlink(&conn->chan_list, chan); + /* Delete from channel list */ + write_lock_bh(&conn->chan_lock); + list_del(&chan->list); + write_unlock_bh(&conn->chan_lock); + __sock_put(sk); + l2cap_pi(sk)->conn = NULL; hci_conn_put(conn->hcon); } @@ -502,7 +487,6 @@ void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err) /* ---- L2CAP connections ---- */ static void l2cap_conn_start(struct l2cap_conn *conn) { - struct l2cap_chan_list *l = &conn->chan_list; struct sock_del_list del, *tmp1, *tmp2; struct l2cap_chan *chan; @@ -510,10 +494,11 @@ static void l2cap_conn_start(struct l2cap_conn *conn) INIT_LIST_HEAD(&del.list); - read_lock(&l->lock); + read_lock(&conn->chan_lock); - for (chan = l->head; chan; chan = chan->next_c) { + list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; + bh_lock_sock(sk); if (sk->sk_type != SOCK_SEQPACKET && @@ -593,7 +578,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) bh_unlock_sock(sk); } - read_unlock(&l->lock); + read_unlock(&conn->chan_lock); list_for_each_entry_safe(tmp1, tmp2, &del.list, list) { bh_lock_sock(tmp1->sk); @@ -638,7 +623,6 @@ static struct sock *l2cap_get_sock_by_scid(int state, __le16 cid, bdaddr_t *src) static void l2cap_le_conn_ready(struct l2cap_conn *conn) { - struct l2cap_chan_list *list = &conn->chan_list; struct sock *parent, *uninitialized_var(sk); struct l2cap_chan *chan; @@ -666,11 +650,12 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) goto clean; } - write_lock_bh(&list->lock); + write_lock_bh(&conn->chan_lock); hci_conn_hold(conn->hcon); l2cap_sock_init(sk, parent); + bacpy(&bt_sk(sk)->src, conn->src); bacpy(&bt_sk(sk)->dst, conn->dst); @@ -685,7 +670,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) sk->sk_state = BT_CONNECTED; parent->sk_data_ready(parent, 0); - write_unlock_bh(&list->lock); + write_unlock_bh(&conn->chan_lock); clean: bh_unlock_sock(parent); @@ -693,7 +678,6 @@ clean: static void l2cap_conn_ready(struct l2cap_conn *conn) { - struct l2cap_chan_list *l = &conn->chan_list; struct l2cap_chan *chan; BT_DBG("conn %p", conn); @@ -701,10 +685,11 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) if (!conn->hcon->out && conn->hcon->type == LE_LINK) l2cap_le_conn_ready(conn); - read_lock(&l->lock); + read_lock(&conn->chan_lock); - for (chan = l->head; chan; chan = chan->next_c) { + list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; + bh_lock_sock(sk); if (conn->hcon->type == LE_LINK) { @@ -724,26 +709,26 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) bh_unlock_sock(sk); } - read_unlock(&l->lock); + read_unlock(&conn->chan_lock); } /* Notify sockets that we cannot guaranty reliability anymore */ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err) { - struct l2cap_chan_list *l = &conn->chan_list; struct l2cap_chan *chan; BT_DBG("conn %p", conn); - read_lock(&l->lock); + read_lock(&conn->chan_lock); - for (chan = l->head; chan; chan = chan->next_c) { + list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; + if (l2cap_pi(sk)->force_reliable) sk->sk_err = err; } - read_unlock(&l->lock); + read_unlock(&conn->chan_lock); } static void l2cap_info_timeout(unsigned long arg) @@ -783,7 +768,9 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) conn->feat_mask = 0; spin_lock_init(&conn->lock); - rwlock_init(&conn->chan_list.lock); + rwlock_init(&conn->chan_lock); + + INIT_LIST_HEAD(&conn->chan_l); if (hcon->type != LE_LINK) setup_timer(&conn->info_timer, l2cap_info_timeout, @@ -797,7 +784,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status) static void l2cap_conn_del(struct hci_conn *hcon, int err) { struct l2cap_conn *conn = hcon->l2cap_data; - struct l2cap_chan *chan; + struct l2cap_chan *chan, *l; struct sock *sk; if (!conn) @@ -808,7 +795,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) kfree_skb(conn->rx_skb); /* Kill channels */ - while ((chan = conn->chan_list.head)) { + list_for_each_entry_safe(chan, l, &conn->chan_l, list) { sk = chan->sk; bh_lock_sock(sk); l2cap_chan_del(chan, err); @@ -825,10 +812,9 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err) static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { - struct l2cap_chan_list *l = &conn->chan_list; - write_lock_bh(&l->lock); + write_lock_bh(&conn->chan_lock); __l2cap_chan_add(conn, chan); - write_unlock_bh(&l->lock); + write_unlock_bh(&conn->chan_lock); } /* ---- Socket interface ---- */ @@ -1426,14 +1412,13 @@ static void l2cap_chan_ready(struct sock *sk) /* Copy frame to all raw sockets on that connection */ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) { - struct l2cap_chan_list *l = &conn->chan_list; struct sk_buff *nskb; struct l2cap_chan *chan; BT_DBG("conn %p", conn); - read_lock(&l->lock); - for (chan = l->head; chan; chan = chan->next_c) { + read_lock(&conn->chan_lock); + list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; if (sk->sk_type != SOCK_RAW) continue; @@ -1448,7 +1433,7 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb) if (sock_queue_rcv_skb(sk, nskb)) kfree_skb(nskb); } - read_unlock(&l->lock); + read_unlock(&conn->chan_lock); } /* ---- L2CAP signalling commands ---- */ @@ -2015,7 +2000,6 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data) { - struct l2cap_chan_list *list = &conn->chan_list; struct l2cap_conn_req *req = (struct l2cap_conn_req *) data; struct l2cap_conn_rsp rsp; struct l2cap_chan *chan; @@ -2062,11 +2046,11 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd goto response; } - write_lock_bh(&list->lock); + write_lock_bh(&conn->chan_lock); /* Check if we already have channel with that dcid */ - if (__l2cap_get_chan_by_dcid(list, scid)) { - write_unlock_bh(&list->lock); + if (__l2cap_get_chan_by_dcid(conn, scid)) { + write_unlock_bh(&conn->chan_lock); sock_set_flag(sk, SOCK_ZAPPED); l2cap_sock_kill(sk); goto response; @@ -2115,7 +2099,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd status = L2CAP_CS_NO_INFO; } - write_unlock_bh(&list->lock); + write_unlock_bh(&conn->chan_lock); response: bh_unlock_sock(parent); @@ -2169,11 +2153,11 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x", dcid, scid, result, status); if (scid) { - chan = l2cap_get_chan_by_scid(&conn->chan_list, scid); + chan = l2cap_get_chan_by_scid(conn, scid); if (!chan) return -EFAULT; } else { - chan = l2cap_get_chan_by_ident(&conn->chan_list, cmd->ident); + chan = l2cap_get_chan_by_ident(conn, cmd->ident); if (!chan) return -EFAULT; } @@ -2243,7 +2227,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr BT_DBG("dcid 0x%4.4x flags 0x%2.2x", dcid, flags); - chan = l2cap_get_chan_by_scid(&conn->chan_list, dcid); + chan = l2cap_get_chan_by_scid(conn, dcid); if (!chan) return -ENOENT; @@ -2338,7 +2322,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr BT_DBG("scid 0x%4.4x flags 0x%2.2x result 0x%2.2x", scid, flags, result); - chan = l2cap_get_chan_by_scid(&conn->chan_list, scid); + chan = l2cap_get_chan_by_scid(conn, scid); if (!chan) return 0; @@ -2418,7 +2402,7 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd BT_DBG("scid 0x%4.4x dcid 0x%4.4x", scid, dcid); - chan = l2cap_get_chan_by_scid(&conn->chan_list, dcid); + chan = l2cap_get_chan_by_scid(conn, dcid); if (!chan) return 0; @@ -2458,7 +2442,7 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd BT_DBG("dcid 0x%4.4x scid 0x%4.4x", dcid, scid); - chan = l2cap_get_chan_by_scid(&conn->chan_list, scid); + chan = l2cap_get_chan_by_scid(conn, scid); if (!chan) return 0; @@ -3612,7 +3596,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk u8 tx_seq; int len; - chan = l2cap_get_chan_by_scid(&conn->chan_list, cid); + chan = l2cap_get_chan_by_scid(conn, cid); if (!chan) { BT_DBG("unknown cid 0x%4.4x", cid); goto drop; @@ -3855,21 +3839,19 @@ static inline void l2cap_check_encryption(struct sock *sk, u8 encrypt) static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) { - struct l2cap_chan_list *l; struct l2cap_conn *conn = hcon->l2cap_data; struct l2cap_chan *chan; if (!conn) return 0; - l = &conn->chan_list; - BT_DBG("conn %p", conn); - read_lock(&l->lock); + read_lock(&conn->chan_lock); - for (chan = l->head; chan; chan = chan->next_c) { + list_for_each_entry(chan, &conn->chan_l, list) { struct sock *sk = chan->sk; + bh_lock_sock(sk); if (l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND) { @@ -3923,7 +3905,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) bh_unlock_sock(sk); } - read_unlock(&l->lock); + read_unlock(&conn->chan_lock); return 0; } @@ -3980,7 +3962,7 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl goto drop; } - chan = l2cap_get_chan_by_scid(&conn->chan_list, cid); + chan = l2cap_get_chan_by_scid(conn, cid); if (chan && chan->sk) { struct sock *sk = chan->sk; -- cgit v1.2.3 From 820ffdb3d25f74fbd553453f461709d52dfa72a2 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 1 Apr 2011 00:35:21 -0300 Subject: Bluetooth: Remove struct del_list As we use struct list_head to keep L2CAP channels list the workaround with del_list is not needed anymore. Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 5 ----- net/bluetooth/l2cap_core.c | 24 +++++++----------------- 2 files changed, 7 insertions(+), 22 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index ddf4bc56a5b5..d24b51c3ff8c 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -309,11 +309,6 @@ struct l2cap_conn { rwlock_t chan_lock; }; -struct sock_del_list { - struct sock *sk; - struct list_head list; -}; - #define L2CAP_INFO_CL_MTU_REQ_SENT 0x01 #define L2CAP_INFO_FEAT_MASK_REQ_SENT 0x04 #define L2CAP_INFO_FEAT_MASK_REQ_DONE 0x08 diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 0dbbaf394c13..b0aaaa9cf00e 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -487,16 +487,13 @@ void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err) /* ---- L2CAP connections ---- */ static void l2cap_conn_start(struct l2cap_conn *conn) { - struct sock_del_list del, *tmp1, *tmp2; - struct l2cap_chan *chan; + struct l2cap_chan *chan, *tmp; BT_DBG("conn %p", conn); - INIT_LIST_HEAD(&del.list); - read_lock(&conn->chan_lock); - list_for_each_entry(chan, &conn->chan_l, list) { + list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) { struct sock *sk = chan->sk; bh_lock_sock(sk); @@ -520,10 +517,11 @@ static void l2cap_conn_start(struct l2cap_conn *conn) conn->feat_mask) && l2cap_pi(sk)->conf_state & L2CAP_CONF_STATE2_DEVICE) { - tmp1 = kzalloc(sizeof(struct sock_del_list), - GFP_ATOMIC); - tmp1->sk = sk; - list_add_tail(&tmp1->list, &del.list); + /* __l2cap_sock_close() calls list_del(chan) + * so release the lock */ + read_unlock_bh(&conn->chan_lock); + __l2cap_sock_close(sk, ECONNRESET); + read_lock_bh(&conn->chan_lock); bh_unlock_sock(sk); continue; } @@ -579,14 +577,6 @@ static void l2cap_conn_start(struct l2cap_conn *conn) } read_unlock(&conn->chan_lock); - - list_for_each_entry_safe(tmp1, tmp2, &del.list, list) { - bh_lock_sock(tmp1->sk); - __l2cap_sock_close(tmp1->sk, ECONNRESET); - bh_unlock_sock(tmp1->sk); - list_del(&tmp1->list); - kfree(tmp1); - } } /* Find socket with cid and source bdaddr. -- cgit v1.2.3 From fc7f8a7ed4543853a99852ca405ea71fabe78946 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 25 Mar 2011 13:59:37 -0300 Subject: Bluetooth: Move ident to struct l2cap_chan ident is chan property, no need to reside on socket. Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 4 ++-- net/bluetooth/l2cap_core.c | 38 +++++++++++++++++++------------------- net/bluetooth/l2cap_sock.c | 4 ++-- 3 files changed, 23 insertions(+), 23 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index d24b51c3ff8c..81829e5c407d 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -279,6 +279,8 @@ struct l2cap_conn_param_update_rsp { /* ----- L2CAP channels and connections ----- */ struct l2cap_chan { struct sock *sk; + __u8 ident; + struct list_head list; }; @@ -363,8 +365,6 @@ struct l2cap_pinfo { __u16 partial_sdu_len; struct sk_buff *sdu; - __u8 ident; - __u8 tx_win; __u8 max_tx; __u8 remote_tx_win; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index b0aaaa9cf00e..6020e1e2f500 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -118,8 +118,7 @@ static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 struct l2cap_chan *c; list_for_each_entry(c, &conn->chan_l, list) { - struct sock *s = c->sk; - if (l2cap_pi(s)->ident == ident) + if (c->ident == ident) return c; } return NULL; @@ -410,8 +409,9 @@ static inline int __l2cap_no_conn_pending(struct sock *sk) return !(l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND); } -static void l2cap_do_start(struct sock *sk) +static void l2cap_do_start(struct l2cap_chan *chan) { + struct sock *sk = chan->sk; struct l2cap_conn *conn = l2cap_pi(sk)->conn; if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) { @@ -423,11 +423,11 @@ static void l2cap_do_start(struct sock *sk) req.scid = cpu_to_le16(l2cap_pi(sk)->scid); req.psm = l2cap_pi(sk)->psm; - l2cap_pi(sk)->ident = l2cap_get_ident(conn); + chan->ident = l2cap_get_ident(conn); l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; - l2cap_send_cmd(conn, l2cap_pi(sk)->ident, - L2CAP_CONN_REQ, sizeof(req), &req); + l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, + sizeof(req), &req); } } else { struct l2cap_info_req req; @@ -529,11 +529,11 @@ static void l2cap_conn_start(struct l2cap_conn *conn) req.scid = cpu_to_le16(l2cap_pi(sk)->scid); req.psm = l2cap_pi(sk)->psm; - l2cap_pi(sk)->ident = l2cap_get_ident(conn); + chan->ident = l2cap_get_ident(conn); l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; - l2cap_send_cmd(conn, l2cap_pi(sk)->ident, - L2CAP_CONN_REQ, sizeof(req), &req); + l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, + sizeof(req), &req); } else if (sk->sk_state == BT_CONNECT2) { struct l2cap_conn_rsp rsp; @@ -558,8 +558,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn) rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND); } - l2cap_send_cmd(conn, l2cap_pi(sk)->ident, - L2CAP_CONN_RSP, sizeof(rsp), &rsp); + l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, + sizeof(rsp), &rsp); if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT || rsp.result != L2CAP_CR_SUCCESS) { @@ -694,7 +694,7 @@ static void l2cap_conn_ready(struct l2cap_conn *conn) sk->sk_state = BT_CONNECTED; sk->sk_state_change(sk); } else if (sk->sk_state == BT_CONNECT) - l2cap_do_start(sk); + l2cap_do_start(chan); bh_unlock_sock(sk); } @@ -904,7 +904,7 @@ int l2cap_do_connect(struct sock *sk) if (l2cap_check_security(sk)) sk->sk_state = BT_CONNECTED; } else - l2cap_do_start(sk); + l2cap_do_start(chan); } err = 0; @@ -2064,7 +2064,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd l2cap_sock_set_timer(sk, sk->sk_sndtimeo); - l2cap_pi(sk)->ident = cmd->ident; + chan->ident = cmd->ident; if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) { if (l2cap_check_security(sk)) { @@ -2157,7 +2157,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd switch (result) { case L2CAP_CR_SUCCESS: sk->sk_state = BT_CONFIG; - l2cap_pi(sk)->ident = 0; + chan->ident = 0; l2cap_pi(sk)->dcid = dcid; l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_CONNECT_PEND; @@ -3862,10 +3862,10 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) req.scid = cpu_to_le16(l2cap_pi(sk)->scid); req.psm = l2cap_pi(sk)->psm; - l2cap_pi(sk)->ident = l2cap_get_ident(conn); + chan->ident = l2cap_get_ident(conn); l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; - l2cap_send_cmd(conn, l2cap_pi(sk)->ident, + l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req); } else { l2cap_sock_clear_timer(sk); @@ -3888,8 +3888,8 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); rsp.result = cpu_to_le16(result); rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); - l2cap_send_cmd(conn, l2cap_pi(sk)->ident, - L2CAP_CONN_RSP, sizeof(rsp), &rsp); + l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, + sizeof(rsp), &rsp); } bh_unlock_sock(sk); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 7df81181a119..cad4bc7d36b2 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -818,7 +818,7 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); - l2cap_send_cmd(l2cap_pi(sk)->conn, l2cap_pi(sk)->ident, + l2cap_send_cmd(l2cap_pi(sk)->conn, l2cap_pi(sk)->chan->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) { @@ -921,7 +921,7 @@ void __l2cap_sock_close(struct sock *sk, int reason) rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); rsp.result = cpu_to_le16(result); rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); - l2cap_send_cmd(conn, l2cap_pi(sk)->ident, + l2cap_send_cmd(conn, l2cap_pi(sk)->chan->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); } -- cgit v1.2.3 From 73ffa904b78287f6acf8797e040150aa26a4af4a Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 25 Mar 2011 14:16:54 -0300 Subject: Bluetooth: Move conf_{req,rsp} stuff to struct l2cap_chan They are also l2cap_chan specific. Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 11 +++++---- net/bluetooth/l2cap_core.c | 55 ++++++++++++++++++++++--------------------- net/bluetooth/l2cap_sock.c | 8 +++---- 3 files changed, 38 insertions(+), 36 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 81829e5c407d..bf918283712a 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -281,6 +281,11 @@ struct l2cap_chan { struct sock *sk; __u8 ident; + __u8 conf_req[64]; + __u8 conf_len; + __u8 num_conf_req; + __u8 num_conf_rsp; + struct list_head list; }; @@ -337,8 +342,6 @@ struct l2cap_pinfo { __u16 omtu; __u16 flush_to; __u8 mode; - __u8 num_conf_req; - __u8 num_conf_rsp; __u8 fcs; __u8 sec_level; @@ -346,8 +349,6 @@ struct l2cap_pinfo { __u8 force_reliable; __u8 flushable; - __u8 conf_req[64]; - __u8 conf_len; __u8 conf_state; __u16 conn_state; @@ -447,7 +448,7 @@ void l2cap_cleanup_sockets(void); u8 l2cap_get_ident(struct l2cap_conn *conn); void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data); -int l2cap_build_conf_req(struct sock *sk, void *data); +int l2cap_build_conf_req(struct l2cap_chan *chan, void *data); int __l2cap_wait_ack(struct sock *sk); struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 6020e1e2f500..cb849b51632f 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -569,8 +569,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn) l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, - l2cap_build_conf_req(sk, buf), buf); - l2cap_pi(sk)->num_conf_req++; + l2cap_build_conf_req(chan, buf), buf); + chan->num_conf_req++; } bh_unlock_sock(sk); @@ -1598,8 +1598,9 @@ static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) } } -int l2cap_build_conf_req(struct sock *sk, void *data) +int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) { + struct sock *sk = chan->sk; struct l2cap_pinfo *pi = l2cap_pi(sk); struct l2cap_conf_req *req = data; struct l2cap_conf_rfc rfc = { .mode = pi->mode }; @@ -1607,7 +1608,7 @@ int l2cap_build_conf_req(struct sock *sk, void *data) BT_DBG("sk %p", sk); - if (pi->num_conf_req || pi->num_conf_rsp) + if (chan->num_conf_req || chan->num_conf_rsp) goto done; switch (pi->mode) { @@ -1696,20 +1697,20 @@ done: return ptr - data; } -static int l2cap_parse_conf_req(struct sock *sk, void *data) +static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data) { - struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_pinfo *pi = l2cap_pi(chan->sk); struct l2cap_conf_rsp *rsp = data; void *ptr = rsp->data; - void *req = pi->conf_req; - int len = pi->conf_len; + void *req = chan->conf_req; + int len = chan->conf_len; int type, hint, olen; unsigned long val; struct l2cap_conf_rfc rfc = { .mode = L2CAP_MODE_BASIC }; u16 mtu = L2CAP_DEFAULT_MTU; u16 result = L2CAP_CONF_SUCCESS; - BT_DBG("sk %p", sk); + BT_DBG("chan %p", chan); while (len >= L2CAP_CONF_OPT_SIZE) { len -= l2cap_get_conf_opt(&req, &type, &olen, &val); @@ -1750,7 +1751,7 @@ static int l2cap_parse_conf_req(struct sock *sk, void *data) } } - if (pi->num_conf_rsp || pi->num_conf_req > 1) + if (chan->num_conf_rsp || chan->num_conf_req > 1) goto done; switch (pi->mode) { @@ -1773,7 +1774,7 @@ done: result = L2CAP_CONF_UNACCEPT; rfc.mode = pi->mode; - if (pi->num_conf_rsp == 1) + if (chan->num_conf_rsp == 1) return -ECONNREFUSED; l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, @@ -1992,7 +1993,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd { struct l2cap_conn_req *req = (struct l2cap_conn_req *) data; struct l2cap_conn_rsp rsp; - struct l2cap_chan *chan; + struct l2cap_chan *chan = NULL; struct sock *parent, *sk = NULL; int result, status = L2CAP_CS_NO_INFO; @@ -2115,13 +2116,13 @@ sendresp: L2CAP_INFO_REQ, sizeof(info), &info); } - if (sk && !(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) && + if (chan && !(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) && result == L2CAP_CR_SUCCESS) { u8 buf[128]; l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, - l2cap_build_conf_req(sk, buf), buf); - l2cap_pi(sk)->num_conf_req++; + l2cap_build_conf_req(chan, buf), buf); + chan->num_conf_req++; } return 0; @@ -2167,8 +2168,8 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, - l2cap_build_conf_req(sk, req), req); - l2cap_pi(sk)->num_conf_req++; + l2cap_build_conf_req(chan, req), req); + chan->num_conf_req++; break; case L2CAP_CR_PEND: @@ -2234,7 +2235,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr /* Reject if config buffer is too small. */ len = cmd_len - sizeof(*req); - if (l2cap_pi(sk)->conf_len + len > sizeof(l2cap_pi(sk)->conf_req)) { + if (chan->conf_len + len > sizeof(chan->conf_req)) { l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, L2CAP_CONF_REJECT, flags), rsp); @@ -2242,8 +2243,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr } /* Store config. */ - memcpy(l2cap_pi(sk)->conf_req + l2cap_pi(sk)->conf_len, req->data, len); - l2cap_pi(sk)->conf_len += len; + memcpy(chan->conf_req + chan->conf_len, req->data, len); + chan->conf_len += len; if (flags & 0x0001) { /* Incomplete config. Send empty response. */ @@ -2254,17 +2255,17 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr } /* Complete config. */ - len = l2cap_parse_conf_req(sk, rsp); + len = l2cap_parse_conf_req(chan, rsp); if (len < 0) { l2cap_send_disconn_req(conn, sk, ECONNRESET); goto unlock; } l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp); - l2cap_pi(sk)->num_conf_rsp++; + chan->num_conf_rsp++; /* Reset config buffer. */ - l2cap_pi(sk)->conf_len = 0; + chan->conf_len = 0; if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE)) goto unlock; @@ -2288,8 +2289,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr u8 buf[64]; l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, - l2cap_build_conf_req(sk, buf), buf); - l2cap_pi(sk)->num_conf_req++; + l2cap_build_conf_req(chan, buf), buf); + chan->num_conf_req++; } unlock: @@ -2324,7 +2325,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr break; case L2CAP_CONF_UNACCEPT: - if (l2cap_pi(sk)->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) { + if (chan->num_conf_rsp <= L2CAP_CONF_MAX_CONF_RSP) { char req[64]; if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) { @@ -2343,7 +2344,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, len, req); - l2cap_pi(sk)->num_conf_req++; + chan->num_conf_req++; if (result != L2CAP_CONF_SUCCESS) goto done; break; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index cad4bc7d36b2..244475ea045c 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -810,6 +810,7 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) { struct l2cap_conn_rsp rsp; struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; u8 buf[128]; sk->sk_state = BT_CONFIG; @@ -818,7 +819,7 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); - l2cap_send_cmd(l2cap_pi(sk)->conn, l2cap_pi(sk)->chan->ident, + l2cap_send_cmd(l2cap_pi(sk)->conn, chan->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) { @@ -828,8 +829,8 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, - l2cap_build_conf_req(sk, buf), buf); - l2cap_pi(sk)->num_conf_req++; + l2cap_build_conf_req(chan, buf), buf); + chan->num_conf_req++; release_sock(sk); return 0; @@ -1035,7 +1036,6 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent) } /* Default config options */ - pi->conf_len = 0; pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; skb_queue_head_init(TX_QUEUE(sk)); skb_queue_head_init(SREJ_QUEUE(sk)); -- cgit v1.2.3 From 710f9b0a423cad155144742f6497efe5163ed750 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 25 Mar 2011 14:30:37 -0300 Subject: Bluetooth: clean up l2cap_sock_recvmsg() Move some channel specific stuff to l2cap_core.c, this will make things more clear. Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 3 +-- net/bluetooth/l2cap_core.c | 28 +++++++++++++++++++++++++++- net/bluetooth/l2cap_sock.c | 25 +------------------------ 3 files changed, 29 insertions(+), 27 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index bf918283712a..469241353d78 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -446,9 +446,8 @@ extern struct bt_sock_list l2cap_sk_list; int l2cap_init_sockets(void); void l2cap_cleanup_sockets(void); -u8 l2cap_get_ident(struct l2cap_conn *conn); void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data); -int l2cap_build_conf_req(struct l2cap_chan *chan, void *data); +void __l2cap_connect_rsp_defer(struct sock *sk); int __l2cap_wait_ack(struct sock *sk); struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index cb849b51632f..b41e21f46231 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -70,6 +70,7 @@ static void l2cap_busy_work(struct work_struct *work); static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, u8 code, u8 ident, u16 dlen, void *data); +static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data); static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb); @@ -1598,7 +1599,7 @@ static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) } } -int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) +static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) { struct sock *sk = chan->sk; struct l2cap_pinfo *pi = l2cap_pi(sk); @@ -1934,6 +1935,31 @@ static int l2cap_build_conf_rsp(struct sock *sk, void *data, u16 result, u16 fla return ptr - data; } +void __l2cap_connect_rsp_defer(struct sock *sk) +{ + struct l2cap_conn_rsp rsp; + struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; + u8 buf[128]; + + sk->sk_state = BT_CONFIG; + + rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); + rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); + rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); + rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); + l2cap_send_cmd(conn, chan->ident, + L2CAP_CONN_RSP, sizeof(rsp), &rsp); + + if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) + return; + + l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; + l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, + l2cap_build_conf_req(chan, buf), buf); + chan->num_conf_req++; +} + static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len) { struct l2cap_pinfo *pi = l2cap_pi(sk); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 244475ea045c..450f57b106b9 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -808,30 +808,7 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms lock_sock(sk); if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) { - struct l2cap_conn_rsp rsp; - struct l2cap_conn *conn = l2cap_pi(sk)->conn; - struct l2cap_chan *chan = l2cap_pi(sk)->chan; - u8 buf[128]; - - sk->sk_state = BT_CONFIG; - - rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); - rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); - rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); - rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); - l2cap_send_cmd(l2cap_pi(sk)->conn, chan->ident, - L2CAP_CONN_RSP, sizeof(rsp), &rsp); - - if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) { - release_sock(sk); - return 0; - } - - l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; - l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, - l2cap_build_conf_req(chan, buf), buf); - chan->num_conf_req++; - + __l2cap_connect_rsp_defer(sk); release_sock(sk); return 0; } -- cgit v1.2.3 From 525cd1851b9faaadf5ea33e05192b8d22f42487e Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 25 Mar 2011 19:43:39 -0300 Subject: Bluetooth: Move conn_state to struct l2cap_chan This is part of "moving things to l2cap_chan". As one the first move it triggered a big number of changes in the funcions parameters, basically changing the struct sock param to struct l2cap_chan. Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 5 +- net/bluetooth/l2cap_core.c | 391 ++++++++++++++++++++++-------------------- net/bluetooth/l2cap_sock.c | 16 +- 3 files changed, 217 insertions(+), 195 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 469241353d78..82d5b81a779b 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -286,6 +286,8 @@ struct l2cap_chan { __u8 num_conf_req; __u8 num_conf_rsp; + __u16 conn_state; + struct list_head list; }; @@ -350,7 +352,6 @@ struct l2cap_pinfo { __u8 flushable; __u8 conf_state; - __u16 conn_state; __u8 next_tx_seq; __u8 expected_ack_seq; @@ -456,7 +457,7 @@ struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, siz int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, size_t len); void l2cap_do_send(struct sock *sk, struct sk_buff *skb); void l2cap_streaming_send(struct sock *sk); -int l2cap_ertm_send(struct sock *sk); +int l2cap_ertm_send(struct l2cap_chan *chan); void l2cap_sock_set_timer(struct sock *sk, long timeout); void l2cap_sock_clear_timer(struct sock *sk); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index b41e21f46231..b5435cd74f99 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -340,10 +340,11 @@ void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *d hci_send_acl(conn->hcon, skb, flags); } -static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control) +static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control) { struct sk_buff *skb; struct l2cap_hdr *lh; + struct l2cap_pinfo *pi = l2cap_pi(chan->sk); struct l2cap_conn *conn = pi->conn; struct sock *sk = (struct sock *)pi; int count, hlen = L2CAP_HDR_SIZE + 2; @@ -360,14 +361,14 @@ static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control) count = min_t(unsigned int, conn->mtu, hlen); control |= L2CAP_CTRL_FRAME_TYPE; - if (pi->conn_state & L2CAP_CONN_SEND_FBIT) { + if (chan->conn_state & L2CAP_CONN_SEND_FBIT) { control |= L2CAP_CTRL_FINAL; - pi->conn_state &= ~L2CAP_CONN_SEND_FBIT; + chan->conn_state &= ~L2CAP_CONN_SEND_FBIT; } - if (pi->conn_state & L2CAP_CONN_SEND_PBIT) { + if (chan->conn_state & L2CAP_CONN_SEND_PBIT) { control |= L2CAP_CTRL_POLL; - pi->conn_state &= ~L2CAP_CONN_SEND_PBIT; + chan->conn_state &= ~L2CAP_CONN_SEND_PBIT; } skb = bt_skb_alloc(count, GFP_ATOMIC); @@ -392,17 +393,19 @@ static inline void l2cap_send_sframe(struct l2cap_pinfo *pi, u16 control) hci_send_acl(pi->conn->hcon, skb, flags); } -static inline void l2cap_send_rr_or_rnr(struct l2cap_pinfo *pi, u16 control) +static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control) { - if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { + struct l2cap_pinfo *pi = l2cap_pi(chan->sk); + + if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) { control |= L2CAP_SUPER_RCV_NOT_READY; - pi->conn_state |= L2CAP_CONN_RNR_SENT; + chan->conn_state |= L2CAP_CONN_RNR_SENT; } else control |= L2CAP_SUPER_RCV_READY; control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; - l2cap_send_sframe(pi, control); + l2cap_send_sframe(chan, control); } static inline int __l2cap_no_conn_pending(struct sock *sk) @@ -949,9 +952,10 @@ int __l2cap_wait_ack(struct sock *sk) static void l2cap_monitor_timeout(unsigned long arg) { - struct sock *sk = (void *) arg; + struct l2cap_chan *chan = (void *) arg; + struct sock *sk = chan->sk; - BT_DBG("sk %p", sk); + BT_DBG("chan %p", chan); bh_lock_sock(sk); if (l2cap_pi(sk)->retry_count >= l2cap_pi(sk)->remote_max_tx) { @@ -963,13 +967,14 @@ static void l2cap_monitor_timeout(unsigned long arg) l2cap_pi(sk)->retry_count++; __mod_monitor_timer(); - l2cap_send_rr_or_rnr(l2cap_pi(sk), L2CAP_CTRL_POLL); + l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); bh_unlock_sock(sk); } static void l2cap_retrans_timeout(unsigned long arg) { - struct sock *sk = (void *) arg; + struct l2cap_chan *chan = (void *) arg; + struct sock *sk = chan->sk; BT_DBG("sk %p", sk); @@ -977,9 +982,9 @@ static void l2cap_retrans_timeout(unsigned long arg) l2cap_pi(sk)->retry_count = 1; __mod_monitor_timer(); - l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F; + chan->conn_state |= L2CAP_CONN_WAIT_F; - l2cap_send_rr_or_rnr(l2cap_pi(sk), L2CAP_CTRL_POLL); + l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); bh_unlock_sock(sk); } @@ -1040,8 +1045,9 @@ void l2cap_streaming_send(struct sock *sk) } } -static void l2cap_retransmit_one_frame(struct sock *sk, u8 tx_seq) +static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) { + struct sock *sk = chan->sk; struct l2cap_pinfo *pi = l2cap_pi(sk); struct sk_buff *skb, *tx_skb; u16 control, fcs; @@ -1069,9 +1075,9 @@ static void l2cap_retransmit_one_frame(struct sock *sk, u8 tx_seq) bt_cb(skb)->retries++; control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); - if (pi->conn_state & L2CAP_CONN_SEND_FBIT) { + if (chan->conn_state & L2CAP_CONN_SEND_FBIT) { control |= L2CAP_CTRL_FINAL; - pi->conn_state &= ~L2CAP_CONN_SEND_FBIT; + chan->conn_state &= ~L2CAP_CONN_SEND_FBIT; } control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT) @@ -1087,9 +1093,10 @@ static void l2cap_retransmit_one_frame(struct sock *sk, u8 tx_seq) l2cap_do_send(sk, tx_skb); } -int l2cap_ertm_send(struct sock *sk) +int l2cap_ertm_send(struct l2cap_chan *chan) { struct sk_buff *skb, *tx_skb; + struct sock *sk = chan->sk; struct l2cap_pinfo *pi = l2cap_pi(sk); u16 control, fcs; int nsent = 0; @@ -1112,9 +1119,9 @@ int l2cap_ertm_send(struct sock *sk) control = get_unaligned_le16(tx_skb->data + L2CAP_HDR_SIZE); control &= L2CAP_CTRL_SAR; - if (pi->conn_state & L2CAP_CONN_SEND_FBIT) { + if (chan->conn_state & L2CAP_CONN_SEND_FBIT) { control |= L2CAP_CTRL_FINAL; - pi->conn_state &= ~L2CAP_CONN_SEND_FBIT; + chan->conn_state &= ~L2CAP_CONN_SEND_FBIT; } control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT) | (pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); @@ -1149,8 +1156,9 @@ int l2cap_ertm_send(struct sock *sk) return nsent; } -static int l2cap_retransmit_frames(struct sock *sk) +static int l2cap_retransmit_frames(struct l2cap_chan *chan) { + struct sock *sk = chan->sk; struct l2cap_pinfo *pi = l2cap_pi(sk); int ret; @@ -1158,32 +1166,32 @@ static int l2cap_retransmit_frames(struct sock *sk) sk->sk_send_head = TX_QUEUE(sk)->next; pi->next_tx_seq = pi->expected_ack_seq; - ret = l2cap_ertm_send(sk); + ret = l2cap_ertm_send(chan); return ret; } -static void l2cap_send_ack(struct l2cap_pinfo *pi) +static void l2cap_send_ack(struct l2cap_chan *chan) { - struct sock *sk = (struct sock *)pi; + struct sock *sk = chan->sk; u16 control = 0; - control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + control |= l2cap_pi(sk)->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; - if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { + if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) { control |= L2CAP_SUPER_RCV_NOT_READY; - pi->conn_state |= L2CAP_CONN_RNR_SENT; - l2cap_send_sframe(pi, control); + chan->conn_state |= L2CAP_CONN_RNR_SENT; + l2cap_send_sframe(chan, control); return; } - if (l2cap_ertm_send(sk) > 0) + if (l2cap_ertm_send(chan) > 0) return; control |= L2CAP_SUPER_RCV_READY; - l2cap_send_sframe(pi, control); + l2cap_send_sframe(chan, control); } -static void l2cap_send_srejtail(struct sock *sk) +static void l2cap_send_srejtail(struct l2cap_chan *chan) { struct srej_list *tail; u16 control; @@ -1191,10 +1199,10 @@ static void l2cap_send_srejtail(struct sock *sk) control = L2CAP_SUPER_SELECT_REJECT; control |= L2CAP_CTRL_FINAL; - tail = list_entry(SREJ_LIST(sk)->prev, struct srej_list, list); + tail = list_entry(SREJ_LIST(chan->sk)->prev, struct srej_list, list); control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; - l2cap_send_sframe(l2cap_pi(sk), control); + l2cap_send_sframe(chan, control); } static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, int len, int count, struct sk_buff *skb) @@ -1556,15 +1564,17 @@ static void l2cap_add_conf_opt(void **ptr, u8 type, u8 len, unsigned long val) static void l2cap_ack_timeout(unsigned long arg) { - struct sock *sk = (void *) arg; + struct l2cap_chan *chan = (void *) arg; - bh_lock_sock(sk); - l2cap_send_ack(l2cap_pi(sk)); - bh_unlock_sock(sk); + bh_lock_sock(chan->sk); + l2cap_send_ack(chan); + bh_unlock_sock(chan->sk); } -static inline void l2cap_ertm_init(struct sock *sk) +static inline void l2cap_ertm_init(struct l2cap_chan *chan) { + struct sock *sk = chan->sk; + l2cap_pi(sk)->expected_ack_seq = 0; l2cap_pi(sk)->unacked_frames = 0; l2cap_pi(sk)->buffer_seq = 0; @@ -1572,11 +1582,11 @@ static inline void l2cap_ertm_init(struct sock *sk) l2cap_pi(sk)->frames_sent = 0; setup_timer(&l2cap_pi(sk)->retrans_timer, - l2cap_retrans_timeout, (unsigned long) sk); + l2cap_retrans_timeout, (unsigned long) chan); setup_timer(&l2cap_pi(sk)->monitor_timer, - l2cap_monitor_timeout, (unsigned long) sk); + l2cap_monitor_timeout, (unsigned long) chan); setup_timer(&l2cap_pi(sk)->ack_timer, - l2cap_ack_timeout, (unsigned long) sk); + l2cap_ack_timeout, (unsigned long) chan); __skb_queue_head_init(SREJ_QUEUE(sk)); __skb_queue_head_init(BUSY_QUEUE(sk)); @@ -2305,7 +2315,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr l2cap_pi(sk)->expected_tx_seq = 0; __skb_queue_head_init(TX_QUEUE(sk)); if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) - l2cap_ertm_init(sk); + l2cap_ertm_init(chan); l2cap_chan_ready(sk); goto unlock; @@ -2396,7 +2406,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr l2cap_pi(sk)->expected_tx_seq = 0; __skb_queue_head_init(TX_QUEUE(sk)); if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) - l2cap_ertm_init(sk); + l2cap_ertm_init(chan); l2cap_chan_ready(sk); } @@ -2777,30 +2787,30 @@ static int l2cap_check_fcs(struct l2cap_pinfo *pi, struct sk_buff *skb) return 0; } -static inline void l2cap_send_i_or_rr_or_rnr(struct sock *sk) +static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan) { - struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_pinfo *pi = l2cap_pi(chan->sk); u16 control = 0; pi->frames_sent = 0; control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; - if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { + if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) { control |= L2CAP_SUPER_RCV_NOT_READY; - l2cap_send_sframe(pi, control); - pi->conn_state |= L2CAP_CONN_RNR_SENT; + l2cap_send_sframe(chan, control); + chan->conn_state |= L2CAP_CONN_RNR_SENT; } - if (pi->conn_state & L2CAP_CONN_REMOTE_BUSY) - l2cap_retransmit_frames(sk); + if (chan->conn_state & L2CAP_CONN_REMOTE_BUSY) + l2cap_retransmit_frames(chan); - l2cap_ertm_send(sk); + l2cap_ertm_send(chan); - if (!(pi->conn_state & L2CAP_CONN_LOCAL_BUSY) && + if (!(chan->conn_state & L2CAP_CONN_LOCAL_BUSY) && pi->frames_sent == 0) { control |= L2CAP_SUPER_RCV_READY; - l2cap_send_sframe(pi, control); + l2cap_send_sframe(chan, control); } } @@ -2847,25 +2857,25 @@ static int l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_s return 0; } -static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control) +static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) { - struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_pinfo *pi = l2cap_pi(chan->sk); struct sk_buff *_skb; int err; switch (control & L2CAP_CTRL_SAR) { case L2CAP_SDU_UNSEGMENTED: - if (pi->conn_state & L2CAP_CONN_SAR_SDU) + if (chan->conn_state & L2CAP_CONN_SAR_SDU) goto drop; - err = sock_queue_rcv_skb(sk, skb); + err = sock_queue_rcv_skb(chan->sk, skb); if (!err) return err; break; case L2CAP_SDU_START: - if (pi->conn_state & L2CAP_CONN_SAR_SDU) + if (chan->conn_state & L2CAP_CONN_SAR_SDU) goto drop; pi->sdu_len = get_unaligned_le16(skb->data); @@ -2884,12 +2894,12 @@ static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 c memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); - pi->conn_state |= L2CAP_CONN_SAR_SDU; + chan->conn_state |= L2CAP_CONN_SAR_SDU; pi->partial_sdu_len = skb->len; break; case L2CAP_SDU_CONTINUE: - if (!(pi->conn_state & L2CAP_CONN_SAR_SDU)) + if (!(chan->conn_state & L2CAP_CONN_SAR_SDU)) goto disconnect; if (!pi->sdu) @@ -2904,13 +2914,13 @@ static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 c break; case L2CAP_SDU_END: - if (!(pi->conn_state & L2CAP_CONN_SAR_SDU)) + if (!(chan->conn_state & L2CAP_CONN_SAR_SDU)) goto disconnect; if (!pi->sdu) goto disconnect; - if (!(pi->conn_state & L2CAP_CONN_SAR_RETRY)) { + if (!(chan->conn_state & L2CAP_CONN_SAR_RETRY)) { pi->partial_sdu_len += skb->len; if (pi->partial_sdu_len > pi->imtu) @@ -2924,19 +2934,19 @@ static int l2cap_ertm_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 c _skb = skb_clone(pi->sdu, GFP_ATOMIC); if (!_skb) { - pi->conn_state |= L2CAP_CONN_SAR_RETRY; + chan->conn_state |= L2CAP_CONN_SAR_RETRY; return -ENOMEM; } - err = sock_queue_rcv_skb(sk, _skb); + err = sock_queue_rcv_skb(chan->sk, _skb); if (err < 0) { kfree_skb(_skb); - pi->conn_state |= L2CAP_CONN_SAR_RETRY; + chan->conn_state |= L2CAP_CONN_SAR_RETRY; return err; } - pi->conn_state &= ~L2CAP_CONN_SAR_RETRY; - pi->conn_state &= ~L2CAP_CONN_SAR_SDU; + chan->conn_state &= ~L2CAP_CONN_SAR_RETRY; + chan->conn_state &= ~L2CAP_CONN_SAR_SDU; kfree_skb(pi->sdu); break; @@ -2950,13 +2960,14 @@ drop: pi->sdu = NULL; disconnect: - l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); + l2cap_send_disconn_req(pi->conn, chan->sk, ECONNRESET); kfree_skb(skb); return 0; } -static int l2cap_try_push_rx_skb(struct sock *sk) +static int l2cap_try_push_rx_skb(struct l2cap_chan *chan) { + struct sock *sk = chan->sk; struct l2cap_pinfo *pi = l2cap_pi(sk); struct sk_buff *skb; u16 control; @@ -2964,7 +2975,7 @@ static int l2cap_try_push_rx_skb(struct sock *sk) while ((skb = skb_dequeue(BUSY_QUEUE(sk)))) { control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; - err = l2cap_ertm_reassembly_sdu(sk, skb, control); + err = l2cap_ertm_reassembly_sdu(chan, skb, control); if (err < 0) { skb_queue_head(BUSY_QUEUE(sk), skb); return -EBUSY; @@ -2973,22 +2984,22 @@ static int l2cap_try_push_rx_skb(struct sock *sk) pi->buffer_seq = (pi->buffer_seq + 1) % 64; } - if (!(pi->conn_state & L2CAP_CONN_RNR_SENT)) + if (!(chan->conn_state & L2CAP_CONN_RNR_SENT)) goto done; control = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL; - l2cap_send_sframe(pi, control); + l2cap_send_sframe(chan, control); l2cap_pi(sk)->retry_count = 1; del_timer(&pi->retrans_timer); __mod_monitor_timer(); - l2cap_pi(sk)->conn_state |= L2CAP_CONN_WAIT_F; + chan->conn_state |= L2CAP_CONN_WAIT_F; done: - pi->conn_state &= ~L2CAP_CONN_LOCAL_BUSY; - pi->conn_state &= ~L2CAP_CONN_RNR_SENT; + chan->conn_state &= ~L2CAP_CONN_LOCAL_BUSY; + chan->conn_state &= ~L2CAP_CONN_RNR_SENT; BT_DBG("sk %p, Exit local busy", sk); @@ -3032,7 +3043,7 @@ static void l2cap_busy_work(struct work_struct *work) if (err) break; - if (l2cap_try_push_rx_skb(sk) == 0) + if (l2cap_try_push_rx_skb(l2cap_pi(sk)->chan) == 0) break; } @@ -3042,20 +3053,21 @@ static void l2cap_busy_work(struct work_struct *work) release_sock(sk); } -static int l2cap_push_rx_skb(struct sock *sk, struct sk_buff *skb, u16 control) +static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) { + struct sock *sk = chan->sk; struct l2cap_pinfo *pi = l2cap_pi(sk); int sctrl, err; - if (pi->conn_state & L2CAP_CONN_LOCAL_BUSY) { + if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) { bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT; __skb_queue_tail(BUSY_QUEUE(sk), skb); - return l2cap_try_push_rx_skb(sk); + return l2cap_try_push_rx_skb(chan); } - err = l2cap_ertm_reassembly_sdu(sk, skb, control); + err = l2cap_ertm_reassembly_sdu(chan, skb, control); if (err >= 0) { pi->buffer_seq = (pi->buffer_seq + 1) % 64; return err; @@ -3064,15 +3076,15 @@ static int l2cap_push_rx_skb(struct sock *sk, struct sk_buff *skb, u16 control) /* Busy Condition */ BT_DBG("sk %p, Enter local busy", sk); - pi->conn_state |= L2CAP_CONN_LOCAL_BUSY; + chan->conn_state |= L2CAP_CONN_LOCAL_BUSY; bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT; __skb_queue_tail(BUSY_QUEUE(sk), skb); sctrl = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; sctrl |= L2CAP_SUPER_RCV_NOT_READY; - l2cap_send_sframe(pi, sctrl); + l2cap_send_sframe(chan, sctrl); - pi->conn_state |= L2CAP_CONN_RNR_SENT; + chan->conn_state |= L2CAP_CONN_RNR_SENT; del_timer(&pi->ack_timer); @@ -3081,9 +3093,9 @@ static int l2cap_push_rx_skb(struct sock *sk, struct sk_buff *skb, u16 control) return err; } -static int l2cap_streaming_reassembly_sdu(struct sock *sk, struct sk_buff *skb, u16 control) +static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) { - struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_pinfo *pi = l2cap_pi(chan->sk); struct sk_buff *_skb; int err = -EINVAL; @@ -3094,19 +3106,19 @@ static int l2cap_streaming_reassembly_sdu(struct sock *sk, struct sk_buff *skb, switch (control & L2CAP_CTRL_SAR) { case L2CAP_SDU_UNSEGMENTED: - if (pi->conn_state & L2CAP_CONN_SAR_SDU) { + if (chan->conn_state & L2CAP_CONN_SAR_SDU) { kfree_skb(pi->sdu); break; } - err = sock_queue_rcv_skb(sk, skb); + err = sock_queue_rcv_skb(chan->sk, skb); if (!err) return 0; break; case L2CAP_SDU_START: - if (pi->conn_state & L2CAP_CONN_SAR_SDU) { + if (chan->conn_state & L2CAP_CONN_SAR_SDU) { kfree_skb(pi->sdu); break; } @@ -3127,13 +3139,13 @@ static int l2cap_streaming_reassembly_sdu(struct sock *sk, struct sk_buff *skb, memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); - pi->conn_state |= L2CAP_CONN_SAR_SDU; + chan->conn_state |= L2CAP_CONN_SAR_SDU; pi->partial_sdu_len = skb->len; err = 0; break; case L2CAP_SDU_CONTINUE: - if (!(pi->conn_state & L2CAP_CONN_SAR_SDU)) + if (!(chan->conn_state & L2CAP_CONN_SAR_SDU)) break; memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); @@ -3147,12 +3159,12 @@ static int l2cap_streaming_reassembly_sdu(struct sock *sk, struct sk_buff *skb, break; case L2CAP_SDU_END: - if (!(pi->conn_state & L2CAP_CONN_SAR_SDU)) + if (!(chan->conn_state & L2CAP_CONN_SAR_SDU)) break; memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); - pi->conn_state &= ~L2CAP_CONN_SAR_SDU; + chan->conn_state &= ~L2CAP_CONN_SAR_SDU; pi->partial_sdu_len += skb->len; if (pi->partial_sdu_len > pi->imtu) @@ -3160,7 +3172,7 @@ static int l2cap_streaming_reassembly_sdu(struct sock *sk, struct sk_buff *skb, if (pi->partial_sdu_len == pi->sdu_len) { _skb = skb_clone(pi->sdu, GFP_ATOMIC); - err = sock_queue_rcv_skb(sk, _skb); + err = sock_queue_rcv_skb(chan->sk, _skb); if (err < 0) kfree_skb(_skb); } @@ -3175,8 +3187,9 @@ drop: return err; } -static void l2cap_check_srej_gap(struct sock *sk, u8 tx_seq) +static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq) { + struct sock *sk = chan->sk; struct sk_buff *skb; u16 control; @@ -3186,16 +3199,16 @@ static void l2cap_check_srej_gap(struct sock *sk, u8 tx_seq) skb = skb_dequeue(SREJ_QUEUE(sk)); control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; - l2cap_ertm_reassembly_sdu(sk, skb, control); + l2cap_ertm_reassembly_sdu(chan, skb, control); l2cap_pi(sk)->buffer_seq_srej = (l2cap_pi(sk)->buffer_seq_srej + 1) % 64; tx_seq = (tx_seq + 1) % 64; } } -static void l2cap_resend_srejframe(struct sock *sk, u8 tx_seq) +static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq) { - struct l2cap_pinfo *pi = l2cap_pi(sk); + struct sock *sk = chan->sk; struct srej_list *l, *tmp; u16 control; @@ -3207,14 +3220,15 @@ static void l2cap_resend_srejframe(struct sock *sk, u8 tx_seq) } control = L2CAP_SUPER_SELECT_REJECT; control |= l->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; - l2cap_send_sframe(pi, control); + l2cap_send_sframe(chan, control); list_del(&l->list); list_add_tail(&l->list, SREJ_LIST(sk)); } } -static void l2cap_send_srejframe(struct sock *sk, u8 tx_seq) +static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq) { + struct sock *sk = chan->sk; struct l2cap_pinfo *pi = l2cap_pi(sk); struct srej_list *new; u16 control; @@ -3222,7 +3236,7 @@ static void l2cap_send_srejframe(struct sock *sk, u8 tx_seq) while (tx_seq != pi->expected_tx_seq) { control = L2CAP_SUPER_SELECT_REJECT; control |= pi->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; - l2cap_send_sframe(pi, control); + l2cap_send_sframe(chan, control); new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC); new->tx_seq = pi->expected_tx_seq; @@ -3232,8 +3246,9 @@ static void l2cap_send_srejframe(struct sock *sk, u8 tx_seq) pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; } -static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, struct sk_buff *skb) +static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb) { + struct sock *sk = chan->sk; struct l2cap_pinfo *pi = l2cap_pi(sk); u8 tx_seq = __get_txseq(rx_control); u8 req_seq = __get_reqseq(rx_control); @@ -3242,15 +3257,15 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str int num_to_ack = (pi->tx_win/6) + 1; int err = 0; - BT_DBG("sk %p len %d tx_seq %d rx_control 0x%4.4x", sk, skb->len, tx_seq, - rx_control); + BT_DBG("chan %p len %d tx_seq %d rx_control 0x%4.4x", chan, skb->len, + tx_seq, rx_control); if (L2CAP_CTRL_FINAL & rx_control && - l2cap_pi(sk)->conn_state & L2CAP_CONN_WAIT_F) { + chan->conn_state & L2CAP_CONN_WAIT_F) { del_timer(&pi->monitor_timer); if (pi->unacked_frames > 0) __mod_retrans_timer(); - pi->conn_state &= ~L2CAP_CONN_WAIT_F; + chan->conn_state &= ~L2CAP_CONN_WAIT_F; } pi->expected_ack_seq = req_seq; @@ -3269,25 +3284,25 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str goto drop; } - if (pi->conn_state == L2CAP_CONN_LOCAL_BUSY) + if (chan->conn_state == L2CAP_CONN_LOCAL_BUSY) goto drop; - if (pi->conn_state & L2CAP_CONN_SREJ_SENT) { + if (chan->conn_state & L2CAP_CONN_SREJ_SENT) { struct srej_list *first; first = list_first_entry(SREJ_LIST(sk), struct srej_list, list); if (tx_seq == first->tx_seq) { l2cap_add_to_srej_queue(sk, skb, tx_seq, sar); - l2cap_check_srej_gap(sk, tx_seq); + l2cap_check_srej_gap(chan, tx_seq); list_del(&first->list); kfree(first); if (list_empty(SREJ_LIST(sk))) { pi->buffer_seq = pi->buffer_seq_srej; - pi->conn_state &= ~L2CAP_CONN_SREJ_SENT; - l2cap_send_ack(pi); + chan->conn_state &= ~L2CAP_CONN_SREJ_SENT; + l2cap_send_ack(chan); BT_DBG("sk %p, Exit SREJ_SENT", sk); } } else { @@ -3299,11 +3314,11 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str list_for_each_entry(l, SREJ_LIST(sk), list) { if (l->tx_seq == tx_seq) { - l2cap_resend_srejframe(sk, tx_seq); + l2cap_resend_srejframe(chan, tx_seq); return 0; } } - l2cap_send_srejframe(sk, tx_seq); + l2cap_send_srejframe(chan, tx_seq); } } else { expected_tx_seq_offset = @@ -3315,7 +3330,7 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str if (tx_seq_offset < expected_tx_seq_offset) goto drop; - pi->conn_state |= L2CAP_CONN_SREJ_SENT; + chan->conn_state |= L2CAP_CONN_SREJ_SENT; BT_DBG("sk %p, Enter SREJ", sk); @@ -3326,9 +3341,9 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str __skb_queue_head_init(BUSY_QUEUE(sk)); l2cap_add_to_srej_queue(sk, skb, tx_seq, sar); - pi->conn_state |= L2CAP_CONN_SEND_PBIT; + chan->conn_state |= L2CAP_CONN_SEND_PBIT; - l2cap_send_srejframe(sk, tx_seq); + l2cap_send_srejframe(chan, tx_seq); del_timer(&pi->ack_timer); } @@ -3337,29 +3352,29 @@ static inline int l2cap_data_channel_iframe(struct sock *sk, u16 rx_control, str expected: pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; - if (pi->conn_state & L2CAP_CONN_SREJ_SENT) { + if (chan->conn_state & L2CAP_CONN_SREJ_SENT) { bt_cb(skb)->tx_seq = tx_seq; bt_cb(skb)->sar = sar; __skb_queue_tail(SREJ_QUEUE(sk), skb); return 0; } - err = l2cap_push_rx_skb(sk, skb, rx_control); + err = l2cap_push_rx_skb(chan, skb, rx_control); if (err < 0) return 0; if (rx_control & L2CAP_CTRL_FINAL) { - if (pi->conn_state & L2CAP_CONN_REJ_ACT) - pi->conn_state &= ~L2CAP_CONN_REJ_ACT; + if (chan->conn_state & L2CAP_CONN_REJ_ACT) + chan->conn_state &= ~L2CAP_CONN_REJ_ACT; else - l2cap_retransmit_frames(sk); + l2cap_retransmit_frames(chan); } __mod_ack_timer(); pi->num_acked = (pi->num_acked + 1) % num_to_ack; if (pi->num_acked == num_to_ack - 1) - l2cap_send_ack(pi); + l2cap_send_ack(chan); return 0; @@ -3368,8 +3383,9 @@ drop: return 0; } -static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control) +static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_control) { + struct sock *sk = chan->sk; struct l2cap_pinfo *pi = l2cap_pi(sk); BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, __get_reqseq(rx_control), @@ -3379,154 +3395,156 @@ static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control) l2cap_drop_acked_frames(sk); if (rx_control & L2CAP_CTRL_POLL) { - pi->conn_state |= L2CAP_CONN_SEND_FBIT; - if (pi->conn_state & L2CAP_CONN_SREJ_SENT) { - if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) && + chan->conn_state |= L2CAP_CONN_SEND_FBIT; + if (chan->conn_state & L2CAP_CONN_SREJ_SENT) { + if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) && (pi->unacked_frames > 0)) __mod_retrans_timer(); - pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; - l2cap_send_srejtail(sk); + chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + l2cap_send_srejtail(chan); } else { - l2cap_send_i_or_rr_or_rnr(sk); + l2cap_send_i_or_rr_or_rnr(chan); } } else if (rx_control & L2CAP_CTRL_FINAL) { - pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; - if (pi->conn_state & L2CAP_CONN_REJ_ACT) - pi->conn_state &= ~L2CAP_CONN_REJ_ACT; + if (chan->conn_state & L2CAP_CONN_REJ_ACT) + chan->conn_state &= ~L2CAP_CONN_REJ_ACT; else - l2cap_retransmit_frames(sk); + l2cap_retransmit_frames(chan); } else { - if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) && + if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) && (pi->unacked_frames > 0)) __mod_retrans_timer(); - pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; - if (pi->conn_state & L2CAP_CONN_SREJ_SENT) - l2cap_send_ack(pi); + chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + if (chan->conn_state & L2CAP_CONN_SREJ_SENT) + l2cap_send_ack(chan); else - l2cap_ertm_send(sk); + l2cap_ertm_send(chan); } } -static inline void l2cap_data_channel_rejframe(struct sock *sk, u16 rx_control) +static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_control) { - struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_pinfo *pi = l2cap_pi(chan->sk); u8 tx_seq = __get_reqseq(rx_control); - BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control); + BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control); - pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; pi->expected_ack_seq = tx_seq; - l2cap_drop_acked_frames(sk); + l2cap_drop_acked_frames(chan->sk); if (rx_control & L2CAP_CTRL_FINAL) { - if (pi->conn_state & L2CAP_CONN_REJ_ACT) - pi->conn_state &= ~L2CAP_CONN_REJ_ACT; + if (chan->conn_state & L2CAP_CONN_REJ_ACT) + chan->conn_state &= ~L2CAP_CONN_REJ_ACT; else - l2cap_retransmit_frames(sk); + l2cap_retransmit_frames(chan); } else { - l2cap_retransmit_frames(sk); + l2cap_retransmit_frames(chan); - if (pi->conn_state & L2CAP_CONN_WAIT_F) - pi->conn_state |= L2CAP_CONN_REJ_ACT; + if (chan->conn_state & L2CAP_CONN_WAIT_F) + chan->conn_state |= L2CAP_CONN_REJ_ACT; } } -static inline void l2cap_data_channel_srejframe(struct sock *sk, u16 rx_control) +static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_control) { - struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_pinfo *pi = l2cap_pi(chan->sk); u8 tx_seq = __get_reqseq(rx_control); - BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control); + BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control); - pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; + chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; if (rx_control & L2CAP_CTRL_POLL) { pi->expected_ack_seq = tx_seq; - l2cap_drop_acked_frames(sk); + l2cap_drop_acked_frames(chan->sk); - pi->conn_state |= L2CAP_CONN_SEND_FBIT; - l2cap_retransmit_one_frame(sk, tx_seq); + chan->conn_state |= L2CAP_CONN_SEND_FBIT; + l2cap_retransmit_one_frame(chan, tx_seq); - l2cap_ertm_send(sk); + l2cap_ertm_send(chan); - if (pi->conn_state & L2CAP_CONN_WAIT_F) { + if (chan->conn_state & L2CAP_CONN_WAIT_F) { pi->srej_save_reqseq = tx_seq; - pi->conn_state |= L2CAP_CONN_SREJ_ACT; + chan->conn_state |= L2CAP_CONN_SREJ_ACT; } } else if (rx_control & L2CAP_CTRL_FINAL) { - if ((pi->conn_state & L2CAP_CONN_SREJ_ACT) && + if ((chan->conn_state & L2CAP_CONN_SREJ_ACT) && pi->srej_save_reqseq == tx_seq) - pi->conn_state &= ~L2CAP_CONN_SREJ_ACT; + chan->conn_state &= ~L2CAP_CONN_SREJ_ACT; else - l2cap_retransmit_one_frame(sk, tx_seq); + l2cap_retransmit_one_frame(chan, tx_seq); } else { - l2cap_retransmit_one_frame(sk, tx_seq); - if (pi->conn_state & L2CAP_CONN_WAIT_F) { + l2cap_retransmit_one_frame(chan, tx_seq); + if (chan->conn_state & L2CAP_CONN_WAIT_F) { pi->srej_save_reqseq = tx_seq; - pi->conn_state |= L2CAP_CONN_SREJ_ACT; + chan->conn_state |= L2CAP_CONN_SREJ_ACT; } } } -static inline void l2cap_data_channel_rnrframe(struct sock *sk, u16 rx_control) +static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_control) { - struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_pinfo *pi = l2cap_pi(chan->sk); u8 tx_seq = __get_reqseq(rx_control); - BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, tx_seq, rx_control); + BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control); - pi->conn_state |= L2CAP_CONN_REMOTE_BUSY; + chan->conn_state |= L2CAP_CONN_REMOTE_BUSY; pi->expected_ack_seq = tx_seq; - l2cap_drop_acked_frames(sk); + l2cap_drop_acked_frames(chan->sk); if (rx_control & L2CAP_CTRL_POLL) - pi->conn_state |= L2CAP_CONN_SEND_FBIT; + chan->conn_state |= L2CAP_CONN_SEND_FBIT; - if (!(pi->conn_state & L2CAP_CONN_SREJ_SENT)) { + if (!(chan->conn_state & L2CAP_CONN_SREJ_SENT)) { del_timer(&pi->retrans_timer); if (rx_control & L2CAP_CTRL_POLL) - l2cap_send_rr_or_rnr(pi, L2CAP_CTRL_FINAL); + l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL); return; } if (rx_control & L2CAP_CTRL_POLL) - l2cap_send_srejtail(sk); + l2cap_send_srejtail(chan); else - l2cap_send_sframe(pi, L2CAP_SUPER_RCV_READY); + l2cap_send_sframe(chan, L2CAP_SUPER_RCV_READY); } -static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, struct sk_buff *skb) +static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb) { - BT_DBG("sk %p rx_control 0x%4.4x len %d", sk, rx_control, skb->len); + struct sock *sk = chan->sk; + + BT_DBG("chan %p rx_control 0x%4.4x len %d", chan, rx_control, skb->len); if (L2CAP_CTRL_FINAL & rx_control && - l2cap_pi(sk)->conn_state & L2CAP_CONN_WAIT_F) { + chan->conn_state & L2CAP_CONN_WAIT_F) { del_timer(&l2cap_pi(sk)->monitor_timer); if (l2cap_pi(sk)->unacked_frames > 0) __mod_retrans_timer(); - l2cap_pi(sk)->conn_state &= ~L2CAP_CONN_WAIT_F; + chan->conn_state &= ~L2CAP_CONN_WAIT_F; } switch (rx_control & L2CAP_CTRL_SUPERVISE) { case L2CAP_SUPER_RCV_READY: - l2cap_data_channel_rrframe(sk, rx_control); + l2cap_data_channel_rrframe(chan, rx_control); break; case L2CAP_SUPER_REJECT: - l2cap_data_channel_rejframe(sk, rx_control); + l2cap_data_channel_rejframe(chan, rx_control); break; case L2CAP_SUPER_SELECT_REJECT: - l2cap_data_channel_srejframe(sk, rx_control); + l2cap_data_channel_srejframe(chan, rx_control); break; case L2CAP_SUPER_RCV_NOT_READY: - l2cap_data_channel_rnrframe(sk, rx_control); + l2cap_data_channel_rnrframe(chan, rx_control); break; } @@ -3536,6 +3554,7 @@ static inline int l2cap_data_channel_sframe(struct sock *sk, u16 rx_control, str static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) { + struct l2cap_chan *chan = l2cap_pi(sk)->chan; struct l2cap_pinfo *pi = l2cap_pi(sk); u16 control; u8 req_seq; @@ -3586,7 +3605,7 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) goto drop; } - l2cap_data_channel_iframe(sk, control, skb); + l2cap_data_channel_iframe(chan, control, skb); } else { if (len != 0) { BT_ERR("%d", len); @@ -3594,7 +3613,7 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) goto drop; } - l2cap_data_channel_sframe(sk, control, skb); + l2cap_data_channel_sframe(chan, control, skb); } return 0; @@ -3675,7 +3694,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk else pi->expected_tx_seq = (tx_seq + 1) % 64; - l2cap_streaming_reassembly_sdu(sk, skb, control); + l2cap_streaming_reassembly_sdu(chan, skb, control); goto done; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 450f57b106b9..66ec966ffc18 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -778,14 +778,16 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms if (pi->mode == L2CAP_MODE_STREAMING) { l2cap_streaming_send(sk); - } else { - if ((pi->conn_state & L2CAP_CONN_REMOTE_BUSY) && - (pi->conn_state & L2CAP_CONN_WAIT_F)) { - err = len; - break; - } - err = l2cap_ertm_send(sk); + err = len; + break; + } + + if ((pi->chan->conn_state & L2CAP_CONN_REMOTE_BUSY) && + (pi->chan->conn_state & L2CAP_CONN_WAIT_F)) { + err = len; + break; } + err = l2cap_ertm_send(pi->chan); if (err >= 0) err = len; -- cgit v1.2.3 From 42e5c8027bad6f1591032941f0ebf4fc079405c8 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 25 Mar 2011 19:58:34 -0300 Subject: Bluetooth: Move of ERTM *_seq vars to struct l2cap_chan As part of the moving channel to stuff to struct l2cap_chan. Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 20 +++---- net/bluetooth/l2cap_core.c | 128 ++++++++++++++++++++---------------------- net/bluetooth/l2cap_sock.c | 2 +- 3 files changed, 73 insertions(+), 77 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 82d5b81a779b..9b43874ca6e4 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -288,6 +288,12 @@ struct l2cap_chan { __u16 conn_state; + __u8 next_tx_seq; + __u8 expected_ack_seq; + __u8 expected_tx_seq; + __u8 buffer_seq; + __u8 buffer_seq_srej; + struct list_head list; }; @@ -353,11 +359,6 @@ struct l2cap_pinfo { __u8 conf_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; @@ -421,17 +422,16 @@ struct l2cap_pinfo { #define __mod_ack_timer() mod_timer(&l2cap_pi(sk)->ack_timer, \ jiffies + msecs_to_jiffies(L2CAP_DEFAULT_ACK_TO)); -static inline int l2cap_tx_window_full(struct sock *sk) +static inline int l2cap_tx_window_full(struct l2cap_chan *ch) { - struct l2cap_pinfo *pi = l2cap_pi(sk); int sub; - sub = (pi->next_tx_seq - pi->expected_ack_seq) % 64; + sub = (ch->next_tx_seq - ch->expected_ack_seq) % 64; if (sub < 0) sub += 64; - return sub == pi->remote_tx_win; + return sub == l2cap_pi(ch->sk)->remote_tx_win; } #define __get_txseq(ctrl) (((ctrl) & L2CAP_CTRL_TXSEQ) >> 1) @@ -456,7 +456,7 @@ struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen); int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, size_t len); void l2cap_do_send(struct sock *sk, struct sk_buff *skb); -void l2cap_streaming_send(struct sock *sk); +void l2cap_streaming_send(struct l2cap_chan *chan); int l2cap_ertm_send(struct l2cap_chan *chan); void l2cap_sock_set_timer(struct sock *sk, long timeout); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index b5435cd74f99..d975092904c1 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -395,15 +395,13 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control) static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control) { - struct l2cap_pinfo *pi = l2cap_pi(chan->sk); - if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) { control |= L2CAP_SUPER_RCV_NOT_READY; chan->conn_state |= L2CAP_CONN_RNR_SENT; } else control |= L2CAP_SUPER_RCV_READY; - control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; l2cap_send_sframe(chan, control); } @@ -988,13 +986,14 @@ static void l2cap_retrans_timeout(unsigned long arg) bh_unlock_sock(sk); } -static void l2cap_drop_acked_frames(struct sock *sk) +static void l2cap_drop_acked_frames(struct l2cap_chan *chan) { + struct sock *sk = chan->sk; struct sk_buff *skb; while ((skb = skb_peek(TX_QUEUE(sk))) && l2cap_pi(sk)->unacked_frames) { - if (bt_cb(skb)->tx_seq == l2cap_pi(sk)->expected_ack_seq) + if (bt_cb(skb)->tx_seq == chan->expected_ack_seq) break; skb = skb_dequeue(TX_QUEUE(sk)); @@ -1023,15 +1022,16 @@ void l2cap_do_send(struct sock *sk, struct sk_buff *skb) hci_send_acl(hcon, skb, flags); } -void l2cap_streaming_send(struct sock *sk) +void l2cap_streaming_send(struct l2cap_chan *chan) { + struct sock *sk = chan->sk; struct sk_buff *skb; struct l2cap_pinfo *pi = l2cap_pi(sk); u16 control, fcs; while ((skb = skb_dequeue(TX_QUEUE(sk)))) { control = get_unaligned_le16(skb->data + L2CAP_HDR_SIZE); - control |= pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT; + control |= chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT; put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE); if (pi->fcs == L2CAP_FCS_CRC16) { @@ -1041,7 +1041,7 @@ void l2cap_streaming_send(struct sock *sk) l2cap_do_send(sk, skb); - pi->next_tx_seq = (pi->next_tx_seq + 1) % 64; + chan->next_tx_seq = (chan->next_tx_seq + 1) % 64; } } @@ -1080,7 +1080,7 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) chan->conn_state &= ~L2CAP_CONN_SEND_FBIT; } - control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT) + control |= (chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT) | (tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); @@ -1104,7 +1104,7 @@ int l2cap_ertm_send(struct l2cap_chan *chan) if (sk->sk_state != BT_CONNECTED) return -ENOTCONN; - while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(sk))) { + while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(chan))) { if (pi->remote_max_tx && bt_cb(skb)->retries == pi->remote_max_tx) { @@ -1123,8 +1123,8 @@ int l2cap_ertm_send(struct l2cap_chan *chan) control |= L2CAP_CTRL_FINAL; chan->conn_state &= ~L2CAP_CONN_SEND_FBIT; } - control |= (pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT) - | (pi->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT); + 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); @@ -1137,8 +1137,8 @@ int l2cap_ertm_send(struct l2cap_chan *chan) __mod_retrans_timer(); - bt_cb(skb)->tx_seq = pi->next_tx_seq; - pi->next_tx_seq = (pi->next_tx_seq + 1) % 64; + bt_cb(skb)->tx_seq = chan->next_tx_seq; + chan->next_tx_seq = (chan->next_tx_seq + 1) % 64; if (bt_cb(skb)->retries == 1) pi->unacked_frames++; @@ -1159,23 +1159,21 @@ int l2cap_ertm_send(struct l2cap_chan *chan) static int l2cap_retransmit_frames(struct l2cap_chan *chan) { struct sock *sk = chan->sk; - struct l2cap_pinfo *pi = l2cap_pi(sk); int ret; if (!skb_queue_empty(TX_QUEUE(sk))) sk->sk_send_head = TX_QUEUE(sk)->next; - pi->next_tx_seq = pi->expected_ack_seq; + chan->next_tx_seq = chan->expected_ack_seq; ret = l2cap_ertm_send(chan); return ret; } static void l2cap_send_ack(struct l2cap_chan *chan) { - struct sock *sk = chan->sk; u16 control = 0; - control |= l2cap_pi(sk)->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) { control |= L2CAP_SUPER_RCV_NOT_READY; @@ -1575,9 +1573,9 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan) { struct sock *sk = chan->sk; - l2cap_pi(sk)->expected_ack_seq = 0; + chan->expected_ack_seq = 0; l2cap_pi(sk)->unacked_frames = 0; - l2cap_pi(sk)->buffer_seq = 0; + chan->buffer_seq = 0; l2cap_pi(sk)->num_acked = 0; l2cap_pi(sk)->frames_sent = 0; @@ -2311,8 +2309,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr sk->sk_state = BT_CONNECTED; - l2cap_pi(sk)->next_tx_seq = 0; - l2cap_pi(sk)->expected_tx_seq = 0; + chan->next_tx_seq = 0; + chan->expected_tx_seq = 0; __skb_queue_head_init(TX_QUEUE(sk)); if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) l2cap_ertm_init(chan); @@ -2402,8 +2400,8 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr set_default_fcs(l2cap_pi(sk)); sk->sk_state = BT_CONNECTED; - l2cap_pi(sk)->next_tx_seq = 0; - l2cap_pi(sk)->expected_tx_seq = 0; + chan->next_tx_seq = 0; + chan->expected_tx_seq = 0; __skb_queue_head_init(TX_QUEUE(sk)); if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) l2cap_ertm_init(chan); @@ -2794,7 +2792,7 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan) pi->frames_sent = 0; - control |= pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) { control |= L2CAP_SUPER_RCV_NOT_READY; @@ -2814,10 +2812,10 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan) } } -static int l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_seq, u8 sar) +static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u8 tx_seq, u8 sar) { + struct sock *sk = chan->sk; struct sk_buff *next_skb; - struct l2cap_pinfo *pi = l2cap_pi(sk); int tx_seq_offset, next_tx_seq_offset; bt_cb(skb)->tx_seq = tx_seq; @@ -2829,7 +2827,7 @@ static int l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_s return 0; } - tx_seq_offset = (tx_seq - pi->buffer_seq) % 64; + tx_seq_offset = (tx_seq - chan->buffer_seq) % 64; if (tx_seq_offset < 0) tx_seq_offset += 64; @@ -2838,7 +2836,7 @@ static int l2cap_add_to_srej_queue(struct sock *sk, struct sk_buff *skb, u8 tx_s return -EINVAL; next_tx_seq_offset = (bt_cb(next_skb)->tx_seq - - pi->buffer_seq) % 64; + chan->buffer_seq) % 64; if (next_tx_seq_offset < 0) next_tx_seq_offset += 64; @@ -2981,13 +2979,13 @@ static int l2cap_try_push_rx_skb(struct l2cap_chan *chan) return -EBUSY; } - pi->buffer_seq = (pi->buffer_seq + 1) % 64; + chan->buffer_seq = (chan->buffer_seq + 1) % 64; } if (!(chan->conn_state & L2CAP_CONN_RNR_SENT)) goto done; - control = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL; l2cap_send_sframe(chan, control); l2cap_pi(sk)->retry_count = 1; @@ -3069,7 +3067,7 @@ static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 c err = l2cap_ertm_reassembly_sdu(chan, skb, control); if (err >= 0) { - pi->buffer_seq = (pi->buffer_seq + 1) % 64; + chan->buffer_seq = (chan->buffer_seq + 1) % 64; return err; } @@ -3080,7 +3078,7 @@ static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 c bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT; __skb_queue_tail(BUSY_QUEUE(sk), skb); - sctrl = pi->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; + sctrl = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; sctrl |= L2CAP_SUPER_RCV_NOT_READY; l2cap_send_sframe(chan, sctrl); @@ -3200,8 +3198,8 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq) skb = skb_dequeue(SREJ_QUEUE(sk)); control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; l2cap_ertm_reassembly_sdu(chan, skb, control); - l2cap_pi(sk)->buffer_seq_srej = - (l2cap_pi(sk)->buffer_seq_srej + 1) % 64; + chan->buffer_seq_srej = + (chan->buffer_seq_srej + 1) % 64; tx_seq = (tx_seq + 1) % 64; } } @@ -3229,21 +3227,20 @@ static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq) static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq) { struct sock *sk = chan->sk; - struct l2cap_pinfo *pi = l2cap_pi(sk); struct srej_list *new; u16 control; - while (tx_seq != pi->expected_tx_seq) { + while (tx_seq != chan->expected_tx_seq) { control = L2CAP_SUPER_SELECT_REJECT; - control |= pi->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; + control |= chan->expected_tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; l2cap_send_sframe(chan, control); new = kzalloc(sizeof(struct srej_list), GFP_ATOMIC); - new->tx_seq = pi->expected_tx_seq; - pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; + new->tx_seq = chan->expected_tx_seq; + chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64; list_add_tail(&new->list, SREJ_LIST(sk)); } - pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; + chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64; } static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb) @@ -3268,13 +3265,13 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont chan->conn_state &= ~L2CAP_CONN_WAIT_F; } - pi->expected_ack_seq = req_seq; - l2cap_drop_acked_frames(sk); + chan->expected_ack_seq = req_seq; + l2cap_drop_acked_frames(chan); - if (tx_seq == pi->expected_tx_seq) + if (tx_seq == chan->expected_tx_seq) goto expected; - tx_seq_offset = (tx_seq - pi->buffer_seq) % 64; + tx_seq_offset = (tx_seq - chan->buffer_seq) % 64; if (tx_seq_offset < 0) tx_seq_offset += 64; @@ -3293,14 +3290,14 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont first = list_first_entry(SREJ_LIST(sk), struct srej_list, list); if (tx_seq == first->tx_seq) { - l2cap_add_to_srej_queue(sk, skb, tx_seq, sar); + l2cap_add_to_srej_queue(chan, skb, tx_seq, sar); l2cap_check_srej_gap(chan, tx_seq); list_del(&first->list); kfree(first); if (list_empty(SREJ_LIST(sk))) { - pi->buffer_seq = pi->buffer_seq_srej; + chan->buffer_seq = chan->buffer_seq_srej; chan->conn_state &= ~L2CAP_CONN_SREJ_SENT; l2cap_send_ack(chan); BT_DBG("sk %p, Exit SREJ_SENT", sk); @@ -3309,7 +3306,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont struct srej_list *l; /* duplicated tx_seq */ - if (l2cap_add_to_srej_queue(sk, skb, tx_seq, sar) < 0) + if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0) goto drop; list_for_each_entry(l, SREJ_LIST(sk), list) { @@ -3322,7 +3319,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont } } else { expected_tx_seq_offset = - (pi->expected_tx_seq - pi->buffer_seq) % 64; + (chan->expected_tx_seq - chan->buffer_seq) % 64; if (expected_tx_seq_offset < 0) expected_tx_seq_offset += 64; @@ -3335,11 +3332,11 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont BT_DBG("sk %p, Enter SREJ", sk); INIT_LIST_HEAD(SREJ_LIST(sk)); - pi->buffer_seq_srej = pi->buffer_seq; + chan->buffer_seq_srej = chan->buffer_seq; __skb_queue_head_init(SREJ_QUEUE(sk)); __skb_queue_head_init(BUSY_QUEUE(sk)); - l2cap_add_to_srej_queue(sk, skb, tx_seq, sar); + l2cap_add_to_srej_queue(chan, skb, tx_seq, sar); chan->conn_state |= L2CAP_CONN_SEND_PBIT; @@ -3350,7 +3347,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont return 0; expected: - pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; + chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64; if (chan->conn_state & L2CAP_CONN_SREJ_SENT) { bt_cb(skb)->tx_seq = tx_seq; @@ -3391,8 +3388,8 @@ static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_co BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, __get_reqseq(rx_control), rx_control); - pi->expected_ack_seq = __get_reqseq(rx_control); - l2cap_drop_acked_frames(sk); + chan->expected_ack_seq = __get_reqseq(rx_control); + l2cap_drop_acked_frames(chan); if (rx_control & L2CAP_CTRL_POLL) { chan->conn_state |= L2CAP_CONN_SEND_FBIT; @@ -3430,15 +3427,14 @@ 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) { - struct l2cap_pinfo *pi = l2cap_pi(chan->sk); u8 tx_seq = __get_reqseq(rx_control); BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control); chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; - pi->expected_ack_seq = tx_seq; - l2cap_drop_acked_frames(chan->sk); + chan->expected_ack_seq = tx_seq; + l2cap_drop_acked_frames(chan); if (rx_control & L2CAP_CTRL_FINAL) { if (chan->conn_state & L2CAP_CONN_REJ_ACT) @@ -3462,8 +3458,8 @@ static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_ chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; if (rx_control & L2CAP_CTRL_POLL) { - pi->expected_ack_seq = tx_seq; - l2cap_drop_acked_frames(chan->sk); + chan->expected_ack_seq = tx_seq; + l2cap_drop_acked_frames(chan); chan->conn_state |= L2CAP_CONN_SEND_FBIT; l2cap_retransmit_one_frame(chan, tx_seq); @@ -3497,8 +3493,8 @@ static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_c BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control); chan->conn_state |= L2CAP_CONN_REMOTE_BUSY; - pi->expected_ack_seq = tx_seq; - l2cap_drop_acked_frames(chan->sk); + chan->expected_ack_seq = tx_seq; + l2cap_drop_acked_frames(chan); if (rx_control & L2CAP_CTRL_POLL) chan->conn_state |= L2CAP_CONN_SEND_FBIT; @@ -3584,12 +3580,12 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) } req_seq = __get_reqseq(control); - req_seq_offset = (req_seq - pi->expected_ack_seq) % 64; + req_seq_offset = (req_seq - chan->expected_ack_seq) % 64; if (req_seq_offset < 0) req_seq_offset += 64; next_tx_seq_offset = - (pi->next_tx_seq - pi->expected_ack_seq) % 64; + (chan->next_tx_seq - chan->expected_ack_seq) % 64; if (next_tx_seq_offset < 0) next_tx_seq_offset += 64; @@ -3689,10 +3685,10 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk tx_seq = __get_txseq(control); - if (pi->expected_tx_seq == tx_seq) - pi->expected_tx_seq = (pi->expected_tx_seq + 1) % 64; + if (chan->expected_tx_seq == tx_seq) + chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64; else - pi->expected_tx_seq = (tx_seq + 1) % 64; + chan->expected_tx_seq = (tx_seq + 1) % 64; l2cap_streaming_reassembly_sdu(chan, skb, control); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 66ec966ffc18..19574e43226a 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -777,7 +777,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms } if (pi->mode == L2CAP_MODE_STREAMING) { - l2cap_streaming_send(sk); + l2cap_streaming_send(pi->chan); err = len; break; } -- cgit v1.2.3 From 6a026610eee2c53ff59598905fcbaa979aec68d1 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 1 Apr 2011 00:38:50 -0300 Subject: Bluetooth: Move more ERTM stuff to struct l2cap_chan As part of the moving channel stuff to l2cap_chan. Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 10 ++++----- net/bluetooth/l2cap_core.c | 51 ++++++++++++++++++++----------------------- 2 files changed, 29 insertions(+), 32 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 9b43874ca6e4..041213b4175a 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -293,6 +293,11 @@ struct l2cap_chan { __u8 expected_tx_seq; __u8 buffer_seq; __u8 buffer_seq_srej; + __u8 srej_save_reqseq; + __u8 frames_sent; + __u8 unacked_frames; + __u8 retry_count; + __u8 num_acked; struct list_head list; }; @@ -359,11 +364,6 @@ struct l2cap_pinfo { __u8 conf_state; - __u8 srej_save_reqseq; - __u8 frames_sent; - __u8 unacked_frames; - __u8 retry_count; - __u8 num_acked; __u16 sdu_len; __u16 partial_sdu_len; struct sk_buff *sdu; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d975092904c1..3f601d1c164a 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -924,7 +924,7 @@ int __l2cap_wait_ack(struct sock *sk) int timeo = HZ/5; add_wait_queue(sk_sleep(sk), &wait); - while ((l2cap_pi(sk)->unacked_frames > 0 && l2cap_pi(sk)->conn)) { + while ((l2cap_pi(sk)->chan->unacked_frames > 0 && l2cap_pi(sk)->conn)) { set_current_state(TASK_INTERRUPTIBLE); if (!timeo) @@ -956,13 +956,13 @@ static void l2cap_monitor_timeout(unsigned long arg) BT_DBG("chan %p", chan); bh_lock_sock(sk); - if (l2cap_pi(sk)->retry_count >= l2cap_pi(sk)->remote_max_tx) { + if (chan->retry_count >= l2cap_pi(sk)->remote_max_tx) { l2cap_send_disconn_req(l2cap_pi(sk)->conn, sk, ECONNABORTED); bh_unlock_sock(sk); return; } - l2cap_pi(sk)->retry_count++; + chan->retry_count++; __mod_monitor_timer(); l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL); @@ -977,7 +977,7 @@ static void l2cap_retrans_timeout(unsigned long arg) BT_DBG("sk %p", sk); bh_lock_sock(sk); - l2cap_pi(sk)->retry_count = 1; + chan->retry_count = 1; __mod_monitor_timer(); chan->conn_state |= L2CAP_CONN_WAIT_F; @@ -992,17 +992,17 @@ static void l2cap_drop_acked_frames(struct l2cap_chan *chan) struct sk_buff *skb; while ((skb = skb_peek(TX_QUEUE(sk))) && - l2cap_pi(sk)->unacked_frames) { + chan->unacked_frames) { if (bt_cb(skb)->tx_seq == chan->expected_ack_seq) break; skb = skb_dequeue(TX_QUEUE(sk)); kfree_skb(skb); - l2cap_pi(sk)->unacked_frames--; + chan->unacked_frames--; } - if (!l2cap_pi(sk)->unacked_frames) + if (!chan->unacked_frames) del_timer(&l2cap_pi(sk)->retrans_timer); } @@ -1141,9 +1141,9 @@ int l2cap_ertm_send(struct l2cap_chan *chan) chan->next_tx_seq = (chan->next_tx_seq + 1) % 64; if (bt_cb(skb)->retries == 1) - pi->unacked_frames++; + chan->unacked_frames++; - pi->frames_sent++; + chan->frames_sent++; if (skb_queue_is_last(TX_QUEUE(sk), skb)) sk->sk_send_head = NULL; @@ -1574,10 +1574,10 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan) struct sock *sk = chan->sk; chan->expected_ack_seq = 0; - l2cap_pi(sk)->unacked_frames = 0; + chan->unacked_frames = 0; chan->buffer_seq = 0; - l2cap_pi(sk)->num_acked = 0; - l2cap_pi(sk)->frames_sent = 0; + chan->num_acked = 0; + chan->frames_sent = 0; setup_timer(&l2cap_pi(sk)->retrans_timer, l2cap_retrans_timeout, (unsigned long) chan); @@ -2787,10 +2787,9 @@ static int l2cap_check_fcs(struct l2cap_pinfo *pi, struct sk_buff *skb) static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan) { - struct l2cap_pinfo *pi = l2cap_pi(chan->sk); u16 control = 0; - pi->frames_sent = 0; + chan->frames_sent = 0; control |= chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; @@ -2806,7 +2805,7 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan) l2cap_ertm_send(chan); if (!(chan->conn_state & L2CAP_CONN_LOCAL_BUSY) && - pi->frames_sent == 0) { + chan->frames_sent == 0) { control |= L2CAP_SUPER_RCV_READY; l2cap_send_sframe(chan, control); } @@ -2988,7 +2987,7 @@ static int l2cap_try_push_rx_skb(struct l2cap_chan *chan) control = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; control |= L2CAP_SUPER_RCV_READY | L2CAP_CTRL_POLL; l2cap_send_sframe(chan, control); - l2cap_pi(sk)->retry_count = 1; + chan->retry_count = 1; del_timer(&pi->retrans_timer); __mod_monitor_timer(); @@ -3260,7 +3259,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont if (L2CAP_CTRL_FINAL & rx_control && chan->conn_state & L2CAP_CONN_WAIT_F) { del_timer(&pi->monitor_timer); - if (pi->unacked_frames > 0) + if (chan->unacked_frames > 0) __mod_retrans_timer(); chan->conn_state &= ~L2CAP_CONN_WAIT_F; } @@ -3369,8 +3368,8 @@ expected: __mod_ack_timer(); - pi->num_acked = (pi->num_acked + 1) % num_to_ack; - if (pi->num_acked == num_to_ack - 1) + chan->num_acked = (chan->num_acked + 1) % num_to_ack; + if (chan->num_acked == num_to_ack - 1) l2cap_send_ack(chan); return 0; @@ -3383,7 +3382,6 @@ drop: static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_control) { struct sock *sk = chan->sk; - struct l2cap_pinfo *pi = l2cap_pi(sk); BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, __get_reqseq(rx_control), rx_control); @@ -3395,7 +3393,7 @@ static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_co chan->conn_state |= L2CAP_CONN_SEND_FBIT; if (chan->conn_state & L2CAP_CONN_SREJ_SENT) { if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) && - (pi->unacked_frames > 0)) + (chan->unacked_frames > 0)) __mod_retrans_timer(); chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; @@ -3414,7 +3412,7 @@ static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_co } else { if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) && - (pi->unacked_frames > 0)) + (chan->unacked_frames > 0)) __mod_retrans_timer(); chan->conn_state &= ~L2CAP_CONN_REMOTE_BUSY; @@ -3450,7 +3448,6 @@ static inline void l2cap_data_channel_rejframe(struct l2cap_chan *chan, u16 rx_c } static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_control) { - struct l2cap_pinfo *pi = l2cap_pi(chan->sk); u8 tx_seq = __get_reqseq(rx_control); BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control); @@ -3467,19 +3464,19 @@ static inline void l2cap_data_channel_srejframe(struct l2cap_chan *chan, u16 rx_ l2cap_ertm_send(chan); if (chan->conn_state & L2CAP_CONN_WAIT_F) { - pi->srej_save_reqseq = tx_seq; + chan->srej_save_reqseq = tx_seq; chan->conn_state |= L2CAP_CONN_SREJ_ACT; } } else if (rx_control & L2CAP_CTRL_FINAL) { if ((chan->conn_state & L2CAP_CONN_SREJ_ACT) && - pi->srej_save_reqseq == tx_seq) + chan->srej_save_reqseq == tx_seq) chan->conn_state &= ~L2CAP_CONN_SREJ_ACT; else l2cap_retransmit_one_frame(chan, tx_seq); } else { l2cap_retransmit_one_frame(chan, tx_seq); if (chan->conn_state & L2CAP_CONN_WAIT_F) { - pi->srej_save_reqseq = tx_seq; + chan->srej_save_reqseq = tx_seq; chan->conn_state |= L2CAP_CONN_SREJ_ACT; } } @@ -3521,7 +3518,7 @@ static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_cont if (L2CAP_CTRL_FINAL & rx_control && chan->conn_state & L2CAP_CONN_WAIT_F) { del_timer(&l2cap_pi(sk)->monitor_timer); - if (l2cap_pi(sk)->unacked_frames > 0) + if (chan->unacked_frames > 0) __mod_retrans_timer(); chan->conn_state &= ~L2CAP_CONN_WAIT_F; } -- cgit v1.2.3 From 6f61fd475907bf0a1470cb969ee993a31d305513 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 25 Mar 2011 20:09:37 -0300 Subject: Bluetooth: Move SDU related vars to struct l2cap_chan As part of the moving channel stuff to l2cap_chan. Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 8 ++--- net/bluetooth/l2cap_core.c | 74 +++++++++++++++++++++---------------------- 2 files changed, 41 insertions(+), 41 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 041213b4175a..19d613bbcf00 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -298,6 +298,10 @@ struct l2cap_chan { __u8 unacked_frames; __u8 retry_count; __u8 num_acked; + __u16 sdu_len; + __u16 partial_sdu_len; + struct sk_buff *sdu; + struct list_head list; }; @@ -364,10 +368,6 @@ struct l2cap_pinfo { __u8 conf_state; - __u16 sdu_len; - __u16 partial_sdu_len; - struct sk_buff *sdu; - __u8 tx_win; __u8 max_tx; __u8 remote_tx_win; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 3f601d1c164a..8ccfcdf3e083 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2875,13 +2875,13 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk if (chan->conn_state & L2CAP_CONN_SAR_SDU) goto drop; - pi->sdu_len = get_unaligned_le16(skb->data); + chan->sdu_len = get_unaligned_le16(skb->data); - if (pi->sdu_len > pi->imtu) + if (chan->sdu_len > pi->imtu) goto disconnect; - pi->sdu = bt_skb_alloc(pi->sdu_len, GFP_ATOMIC); - if (!pi->sdu) + chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC); + if (!chan->sdu) return -ENOMEM; /* pull sdu_len bytes only after alloc, because of Local Busy @@ -2889,24 +2889,24 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk * only once, i.e., when alloc does not fail */ skb_pull(skb, 2); - memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); + memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); chan->conn_state |= L2CAP_CONN_SAR_SDU; - pi->partial_sdu_len = skb->len; + chan->partial_sdu_len = skb->len; break; case L2CAP_SDU_CONTINUE: if (!(chan->conn_state & L2CAP_CONN_SAR_SDU)) goto disconnect; - if (!pi->sdu) + if (!chan->sdu) goto disconnect; - pi->partial_sdu_len += skb->len; - if (pi->partial_sdu_len > pi->sdu_len) + chan->partial_sdu_len += skb->len; + if (chan->partial_sdu_len > chan->sdu_len) goto drop; - memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); + memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); break; @@ -2914,22 +2914,22 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk if (!(chan->conn_state & L2CAP_CONN_SAR_SDU)) goto disconnect; - if (!pi->sdu) + if (!chan->sdu) goto disconnect; if (!(chan->conn_state & L2CAP_CONN_SAR_RETRY)) { - pi->partial_sdu_len += skb->len; + chan->partial_sdu_len += skb->len; - if (pi->partial_sdu_len > pi->imtu) + if (chan->partial_sdu_len > pi->imtu) goto drop; - if (pi->partial_sdu_len != pi->sdu_len) + if (chan->partial_sdu_len != chan->sdu_len) goto drop; - memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); + memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); } - _skb = skb_clone(pi->sdu, GFP_ATOMIC); + _skb = skb_clone(chan->sdu, GFP_ATOMIC); if (!_skb) { chan->conn_state |= L2CAP_CONN_SAR_RETRY; return -ENOMEM; @@ -2945,7 +2945,7 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk chan->conn_state &= ~L2CAP_CONN_SAR_RETRY; chan->conn_state &= ~L2CAP_CONN_SAR_SDU; - kfree_skb(pi->sdu); + kfree_skb(chan->sdu); break; } @@ -2953,8 +2953,8 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk return 0; drop: - kfree_skb(pi->sdu); - pi->sdu = NULL; + kfree_skb(chan->sdu); + chan->sdu = NULL; disconnect: l2cap_send_disconn_req(pi->conn, chan->sk, ECONNRESET); @@ -3104,7 +3104,7 @@ static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buf switch (control & L2CAP_CTRL_SAR) { case L2CAP_SDU_UNSEGMENTED: if (chan->conn_state & L2CAP_CONN_SAR_SDU) { - kfree_skb(pi->sdu); + kfree_skb(chan->sdu); break; } @@ -3116,28 +3116,28 @@ static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buf case L2CAP_SDU_START: if (chan->conn_state & L2CAP_CONN_SAR_SDU) { - kfree_skb(pi->sdu); + kfree_skb(chan->sdu); break; } - pi->sdu_len = get_unaligned_le16(skb->data); + chan->sdu_len = get_unaligned_le16(skb->data); skb_pull(skb, 2); - if (pi->sdu_len > pi->imtu) { + if (chan->sdu_len > pi->imtu) { err = -EMSGSIZE; break; } - pi->sdu = bt_skb_alloc(pi->sdu_len, GFP_ATOMIC); - if (!pi->sdu) { + chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC); + if (!chan->sdu) { err = -ENOMEM; break; } - memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); + memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); chan->conn_state |= L2CAP_CONN_SAR_SDU; - pi->partial_sdu_len = skb->len; + chan->partial_sdu_len = skb->len; err = 0; break; @@ -3145,11 +3145,11 @@ static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buf if (!(chan->conn_state & L2CAP_CONN_SAR_SDU)) break; - memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); + memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); - pi->partial_sdu_len += skb->len; - if (pi->partial_sdu_len > pi->sdu_len) - kfree_skb(pi->sdu); + chan->partial_sdu_len += skb->len; + if (chan->partial_sdu_len > chan->sdu_len) + kfree_skb(chan->sdu); else err = 0; @@ -3159,16 +3159,16 @@ static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buf if (!(chan->conn_state & L2CAP_CONN_SAR_SDU)) break; - memcpy(skb_put(pi->sdu, skb->len), skb->data, skb->len); + memcpy(skb_put(chan->sdu, skb->len), skb->data, skb->len); chan->conn_state &= ~L2CAP_CONN_SAR_SDU; - pi->partial_sdu_len += skb->len; + chan->partial_sdu_len += skb->len; - if (pi->partial_sdu_len > pi->imtu) + if (chan->partial_sdu_len > pi->imtu) goto drop; - if (pi->partial_sdu_len == pi->sdu_len) { - _skb = skb_clone(pi->sdu, GFP_ATOMIC); + if (chan->partial_sdu_len == chan->sdu_len) { + _skb = skb_clone(chan->sdu, GFP_ATOMIC); err = sock_queue_rcv_skb(chan->sk, _skb); if (err < 0) kfree_skb(_skb); @@ -3176,7 +3176,7 @@ static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buf err = 0; drop: - kfree_skb(pi->sdu); + kfree_skb(chan->sdu); break; } -- cgit v1.2.3 From 2c03a7a49e0831646bd35d0877ec7d051d8f174b Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 25 Mar 2011 20:15:28 -0300 Subject: Bluetooth: Move remote info to struct l2cap_chan As part of the moving channel stuff to l2cap_chan. Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 10 +++++----- net/bluetooth/l2cap_core.c | 32 ++++++++++++++++---------------- net/bluetooth/l2cap_sock.c | 4 ++-- 3 files changed, 23 insertions(+), 23 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 19d613bbcf00..11c53cb4a116 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -302,6 +302,9 @@ struct l2cap_chan { __u16 partial_sdu_len; struct sk_buff *sdu; + __u8 remote_tx_win; + __u8 remote_max_tx; + __u16 remote_mps; struct list_head list; }; @@ -370,11 +373,8 @@ struct l2cap_pinfo { __u8 tx_win; __u8 max_tx; - __u8 remote_tx_win; - __u8 remote_max_tx; __u16 retrans_timeout; __u16 monitor_timeout; - __u16 remote_mps; __u16 mps; __le16 sport; @@ -431,7 +431,7 @@ static inline int l2cap_tx_window_full(struct l2cap_chan *ch) if (sub < 0) sub += 64; - return sub == l2cap_pi(ch->sk)->remote_tx_win; + return sub == ch->remote_tx_win; } #define __get_txseq(ctrl) (((ctrl) & L2CAP_CTRL_TXSEQ) >> 1) @@ -454,7 +454,7 @@ int __l2cap_wait_ack(struct sock *sk); struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len); struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size_t len); struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen); -int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, size_t len); +int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len); void l2cap_do_send(struct sock *sk, struct sk_buff *skb); void l2cap_streaming_send(struct l2cap_chan *chan); int l2cap_ertm_send(struct l2cap_chan *chan); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8ccfcdf3e083..2176a003087e 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -956,7 +956,7 @@ static void l2cap_monitor_timeout(unsigned long arg) BT_DBG("chan %p", chan); bh_lock_sock(sk); - if (chan->retry_count >= l2cap_pi(sk)->remote_max_tx) { + if (chan->retry_count >= chan->remote_max_tx) { l2cap_send_disconn_req(l2cap_pi(sk)->conn, sk, ECONNABORTED); bh_unlock_sock(sk); return; @@ -1065,8 +1065,8 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) } while ((skb = skb_queue_next(TX_QUEUE(sk), skb))); - if (pi->remote_max_tx && - bt_cb(skb)->retries == pi->remote_max_tx) { + if (chan->remote_max_tx && + bt_cb(skb)->retries == chan->remote_max_tx) { l2cap_send_disconn_req(pi->conn, sk, ECONNABORTED); return; } @@ -1106,8 +1106,8 @@ int l2cap_ertm_send(struct l2cap_chan *chan) while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(chan))) { - if (pi->remote_max_tx && - bt_cb(skb)->retries == pi->remote_max_tx) { + if (chan->remote_max_tx && + bt_cb(skb)->retries == chan->remote_max_tx) { l2cap_send_disconn_req(pi->conn, sk, ECONNABORTED); break; } @@ -1337,9 +1337,9 @@ struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, siz return skb; } -int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, size_t len) +int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) { - struct l2cap_pinfo *pi = l2cap_pi(sk); + struct sock *sk = chan->sk; struct sk_buff *skb; struct sk_buff_head sar_queue; u16 control; @@ -1347,20 +1347,20 @@ int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, size_t len) skb_queue_head_init(&sar_queue); control = L2CAP_SDU_START; - skb = l2cap_create_iframe_pdu(sk, msg, pi->remote_mps, control, len); + skb = l2cap_create_iframe_pdu(sk, msg, chan->remote_mps, control, len); if (IS_ERR(skb)) return PTR_ERR(skb); __skb_queue_tail(&sar_queue, skb); - len -= pi->remote_mps; - size += pi->remote_mps; + len -= chan->remote_mps; + size += chan->remote_mps; while (len > 0) { size_t buflen; - if (len > pi->remote_mps) { + if (len > chan->remote_mps) { control = L2CAP_SDU_CONTINUE; - buflen = pi->remote_mps; + buflen = chan->remote_mps; } else { control = L2CAP_SDU_END; buflen = len; @@ -1810,13 +1810,13 @@ done: break; case L2CAP_MODE_ERTM: - pi->remote_tx_win = rfc.txwin_size; - pi->remote_max_tx = rfc.max_transmit; + chan->remote_tx_win = rfc.txwin_size; + chan->remote_max_tx = rfc.max_transmit; if (le16_to_cpu(rfc.max_pdu_size) > pi->conn->mtu - 10) rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10); - pi->remote_mps = le16_to_cpu(rfc.max_pdu_size); + chan->remote_mps = le16_to_cpu(rfc.max_pdu_size); rfc.retrans_timeout = le16_to_cpu(L2CAP_DEFAULT_RETRANS_TO); @@ -1834,7 +1834,7 @@ done: if (le16_to_cpu(rfc.max_pdu_size) > pi->conn->mtu - 10) rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10); - pi->remote_mps = le16_to_cpu(rfc.max_pdu_size); + chan->remote_mps = le16_to_cpu(rfc.max_pdu_size); pi->conf_state |= L2CAP_CONF_MODE_DONE; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 19574e43226a..f90ca2586eaf 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -757,7 +757,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms case L2CAP_MODE_ERTM: case L2CAP_MODE_STREAMING: /* Entire SDU fits into one PDU */ - if (len <= pi->remote_mps) { + if (len <= pi->chan->remote_mps) { control = L2CAP_SDU_UNSEGMENTED; skb = l2cap_create_iframe_pdu(sk, msg, len, control, 0); if (IS_ERR(skb)) { @@ -771,7 +771,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms } else { /* Segment SDU into multiples PDUs */ - err = l2cap_sar_segment_sdu(sk, msg, len); + err = l2cap_sar_segment_sdu(pi->chan, msg, len); if (err < 0) goto done; } -- cgit v1.2.3 From e92c8e70faf5e3cc22979daba2a895359aa1eab2 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 1 Apr 2011 00:53:45 -0300 Subject: Bluetooth: Move ERTM timers to struct l2cap_chan This also triggered a change in l2cap_send_disconn_req() parameters. Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 15 +++++---- net/bluetooth/l2cap_core.c | 74 +++++++++++++++++++++---------------------- net/bluetooth/l2cap_sock.c | 13 ++++---- 3 files changed, 51 insertions(+), 51 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 11c53cb4a116..5f4abea313a2 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -306,6 +306,10 @@ struct l2cap_chan { __u8 remote_max_tx; __u16 remote_mps; + struct timer_list retrans_timer; + struct timer_list monitor_timer; + struct timer_list ack_timer; + struct list_head list; }; @@ -379,9 +383,6 @@ struct l2cap_pinfo { __le16 sport; - struct timer_list retrans_timer; - struct timer_list monitor_timer; - struct timer_list ack_timer; struct sk_buff_head tx_queue; struct sk_buff_head srej_queue; struct sk_buff_head busy_queue; @@ -415,11 +416,11 @@ struct l2cap_pinfo { #define L2CAP_CONN_RNR_SENT 0x0200 #define L2CAP_CONN_SAR_RETRY 0x0400 -#define __mod_retrans_timer() mod_timer(&l2cap_pi(sk)->retrans_timer, \ +#define __mod_retrans_timer() mod_timer(&chan->retrans_timer, \ jiffies + msecs_to_jiffies(L2CAP_DEFAULT_RETRANS_TO)); -#define __mod_monitor_timer() mod_timer(&l2cap_pi(sk)->monitor_timer, \ +#define __mod_monitor_timer() mod_timer(&chan->monitor_timer, \ jiffies + msecs_to_jiffies(L2CAP_DEFAULT_MONITOR_TO)); -#define __mod_ack_timer() mod_timer(&l2cap_pi(sk)->ack_timer, \ +#define __mod_ack_timer() mod_timer(&chan->ack_timer, \ jiffies + msecs_to_jiffies(L2CAP_DEFAULT_ACK_TO)); static inline int l2cap_tx_window_full(struct l2cap_chan *ch) @@ -466,7 +467,7 @@ void l2cap_sock_kill(struct sock *sk); void l2cap_sock_init(struct sock *sk, struct sock *parent); struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio); -void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err); +void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err); void l2cap_chan_del(struct l2cap_chan *chan, int err); int l2cap_do_connect(struct sock *sk); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 2176a003087e..eaac13cb7932 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -241,9 +241,9 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { struct srej_list *l, *tmp; - del_timer(&l2cap_pi(sk)->retrans_timer); - del_timer(&l2cap_pi(sk)->monitor_timer); - del_timer(&l2cap_pi(sk)->ack_timer); + del_timer(&chan->retrans_timer); + del_timer(&chan->monitor_timer); + del_timer(&chan->ack_timer); skb_queue_purge(SREJ_QUEUE(sk)); skb_queue_purge(BUSY_QUEUE(sk)); @@ -462,19 +462,22 @@ static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask) } } -void l2cap_send_disconn_req(struct l2cap_conn *conn, struct sock *sk, int err) +void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err) { + struct sock *sk; struct l2cap_disconn_req req; if (!conn) return; + sk = chan->sk; + skb_queue_purge(TX_QUEUE(sk)); if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { - del_timer(&l2cap_pi(sk)->retrans_timer); - del_timer(&l2cap_pi(sk)->monitor_timer); - del_timer(&l2cap_pi(sk)->ack_timer); + del_timer(&chan->retrans_timer); + del_timer(&chan->monitor_timer); + del_timer(&chan->ack_timer); } req.dcid = cpu_to_le16(l2cap_pi(sk)->dcid); @@ -957,7 +960,7 @@ static void l2cap_monitor_timeout(unsigned long arg) bh_lock_sock(sk); if (chan->retry_count >= chan->remote_max_tx) { - l2cap_send_disconn_req(l2cap_pi(sk)->conn, sk, ECONNABORTED); + l2cap_send_disconn_req(l2cap_pi(sk)->conn, chan, ECONNABORTED); bh_unlock_sock(sk); return; } @@ -1003,7 +1006,7 @@ static void l2cap_drop_acked_frames(struct l2cap_chan *chan) } if (!chan->unacked_frames) - del_timer(&l2cap_pi(sk)->retrans_timer); + del_timer(&chan->retrans_timer); } void l2cap_do_send(struct sock *sk, struct sk_buff *skb) @@ -1067,7 +1070,7 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) if (chan->remote_max_tx && bt_cb(skb)->retries == chan->remote_max_tx) { - l2cap_send_disconn_req(pi->conn, sk, ECONNABORTED); + l2cap_send_disconn_req(pi->conn, chan, ECONNABORTED); return; } @@ -1108,7 +1111,7 @@ int l2cap_ertm_send(struct l2cap_chan *chan) if (chan->remote_max_tx && bt_cb(skb)->retries == chan->remote_max_tx) { - l2cap_send_disconn_req(pi->conn, sk, ECONNABORTED); + l2cap_send_disconn_req(pi->conn, chan, ECONNABORTED); break; } @@ -1579,12 +1582,11 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan) chan->num_acked = 0; chan->frames_sent = 0; - setup_timer(&l2cap_pi(sk)->retrans_timer, - l2cap_retrans_timeout, (unsigned long) chan); - setup_timer(&l2cap_pi(sk)->monitor_timer, - l2cap_monitor_timeout, (unsigned long) chan); - setup_timer(&l2cap_pi(sk)->ack_timer, - l2cap_ack_timeout, (unsigned long) chan); + setup_timer(&chan->retrans_timer, l2cap_retrans_timeout, + (unsigned long) chan); + setup_timer(&chan->monitor_timer, l2cap_monitor_timeout, + (unsigned long) chan); + setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan); __skb_queue_head_init(SREJ_QUEUE(sk)); __skb_queue_head_init(BUSY_QUEUE(sk)); @@ -2291,7 +2293,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr /* Complete config. */ len = l2cap_parse_conf_req(chan, rsp); if (len < 0) { - l2cap_send_disconn_req(conn, sk, ECONNRESET); + l2cap_send_disconn_req(conn, chan, ECONNRESET); goto unlock; } @@ -2363,7 +2365,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr char req[64]; if (len > sizeof(req) - sizeof(struct l2cap_conf_req)) { - l2cap_send_disconn_req(conn, sk, ECONNRESET); + l2cap_send_disconn_req(conn, chan, ECONNRESET); goto done; } @@ -2372,7 +2374,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr len = l2cap_parse_conf_rsp(sk, rsp->data, len, req, &result); if (len < 0) { - l2cap_send_disconn_req(conn, sk, ECONNRESET); + l2cap_send_disconn_req(conn, chan, ECONNRESET); goto done; } @@ -2387,7 +2389,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr default: sk->sk_err = ECONNRESET; l2cap_sock_set_timer(sk, HZ * 5); - l2cap_send_disconn_req(conn, sk, ECONNRESET); + l2cap_send_disconn_req(conn, chan, ECONNRESET); goto done; } @@ -2957,7 +2959,7 @@ drop: chan->sdu = NULL; disconnect: - l2cap_send_disconn_req(pi->conn, chan->sk, ECONNRESET); + l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); kfree_skb(skb); return 0; } @@ -2965,7 +2967,6 @@ disconnect: static int l2cap_try_push_rx_skb(struct l2cap_chan *chan) { struct sock *sk = chan->sk; - struct l2cap_pinfo *pi = l2cap_pi(sk); struct sk_buff *skb; u16 control; int err; @@ -2989,7 +2990,7 @@ static int l2cap_try_push_rx_skb(struct l2cap_chan *chan) l2cap_send_sframe(chan, control); chan->retry_count = 1; - del_timer(&pi->retrans_timer); + del_timer(&chan->retrans_timer); __mod_monitor_timer(); chan->conn_state |= L2CAP_CONN_WAIT_F; @@ -3020,7 +3021,7 @@ static void l2cap_busy_work(struct work_struct *work) if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) { err = -EBUSY; - l2cap_send_disconn_req(pi->conn, sk, EBUSY); + l2cap_send_disconn_req(pi->conn, pi->chan, EBUSY); break; } @@ -3083,7 +3084,7 @@ static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 c chan->conn_state |= L2CAP_CONN_RNR_SENT; - del_timer(&pi->ack_timer); + del_timer(&chan->ack_timer); queue_work(_busy_wq, &pi->busy_work); @@ -3258,7 +3259,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont if (L2CAP_CTRL_FINAL & rx_control && chan->conn_state & L2CAP_CONN_WAIT_F) { - del_timer(&pi->monitor_timer); + del_timer(&chan->monitor_timer); if (chan->unacked_frames > 0) __mod_retrans_timer(); chan->conn_state &= ~L2CAP_CONN_WAIT_F; @@ -3276,7 +3277,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont /* invalid tx_seq */ if (tx_seq_offset >= pi->tx_win) { - l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); + l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); goto drop; } @@ -3341,7 +3342,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont l2cap_send_srejframe(chan, tx_seq); - del_timer(&pi->ack_timer); + del_timer(&chan->ack_timer); } return 0; @@ -3484,7 +3485,6 @@ 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) { - struct l2cap_pinfo *pi = l2cap_pi(chan->sk); u8 tx_seq = __get_reqseq(rx_control); BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, tx_seq, rx_control); @@ -3497,7 +3497,7 @@ static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_c chan->conn_state |= L2CAP_CONN_SEND_FBIT; if (!(chan->conn_state & L2CAP_CONN_SREJ_SENT)) { - del_timer(&pi->retrans_timer); + del_timer(&chan->retrans_timer); if (rx_control & L2CAP_CTRL_POLL) l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_FINAL); return; @@ -3511,13 +3511,11 @@ static inline void l2cap_data_channel_rnrframe(struct l2cap_chan *chan, u16 rx_c static inline int l2cap_data_channel_sframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb) { - struct sock *sk = chan->sk; - BT_DBG("chan %p rx_control 0x%4.4x len %d", chan, rx_control, skb->len); if (L2CAP_CTRL_FINAL & rx_control && chan->conn_state & L2CAP_CONN_WAIT_F) { - del_timer(&l2cap_pi(sk)->monitor_timer); + del_timer(&chan->monitor_timer); if (chan->unacked_frames > 0) __mod_retrans_timer(); chan->conn_state &= ~L2CAP_CONN_WAIT_F; @@ -3572,7 +3570,7 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) len -= 2; if (len > pi->mps) { - l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); + l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); goto drop; } @@ -3588,13 +3586,13 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) /* check for invalid req-seq */ if (req_seq_offset > next_tx_seq_offset) { - l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); + l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); goto drop; } if (__is_iframe(control)) { if (len < 0) { - l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); + l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); goto drop; } @@ -3602,7 +3600,7 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) } else { if (len != 0) { BT_ERR("%d", len); - l2cap_send_disconn_req(pi->conn, sk, ECONNRESET); + l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); goto drop; } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index f90ca2586eaf..d66886f7eccb 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -866,6 +866,7 @@ static void l2cap_sock_cleanup_listen(struct sock *parent) void __l2cap_sock_close(struct sock *sk, int reason) { struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket); @@ -880,9 +881,9 @@ void __l2cap_sock_close(struct sock *sk, int reason) sk->sk_type == SOCK_STREAM) && conn->hcon->type == ACL_LINK) { l2cap_sock_set_timer(sk, sk->sk_sndtimeo); - l2cap_send_disconn_req(conn, sk, reason); + l2cap_send_disconn_req(conn, chan, reason); } else - l2cap_chan_del(l2cap_pi(sk)->chan, reason); + l2cap_chan_del(chan, reason); break; case BT_CONNECT2: @@ -901,16 +902,16 @@ void __l2cap_sock_close(struct sock *sk, int reason) rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); rsp.result = cpu_to_le16(result); rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); - l2cap_send_cmd(conn, l2cap_pi(sk)->chan->ident, - L2CAP_CONN_RSP, sizeof(rsp), &rsp); + l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, + sizeof(rsp), &rsp); } - l2cap_chan_del(l2cap_pi(sk)->chan, reason); + l2cap_chan_del(chan, reason); break; case BT_CONNECT: case BT_DISCONN: - l2cap_chan_del(l2cap_pi(sk)->chan, reason); + l2cap_chan_del(chan, reason); break; default: -- cgit v1.2.3 From f1c6775be6fc944e32e0150305d9753b9a846519 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 25 Mar 2011 20:36:10 -0300 Subject: Bluetooth: Move srej and busy queues to struct l2cap_chan As part of the moving channel stuff to l2cap_chan. Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 6 ++---- net/bluetooth/l2cap_core.c | 42 ++++++++++++++++++++---------------------- net/bluetooth/l2cap_sock.c | 2 -- 3 files changed, 22 insertions(+), 28 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 5f4abea313a2..09f4a2fc2e20 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -309,6 +309,8 @@ struct l2cap_chan { struct timer_list retrans_timer; struct timer_list monitor_timer; struct timer_list ack_timer; + struct sk_buff_head srej_q; + struct sk_buff_head busy_q; struct list_head list; }; @@ -347,8 +349,6 @@ struct l2cap_conn { /* ----- L2CAP socket info ----- */ #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk) #define TX_QUEUE(sk) (&l2cap_pi(sk)->tx_queue) -#define SREJ_QUEUE(sk) (&l2cap_pi(sk)->srej_queue) -#define BUSY_QUEUE(sk) (&l2cap_pi(sk)->busy_queue) #define SREJ_LIST(sk) (&l2cap_pi(sk)->srej_l.list) struct srej_list { @@ -384,8 +384,6 @@ struct l2cap_pinfo { __le16 sport; struct sk_buff_head tx_queue; - struct sk_buff_head srej_queue; - struct sk_buff_head busy_queue; struct work_struct busy_work; struct srej_list srej_l; struct l2cap_conn *conn; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index eaac13cb7932..06c505b1476d 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -245,8 +245,8 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) del_timer(&chan->monitor_timer); del_timer(&chan->ack_timer); - skb_queue_purge(SREJ_QUEUE(sk)); - skb_queue_purge(BUSY_QUEUE(sk)); + skb_queue_purge(&chan->srej_q); + skb_queue_purge(&chan->busy_q); list_for_each_entry_safe(l, tmp, SREJ_LIST(sk), list) { list_del(&l->list); @@ -1588,8 +1588,8 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan) (unsigned long) chan); setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan); - __skb_queue_head_init(SREJ_QUEUE(sk)); - __skb_queue_head_init(BUSY_QUEUE(sk)); + skb_queue_head_init(&chan->srej_q); + skb_queue_head_init(&chan->busy_q); INIT_WORK(&l2cap_pi(sk)->busy_work, l2cap_busy_work); @@ -2815,16 +2815,15 @@ static inline void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan) static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, u8 tx_seq, u8 sar) { - struct sock *sk = chan->sk; struct sk_buff *next_skb; int tx_seq_offset, next_tx_seq_offset; bt_cb(skb)->tx_seq = tx_seq; bt_cb(skb)->sar = sar; - next_skb = skb_peek(SREJ_QUEUE(sk)); + next_skb = skb_peek(&chan->srej_q); if (!next_skb) { - __skb_queue_tail(SREJ_QUEUE(sk), skb); + __skb_queue_tail(&chan->srej_q, skb); return 0; } @@ -2842,16 +2841,16 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, next_tx_seq_offset += 64; if (next_tx_seq_offset > tx_seq_offset) { - __skb_queue_before(SREJ_QUEUE(sk), next_skb, skb); + __skb_queue_before(&chan->srej_q, next_skb, skb); return 0; } - if (skb_queue_is_last(SREJ_QUEUE(sk), next_skb)) + if (skb_queue_is_last(&chan->srej_q, next_skb)) break; - } while ((next_skb = skb_queue_next(SREJ_QUEUE(sk), next_skb))); + } while ((next_skb = skb_queue_next(&chan->srej_q, next_skb))); - __skb_queue_tail(SREJ_QUEUE(sk), skb); + __skb_queue_tail(&chan->srej_q, skb); return 0; } @@ -2971,11 +2970,11 @@ static int l2cap_try_push_rx_skb(struct l2cap_chan *chan) u16 control; int err; - while ((skb = skb_dequeue(BUSY_QUEUE(sk)))) { + while ((skb = skb_dequeue(&chan->busy_q))) { control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; err = l2cap_ertm_reassembly_sdu(chan, skb, control); if (err < 0) { - skb_queue_head(BUSY_QUEUE(sk), skb); + skb_queue_head(&chan->busy_q, skb); return -EBUSY; } @@ -3016,7 +3015,7 @@ static void l2cap_busy_work(struct work_struct *work) lock_sock(sk); add_wait_queue(sk_sleep(sk), &wait); - while ((skb = skb_peek(BUSY_QUEUE(sk)))) { + while ((skb = skb_peek(&pi->chan->busy_q))) { set_current_state(TASK_INTERRUPTIBLE); if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) { @@ -3059,7 +3058,7 @@ static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 c if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) { bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT; - __skb_queue_tail(BUSY_QUEUE(sk), skb); + __skb_queue_tail(&chan->busy_q, skb); return l2cap_try_push_rx_skb(chan); @@ -3076,7 +3075,7 @@ static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 c chan->conn_state |= L2CAP_CONN_LOCAL_BUSY; bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT; - __skb_queue_tail(BUSY_QUEUE(sk), skb); + __skb_queue_tail(&chan->busy_q, skb); sctrl = chan->buffer_seq << L2CAP_CTRL_REQSEQ_SHIFT; sctrl |= L2CAP_SUPER_RCV_NOT_READY; @@ -3187,15 +3186,14 @@ drop: static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq) { - struct sock *sk = chan->sk; struct sk_buff *skb; u16 control; - while ((skb = skb_peek(SREJ_QUEUE(sk)))) { + while ((skb = skb_peek(&chan->srej_q))) { if (bt_cb(skb)->tx_seq != tx_seq) break; - skb = skb_dequeue(SREJ_QUEUE(sk)); + skb = skb_dequeue(&chan->srej_q); control = bt_cb(skb)->sar << L2CAP_CTRL_SAR_SHIFT; l2cap_ertm_reassembly_sdu(chan, skb, control); chan->buffer_seq_srej = @@ -3334,8 +3332,8 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont INIT_LIST_HEAD(SREJ_LIST(sk)); chan->buffer_seq_srej = chan->buffer_seq; - __skb_queue_head_init(SREJ_QUEUE(sk)); - __skb_queue_head_init(BUSY_QUEUE(sk)); + __skb_queue_head_init(&chan->srej_q); + __skb_queue_head_init(&chan->busy_q); l2cap_add_to_srej_queue(chan, skb, tx_seq, sar); chan->conn_state |= L2CAP_CONN_SEND_PBIT; @@ -3352,7 +3350,7 @@ expected: if (chan->conn_state & L2CAP_CONN_SREJ_SENT) { bt_cb(skb)->tx_seq = tx_seq; bt_cb(skb)->sar = sar; - __skb_queue_tail(SREJ_QUEUE(sk), skb); + __skb_queue_tail(&chan->srej_q, skb); return 0; } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index d66886f7eccb..55dee999af94 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1018,8 +1018,6 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent) /* Default config options */ pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; skb_queue_head_init(TX_QUEUE(sk)); - skb_queue_head_init(SREJ_QUEUE(sk)); - skb_queue_head_init(BUSY_QUEUE(sk)); INIT_LIST_HEAD(SREJ_LIST(sk)); } -- cgit v1.2.3 From 311bb895e325e5f4d708c1ed2206da8a3885c83a Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 25 Mar 2011 20:41:00 -0300 Subject: Bluetooth: Move busy workqueue to struct l2cap_chan As part of the moving channel stuff to l2cap_chan. Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 2 +- net/bluetooth/l2cap_core.c | 20 +++++++++----------- 2 files changed, 10 insertions(+), 12 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 09f4a2fc2e20..d05d91f2fd32 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -311,6 +311,7 @@ struct l2cap_chan { struct timer_list ack_timer; struct sk_buff_head srej_q; struct sk_buff_head busy_q; + struct work_struct busy_work; struct list_head list; }; @@ -384,7 +385,6 @@ struct l2cap_pinfo { __le16 sport; struct sk_buff_head tx_queue; - struct work_struct busy_work; struct srej_list srej_l; struct l2cap_conn *conn; struct l2cap_chan *chan; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 06c505b1476d..d3b5d6489a80 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -1591,7 +1591,7 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan) skb_queue_head_init(&chan->srej_q); skb_queue_head_init(&chan->busy_q); - INIT_WORK(&l2cap_pi(sk)->busy_work, l2cap_busy_work); + INIT_WORK(&chan->busy_work, l2cap_busy_work); sk->sk_backlog_rcv = l2cap_ertm_data_rcv; } @@ -3006,21 +3006,21 @@ done: static void l2cap_busy_work(struct work_struct *work) { DECLARE_WAITQUEUE(wait, current); - struct l2cap_pinfo *pi = - container_of(work, struct l2cap_pinfo, busy_work); - struct sock *sk = (struct sock *)pi; + struct l2cap_chan *chan = + container_of(work, struct l2cap_chan, busy_work); + struct sock *sk = chan->sk; int n_tries = 0, timeo = HZ/5, err; struct sk_buff *skb; lock_sock(sk); add_wait_queue(sk_sleep(sk), &wait); - while ((skb = skb_peek(&pi->chan->busy_q))) { + while ((skb = skb_peek(&chan->busy_q))) { set_current_state(TASK_INTERRUPTIBLE); if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) { err = -EBUSY; - l2cap_send_disconn_req(pi->conn, pi->chan, EBUSY); + l2cap_send_disconn_req(l2cap_pi(sk)->conn, chan, EBUSY); break; } @@ -3040,7 +3040,7 @@ static void l2cap_busy_work(struct work_struct *work) if (err) break; - if (l2cap_try_push_rx_skb(l2cap_pi(sk)->chan) == 0) + if (l2cap_try_push_rx_skb(chan) == 0) break; } @@ -3052,8 +3052,6 @@ static void l2cap_busy_work(struct work_struct *work) static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) { - struct sock *sk = chan->sk; - struct l2cap_pinfo *pi = l2cap_pi(sk); int sctrl, err; if (chan->conn_state & L2CAP_CONN_LOCAL_BUSY) { @@ -3071,7 +3069,7 @@ static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 c } /* Busy Condition */ - BT_DBG("sk %p, Enter local busy", sk); + BT_DBG("chan %p, Enter local busy", chan); chan->conn_state |= L2CAP_CONN_LOCAL_BUSY; bt_cb(skb)->sar = control >> L2CAP_CTRL_SAR_SHIFT; @@ -3085,7 +3083,7 @@ static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 c del_timer(&chan->ack_timer); - queue_work(_busy_wq, &pi->busy_work); + queue_work(_busy_wq, &chan->busy_work); return err; } -- cgit v1.2.3 From 2ead70b8390d199ca04cd35311b51f5f3676079e Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 1 Apr 2011 15:13:36 -0300 Subject: Bluetooth: Fix lockdep warning with skb list lock This is a regression acctually, caused by the first patch series for creating a formal strcut l2cap_chan. Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_core.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d3b5d6489a80..7264119b64a6 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -236,6 +236,10 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) } else sk->sk_state_change(sk); + if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE && + l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE)) + goto free; + skb_queue_purge(TX_QUEUE(sk)); if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { @@ -254,6 +258,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) } } +free: kfree(chan); } -- cgit v1.2.3 From 39d5a3ee355fa903ef4609402c79f570eb9fc4d2 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 4 Apr 2011 15:40:12 -0300 Subject: Bluetooth: Move SREJ list to struct l2cap_chan As part of moving all the Channel related operation to struct l2cap_chan. Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 13 ++++++------- net/bluetooth/l2cap_core.c | 22 +++++++++++----------- net/bluetooth/l2cap_sock.c | 1 - 3 files changed, 17 insertions(+), 19 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index d05d91f2fd32..ec56d8861a4e 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -277,6 +277,11 @@ struct l2cap_conn_param_update_rsp { #define L2CAP_CONN_PARAM_REJECTED 0x0001 /* ----- L2CAP channels and connections ----- */ +struct srej_list { + __u8 tx_seq; + struct list_head list; +}; + struct l2cap_chan { struct sock *sk; __u8 ident; @@ -312,6 +317,7 @@ struct l2cap_chan { struct sk_buff_head srej_q; struct sk_buff_head busy_q; struct work_struct busy_work; + struct list_head srej_l; struct list_head list; }; @@ -350,12 +356,6 @@ struct l2cap_conn { /* ----- L2CAP socket info ----- */ #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk) #define TX_QUEUE(sk) (&l2cap_pi(sk)->tx_queue) -#define SREJ_LIST(sk) (&l2cap_pi(sk)->srej_l.list) - -struct srej_list { - __u8 tx_seq; - struct list_head list; -}; struct l2cap_pinfo { struct bt_sock bt; @@ -385,7 +385,6 @@ struct l2cap_pinfo { __le16 sport; struct sk_buff_head tx_queue; - struct srej_list srej_l; struct l2cap_conn *conn; struct l2cap_chan *chan; }; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 7264119b64a6..9580d6cd55da 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -252,7 +252,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) skb_queue_purge(&chan->srej_q); skb_queue_purge(&chan->busy_q); - list_for_each_entry_safe(l, tmp, SREJ_LIST(sk), list) { + list_for_each_entry_safe(l, tmp, &chan->srej_l, list) { list_del(&l->list); kfree(l); } @@ -1205,7 +1205,7 @@ static void l2cap_send_srejtail(struct l2cap_chan *chan) control = L2CAP_SUPER_SELECT_REJECT; control |= L2CAP_CTRL_FINAL; - tail = list_entry(SREJ_LIST(chan->sk)->prev, struct srej_list, list); + tail = list_entry((&chan->srej_l)->prev, struct srej_list, list); control |= tail->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; l2cap_send_sframe(chan, control); @@ -1596,6 +1596,8 @@ static inline void l2cap_ertm_init(struct l2cap_chan *chan) skb_queue_head_init(&chan->srej_q); skb_queue_head_init(&chan->busy_q); + INIT_LIST_HEAD(&chan->srej_l); + INIT_WORK(&chan->busy_work, l2cap_busy_work); sk->sk_backlog_rcv = l2cap_ertm_data_rcv; @@ -3207,11 +3209,10 @@ static void l2cap_check_srej_gap(struct l2cap_chan *chan, u8 tx_seq) static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq) { - struct sock *sk = chan->sk; struct srej_list *l, *tmp; u16 control; - list_for_each_entry_safe(l, tmp, SREJ_LIST(sk), list) { + list_for_each_entry_safe(l, tmp, &chan->srej_l, list) { if (l->tx_seq == tx_seq) { list_del(&l->list); kfree(l); @@ -3221,13 +3222,12 @@ static void l2cap_resend_srejframe(struct l2cap_chan *chan, u8 tx_seq) control |= l->tx_seq << L2CAP_CTRL_REQSEQ_SHIFT; l2cap_send_sframe(chan, control); list_del(&l->list); - list_add_tail(&l->list, SREJ_LIST(sk)); + list_add_tail(&l->list, &chan->srej_l); } } static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq) { - struct sock *sk = chan->sk; struct srej_list *new; u16 control; @@ -3239,7 +3239,7 @@ static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq) 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; - list_add_tail(&new->list, SREJ_LIST(sk)); + list_add_tail(&new->list, &chan->srej_l); } chan->expected_tx_seq = (chan->expected_tx_seq + 1) % 64; } @@ -3288,7 +3288,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont if (chan->conn_state & L2CAP_CONN_SREJ_SENT) { struct srej_list *first; - first = list_first_entry(SREJ_LIST(sk), + first = list_first_entry(&chan->srej_l, struct srej_list, list); if (tx_seq == first->tx_seq) { l2cap_add_to_srej_queue(chan, skb, tx_seq, sar); @@ -3297,7 +3297,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont list_del(&first->list); kfree(first); - if (list_empty(SREJ_LIST(sk))) { + if (list_empty(&chan->srej_l)) { chan->buffer_seq = chan->buffer_seq_srej; chan->conn_state &= ~L2CAP_CONN_SREJ_SENT; l2cap_send_ack(chan); @@ -3310,7 +3310,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont if (l2cap_add_to_srej_queue(chan, skb, tx_seq, sar) < 0) goto drop; - list_for_each_entry(l, SREJ_LIST(sk), list) { + list_for_each_entry(l, &chan->srej_l, list) { if (l->tx_seq == tx_seq) { l2cap_resend_srejframe(chan, tx_seq); return 0; @@ -3332,7 +3332,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont BT_DBG("sk %p, Enter SREJ", sk); - INIT_LIST_HEAD(SREJ_LIST(sk)); + INIT_LIST_HEAD(&chan->srej_l); chan->buffer_seq_srej = chan->buffer_seq; __skb_queue_head_init(&chan->srej_q); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 55dee999af94..16a223bfa8f5 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -1018,7 +1018,6 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent) /* Default config options */ pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; skb_queue_head_init(TX_QUEUE(sk)); - INIT_LIST_HEAD(SREJ_LIST(sk)); } static struct proto l2cap_proto = { -- cgit v1.2.3 From 49208c9c7b483098401683fef5cfbd66931ca643 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 4 Apr 2011 15:59:54 -0300 Subject: Bluetooth: Remove some sk references from l2cap_core.c Change some BT_DBG messages and consequently remove some struct sock declarations. Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_core.c | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 9580d6cd55da..0edfa658090a 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -211,7 +211,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) l2cap_sock_clear_timer(sk); - BT_DBG("sk %p, conn %p, err %d", sk, conn, err); + BT_DBG("chan %p, conn %p, err %d", chan, conn, err); if (conn) { /* Delete from channel list */ @@ -361,7 +361,7 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control) if (pi->fcs == L2CAP_FCS_CRC16) hlen += 2; - BT_DBG("pi %p, control 0x%2.2x", pi, control); + BT_DBG("chan %p, control 0x%2.2x", chan, control); count = min_t(unsigned int, conn->mtu, hlen); control |= L2CAP_CTRL_FRAME_TYPE; @@ -982,7 +982,7 @@ static void l2cap_retrans_timeout(unsigned long arg) struct l2cap_chan *chan = (void *) arg; struct sock *sk = chan->sk; - BT_DBG("sk %p", sk); + BT_DBG("chan %p", chan); bh_lock_sock(sk); chan->retry_count = 1; @@ -1618,13 +1618,12 @@ static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) { - struct sock *sk = chan->sk; - struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_pinfo *pi = l2cap_pi(chan->sk); struct l2cap_conf_req *req = data; struct l2cap_conf_rfc rfc = { .mode = pi->mode }; void *ptr = req->data; - BT_DBG("sk %p", sk); + BT_DBG("chan %p", chan); if (chan->num_conf_req || chan->num_conf_rsp) goto done; @@ -2972,7 +2971,6 @@ disconnect: static int l2cap_try_push_rx_skb(struct l2cap_chan *chan) { - struct sock *sk = chan->sk; struct sk_buff *skb; u16 control; int err; @@ -3005,7 +3003,7 @@ done: chan->conn_state &= ~L2CAP_CONN_LOCAL_BUSY; chan->conn_state &= ~L2CAP_CONN_RNR_SENT; - BT_DBG("sk %p, Exit local busy", sk); + BT_DBG("chan %p, Exit local busy", chan); return 0; } @@ -3246,8 +3244,7 @@ static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq) static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb) { - struct sock *sk = chan->sk; - struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_pinfo *pi = l2cap_pi(chan->sk); u8 tx_seq = __get_txseq(rx_control); u8 req_seq = __get_reqseq(rx_control); u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT; @@ -3301,7 +3298,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont chan->buffer_seq = chan->buffer_seq_srej; chan->conn_state &= ~L2CAP_CONN_SREJ_SENT; l2cap_send_ack(chan); - BT_DBG("sk %p, Exit SREJ_SENT", sk); + BT_DBG("chan %p, Exit SREJ_SENT", chan); } } else { struct srej_list *l; @@ -3330,7 +3327,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont chan->conn_state |= L2CAP_CONN_SREJ_SENT; - BT_DBG("sk %p, Enter SREJ", sk); + BT_DBG("chan %p, Enter SREJ", chan); INIT_LIST_HEAD(&chan->srej_l); chan->buffer_seq_srej = chan->buffer_seq; @@ -3383,9 +3380,7 @@ drop: static inline void l2cap_data_channel_rrframe(struct l2cap_chan *chan, u16 rx_control) { - struct sock *sk = chan->sk; - - BT_DBG("sk %p, req_seq %d ctrl 0x%4.4x", sk, __get_reqseq(rx_control), + BT_DBG("chan %p, req_seq %d ctrl 0x%4.4x", chan, __get_reqseq(rx_control), rx_control); chan->expected_ack_seq = __get_reqseq(rx_control); @@ -3633,7 +3628,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk sk = chan->sk; pi = l2cap_pi(sk); - BT_DBG("sk %p, len %d", sk, skb->len); + BT_DBG("chan %p, len %d", chan, skb->len); if (sk->sk_state != BT_CONNECTED) goto drop; @@ -3691,7 +3686,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk goto done; default: - BT_DBG("sk %p: bad mode 0x%2.2x", sk, pi->mode); + BT_DBG("chan %p: bad mode 0x%2.2x", chan, pi->mode); break; } -- cgit v1.2.3 From c916fbe45c1f30417fa28e62cbbfae295a3f315c Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 4 Apr 2011 16:00:55 -0300 Subject: Bluetooth: Remove unneeded uninitialized_vars() That was unnecessary use of it. Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 0edfa658090a..5fc852a9ae59 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -623,7 +623,7 @@ static struct sock *l2cap_get_sock_by_scid(int state, __le16 cid, bdaddr_t *src) static void l2cap_le_conn_ready(struct l2cap_conn *conn) { - struct sock *parent, *uninitialized_var(sk); + struct sock *parent, *sk; struct l2cap_chan *chan; BT_DBG(""); -- cgit v1.2.3 From 58d35f87effa0235181a24d55576aaa756ef7312 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 4 Apr 2011 16:16:44 -0300 Subject: Bluetooth: Move tx queue to struct l2cap_chan tx_q is the queue used by ERTM mode. Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 4 ++-- net/bluetooth/l2cap_core.c | 40 +++++++++++++++++++--------------------- net/bluetooth/l2cap_sock.c | 7 +++---- 3 files changed, 24 insertions(+), 27 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index ec56d8861a4e..7a215a7f9e39 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -314,6 +314,8 @@ struct l2cap_chan { struct timer_list retrans_timer; struct timer_list monitor_timer; struct timer_list ack_timer; + struct sk_buff *tx_send_head; + struct sk_buff_head tx_q; struct sk_buff_head srej_q; struct sk_buff_head busy_q; struct work_struct busy_work; @@ -355,7 +357,6 @@ struct l2cap_conn { /* ----- L2CAP socket info ----- */ #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk) -#define TX_QUEUE(sk) (&l2cap_pi(sk)->tx_queue) struct l2cap_pinfo { struct bt_sock bt; @@ -384,7 +385,6 @@ struct l2cap_pinfo { __le16 sport; - struct sk_buff_head tx_queue; struct l2cap_conn *conn; struct l2cap_chan *chan; }; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 5fc852a9ae59..97827506dc94 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -240,7 +240,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE)) goto free; - skb_queue_purge(TX_QUEUE(sk)); + skb_queue_purge(&chan->tx_q); if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { struct srej_list *l, *tmp; @@ -477,7 +477,7 @@ void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, in sk = chan->sk; - skb_queue_purge(TX_QUEUE(sk)); + skb_queue_purge(&chan->tx_q); if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { del_timer(&chan->retrans_timer); @@ -996,15 +996,14 @@ static void l2cap_retrans_timeout(unsigned long arg) static void l2cap_drop_acked_frames(struct l2cap_chan *chan) { - struct sock *sk = chan->sk; struct sk_buff *skb; - while ((skb = skb_peek(TX_QUEUE(sk))) && + while ((skb = skb_peek(&chan->tx_q)) && chan->unacked_frames) { if (bt_cb(skb)->tx_seq == chan->expected_ack_seq) break; - skb = skb_dequeue(TX_QUEUE(sk)); + skb = skb_dequeue(&chan->tx_q); kfree_skb(skb); chan->unacked_frames--; @@ -1037,7 +1036,7 @@ void l2cap_streaming_send(struct l2cap_chan *chan) struct l2cap_pinfo *pi = l2cap_pi(sk); u16 control, fcs; - while ((skb = skb_dequeue(TX_QUEUE(sk)))) { + 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); @@ -1060,7 +1059,7 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) struct sk_buff *skb, *tx_skb; u16 control, fcs; - skb = skb_peek(TX_QUEUE(sk)); + skb = skb_peek(&chan->tx_q); if (!skb) return; @@ -1068,10 +1067,10 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) if (bt_cb(skb)->tx_seq == tx_seq) break; - if (skb_queue_is_last(TX_QUEUE(sk), skb)) + if (skb_queue_is_last(&chan->tx_q, skb)) return; - } while ((skb = skb_queue_next(TX_QUEUE(sk), skb))); + } while ((skb = skb_queue_next(&chan->tx_q, skb))); if (chan->remote_max_tx && bt_cb(skb)->retries == chan->remote_max_tx) { @@ -1112,7 +1111,7 @@ int l2cap_ertm_send(struct l2cap_chan *chan) if (sk->sk_state != BT_CONNECTED) return -ENOTCONN; - while ((skb = sk->sk_send_head) && (!l2cap_tx_window_full(chan))) { + while ((skb = chan->tx_send_head) && (!l2cap_tx_window_full(chan))) { if (chan->remote_max_tx && bt_cb(skb)->retries == chan->remote_max_tx) { @@ -1153,10 +1152,10 @@ int l2cap_ertm_send(struct l2cap_chan *chan) chan->frames_sent++; - if (skb_queue_is_last(TX_QUEUE(sk), skb)) - sk->sk_send_head = NULL; + if (skb_queue_is_last(&chan->tx_q, skb)) + chan->tx_send_head = NULL; else - sk->sk_send_head = skb_queue_next(TX_QUEUE(sk), skb); + chan->tx_send_head = skb_queue_next(&chan->tx_q, skb); nsent++; } @@ -1166,11 +1165,10 @@ int l2cap_ertm_send(struct l2cap_chan *chan) static int l2cap_retransmit_frames(struct l2cap_chan *chan) { - struct sock *sk = chan->sk; int ret; - if (!skb_queue_empty(TX_QUEUE(sk))) - sk->sk_send_head = TX_QUEUE(sk)->next; + if (!skb_queue_empty(&chan->tx_q)) + chan->tx_send_head = chan->tx_q.next; chan->next_tx_seq = chan->expected_ack_seq; ret = l2cap_ertm_send(chan); @@ -1384,9 +1382,9 @@ int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t le len -= buflen; size += buflen; } - skb_queue_splice_tail(&sar_queue, TX_QUEUE(sk)); - if (sk->sk_send_head == NULL) - sk->sk_send_head = sar_queue.next; + skb_queue_splice_tail(&sar_queue, &chan->tx_q); + if (chan->tx_send_head == NULL) + chan->tx_send_head = sar_queue.next; return size; } @@ -2319,7 +2317,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr chan->next_tx_seq = 0; chan->expected_tx_seq = 0; - __skb_queue_head_init(TX_QUEUE(sk)); + skb_queue_head_init(&chan->tx_q); if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) l2cap_ertm_init(chan); @@ -2410,7 +2408,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr sk->sk_state = BT_CONNECTED; chan->next_tx_seq = 0; chan->expected_tx_seq = 0; - __skb_queue_head_init(TX_QUEUE(sk)); + skb_queue_head_init(&chan->tx_q); if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) l2cap_ertm_init(chan); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 16a223bfa8f5..b2bfa1e0d74e 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -764,10 +764,10 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms err = PTR_ERR(skb); goto done; } - __skb_queue_tail(TX_QUEUE(sk), skb); + __skb_queue_tail(&pi->chan->tx_q, skb); - if (sk->sk_send_head == NULL) - sk->sk_send_head = skb; + if (pi->chan->tx_send_head == NULL) + pi->chan->tx_send_head = skb; } else { /* Segment SDU into multiples PDUs */ @@ -1017,7 +1017,6 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent) /* Default config options */ pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; - skb_queue_head_init(TX_QUEUE(sk)); } static struct proto l2cap_proto = { -- cgit v1.2.3 From cd69a03af1106c486033df600c7945957ea5abeb Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 5 Apr 2011 15:24:40 -0300 Subject: Bluetooth: Fix wrong comparison in listen() We should check for the pi->scid there. Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_sock.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index b2bfa1e0d74e..473e5973d8fe 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -269,7 +269,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) goto done; } - if (!l2cap_pi(sk)->psm && !l2cap_pi(sk)->dcid) { + if (!l2cap_pi(sk)->psm && !l2cap_pi(sk)->scid) { bdaddr_t *src = &bt_sk(sk)->src; u16 psm; -- cgit v1.2.3 From 9f69bda6aa8b365169b4a6fd35432ee40574d661 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 7 Apr 2011 16:40:25 -0300 Subject: Bluetooth: Add proper handling of received LE data Despite it works, handling through l2cap_data_channel() is wrongs. That function should handle only connection oriented data. Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_core.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 97827506dc94..c9c1f9257a91 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -3728,6 +3728,36 @@ done: return 0; } +static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb) +{ + struct sock *sk; + + sk = l2cap_get_sock_by_scid(0, cid, conn->src); + if (!sk) + goto drop; + + bh_lock_sock(sk); + + BT_DBG("sk %p, len %d", sk, skb->len); + + if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED) + goto drop; + + if (l2cap_pi(sk)->imtu < skb->len) + goto drop; + + if (!sock_queue_rcv_skb(sk, skb)) + goto done; + +drop: + kfree_skb(skb); + +done: + if (sk) + bh_unlock_sock(sk); + return 0; +} + static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) { struct l2cap_hdr *lh = (void *) skb->data; @@ -3757,6 +3787,10 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) l2cap_conless_channel(conn, psm, skb); break; + case L2CAP_CID_LE_DATA: + l2cap_att_channel(conn, cid, skb); + break; + default: l2cap_data_channel(conn, cid, skb); break; -- cgit v1.2.3 From e1ba1f15469903b6f443fbf00f069d169e3fba6d Mon Sep 17 00:00:00 2001 From: Szymon Janc Date: Wed, 6 Apr 2011 13:01:59 +0200 Subject: Bluetooth: Fix Out Of Band pairing when mgmt interface is disabled Use kernel stored remote Out Of Band data only if management interface is enabled. Otherwise HCI_OP_REMOTE_OOB_DATA_NEG_REPLY was sent to controller even if remote Out Of Band data was present in bluetoothd. Signed-off-by: Szymon Janc Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_event.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 7a3398d9cd65..c7eb073fe633 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2497,6 +2497,9 @@ static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev, hci_dev_lock(hdev); + if (!test_bit(HCI_MGMT, &hdev->flags)) + goto unlock; + data = hci_find_remote_oob_data(hdev, &ev->bdaddr); if (data) { struct hci_cp_remote_oob_data_reply cp; @@ -2515,6 +2518,7 @@ static inline void hci_remote_oob_data_request_evt(struct hci_dev *hdev, &cp); } +unlock: hci_dev_unlock(hdev); } -- cgit v1.2.3 From 280f294f7bd0c14d9f802a551c95dc930e31d723 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 13 Apr 2011 19:01:22 -0300 Subject: Bluetooth: Don't lock sock inside l2cap_get_sock_by_scid() Fix an locking issue with the new l2cap_att_channel(). l2cap_att_channel() was trying to lock a locked socket. Reported-by: Anderson Lizardo Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_core.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index c9c1f9257a91..d5db5a38df6a 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -594,7 +594,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) */ static struct sock *l2cap_get_sock_by_scid(int state, __le16 cid, bdaddr_t *src) { - struct sock *s, *sk = NULL, *sk1 = NULL; + struct sock *sk = NULL, *sk1 = NULL; struct hlist_node *node; read_lock(&l2cap_sk_list.lock); @@ -613,12 +613,10 @@ static struct sock *l2cap_get_sock_by_scid(int state, __le16 cid, bdaddr_t *src) sk1 = sk; } } - s = node ? sk : sk1; - if (s) - bh_lock_sock(s); + read_unlock(&l2cap_sk_list.lock); - return s; + return node ? sk : sk1; } static void l2cap_le_conn_ready(struct l2cap_conn *conn) -- cgit v1.2.3 From 62f3a2cfb1891c070631e496eeea852e949ea8bb Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 14 Apr 2011 18:34:34 -0300 Subject: Bluetooth: Fix another locking unbalance l2cap_get_sock_by_scid was changed to not lock the socket anymore, but I forgot to change all the users of this function. Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d5db5a38df6a..bc84ed1b3320 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -632,6 +632,8 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) if (!parent) return; + bh_lock_sock(parent); + /* Check for backlog size */ if (sk_acceptq_is_full(parent)) { BT_DBG("backlog full %d", parent->sk_ack_backlog); -- cgit v1.2.3 From 26954c7f26068b6ced108806fdd39aee5cd54e6f Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Thu, 14 Apr 2011 17:57:26 -0300 Subject: Bluetooth: Fix lockdep warning in L2CAP Fix a regression from the L2CAP "rewrite" patches. Purge the tx_q already happens on l2cap_chan_del() so we don't need it at l2cap_disconnect_req(). Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_core.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index bc84ed1b3320..d47de2b04b2e 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -477,8 +477,6 @@ void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, in sk = chan->sk; - skb_queue_purge(&chan->tx_q); - if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { del_timer(&chan->retrans_timer); del_timer(&chan->monitor_timer); -- cgit v1.2.3 From bf734843120b905bacc3d24c88d7455ae70bf6e1 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 25 Apr 2011 13:03:02 -0700 Subject: bluetooth: Fix use-before-initiailized var. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit net/bluetooth/l2cap_core.c: In function ‘l2cap_recv_frame’: net/bluetooth/l2cap_core.c:3612:15: warning: ‘sk’ may be used uninitialized in this function net/bluetooth/l2cap_core.c:3612:15: note: ‘sk’ was declared here Actually the problem is in the inline function l2cap_data_channel(), we branch to the label 'done' which tests 'sk' before we set it to anything. Initialize it to NULL to fix this. Signed-off-by: David S. Miller --- net/bluetooth/l2cap_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d47de2b04b2e..8cfa2a663028 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -3609,7 +3609,7 @@ drop: static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk_buff *skb) { struct l2cap_chan *chan; - struct sock *sk; + struct sock *sk = NULL; struct l2cap_pinfo *pi; u16 control; u8 tx_seq; -- cgit v1.2.3 From 5d41ce1dd91bce01d50aff79786dc5d5eedcfab7 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Fri, 8 Apr 2011 15:40:02 -0300 Subject: Bluetooth: Refactor L2CAP channel allocation If the allocation happens at l2cap_sock_create() will be able to use the struct l2cap_chan to store channel info that comes from the user via setsockopt. Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 3 ++- net/bluetooth/l2cap_core.c | 23 +++++++---------------- net/bluetooth/l2cap_sock.c | 11 ++++++++++- 3 files changed, 19 insertions(+), 18 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 7a215a7f9e39..537e3c16339f 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -465,7 +465,8 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent); struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio); void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err); +struct l2cap_chan *l2cap_chan_alloc(struct sock *sk); void l2cap_chan_del(struct l2cap_chan *chan, int err); -int l2cap_do_connect(struct sock *sk); +int l2cap_do_connect(struct l2cap_chan *chan); #endif /* __L2CAP_H */ diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 9e8dc136ef16..4b857adc5361 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -149,7 +149,7 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn) return 0; } -static struct l2cap_chan *l2cap_chan_alloc(struct sock *sk) +struct l2cap_chan *l2cap_chan_alloc(struct sock *sk) { struct l2cap_chan *chan; @@ -648,6 +648,8 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) goto clean; } + l2cap_pi(sk)->chan = chan; + write_lock_bh(&conn->chan_lock); hci_conn_hold(conn->hcon); @@ -661,8 +663,6 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) __l2cap_chan_add(conn, chan); - l2cap_pi(sk)->chan = chan; - l2cap_sock_set_timer(sk, sk->sk_sndtimeo); sk->sk_state = BT_CONNECTED; @@ -847,12 +847,12 @@ static struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src) return node ? sk : sk1; } -int l2cap_do_connect(struct sock *sk) +int l2cap_do_connect(struct l2cap_chan *chan) { + struct sock *sk = chan->sk; bdaddr_t *src = &bt_sk(sk)->src; bdaddr_t *dst = &bt_sk(sk)->dst; struct l2cap_conn *conn; - struct l2cap_chan *chan; struct hci_conn *hcon; struct hci_dev *hdev; __u8 auth_type; @@ -888,20 +888,11 @@ int l2cap_do_connect(struct sock *sk) goto done; } - chan = l2cap_chan_alloc(sk); - if (!chan) { - hci_conn_put(hcon); - err = -ENOMEM; - goto done; - } - /* Update source addr of the socket */ bacpy(src, conn->src); l2cap_chan_add(conn, chan); - l2cap_pi(sk)->chan = chan; - sk->sk_state = BT_CONNECT; l2cap_sock_set_timer(sk, sk->sk_sndtimeo); @@ -2076,6 +2067,8 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd goto response; } + l2cap_pi(sk)->chan = chan; + write_lock_bh(&conn->chan_lock); /* Check if we already have channel with that dcid */ @@ -2098,8 +2091,6 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd __l2cap_chan_add(conn, chan); - l2cap_pi(sk)->chan = chan; - dcid = l2cap_pi(sk)->scid; l2cap_sock_set_timer(sk, sk->sk_sndtimeo); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 473e5973d8fe..e3724572c448 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -229,7 +229,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al l2cap_pi(sk)->psm = la.l2_psm; l2cap_pi(sk)->dcid = la.l2_cid; - err = l2cap_do_connect(sk); + err = l2cap_do_connect(l2cap_pi(sk)->chan); if (err) goto done; @@ -1054,6 +1054,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol, int kern) { struct sock *sk; + struct l2cap_chan *chan; BT_DBG("sock %p", sock); @@ -1072,6 +1073,14 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol, if (!sk) return -ENOMEM; + chan = l2cap_chan_alloc(sk); + if (!chan) { + l2cap_sock_kill(sk); + return -ENOMEM; + } + + l2cap_pi(sk)->chan = chan; + l2cap_sock_init(sk, NULL); return 0; } -- cgit v1.2.3 From b44500351845e4f6df0d752a8870da246be8216f Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 12 Apr 2011 18:15:09 -0300 Subject: Bluetooth: Move conf_state to struct l2cap_chan First move of elements depending on user data. Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 3 +- net/bluetooth/l2cap_core.c | 88 ++++++++++++++++++++++--------------------- net/bluetooth/l2cap_sock.c | 10 +++-- 3 files changed, 53 insertions(+), 48 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 537e3c16339f..b3bb3d492fff 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -291,6 +291,7 @@ struct l2cap_chan { __u8 num_conf_req; __u8 num_conf_rsp; + __u8 conf_state; __u16 conn_state; __u8 next_tx_seq; @@ -375,8 +376,6 @@ struct l2cap_pinfo { __u8 force_reliable; __u8 flushable; - __u8 conf_state; - __u8 tx_win; __u8 max_tx; __u16 retrans_timeout; diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 4b857adc5361..190b04960dae 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -236,8 +236,8 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) } else sk->sk_state_change(sk); - if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE && - l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE)) + if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE && + chan->conf_state & L2CAP_CONF_INPUT_DONE)) goto free; skb_queue_purge(&chan->tx_q); @@ -411,9 +411,9 @@ static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control) l2cap_send_sframe(chan, control); } -static inline int __l2cap_no_conn_pending(struct sock *sk) +static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan) { - return !(l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND); + return !(chan->conf_state & L2CAP_CONF_CONNECT_PEND); } static void l2cap_do_start(struct l2cap_chan *chan) @@ -425,13 +425,13 @@ static void l2cap_do_start(struct l2cap_chan *chan) if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)) return; - if (l2cap_check_security(sk) && __l2cap_no_conn_pending(sk)) { + if (l2cap_check_security(sk) && __l2cap_no_conn_pending(chan)) { struct l2cap_conn_req req; req.scid = cpu_to_le16(l2cap_pi(sk)->scid); req.psm = l2cap_pi(sk)->psm; chan->ident = l2cap_get_ident(conn); - l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; + chan->conf_state |= L2CAP_CONF_CONNECT_PEND; l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req); @@ -516,14 +516,14 @@ static void l2cap_conn_start(struct l2cap_conn *conn) struct l2cap_conn_req req; if (!l2cap_check_security(sk) || - !__l2cap_no_conn_pending(sk)) { + !__l2cap_no_conn_pending(chan)) { bh_unlock_sock(sk); continue; } if (!l2cap_mode_supported(l2cap_pi(sk)->mode, conn->feat_mask) - && l2cap_pi(sk)->conf_state & + && chan->conf_state & L2CAP_CONF_STATE2_DEVICE) { /* __l2cap_sock_close() calls list_del(chan) * so release the lock */ @@ -538,7 +538,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) req.psm = l2cap_pi(sk)->psm; chan->ident = l2cap_get_ident(conn); - l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; + chan->conf_state |= L2CAP_CONF_CONNECT_PEND; l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req); @@ -569,13 +569,13 @@ static void l2cap_conn_start(struct l2cap_conn *conn) l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); - if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT || + if (chan->conf_state & L2CAP_CONF_REQ_SENT || rsp.result != L2CAP_CR_SUCCESS) { bh_unlock_sock(sk); continue; } - l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; + chan->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, l2cap_build_conf_req(chan, buf), buf); chan->num_conf_req++; @@ -1382,10 +1382,11 @@ int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t le static void l2cap_chan_ready(struct sock *sk) { struct sock *parent = bt_sk(sk)->parent; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; BT_DBG("sk %p, parent %p", sk, parent); - l2cap_pi(sk)->conf_state = 0; + chan->conf_state = 0; l2cap_sock_clear_timer(sk); if (!parent) { @@ -1619,7 +1620,7 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) switch (pi->mode) { case L2CAP_MODE_STREAMING: case L2CAP_MODE_ERTM: - if (pi->conf_state & L2CAP_CONF_STATE2_DEVICE) + if (chan->conf_state & L2CAP_CONF_STATE2_DEVICE) break; /* fall through */ @@ -1666,7 +1667,7 @@ done: break; if (pi->fcs == L2CAP_FCS_NONE || - pi->conf_state & L2CAP_CONF_NO_FCS_RECV) { + chan->conf_state & L2CAP_CONF_NO_FCS_RECV) { pi->fcs = L2CAP_FCS_NONE; l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, pi->fcs); } @@ -1689,7 +1690,7 @@ done: break; if (pi->fcs == L2CAP_FCS_NONE || - pi->conf_state & L2CAP_CONF_NO_FCS_RECV) { + chan->conf_state & L2CAP_CONF_NO_FCS_RECV) { pi->fcs = L2CAP_FCS_NONE; l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, pi->fcs); } @@ -1742,7 +1743,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data) case L2CAP_CONF_FCS: if (val == L2CAP_FCS_NONE) - pi->conf_state |= L2CAP_CONF_NO_FCS_RECV; + chan->conf_state |= L2CAP_CONF_NO_FCS_RECV; break; @@ -1762,7 +1763,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data) switch (pi->mode) { case L2CAP_MODE_STREAMING: case L2CAP_MODE_ERTM: - if (!(pi->conf_state & L2CAP_CONF_STATE2_DEVICE)) { + if (!(chan->conf_state & L2CAP_CONF_STATE2_DEVICE)) { pi->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask); break; @@ -1795,14 +1796,14 @@ done: result = L2CAP_CONF_UNACCEPT; else { pi->omtu = mtu; - pi->conf_state |= L2CAP_CONF_MTU_DONE; + chan->conf_state |= L2CAP_CONF_MTU_DONE; } l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu); switch (rfc.mode) { case L2CAP_MODE_BASIC: pi->fcs = L2CAP_FCS_NONE; - pi->conf_state |= L2CAP_CONF_MODE_DONE; + chan->conf_state |= L2CAP_CONF_MODE_DONE; break; case L2CAP_MODE_ERTM: @@ -1819,7 +1820,7 @@ done: rfc.monitor_timeout = le16_to_cpu(L2CAP_DEFAULT_MONITOR_TO); - pi->conf_state |= L2CAP_CONF_MODE_DONE; + chan->conf_state |= L2CAP_CONF_MODE_DONE; l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), (unsigned long) &rfc); @@ -1832,7 +1833,7 @@ done: chan->remote_mps = le16_to_cpu(rfc.max_pdu_size); - pi->conf_state |= L2CAP_CONF_MODE_DONE; + chan->conf_state |= L2CAP_CONF_MODE_DONE; l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), (unsigned long) &rfc); @@ -1847,7 +1848,7 @@ done: } if (result == L2CAP_CONF_SUCCESS) - pi->conf_state |= L2CAP_CONF_OUTPUT_DONE; + chan->conf_state |= L2CAP_CONF_OUTPUT_DONE; } rsp->scid = cpu_to_le16(pi->dcid); rsp->result = cpu_to_le16(result); @@ -1856,8 +1857,9 @@ done: return ptr - data; } -static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data, u16 *result) +static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, void *data, u16 *result) { + struct sock *sk = chan->sk; struct l2cap_pinfo *pi = l2cap_pi(sk); struct l2cap_conf_req *req = data; void *ptr = req->data; @@ -1890,7 +1892,7 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data, if (olen == sizeof(rfc)) memcpy(&rfc, (void *)val, olen); - if ((pi->conf_state & L2CAP_CONF_STATE2_DEVICE) && + if ((chan->conf_state & L2CAP_CONF_STATE2_DEVICE) && rfc.mode != pi->mode) return -ECONNREFUSED; @@ -1955,10 +1957,10 @@ void __l2cap_connect_rsp_defer(struct sock *sk) l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp); - if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) + if (chan->conf_state & L2CAP_CONF_REQ_SENT) return; - l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; + chan->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, l2cap_build_conf_req(chan, buf), buf); chan->num_conf_req++; @@ -2146,10 +2148,10 @@ sendresp: L2CAP_INFO_REQ, sizeof(info), &info); } - if (chan && !(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) && + if (chan && !(chan->conf_state & L2CAP_CONF_REQ_SENT) && result == L2CAP_CR_SUCCESS) { u8 buf[128]; - l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; + chan->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, l2cap_build_conf_req(chan, buf), buf); chan->num_conf_req++; @@ -2190,12 +2192,12 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd sk->sk_state = BT_CONFIG; chan->ident = 0; l2cap_pi(sk)->dcid = dcid; - l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_CONNECT_PEND; + chan->conf_state &= ~L2CAP_CONF_CONNECT_PEND; - if (l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT) + if (chan->conf_state & L2CAP_CONF_REQ_SENT) break; - l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; + chan->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, l2cap_build_conf_req(chan, req), req); @@ -2203,7 +2205,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd break; case L2CAP_CR_PEND: - l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; + chan->conf_state |= L2CAP_CONF_CONNECT_PEND; break; default: @@ -2230,7 +2232,7 @@ static inline void set_default_fcs(struct l2cap_pinfo *pi) */ if (pi->mode != L2CAP_MODE_ERTM && pi->mode != L2CAP_MODE_STREAMING) pi->fcs = L2CAP_FCS_NONE; - else if (!(pi->conf_state & L2CAP_CONF_NO_FCS_RECV)) + else if (!(pi->chan->conf_state & L2CAP_CONF_NO_FCS_RECV)) pi->fcs = L2CAP_FCS_CRC16; } @@ -2297,10 +2299,10 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr /* Reset config buffer. */ chan->conf_len = 0; - if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE)) + if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE)) goto unlock; - if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) { + if (chan->conf_state & L2CAP_CONF_INPUT_DONE) { set_default_fcs(l2cap_pi(sk)); sk->sk_state = BT_CONNECTED; @@ -2315,9 +2317,9 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr goto unlock; } - if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) { + if (!(chan->conf_state & L2CAP_CONF_REQ_SENT)) { u8 buf[64]; - l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; + chan->conf_state |= L2CAP_CONF_REQ_SENT; l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ, l2cap_build_conf_req(chan, buf), buf); chan->num_conf_req++; @@ -2365,8 +2367,8 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr /* throw out any old stored conf requests */ result = L2CAP_CONF_SUCCESS; - len = l2cap_parse_conf_rsp(sk, rsp->data, - len, req, &result); + len = l2cap_parse_conf_rsp(chan, rsp->data, len, + req, &result); if (len < 0) { l2cap_send_disconn_req(conn, chan, ECONNRESET); goto done; @@ -2390,9 +2392,9 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (flags & 0x01) goto done; - l2cap_pi(sk)->conf_state |= L2CAP_CONF_INPUT_DONE; + chan->conf_state |= L2CAP_CONF_INPUT_DONE; - if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) { + if (chan->conf_state & L2CAP_CONF_OUTPUT_DONE) { set_default_fcs(l2cap_pi(sk)); sk->sk_state = BT_CONNECTED; @@ -3899,7 +3901,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) bh_lock_sock(sk); - if (l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND) { + if (chan->conf_state & L2CAP_CONF_CONNECT_PEND) { bh_unlock_sock(sk); continue; } @@ -3918,7 +3920,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) req.psm = l2cap_pi(sk)->psm; chan->ident = l2cap_get_ident(conn); - l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND; + chan->conf_state |= L2CAP_CONF_CONNECT_PEND; l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index e3724572c448..a29782a0083a 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -528,6 +528,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; struct l2cap_options opts; int len, err = 0; u32 opt; @@ -565,7 +566,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us l2cap_pi(sk)->mode = opts.mode; switch (l2cap_pi(sk)->mode) { case L2CAP_MODE_BASIC: - l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_STATE2_DEVICE; + chan->conf_state &= ~L2CAP_CONF_STATE2_DEVICE; break; case L2CAP_MODE_ERTM: case L2CAP_MODE_STREAMING: @@ -979,16 +980,19 @@ static void l2cap_sock_destruct(struct sock *sk) void l2cap_sock_init(struct sock *sk, struct sock *parent) { struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_chan *chan = pi->chan; BT_DBG("sk %p", sk); if (parent) { + struct l2cap_chan *pchan = l2cap_pi(parent)->chan; + sk->sk_type = parent->sk_type; bt_sk(sk)->defer_setup = bt_sk(parent)->defer_setup; pi->imtu = l2cap_pi(parent)->imtu; pi->omtu = l2cap_pi(parent)->omtu; - pi->conf_state = l2cap_pi(parent)->conf_state; + chan->conf_state = pchan->conf_state; pi->mode = l2cap_pi(parent)->mode; pi->fcs = l2cap_pi(parent)->fcs; pi->max_tx = l2cap_pi(parent)->max_tx; @@ -1002,7 +1006,7 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent) pi->omtu = 0; if (!disable_ertm && sk->sk_type == SOCK_STREAM) { pi->mode = L2CAP_MODE_ERTM; - pi->conf_state |= L2CAP_CONF_STATE2_DEVICE; + chan->conf_state |= L2CAP_CONF_STATE2_DEVICE; } else { pi->mode = L2CAP_MODE_BASIC; } -- cgit v1.2.3 From 77a74c7e0861e6ebac7effe233fd7e83f1ad9ecc Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 12 Apr 2011 18:17:14 -0300 Subject: Bluetooth: Rename l2cap_do_connect() to l2cap_chan_connect() l2cap_chan_connect() is a much better name and reflects what this functions is doing (or will do once socket dependence is removed from the core). Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 2 +- net/bluetooth/l2cap_core.c | 2 +- net/bluetooth/l2cap_sock.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index b3bb3d492fff..f70935000345 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -466,6 +466,6 @@ struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err); struct l2cap_chan *l2cap_chan_alloc(struct sock *sk); void l2cap_chan_del(struct l2cap_chan *chan, int err); -int l2cap_do_connect(struct l2cap_chan *chan); +int l2cap_chan_connect(struct l2cap_chan *chan); #endif /* __L2CAP_H */ diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 190b04960dae..29742d875e60 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -847,7 +847,7 @@ static struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src) return node ? sk : sk1; } -int l2cap_do_connect(struct l2cap_chan *chan) +int l2cap_chan_connect(struct l2cap_chan *chan) { struct sock *sk = chan->sk; bdaddr_t *src = &bt_sk(sk)->src; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index a29782a0083a..50437c665d1e 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -229,7 +229,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al l2cap_pi(sk)->psm = la.l2_psm; l2cap_pi(sk)->dcid = la.l2_cid; - err = l2cap_do_connect(l2cap_pi(sk)->chan); + err = l2cap_chan_connect(l2cap_pi(sk)->chan); if (err) goto done; -- cgit v1.2.3 From 4343478f3a4806394136d8141b2e451aa5443f03 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Tue, 12 Apr 2011 18:31:57 -0300 Subject: Bluetooth: Move some more elements to struct l2cap_chan In this commit sec_level, force_reliable, role_switch and flushable. Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 12 ++++--- net/bluetooth/l2cap_core.c | 78 +++++++++++++++++++++++-------------------- net/bluetooth/l2cap_sock.c | 52 ++++++++++++++++------------- 3 files changed, 77 insertions(+), 65 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index f70935000345..684deee6ec52 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -284,6 +284,12 @@ struct srej_list { struct l2cap_chan { struct sock *sk; + + __u8 sec_level; + __u8 role_switch; + __u8 force_reliable; + __u8 flushable; + __u8 ident; __u8 conf_req[64]; @@ -371,10 +377,6 @@ struct l2cap_pinfo { __u8 mode; __u8 fcs; - __u8 sec_level; - __u8 role_switch; - __u8 force_reliable; - __u8 flushable; __u8 tx_win; __u8 max_tx; @@ -452,7 +454,7 @@ struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, s struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size_t len); struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen); int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len); -void l2cap_do_send(struct sock *sk, struct sk_buff *skb); +void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb); void l2cap_streaming_send(struct l2cap_chan *chan); int l2cap_ertm_send(struct l2cap_chan *chan); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 29742d875e60..0fc6bbe85d41 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -262,10 +262,12 @@ free: kfree(chan); } -static inline u8 l2cap_get_auth_type(struct sock *sk) +static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) { + struct sock *sk = chan->sk; + if (sk->sk_type == SOCK_RAW) { - switch (l2cap_pi(sk)->sec_level) { + switch (chan->sec_level) { case BT_SECURITY_HIGH: return HCI_AT_DEDICATED_BONDING_MITM; case BT_SECURITY_MEDIUM: @@ -274,15 +276,15 @@ static inline u8 l2cap_get_auth_type(struct sock *sk) return HCI_AT_NO_BONDING; } } else if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) { - if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW) - l2cap_pi(sk)->sec_level = BT_SECURITY_SDP; + if (chan->sec_level == BT_SECURITY_LOW) + chan->sec_level = BT_SECURITY_SDP; - if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH) + if (chan->sec_level == BT_SECURITY_HIGH) return HCI_AT_NO_BONDING_MITM; else return HCI_AT_NO_BONDING; } else { - switch (l2cap_pi(sk)->sec_level) { + switch (chan->sec_level) { case BT_SECURITY_HIGH: return HCI_AT_GENERAL_BONDING_MITM; case BT_SECURITY_MEDIUM: @@ -294,15 +296,14 @@ static inline u8 l2cap_get_auth_type(struct sock *sk) } /* Service level security */ -static inline int l2cap_check_security(struct sock *sk) +static inline int l2cap_check_security(struct l2cap_chan *chan) { - struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_conn *conn = l2cap_pi(chan->sk)->conn; __u8 auth_type; - auth_type = l2cap_get_auth_type(sk); + auth_type = l2cap_get_auth_type(chan); - return hci_conn_security(conn->hcon, l2cap_pi(sk)->sec_level, - auth_type); + return hci_conn_security(conn->hcon, chan->sec_level, auth_type); } u8 l2cap_get_ident(struct l2cap_conn *conn) @@ -425,7 +426,8 @@ static void l2cap_do_start(struct l2cap_chan *chan) if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)) return; - if (l2cap_check_security(sk) && __l2cap_no_conn_pending(chan)) { + if (l2cap_check_security(chan) && + __l2cap_no_conn_pending(chan)) { struct l2cap_conn_req req; req.scid = cpu_to_le16(l2cap_pi(sk)->scid); req.psm = l2cap_pi(sk)->psm; @@ -515,7 +517,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) if (sk->sk_state == BT_CONNECT) { struct l2cap_conn_req req; - if (!l2cap_check_security(sk) || + if (!l2cap_check_security(chan) || !__l2cap_no_conn_pending(chan)) { bh_unlock_sock(sk); continue; @@ -549,7 +551,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); - if (l2cap_check_security(sk)) { + if (l2cap_check_security(chan)) { if (bt_sk(sk)->defer_setup) { struct sock *parent = bt_sk(sk)->parent; rsp.result = cpu_to_le16(L2CAP_CR_PEND); @@ -722,7 +724,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 (l2cap_pi(sk)->force_reliable) + if (chan->force_reliable) sk->sk_err = err; } @@ -867,14 +869,14 @@ int l2cap_chan_connect(struct l2cap_chan *chan) hci_dev_lock_bh(hdev); - auth_type = l2cap_get_auth_type(sk); + auth_type = l2cap_get_auth_type(chan); if (l2cap_pi(sk)->dcid == L2CAP_CID_LE_DATA) hcon = hci_connect(hdev, LE_LINK, dst, - l2cap_pi(sk)->sec_level, auth_type); + chan->sec_level, auth_type); else hcon = hci_connect(hdev, ACL_LINK, dst, - l2cap_pi(sk)->sec_level, auth_type); + chan->sec_level, auth_type); if (IS_ERR(hcon)) { err = PTR_ERR(hcon); @@ -900,7 +902,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan) if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM) { l2cap_sock_clear_timer(sk); - if (l2cap_check_security(sk)) + if (l2cap_check_security(chan)) sk->sk_state = BT_CONNECTED; } else l2cap_do_start(chan); @@ -1002,15 +1004,15 @@ static void l2cap_drop_acked_frames(struct l2cap_chan *chan) del_timer(&chan->retrans_timer); } -void l2cap_do_send(struct sock *sk, struct sk_buff *skb) +void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) { - struct l2cap_pinfo *pi = l2cap_pi(sk); - struct hci_conn *hcon = pi->conn->hcon; + struct sock *sk = chan->sk; + struct hci_conn *hcon = l2cap_pi(sk)->conn->hcon; u16 flags; - BT_DBG("sk %p, skb %p len %d", sk, skb, skb->len); + BT_DBG("chan %p, skb %p len %d", chan, skb, skb->len); - if (!pi->flushable && lmp_no_flush_capable(hcon->hdev)) + if (!chan->flushable && lmp_no_flush_capable(hcon->hdev)) flags = ACL_START_NO_FLUSH; else flags = ACL_START; @@ -1035,7 +1037,7 @@ void l2cap_streaming_send(struct l2cap_chan *chan) put_unaligned_le16(fcs, skb->data + skb->len - 2); } - l2cap_do_send(sk, skb); + l2cap_do_send(chan, skb); chan->next_tx_seq = (chan->next_tx_seq + 1) % 64; } @@ -1087,7 +1089,7 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) put_unaligned_le16(fcs, tx_skb->data + tx_skb->len - 2); } - l2cap_do_send(sk, tx_skb); + l2cap_do_send(chan, tx_skb); } int l2cap_ertm_send(struct l2cap_chan *chan) @@ -1130,7 +1132,7 @@ int l2cap_ertm_send(struct l2cap_chan *chan) put_unaligned_le16(fcs, skb->data + tx_skb->len - 2); } - l2cap_do_send(sk, tx_skb); + l2cap_do_send(chan, tx_skb); __mod_retrans_timer(); @@ -2100,7 +2102,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd chan->ident = cmd->ident; if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) { - if (l2cap_check_security(sk)) { + if (l2cap_check_security(chan)) { if (bt_sk(sk)->defer_setup) { sk->sk_state = BT_CONNECT2; result = L2CAP_CR_PEND; @@ -3805,17 +3807,19 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) /* Find listening sockets and check their link_mode */ read_lock(&l2cap_sk_list.lock); sk_for_each(sk, node, &l2cap_sk_list.head) { + struct l2cap_chan *chan = l2cap_pi(sk)->chan; + if (sk->sk_state != BT_LISTEN) continue; if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) { lm1 |= HCI_LM_ACCEPT; - if (l2cap_pi(sk)->role_switch) + if (chan->role_switch) lm1 |= HCI_LM_MASTER; exact++; } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) { lm2 |= HCI_LM_ACCEPT; - if (l2cap_pi(sk)->role_switch) + if (chan->role_switch) lm2 |= HCI_LM_MASTER; } } @@ -3867,19 +3871,21 @@ static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason) return 0; } -static inline void l2cap_check_encryption(struct sock *sk, u8 encrypt) +static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt) { + struct sock *sk = chan->sk; + if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM) return; if (encrypt == 0x00) { - if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM) { + if (chan->sec_level == BT_SECURITY_MEDIUM) { l2cap_sock_clear_timer(sk); l2cap_sock_set_timer(sk, HZ * 5); - } else if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH) + } else if (chan->sec_level == BT_SECURITY_HIGH) __l2cap_sock_close(sk, ECONNREFUSED); } else { - if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM) + if (chan->sec_level == BT_SECURITY_MEDIUM) l2cap_sock_clear_timer(sk); } } @@ -3908,7 +3914,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) if (!status && (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG)) { - l2cap_check_encryption(sk, encrypt); + l2cap_check_encryption(chan, encrypt); bh_unlock_sock(sk); continue; } @@ -4083,7 +4089,7 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p) batostr(&bt_sk(sk)->dst), sk->sk_state, __le16_to_cpu(pi->psm), pi->scid, pi->dcid, - pi->imtu, pi->omtu, pi->sec_level, + pi->imtu, pi->omtu, pi->chan->sec_level, pi->mode); } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 50437c665d1e..612955679b34 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -51,7 +51,7 @@ static void l2cap_sock_timeout(unsigned long arg) if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG) reason = ECONNREFUSED; else if (sk->sk_state == BT_CONNECT && - l2cap_pi(sk)->sec_level != BT_SECURITY_SDP) + l2cap_pi(sk)->chan->sec_level != BT_SECURITY_SDP) reason = ECONNREFUSED; else reason = ETIMEDOUT; @@ -91,6 +91,7 @@ found: static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) { struct sock *sk = sock->sk; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; struct sockaddr_l2 la; int len, err = 0; @@ -142,7 +143,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) if (__le16_to_cpu(la.l2_psm) == 0x0001 || __le16_to_cpu(la.l2_psm) == 0x0003) - l2cap_pi(sk)->sec_level = BT_SECURITY_SDP; + chan->sec_level = BT_SECURITY_SDP; } if (la.l2_cid) @@ -382,6 +383,7 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen) { struct sock *sk = sock->sk; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; struct l2cap_options opts; struct l2cap_conninfo cinfo; int len, err = 0; @@ -412,7 +414,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us break; case L2CAP_LM: - switch (l2cap_pi(sk)->sec_level) { + switch (chan->sec_level) { case BT_SECURITY_LOW: opt = L2CAP_LM_AUTH; break; @@ -428,10 +430,10 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us break; } - if (l2cap_pi(sk)->role_switch) + if (chan->role_switch) opt |= L2CAP_LM_MASTER; - if (l2cap_pi(sk)->force_reliable) + if (chan->force_reliable) opt |= L2CAP_LM_RELIABLE; if (put_user(opt, (u32 __user *) optval)) @@ -467,6 +469,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) { struct sock *sk = sock->sk; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; struct bt_security sec; int len, err = 0; @@ -491,7 +494,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch break; } - sec.level = l2cap_pi(sk)->sec_level; + sec.level = chan->sec_level; len = min_t(unsigned int, len, sizeof(sec)); if (copy_to_user(optval, (char *) &sec, len)) @@ -511,7 +514,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch break; case BT_FLUSHABLE: - if (put_user(l2cap_pi(sk)->flushable, (u32 __user *) optval)) + if (put_user(chan->flushable, (u32 __user *) optval)) err = -EFAULT; break; @@ -592,14 +595,14 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us } if (opt & L2CAP_LM_AUTH) - l2cap_pi(sk)->sec_level = BT_SECURITY_LOW; + chan->sec_level = BT_SECURITY_LOW; if (opt & L2CAP_LM_ENCRYPT) - l2cap_pi(sk)->sec_level = BT_SECURITY_MEDIUM; + chan->sec_level = BT_SECURITY_MEDIUM; if (opt & L2CAP_LM_SECURE) - l2cap_pi(sk)->sec_level = BT_SECURITY_HIGH; + chan->sec_level = BT_SECURITY_HIGH; - l2cap_pi(sk)->role_switch = (opt & L2CAP_LM_MASTER); - l2cap_pi(sk)->force_reliable = (opt & L2CAP_LM_RELIABLE); + chan->role_switch = (opt & L2CAP_LM_MASTER); + chan->force_reliable = (opt & L2CAP_LM_RELIABLE); break; default: @@ -614,6 +617,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; struct bt_security sec; int len, err = 0; u32 opt; @@ -650,7 +654,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch break; } - l2cap_pi(sk)->sec_level = sec.level; + chan->sec_level = sec.level; break; case BT_DEFER_SETUP: @@ -688,7 +692,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch } } - l2cap_pi(sk)->flushable = opt; + chan->flushable = opt; break; default: @@ -730,7 +734,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms if (IS_ERR(skb)) { err = PTR_ERR(skb); } else { - l2cap_do_send(sk, skb); + l2cap_do_send(pi->chan, skb); err = len; } goto done; @@ -751,7 +755,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms goto done; } - l2cap_do_send(sk, skb); + l2cap_do_send(pi->chan, skb); err = len; break; @@ -997,10 +1001,10 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent) pi->fcs = l2cap_pi(parent)->fcs; pi->max_tx = l2cap_pi(parent)->max_tx; pi->tx_win = l2cap_pi(parent)->tx_win; - pi->sec_level = l2cap_pi(parent)->sec_level; - pi->role_switch = l2cap_pi(parent)->role_switch; - pi->force_reliable = l2cap_pi(parent)->force_reliable; - pi->flushable = l2cap_pi(parent)->flushable; + chan->sec_level = pchan->sec_level; + chan->role_switch = pchan->role_switch; + chan->force_reliable = pchan->force_reliable; + chan->flushable = pchan->flushable; } else { pi->imtu = L2CAP_DEFAULT_MTU; pi->omtu = 0; @@ -1013,10 +1017,10 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent) pi->max_tx = L2CAP_DEFAULT_MAX_TX; pi->fcs = L2CAP_FCS_CRC16; pi->tx_win = L2CAP_DEFAULT_TX_WINDOW; - pi->sec_level = BT_SECURITY_LOW; - pi->role_switch = 0; - pi->force_reliable = 0; - pi->flushable = BT_FLUSHABLE_OFF; + chan->sec_level = BT_SECURITY_LOW; + chan->role_switch = 0; + chan->force_reliable = 0; + chan->flushable = BT_FLUSHABLE_OFF; } /* Default config options */ -- cgit v1.2.3 From 47d1ec6161da2c7b9dbc56a5200fa26b17d5fdc1 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 13 Apr 2011 15:57:03 -0300 Subject: Bluetooth: Move more vars to struct l2cap_chan In this commit all ERTM and Streaming Mode specific vars. Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 18 ++++---- net/bluetooth/l2cap_core.c | 100 +++++++++++++++++++++--------------------- net/bluetooth/l2cap_sock.c | 33 +++++++------- net/bluetooth/rfcomm/core.c | 2 +- 4 files changed, 77 insertions(+), 76 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 684deee6ec52..02db90210f8d 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -297,6 +297,14 @@ struct l2cap_chan { __u8 num_conf_req; __u8 num_conf_rsp; + __u8 fcs; + + __u8 tx_win; + __u8 max_tx; + __u16 retrans_timeout; + __u16 monitor_timeout; + __u16 mps; + __u8 conf_state; __u16 conn_state; @@ -376,14 +384,6 @@ struct l2cap_pinfo { __u16 flush_to; __u8 mode; - __u8 fcs; - - __u8 tx_win; - __u8 max_tx; - __u16 retrans_timeout; - __u16 monitor_timeout; - __u16 mps; - __le16 sport; struct l2cap_conn *conn; @@ -452,7 +452,7 @@ int __l2cap_wait_ack(struct sock *sk); struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len); struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size_t len); -struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen); +struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u16 control, u16 sdulen); int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len); void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb); void l2cap_streaming_send(struct l2cap_chan *chan); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 0fc6bbe85d41..cb3c4ed47ae2 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -359,7 +359,7 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control) if (sk->sk_state != BT_CONNECTED) return; - if (pi->fcs == L2CAP_FCS_CRC16) + if (chan->fcs == L2CAP_FCS_CRC16) hlen += 2; BT_DBG("chan %p, control 0x%2.2x", chan, control); @@ -386,7 +386,7 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control) lh->cid = cpu_to_le16(pi->dcid); put_unaligned_le16(control, skb_put(skb, 2)); - if (pi->fcs == L2CAP_FCS_CRC16) { + if (chan->fcs == L2CAP_FCS_CRC16) { u16 fcs = crc16(0, (u8 *)lh, count - 2); put_unaligned_le16(fcs, skb_put(skb, 2)); } @@ -1022,9 +1022,7 @@ void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) void l2cap_streaming_send(struct l2cap_chan *chan) { - struct sock *sk = chan->sk; struct sk_buff *skb; - struct l2cap_pinfo *pi = l2cap_pi(sk); u16 control, fcs; while ((skb = skb_dequeue(&chan->tx_q))) { @@ -1032,7 +1030,7 @@ void l2cap_streaming_send(struct l2cap_chan *chan) control |= chan->next_tx_seq << L2CAP_CTRL_TXSEQ_SHIFT; put_unaligned_le16(control, skb->data + L2CAP_HDR_SIZE); - if (pi->fcs == L2CAP_FCS_CRC16) { + if (chan->fcs == L2CAP_FCS_CRC16) { fcs = crc16(0, (u8 *)skb->data, skb->len - 2); put_unaligned_le16(fcs, skb->data + skb->len - 2); } @@ -1084,7 +1082,7 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); - if (pi->fcs == L2CAP_FCS_CRC16) { + 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); } @@ -1127,7 +1125,7 @@ int l2cap_ertm_send(struct l2cap_chan *chan) put_unaligned_le16(control, tx_skb->data + L2CAP_HDR_SIZE); - if (pi->fcs == L2CAP_FCS_CRC16) { + 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); } @@ -1290,8 +1288,9 @@ struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size return skb; } -struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, size_t len, u16 control, u16 sdulen) +struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u16 control, u16 sdulen) { + struct sock *sk = chan->sk; struct l2cap_conn *conn = l2cap_pi(sk)->conn; struct sk_buff *skb; int err, count, hlen = L2CAP_HDR_SIZE + 2; @@ -1305,7 +1304,7 @@ struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, siz if (sdulen) hlen += 2; - if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) + if (chan->fcs == L2CAP_FCS_CRC16) hlen += 2; count = min_t(unsigned int, (conn->mtu - hlen), len); @@ -1328,7 +1327,7 @@ struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, siz return ERR_PTR(err); } - if (l2cap_pi(sk)->fcs == L2CAP_FCS_CRC16) + if (chan->fcs == L2CAP_FCS_CRC16) put_unaligned_le16(0, skb_put(skb, 2)); bt_cb(skb)->retries = 0; @@ -1337,7 +1336,6 @@ struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, siz int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) { - struct sock *sk = chan->sk; struct sk_buff *skb; struct sk_buff_head sar_queue; u16 control; @@ -1345,7 +1343,7 @@ int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t le skb_queue_head_init(&sar_queue); control = L2CAP_SDU_START; - skb = l2cap_create_iframe_pdu(sk, msg, chan->remote_mps, control, len); + skb = l2cap_create_iframe_pdu(chan, msg, chan->remote_mps, control, len); if (IS_ERR(skb)) return PTR_ERR(skb); @@ -1364,7 +1362,7 @@ int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t le buflen = len; } - skb = l2cap_create_iframe_pdu(sk, msg, buflen, control, 0); + skb = l2cap_create_iframe_pdu(chan, msg, buflen, control, 0); if (IS_ERR(skb)) { skb_queue_purge(&sar_queue); return PTR_ERR(skb); @@ -1654,8 +1652,8 @@ done: case L2CAP_MODE_ERTM: rfc.mode = L2CAP_MODE_ERTM; - rfc.txwin_size = pi->tx_win; - rfc.max_transmit = pi->max_tx; + 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); @@ -1668,10 +1666,10 @@ done: if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS)) break; - if (pi->fcs == L2CAP_FCS_NONE || + if (chan->fcs == L2CAP_FCS_NONE || chan->conf_state & L2CAP_CONF_NO_FCS_RECV) { - pi->fcs = L2CAP_FCS_NONE; - l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, pi->fcs); + chan->fcs = L2CAP_FCS_NONE; + l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs); } break; @@ -1691,10 +1689,10 @@ done: if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS)) break; - if (pi->fcs == L2CAP_FCS_NONE || + if (chan->fcs == L2CAP_FCS_NONE || chan->conf_state & L2CAP_CONF_NO_FCS_RECV) { - pi->fcs = L2CAP_FCS_NONE; - l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, pi->fcs); + chan->fcs = L2CAP_FCS_NONE; + l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs); } break; } @@ -1804,7 +1802,7 @@ done: switch (rfc.mode) { case L2CAP_MODE_BASIC: - pi->fcs = L2CAP_FCS_NONE; + chan->fcs = L2CAP_FCS_NONE; chan->conf_state |= L2CAP_CONF_MODE_DONE; break; @@ -1898,7 +1896,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi rfc.mode != pi->mode) return -ECONNREFUSED; - pi->fcs = 0; + chan->fcs = 0; l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), (unsigned long) &rfc); @@ -1914,12 +1912,12 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi if (*result == L2CAP_CONF_SUCCESS) { switch (rfc.mode) { case L2CAP_MODE_ERTM: - pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); - pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); - pi->mps = le16_to_cpu(rfc.max_pdu_size); + 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); break; case L2CAP_MODE_STREAMING: - pi->mps = le16_to_cpu(rfc.max_pdu_size); + chan->mps = le16_to_cpu(rfc.max_pdu_size); } } @@ -1968,14 +1966,14 @@ void __l2cap_connect_rsp_defer(struct sock *sk) chan->num_conf_req++; } -static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len) +static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len) { - struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_pinfo *pi = l2cap_pi(chan->sk); int type, olen; unsigned long val; struct l2cap_conf_rfc rfc; - BT_DBG("sk %p, rsp %p, len %d", sk, rsp, len); + BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len); if ((pi->mode != L2CAP_MODE_ERTM) && (pi->mode != L2CAP_MODE_STREAMING)) return; @@ -1994,12 +1992,12 @@ static void l2cap_conf_rfc_get(struct sock *sk, void *rsp, int len) done: switch (rfc.mode) { case L2CAP_MODE_ERTM: - pi->retrans_timeout = le16_to_cpu(rfc.retrans_timeout); - pi->monitor_timeout = le16_to_cpu(rfc.monitor_timeout); - pi->mps = le16_to_cpu(rfc.max_pdu_size); + 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); break; case L2CAP_MODE_STREAMING: - pi->mps = le16_to_cpu(rfc.max_pdu_size); + chan->mps = le16_to_cpu(rfc.max_pdu_size); } } @@ -2227,15 +2225,17 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd return 0; } -static inline void set_default_fcs(struct l2cap_pinfo *pi) +static inline void set_default_fcs(struct l2cap_chan *chan) { + struct l2cap_pinfo *pi = l2cap_pi(chan->sk); + /* FCS is enabled only in ERTM or streaming mode, if one or both * sides request it. */ if (pi->mode != L2CAP_MODE_ERTM && pi->mode != L2CAP_MODE_STREAMING) - pi->fcs = L2CAP_FCS_NONE; + chan->fcs = L2CAP_FCS_NONE; else if (!(pi->chan->conf_state & L2CAP_CONF_NO_FCS_RECV)) - pi->fcs = L2CAP_FCS_CRC16; + chan->fcs = L2CAP_FCS_CRC16; } static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data) @@ -2305,7 +2305,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr goto unlock; if (chan->conf_state & L2CAP_CONF_INPUT_DONE) { - set_default_fcs(l2cap_pi(sk)); + set_default_fcs(chan); sk->sk_state = BT_CONNECTED; @@ -2355,7 +2355,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr switch (result) { case L2CAP_CONF_SUCCESS: - l2cap_conf_rfc_get(sk, rsp->data, len); + l2cap_conf_rfc_get(chan, rsp->data, len); break; case L2CAP_CONF_UNACCEPT: @@ -2397,7 +2397,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr chan->conf_state |= L2CAP_CONF_INPUT_DONE; if (chan->conf_state & L2CAP_CONF_OUTPUT_DONE) { - set_default_fcs(l2cap_pi(sk)); + set_default_fcs(chan); sk->sk_state = BT_CONNECTED; chan->next_tx_seq = 0; @@ -2769,12 +2769,12 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn, kfree_skb(skb); } -static int l2cap_check_fcs(struct l2cap_pinfo *pi, struct sk_buff *skb) +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; - if (pi->fcs == L2CAP_FCS_CRC16) { + if (chan->fcs == L2CAP_FCS_CRC16) { skb_trim(skb, skb->len - 2); rcv_fcs = get_unaligned_le16(skb->data + skb->len); our_fcs = crc16(0, skb->data - hdr_size, skb->len + hdr_size); @@ -3241,7 +3241,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont u8 req_seq = __get_reqseq(rx_control); u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT; int tx_seq_offset, expected_tx_seq_offset; - int num_to_ack = (pi->tx_win/6) + 1; + 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, @@ -3266,7 +3266,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont tx_seq_offset += 64; /* invalid tx_seq */ - if (tx_seq_offset >= pi->tx_win) { + if (tx_seq_offset >= chan->tx_win) { l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); goto drop; } @@ -3548,16 +3548,16 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) * Receiver will miss it and start proper recovery * procedures and ask retransmission. */ - if (l2cap_check_fcs(pi, skb)) + if (l2cap_check_fcs(chan, skb)) goto drop; if (__is_sar_start(control) && __is_iframe(control)) len -= 2; - if (pi->fcs == L2CAP_FCS_CRC16) + if (chan->fcs == L2CAP_FCS_CRC16) len -= 2; - if (len > pi->mps) { + if (len > chan->mps) { l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); goto drop; } @@ -3654,16 +3654,16 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk skb_pull(skb, 2); len = skb->len; - if (l2cap_check_fcs(pi, skb)) + if (l2cap_check_fcs(chan, skb)) goto drop; if (__is_sar_start(control)) len -= 2; - if (pi->fcs == L2CAP_FCS_CRC16) + if (chan->fcs == L2CAP_FCS_CRC16) len -= 2; - if (len > pi->mps || len < 0 || __is_sframe(control)) + if (len > chan->mps || len < 0 || __is_sframe(control)) goto drop; tx_seq = __get_txseq(control); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 612955679b34..4ba15b3b2e6a 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -403,9 +403,9 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us opts.omtu = l2cap_pi(sk)->omtu; opts.flush_to = l2cap_pi(sk)->flush_to; opts.mode = l2cap_pi(sk)->mode; - opts.fcs = l2cap_pi(sk)->fcs; - opts.max_tx = l2cap_pi(sk)->max_tx; - opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win; + opts.fcs = chan->fcs; + opts.max_tx = chan->max_tx; + opts.txwin_size = (__u16)chan->tx_win; len = min_t(unsigned int, len, sizeof(opts)); if (copy_to_user(optval, (char *) &opts, len)) @@ -551,9 +551,9 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us opts.omtu = l2cap_pi(sk)->omtu; opts.flush_to = l2cap_pi(sk)->flush_to; opts.mode = l2cap_pi(sk)->mode; - opts.fcs = l2cap_pi(sk)->fcs; - opts.max_tx = l2cap_pi(sk)->max_tx; - opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win; + opts.fcs = chan->fcs; + opts.max_tx = chan->max_tx; + opts.txwin_size = (__u16)chan->tx_win; len = min_t(unsigned int, sizeof(opts), optlen); if (copy_from_user((char *) &opts, optval, len)) { @@ -583,9 +583,9 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us l2cap_pi(sk)->imtu = opts.imtu; l2cap_pi(sk)->omtu = opts.omtu; - l2cap_pi(sk)->fcs = opts.fcs; - l2cap_pi(sk)->max_tx = opts.max_tx; - l2cap_pi(sk)->tx_win = (__u8)opts.txwin_size; + chan->fcs = opts.fcs; + chan->max_tx = opts.max_tx; + chan->tx_win = (__u8)opts.txwin_size; break; case L2CAP_LM: @@ -764,7 +764,8 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms /* Entire SDU fits into one PDU */ if (len <= pi->chan->remote_mps) { control = L2CAP_SDU_UNSEGMENTED; - skb = l2cap_create_iframe_pdu(sk, msg, len, control, 0); + skb = l2cap_create_iframe_pdu(pi->chan, msg, len, + control, 0); if (IS_ERR(skb)) { err = PTR_ERR(skb); goto done; @@ -998,9 +999,9 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent) pi->omtu = l2cap_pi(parent)->omtu; chan->conf_state = pchan->conf_state; pi->mode = l2cap_pi(parent)->mode; - pi->fcs = l2cap_pi(parent)->fcs; - pi->max_tx = l2cap_pi(parent)->max_tx; - pi->tx_win = l2cap_pi(parent)->tx_win; + chan->fcs = pchan->fcs; + chan->max_tx = pchan->max_tx; + chan->tx_win = pchan->tx_win; chan->sec_level = pchan->sec_level; chan->role_switch = pchan->role_switch; chan->force_reliable = pchan->force_reliable; @@ -1014,9 +1015,9 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent) } else { pi->mode = L2CAP_MODE_BASIC; } - pi->max_tx = L2CAP_DEFAULT_MAX_TX; - pi->fcs = L2CAP_FCS_CRC16; - pi->tx_win = L2CAP_DEFAULT_TX_WINDOW; + chan->max_tx = L2CAP_DEFAULT_MAX_TX; + chan->fcs = L2CAP_FCS_CRC16; + chan->tx_win = L2CAP_DEFAULT_TX_WINDOW; chan->sec_level = BT_SECURITY_LOW; chan->role_switch = 0; chan->force_reliable = 0; diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index c9973932456f..4f728a4f7177 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -711,7 +711,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, sk = sock->sk; lock_sock(sk); l2cap_pi(sk)->imtu = l2cap_mtu; - l2cap_pi(sk)->sec_level = sec_level; + l2cap_pi(sk)->chan->sec_level = sec_level; if (l2cap_ertm) l2cap_pi(sk)->mode = L2CAP_MODE_ERTM; release_sock(sk); -- cgit v1.2.3 From 0c1bc5c626e9783034264ccca4b262b3acc628f1 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 13 Apr 2011 17:20:49 -0300 Subject: Bluetooth: Move more channel info to struct l2cap_chan In this commit, omtu, imtu, flush_to, mode and sport. It also remove the pi var from l2cap_sock_sendmsg(). Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 14 +++--- net/bluetooth/cmtp/core.c | 3 +- net/bluetooth/hidp/core.c | 6 ++- net/bluetooth/l2cap_core.c | 97 ++++++++++++++++++++-------------------- net/bluetooth/l2cap_sock.c | 100 +++++++++++++++++++++++------------------- net/bluetooth/rfcomm/core.c | 11 ++--- 6 files changed, 121 insertions(+), 110 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 02db90210f8d..7522835c24ee 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -285,6 +285,13 @@ struct srej_list { struct l2cap_chan { struct sock *sk; + __u16 imtu; + __u16 omtu; + __u16 flush_to; + __u8 mode; + + __le16 sport; + __u8 sec_level; __u8 role_switch; __u8 force_reliable; @@ -379,13 +386,6 @@ struct l2cap_pinfo { __u16 dcid; __u16 scid; - __u16 imtu; - __u16 omtu; - __u16 flush_to; - __u8 mode; - - __le16 sport; - struct l2cap_conn *conn; struct l2cap_chan *chan; }; diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c index cce99b0919f5..c5b11af908be 100644 --- a/net/bluetooth/cmtp/core.c +++ b/net/bluetooth/cmtp/core.c @@ -346,7 +346,8 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock) bacpy(&session->bdaddr, &bt_sk(sock->sk)->dst); - session->mtu = min_t(uint, l2cap_pi(sock->sk)->omtu, l2cap_pi(sock->sk)->imtu); + session->mtu = min_t(uint, l2cap_pi(sock->sk)->chan->omtu, + l2cap_pi(sock->sk)->chan->imtu); BT_DBG("mtu %d", session->mtu); diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index ae6ebc6c3481..c405a954a603 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -979,8 +979,10 @@ int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, bacpy(&session->bdaddr, &bt_sk(ctrl_sock->sk)->dst); - session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->omtu, l2cap_pi(ctrl_sock->sk)->imtu); - session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->omtu, l2cap_pi(intr_sock->sk)->imtu); + session->ctrl_mtu = min_t(uint, l2cap_pi(ctrl_sock->sk)->chan->omtu, + l2cap_pi(ctrl_sock->sk)->chan->imtu); + session->intr_mtu = min_t(uint, l2cap_pi(intr_sock->sk)->chan->omtu, + l2cap_pi(intr_sock->sk)->chan->imtu); BT_DBG("ctrl mtu %d intr mtu %d", session->ctrl_mtu, session->intr_mtu); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index cb3c4ed47ae2..7b06375d05a7 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -176,24 +176,24 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) if (sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM) { if (conn->hcon->type == LE_LINK) { /* LE connection */ - l2cap_pi(sk)->omtu = L2CAP_LE_DEFAULT_MTU; + chan->omtu = L2CAP_LE_DEFAULT_MTU; l2cap_pi(sk)->scid = L2CAP_CID_LE_DATA; l2cap_pi(sk)->dcid = L2CAP_CID_LE_DATA; } else { /* Alloc CID for connection-oriented socket */ l2cap_pi(sk)->scid = l2cap_alloc_cid(conn); - l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; + chan->omtu = L2CAP_DEFAULT_MTU; } } else if (sk->sk_type == SOCK_DGRAM) { /* Connectionless socket */ l2cap_pi(sk)->scid = L2CAP_CID_CONN_LESS; l2cap_pi(sk)->dcid = L2CAP_CID_CONN_LESS; - l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; + chan->omtu = L2CAP_DEFAULT_MTU; } else { /* Raw socket can send/recv signalling messages only */ l2cap_pi(sk)->scid = L2CAP_CID_SIGNALING; l2cap_pi(sk)->dcid = L2CAP_CID_SIGNALING; - l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU; + chan->omtu = L2CAP_DEFAULT_MTU; } sock_hold(sk); @@ -242,7 +242,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) skb_queue_purge(&chan->tx_q); - if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { + if (chan->mode == L2CAP_MODE_ERTM) { struct srej_list *l, *tmp; del_timer(&chan->retrans_timer); @@ -479,7 +479,7 @@ void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, in sk = chan->sk; - if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) { + if (chan->mode == L2CAP_MODE_ERTM) { del_timer(&chan->retrans_timer); del_timer(&chan->monitor_timer); del_timer(&chan->ack_timer); @@ -523,7 +523,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn) continue; } - if (!l2cap_mode_supported(l2cap_pi(sk)->mode, + if (!l2cap_mode_supported(chan->mode, conn->feat_mask) && chan->conf_state & L2CAP_CONF_STATE2_DEVICE) { @@ -1609,7 +1609,7 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) { struct l2cap_pinfo *pi = l2cap_pi(chan->sk); struct l2cap_conf_req *req = data; - struct l2cap_conf_rfc rfc = { .mode = pi->mode }; + struct l2cap_conf_rfc rfc = { .mode = chan->mode }; void *ptr = req->data; BT_DBG("chan %p", chan); @@ -1617,7 +1617,7 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) if (chan->num_conf_req || chan->num_conf_rsp) goto done; - switch (pi->mode) { + switch (chan->mode) { case L2CAP_MODE_STREAMING: case L2CAP_MODE_ERTM: if (chan->conf_state & L2CAP_CONF_STATE2_DEVICE) @@ -1625,15 +1625,15 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) /* fall through */ default: - pi->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask); + chan->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask); break; } done: - if (pi->imtu != L2CAP_DEFAULT_MTU) - l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu); + if (chan->imtu != L2CAP_DEFAULT_MTU) + l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu); - switch (pi->mode) { + switch (chan->mode) { case L2CAP_MODE_BASIC: if (!(pi->conn->feat_mask & L2CAP_FEAT_ERTM) && !(pi->conn->feat_mask & L2CAP_FEAT_STREAMING)) @@ -1730,7 +1730,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data) break; case L2CAP_CONF_FLUSH_TO: - pi->flush_to = val; + chan->flush_to = val; break; case L2CAP_CONF_QOS: @@ -1760,25 +1760,25 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data) if (chan->num_conf_rsp || chan->num_conf_req > 1) goto done; - switch (pi->mode) { + switch (chan->mode) { case L2CAP_MODE_STREAMING: case L2CAP_MODE_ERTM: if (!(chan->conf_state & L2CAP_CONF_STATE2_DEVICE)) { - pi->mode = l2cap_select_mode(rfc.mode, + chan->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask); break; } - if (pi->mode != rfc.mode) + if (chan->mode != rfc.mode) return -ECONNREFUSED; break; } done: - if (pi->mode != rfc.mode) { + if (chan->mode != rfc.mode) { result = L2CAP_CONF_UNACCEPT; - rfc.mode = pi->mode; + rfc.mode = chan->mode; if (chan->num_conf_rsp == 1) return -ECONNREFUSED; @@ -1795,10 +1795,10 @@ done: if (mtu < L2CAP_DEFAULT_MIN_MTU) result = L2CAP_CONF_UNACCEPT; else { - pi->omtu = mtu; + chan->omtu = mtu; chan->conf_state |= L2CAP_CONF_MTU_DONE; } - l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->omtu); + l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->omtu); switch (rfc.mode) { case L2CAP_MODE_BASIC: @@ -1844,7 +1844,7 @@ done: result = L2CAP_CONF_UNACCEPT; memset(&rfc, 0, sizeof(rfc)); - rfc.mode = pi->mode; + rfc.mode = chan->mode; } if (result == L2CAP_CONF_SUCCESS) @@ -1876,16 +1876,16 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi case L2CAP_CONF_MTU: if (val < L2CAP_DEFAULT_MIN_MTU) { *result = L2CAP_CONF_UNACCEPT; - pi->imtu = L2CAP_DEFAULT_MIN_MTU; + chan->imtu = L2CAP_DEFAULT_MIN_MTU; } else - pi->imtu = val; - l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, pi->imtu); + chan->imtu = val; + l2cap_add_conf_opt(&ptr, L2CAP_CONF_MTU, 2, chan->imtu); break; case L2CAP_CONF_FLUSH_TO: - pi->flush_to = val; + chan->flush_to = val; l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO, - 2, pi->flush_to); + 2, chan->flush_to); break; case L2CAP_CONF_RFC: @@ -1893,7 +1893,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi memcpy(&rfc, (void *)val, olen); if ((chan->conf_state & L2CAP_CONF_STATE2_DEVICE) && - rfc.mode != pi->mode) + rfc.mode != chan->mode) return -ECONNREFUSED; chan->fcs = 0; @@ -1904,10 +1904,10 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi } } - if (pi->mode == L2CAP_MODE_BASIC && pi->mode != rfc.mode) + if (chan->mode == L2CAP_MODE_BASIC && chan->mode != rfc.mode) return -ECONNREFUSED; - pi->mode = rfc.mode; + chan->mode = rfc.mode; if (*result == L2CAP_CONF_SUCCESS) { switch (rfc.mode) { @@ -1968,14 +1968,13 @@ void __l2cap_connect_rsp_defer(struct sock *sk) static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len) { - struct l2cap_pinfo *pi = l2cap_pi(chan->sk); int type, olen; unsigned long val; struct l2cap_conf_rfc rfc; BT_DBG("chan %p, rsp %p, len %d", chan, rsp, len); - if ((pi->mode != L2CAP_MODE_ERTM) && (pi->mode != L2CAP_MODE_STREAMING)) + if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING)) return; while (len >= L2CAP_CONF_OPT_SIZE) { @@ -2232,7 +2231,7 @@ static inline void set_default_fcs(struct l2cap_chan *chan) /* FCS is enabled only in ERTM or streaming mode, if one or both * sides request it. */ - if (pi->mode != L2CAP_MODE_ERTM && pi->mode != L2CAP_MODE_STREAMING) + if (chan->mode != L2CAP_MODE_ERTM && chan->mode != L2CAP_MODE_STREAMING) chan->fcs = L2CAP_FCS_NONE; else if (!(pi->chan->conf_state & L2CAP_CONF_NO_FCS_RECV)) chan->fcs = L2CAP_FCS_CRC16; @@ -2312,7 +2311,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr chan->next_tx_seq = 0; chan->expected_tx_seq = 0; skb_queue_head_init(&chan->tx_q); - if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) + if (chan->mode == L2CAP_MODE_ERTM) l2cap_ertm_init(chan); l2cap_chan_ready(sk); @@ -2403,7 +2402,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr chan->next_tx_seq = 0; chan->expected_tx_seq = 0; skb_queue_head_init(&chan->tx_q); - if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) + if (chan->mode == L2CAP_MODE_ERTM) l2cap_ertm_init(chan); l2cap_chan_ready(sk); @@ -2876,7 +2875,7 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk chan->sdu_len = get_unaligned_le16(skb->data); - if (chan->sdu_len > pi->imtu) + if (chan->sdu_len > chan->imtu) goto disconnect; chan->sdu = bt_skb_alloc(chan->sdu_len, GFP_ATOMIC); @@ -2919,7 +2918,7 @@ static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *sk if (!(chan->conn_state & L2CAP_CONN_SAR_RETRY)) { chan->partial_sdu_len += skb->len; - if (chan->partial_sdu_len > pi->imtu) + if (chan->partial_sdu_len > chan->imtu) goto drop; if (chan->partial_sdu_len != chan->sdu_len) @@ -3087,7 +3086,6 @@ static int l2cap_push_rx_skb(struct l2cap_chan *chan, struct sk_buff *skb, u16 c static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) { - struct l2cap_pinfo *pi = l2cap_pi(chan->sk); struct sk_buff *_skb; int err = -EINVAL; @@ -3118,7 +3116,7 @@ static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buf chan->sdu_len = get_unaligned_le16(skb->data); skb_pull(skb, 2); - if (chan->sdu_len > pi->imtu) { + if (chan->sdu_len > chan->imtu) { err = -EMSGSIZE; break; } @@ -3159,7 +3157,7 @@ static int l2cap_streaming_reassembly_sdu(struct l2cap_chan *chan, struct sk_buf chan->conn_state &= ~L2CAP_CONN_SAR_SDU; chan->partial_sdu_len += skb->len; - if (chan->partial_sdu_len > pi->imtu) + if (chan->partial_sdu_len > chan->imtu) goto drop; if (chan->partial_sdu_len == chan->sdu_len) { @@ -3625,14 +3623,14 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk if (sk->sk_state != BT_CONNECTED) goto drop; - switch (pi->mode) { + switch (chan->mode) { case L2CAP_MODE_BASIC: /* If socket recv buffers overflows we drop data here * which is *bad* because L2CAP has to be reliable. * But we don't have any other choice. L2CAP doesn't * provide flow control mechanism. */ - if (pi->imtu < skb->len) + if (chan->imtu < skb->len) goto drop; if (!sock_queue_rcv_skb(sk, skb)) @@ -3678,7 +3676,7 @@ static inline int l2cap_data_channel(struct l2cap_conn *conn, u16 cid, struct sk goto done; default: - BT_DBG("chan %p: bad mode 0x%2.2x", chan, pi->mode); + BT_DBG("chan %p: bad mode 0x%2.2x", chan, chan->mode); break; } @@ -3707,7 +3705,7 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED) goto drop; - if (l2cap_pi(sk)->imtu < skb->len) + if (l2cap_pi(sk)->chan->imtu < skb->len) goto drop; if (!sock_queue_rcv_skb(sk, skb)) @@ -3737,7 +3735,7 @@ static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED) goto drop; - if (l2cap_pi(sk)->imtu < skb->len) + if (l2cap_pi(sk)->chan->imtu < skb->len) goto drop; if (!sock_queue_rcv_skb(sk, skb)) @@ -4020,10 +4018,10 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl if (chan && chan->sk) { struct sock *sk = chan->sk; - if (l2cap_pi(sk)->imtu < len - L2CAP_HDR_SIZE) { + if (chan->imtu < len - L2CAP_HDR_SIZE) { BT_ERR("Frame exceeding recv MTU (len %d, " "MTU %d)", len, - l2cap_pi(sk)->imtu); + chan->imtu); bh_unlock_sock(sk); l2cap_conn_unreliable(conn, ECOMM); goto drop; @@ -4083,14 +4081,15 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p) sk_for_each(sk, node, &l2cap_sk_list.head) { struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_chan *chan = pi->chan; seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n", batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), sk->sk_state, __le16_to_cpu(pi->psm), pi->scid, pi->dcid, - pi->imtu, pi->omtu, pi->chan->sec_level, - pi->mode); + chan->imtu, chan->omtu, chan->sec_level, + chan->mode); } read_unlock_bh(&l2cap_sk_list.lock); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 4ba15b3b2e6a..eef33b179f02 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -80,9 +80,13 @@ static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src) { struct sock *sk; struct hlist_node *node; - sk_for_each(sk, node, &l2cap_sk_list.head) - if (l2cap_pi(sk)->sport == psm && !bacmp(&bt_sk(sk)->src, src)) + sk_for_each(sk, node, &l2cap_sk_list.head) { + struct l2cap_chan *chan = l2cap_pi(sk)->chan; + + if (chan->sport == psm && !bacmp(&bt_sk(sk)->src, src)) goto found; + } + sk = NULL; found: return sk; @@ -138,7 +142,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) /* Save source address */ bacpy(&bt_sk(sk)->src, &la.l2_bdaddr); l2cap_pi(sk)->psm = la.l2_psm; - l2cap_pi(sk)->sport = la.l2_psm; + chan->sport = la.l2_psm; sk->sk_state = BT_BOUND; if (__le16_to_cpu(la.l2_psm) == 0x0001 || @@ -159,6 +163,7 @@ done: static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) { struct sock *sk = sock->sk; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; struct sockaddr_l2 la; int len, err = 0; @@ -183,7 +188,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al goto done; } - switch (l2cap_pi(sk)->mode) { + switch (chan->mode) { case L2CAP_MODE_BASIC: break; case L2CAP_MODE_ERTM: @@ -245,6 +250,7 @@ done: static int l2cap_sock_listen(struct socket *sock, int backlog) { struct sock *sk = sock->sk; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; int err = 0; BT_DBG("sk %p backlog %d", sk, backlog); @@ -257,7 +263,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) goto done; } - switch (l2cap_pi(sk)->mode) { + switch (chan->mode) { case L2CAP_MODE_BASIC: break; case L2CAP_MODE_ERTM: @@ -281,7 +287,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) for (psm = 0x1001; psm < 0x1100; psm += 2) if (!__l2cap_get_sock_by_addr(cpu_to_le16(psm), src)) { l2cap_pi(sk)->psm = cpu_to_le16(psm); - l2cap_pi(sk)->sport = cpu_to_le16(psm); + chan->sport = cpu_to_le16(psm); err = 0; break; } @@ -361,6 +367,7 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l { struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr; struct sock *sk = sock->sk; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; BT_DBG("sock %p, sk %p", sock, sk); @@ -372,7 +379,7 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l bacpy(&la->l2_bdaddr, &bt_sk(sk)->dst); la->l2_cid = cpu_to_le16(l2cap_pi(sk)->dcid); } else { - la->l2_psm = l2cap_pi(sk)->sport; + la->l2_psm = chan->sport; bacpy(&la->l2_bdaddr, &bt_sk(sk)->src); la->l2_cid = cpu_to_le16(l2cap_pi(sk)->scid); } @@ -399,10 +406,10 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us switch (optname) { case L2CAP_OPTIONS: memset(&opts, 0, sizeof(opts)); - opts.imtu = l2cap_pi(sk)->imtu; - opts.omtu = l2cap_pi(sk)->omtu; - opts.flush_to = l2cap_pi(sk)->flush_to; - opts.mode = l2cap_pi(sk)->mode; + opts.imtu = chan->imtu; + opts.omtu = chan->omtu; + opts.flush_to = chan->flush_to; + opts.mode = chan->mode; opts.fcs = chan->fcs; opts.max_tx = chan->max_tx; opts.txwin_size = (__u16)chan->tx_win; @@ -547,10 +554,10 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us break; } - opts.imtu = l2cap_pi(sk)->imtu; - opts.omtu = l2cap_pi(sk)->omtu; - opts.flush_to = l2cap_pi(sk)->flush_to; - opts.mode = l2cap_pi(sk)->mode; + opts.imtu = chan->imtu; + opts.omtu = chan->omtu; + opts.flush_to = chan->flush_to; + opts.mode = chan->mode; opts.fcs = chan->fcs; opts.max_tx = chan->max_tx; opts.txwin_size = (__u16)chan->tx_win; @@ -566,8 +573,8 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us break; } - l2cap_pi(sk)->mode = opts.mode; - switch (l2cap_pi(sk)->mode) { + chan->mode = opts.mode; + switch (chan->mode) { case L2CAP_MODE_BASIC: chan->conf_state &= ~L2CAP_CONF_STATE2_DEVICE; break; @@ -581,8 +588,8 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us break; } - l2cap_pi(sk)->imtu = opts.imtu; - l2cap_pi(sk)->omtu = opts.omtu; + chan->imtu = opts.imtu; + chan->omtu = opts.omtu; chan->fcs = opts.fcs; chan->max_tx = opts.max_tx; chan->tx_win = (__u8)opts.txwin_size; @@ -707,7 +714,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len) { struct sock *sk = sock->sk; - struct l2cap_pinfo *pi = l2cap_pi(sk); + struct l2cap_chan *chan = l2cap_pi(sk)->chan; struct sk_buff *skb; u16 control; int err; @@ -734,16 +741,16 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms if (IS_ERR(skb)) { err = PTR_ERR(skb); } else { - l2cap_do_send(pi->chan, skb); + l2cap_do_send(chan, skb); err = len; } goto done; } - switch (pi->mode) { + switch (chan->mode) { case L2CAP_MODE_BASIC: /* Check outgoing MTU */ - if (len > pi->omtu) { + if (len > chan->omtu) { err = -EMSGSIZE; goto done; } @@ -755,52 +762,52 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms goto done; } - l2cap_do_send(pi->chan, skb); + l2cap_do_send(chan, skb); err = len; break; case L2CAP_MODE_ERTM: case L2CAP_MODE_STREAMING: /* Entire SDU fits into one PDU */ - if (len <= pi->chan->remote_mps) { + if (len <= chan->remote_mps) { control = L2CAP_SDU_UNSEGMENTED; - skb = l2cap_create_iframe_pdu(pi->chan, msg, len, - control, 0); + skb = l2cap_create_iframe_pdu(chan, msg, len, control, + 0); if (IS_ERR(skb)) { err = PTR_ERR(skb); goto done; } - __skb_queue_tail(&pi->chan->tx_q, skb); + __skb_queue_tail(&chan->tx_q, skb); - if (pi->chan->tx_send_head == NULL) - pi->chan->tx_send_head = skb; + if (chan->tx_send_head == NULL) + chan->tx_send_head = skb; } else { /* Segment SDU into multiples PDUs */ - err = l2cap_sar_segment_sdu(pi->chan, msg, len); + err = l2cap_sar_segment_sdu(chan, msg, len); if (err < 0) goto done; } - if (pi->mode == L2CAP_MODE_STREAMING) { - l2cap_streaming_send(pi->chan); + if (chan->mode == L2CAP_MODE_STREAMING) { + l2cap_streaming_send(chan); err = len; break; } - if ((pi->chan->conn_state & L2CAP_CONN_REMOTE_BUSY) && - (pi->chan->conn_state & L2CAP_CONN_WAIT_F)) { + if ((chan->conn_state & L2CAP_CONN_REMOTE_BUSY) && + (chan->conn_state & L2CAP_CONN_WAIT_F)) { err = len; break; } - err = l2cap_ertm_send(pi->chan); + err = l2cap_ertm_send(chan); if (err >= 0) err = len; break; default: - BT_DBG("bad state %1.1x", pi->mode); + BT_DBG("bad state %1.1x", chan->mode); err = -EBADFD; } @@ -929,6 +936,7 @@ void __l2cap_sock_close(struct sock *sk, int reason) static int l2cap_sock_shutdown(struct socket *sock, int how) { struct sock *sk = sock->sk; + struct l2cap_chan *chan = l2cap_pi(sk)->chan; int err = 0; BT_DBG("sock %p, sk %p", sock, sk); @@ -938,7 +946,7 @@ static int l2cap_sock_shutdown(struct socket *sock, int how) lock_sock(sk); if (!sk->sk_shutdown) { - if (l2cap_pi(sk)->mode == L2CAP_MODE_ERTM) + if (chan->mode == L2CAP_MODE_ERTM) err = __l2cap_wait_ack(sk); sk->sk_shutdown = SHUTDOWN_MASK; @@ -995,10 +1003,10 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent) sk->sk_type = parent->sk_type; bt_sk(sk)->defer_setup = bt_sk(parent)->defer_setup; - pi->imtu = l2cap_pi(parent)->imtu; - pi->omtu = l2cap_pi(parent)->omtu; + chan->imtu = pchan->imtu; + chan->omtu = pchan->omtu; chan->conf_state = pchan->conf_state; - pi->mode = l2cap_pi(parent)->mode; + chan->mode = pchan->mode; chan->fcs = pchan->fcs; chan->max_tx = pchan->max_tx; chan->tx_win = pchan->tx_win; @@ -1007,13 +1015,13 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent) chan->force_reliable = pchan->force_reliable; chan->flushable = pchan->flushable; } else { - pi->imtu = L2CAP_DEFAULT_MTU; - pi->omtu = 0; + chan->imtu = L2CAP_DEFAULT_MTU; + chan->omtu = 0; if (!disable_ertm && sk->sk_type == SOCK_STREAM) { - pi->mode = L2CAP_MODE_ERTM; + chan->mode = L2CAP_MODE_ERTM; chan->conf_state |= L2CAP_CONF_STATE2_DEVICE; } else { - pi->mode = L2CAP_MODE_BASIC; + chan->mode = L2CAP_MODE_BASIC; } chan->max_tx = L2CAP_DEFAULT_MAX_TX; chan->fcs = L2CAP_FCS_CRC16; @@ -1025,7 +1033,7 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent) } /* Default config options */ - pi->flush_to = L2CAP_DEFAULT_FLUSH_TO; + chan->flush_to = L2CAP_DEFAULT_FLUSH_TO; } static struct proto l2cap_proto = { diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 4f728a4f7177..fdd8f5ab18c1 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -710,10 +710,10 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, /* Set L2CAP options */ sk = sock->sk; lock_sock(sk); - l2cap_pi(sk)->imtu = l2cap_mtu; + l2cap_pi(sk)->chan->imtu = l2cap_mtu; l2cap_pi(sk)->chan->sec_level = sec_level; if (l2cap_ertm) - l2cap_pi(sk)->mode = L2CAP_MODE_ERTM; + l2cap_pi(sk)->chan->mode = L2CAP_MODE_ERTM; release_sock(sk); s = rfcomm_session_add(sock, BT_BOUND); @@ -1890,7 +1890,8 @@ static inline void rfcomm_accept_connection(struct rfcomm_session *s) /* We should adjust MTU on incoming sessions. * L2CAP MTU minus UIH header and FCS. */ - s->mtu = min(l2cap_pi(nsock->sk)->omtu, l2cap_pi(nsock->sk)->imtu) - 5; + s->mtu = min(l2cap_pi(nsock->sk)->chan->omtu, + l2cap_pi(nsock->sk)->chan->imtu) - 5; rfcomm_schedule(); } else @@ -1909,7 +1910,7 @@ static inline void rfcomm_check_connection(struct rfcomm_session *s) /* We can adjust MTU on outgoing sessions. * L2CAP MTU minus UIH header and FCS. */ - s->mtu = min(l2cap_pi(sk)->omtu, l2cap_pi(sk)->imtu) - 5; + s->mtu = min(l2cap_pi(sk)->chan->omtu, l2cap_pi(sk)->chan->imtu) - 5; rfcomm_send_sabm(s, 0); break; @@ -1992,7 +1993,7 @@ static int rfcomm_add_listener(bdaddr_t *ba) /* Set L2CAP options */ sk = sock->sk; lock_sock(sk); - l2cap_pi(sk)->imtu = l2cap_mtu; + l2cap_pi(sk)->chan->imtu = l2cap_mtu; release_sock(sk); /* Start listening on the socket */ -- cgit v1.2.3 From fe4128e0aabc3c748786c00da21e6eff9d3aeddb Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 13 Apr 2011 19:50:45 -0300 Subject: Bluetooth: Move more vars to struct l2cap_chan In this commit, psm, scid and dcid. Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 10 ++-- net/bluetooth/l2cap_core.c | 116 +++++++++++++++++++++--------------------- net/bluetooth/l2cap_sock.c | 26 +++++----- 3 files changed, 77 insertions(+), 75 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 7522835c24ee..fd199cda752c 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -284,6 +284,9 @@ struct srej_list { struct l2cap_chan { struct sock *sk; + __le16 psm; + __u16 dcid; + __u16 scid; __u16 imtu; __u16 omtu; @@ -382,9 +385,6 @@ struct l2cap_conn { struct l2cap_pinfo { struct bt_sock bt; - __le16 psm; - __u16 dcid; - __u16 scid; struct l2cap_conn *conn; struct l2cap_chan *chan; @@ -450,8 +450,8 @@ void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *d void __l2cap_connect_rsp_defer(struct sock *sk); int __l2cap_wait_ack(struct sock *sk); -struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len); -struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size_t len); +struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len); +struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len); struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u16 control, u16 sdulen); int l2cap_sar_segment_sdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len); void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 7b06375d05a7..dd726bdd6e02 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -80,8 +80,7 @@ static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 struct l2cap_chan *c; list_for_each_entry(c, &conn->chan_l, list) { - struct sock *s = c->sk; - if (l2cap_pi(s)->dcid == cid) + if (c->dcid == cid) return c; } return NULL; @@ -93,8 +92,7 @@ static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 struct l2cap_chan *c; list_for_each_entry(c, &conn->chan_l, list) { - struct sock *s = c->sk; - if (l2cap_pi(s)->scid == cid) + if (c->scid == cid) return c; } return NULL; @@ -167,7 +165,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) struct sock *sk = chan->sk; BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, - l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid); + chan->psm, chan->dcid); conn->disc_reason = 0x13; @@ -177,22 +175,22 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) if (conn->hcon->type == LE_LINK) { /* LE connection */ chan->omtu = L2CAP_LE_DEFAULT_MTU; - l2cap_pi(sk)->scid = L2CAP_CID_LE_DATA; - l2cap_pi(sk)->dcid = L2CAP_CID_LE_DATA; + chan->scid = L2CAP_CID_LE_DATA; + chan->dcid = L2CAP_CID_LE_DATA; } else { /* Alloc CID for connection-oriented socket */ - l2cap_pi(sk)->scid = l2cap_alloc_cid(conn); + chan->scid = l2cap_alloc_cid(conn); chan->omtu = L2CAP_DEFAULT_MTU; } } else if (sk->sk_type == SOCK_DGRAM) { /* Connectionless socket */ - l2cap_pi(sk)->scid = L2CAP_CID_CONN_LESS; - l2cap_pi(sk)->dcid = L2CAP_CID_CONN_LESS; + chan->scid = L2CAP_CID_CONN_LESS; + chan->dcid = L2CAP_CID_CONN_LESS; chan->omtu = L2CAP_DEFAULT_MTU; } else { /* Raw socket can send/recv signalling messages only */ - l2cap_pi(sk)->scid = L2CAP_CID_SIGNALING; - l2cap_pi(sk)->dcid = L2CAP_CID_SIGNALING; + chan->scid = L2CAP_CID_SIGNALING; + chan->dcid = L2CAP_CID_SIGNALING; chan->omtu = L2CAP_DEFAULT_MTU; } @@ -275,7 +273,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) default: return HCI_AT_NO_BONDING; } - } else if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) { + } else if (chan->psm == cpu_to_le16(0x0001)) { if (chan->sec_level == BT_SECURITY_LOW) chan->sec_level = BT_SECURITY_SDP; @@ -383,7 +381,7 @@ 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(pi->dcid); + lh->cid = cpu_to_le16(chan->dcid); put_unaligned_le16(control, skb_put(skb, 2)); if (chan->fcs == L2CAP_FCS_CRC16) { @@ -429,8 +427,8 @@ static void l2cap_do_start(struct l2cap_chan *chan) if (l2cap_check_security(chan) && __l2cap_no_conn_pending(chan)) { struct l2cap_conn_req req; - req.scid = cpu_to_le16(l2cap_pi(sk)->scid); - req.psm = l2cap_pi(sk)->psm; + req.scid = cpu_to_le16(chan->scid); + req.psm = chan->psm; chan->ident = l2cap_get_ident(conn); chan->conf_state |= L2CAP_CONF_CONNECT_PEND; @@ -485,8 +483,8 @@ void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, in del_timer(&chan->ack_timer); } - req.dcid = cpu_to_le16(l2cap_pi(sk)->dcid); - req.scid = cpu_to_le16(l2cap_pi(sk)->scid); + req.dcid = cpu_to_le16(chan->dcid); + req.scid = cpu_to_le16(chan->scid); l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_DISCONN_REQ, sizeof(req), &req); @@ -536,8 +534,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn) continue; } - req.scid = cpu_to_le16(l2cap_pi(sk)->scid); - req.psm = l2cap_pi(sk)->psm; + req.scid = cpu_to_le16(chan->scid); + req.psm = chan->psm; chan->ident = l2cap_get_ident(conn); chan->conf_state |= L2CAP_CONF_CONNECT_PEND; @@ -548,8 +546,8 @@ static void l2cap_conn_start(struct l2cap_conn *conn) } else if (sk->sk_state == BT_CONNECT2) { struct l2cap_conn_rsp rsp; char buf[128]; - rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); - rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); + rsp.scid = cpu_to_le16(chan->dcid); + rsp.dcid = cpu_to_le16(chan->scid); if (l2cap_check_security(chan)) { if (bt_sk(sk)->defer_setup) { @@ -600,10 +598,12 @@ static struct sock *l2cap_get_sock_by_scid(int state, __le16 cid, bdaddr_t *src) read_lock(&l2cap_sk_list.lock); sk_for_each(sk, node, &l2cap_sk_list.head) { + struct l2cap_chan *chan = l2cap_pi(sk)->chan; + if (state && sk->sk_state != state) continue; - if (l2cap_pi(sk)->scid == cid) { + if (chan->scid == cid) { /* Exact match. */ if (!bacmp(&bt_sk(sk)->src, src)) break; @@ -830,10 +830,12 @@ static struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src) read_lock(&l2cap_sk_list.lock); sk_for_each(sk, node, &l2cap_sk_list.head) { + struct l2cap_chan *chan = l2cap_pi(sk)->chan; + if (state && sk->sk_state != state) continue; - if (l2cap_pi(sk)->psm == psm) { + if (chan->psm == psm) { /* Exact match. */ if (!bacmp(&bt_sk(sk)->src, src)) break; @@ -861,7 +863,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan) int err; BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), - l2cap_pi(sk)->psm); + chan->psm); hdev = hci_get_route(dst, src); if (!hdev) @@ -871,7 +873,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan) auth_type = l2cap_get_auth_type(chan); - if (l2cap_pi(sk)->dcid == L2CAP_CID_LE_DATA) + if (chan->dcid == L2CAP_CID_LE_DATA) hcon = hci_connect(hdev, LE_LINK, dst, chan->sec_level, auth_type); else @@ -1231,8 +1233,9 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in return sent; } -struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, size_t len) +struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) { + struct sock *sk = chan->sk; struct l2cap_conn *conn = l2cap_pi(sk)->conn; struct sk_buff *skb; int err, count, hlen = L2CAP_HDR_SIZE + 2; @@ -1248,9 +1251,9 @@ struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, s /* Create L2CAP header */ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); - lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid); + lh->cid = cpu_to_le16(chan->dcid); lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); - put_unaligned_le16(l2cap_pi(sk)->psm, skb_put(skb, 2)); + put_unaligned_le16(chan->psm, skb_put(skb, 2)); err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb); if (unlikely(err < 0)) { @@ -1260,8 +1263,9 @@ struct sk_buff *l2cap_create_connless_pdu(struct sock *sk, struct msghdr *msg, s return skb; } -struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size_t len) +struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) { + struct sock *sk = chan->sk; struct l2cap_conn *conn = l2cap_pi(sk)->conn; struct sk_buff *skb; int err, count, hlen = L2CAP_HDR_SIZE; @@ -1277,7 +1281,7 @@ struct sk_buff *l2cap_create_basic_pdu(struct sock *sk, struct msghdr *msg, size /* Create L2CAP header */ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); - lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid); + lh->cid = cpu_to_le16(chan->dcid); lh->len = cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); err = l2cap_skbuff_fromiovec(sk, msg, len, count, skb); @@ -1315,7 +1319,7 @@ struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr * /* Create L2CAP header */ lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE); - lh->cid = cpu_to_le16(l2cap_pi(sk)->dcid); + 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)); if (sdulen) @@ -1697,7 +1701,7 @@ done: break; } - req->dcid = cpu_to_le16(pi->dcid); + req->dcid = cpu_to_le16(chan->dcid); req->flags = cpu_to_le16(0); return ptr - data; @@ -1850,7 +1854,7 @@ done: if (result == L2CAP_CONF_SUCCESS) chan->conf_state |= L2CAP_CONF_OUTPUT_DONE; } - rsp->scid = cpu_to_le16(pi->dcid); + rsp->scid = cpu_to_le16(chan->dcid); rsp->result = cpu_to_le16(result); rsp->flags = cpu_to_le16(0x0000); @@ -1859,15 +1863,13 @@ done: static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, void *data, u16 *result) { - struct sock *sk = chan->sk; - struct l2cap_pinfo *pi = l2cap_pi(sk); struct l2cap_conf_req *req = data; void *ptr = req->data; int type, olen; unsigned long val; struct l2cap_conf_rfc rfc; - BT_DBG("sk %p, rsp %p, len %d, req %p", sk, rsp, len, data); + BT_DBG("chan %p, rsp %p, len %d, req %p", chan, rsp, len, data); while (len >= L2CAP_CONF_OPT_SIZE) { len -= l2cap_get_conf_opt(&rsp, &type, &olen, &val); @@ -1921,20 +1923,20 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi } } - req->dcid = cpu_to_le16(pi->dcid); + req->dcid = cpu_to_le16(chan->dcid); req->flags = cpu_to_le16(0x0000); return ptr - data; } -static int l2cap_build_conf_rsp(struct sock *sk, void *data, u16 result, u16 flags) +static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, u16 flags) { struct l2cap_conf_rsp *rsp = data; void *ptr = rsp->data; - BT_DBG("sk %p", sk); + BT_DBG("chan %p", chan); - rsp->scid = cpu_to_le16(l2cap_pi(sk)->dcid); + rsp->scid = cpu_to_le16(chan->dcid); rsp->result = cpu_to_le16(result); rsp->flags = cpu_to_le16(flags); @@ -1950,8 +1952,8 @@ void __l2cap_connect_rsp_defer(struct sock *sk) sk->sk_state = BT_CONFIG; - rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); - rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); + rsp.scid = cpu_to_le16(chan->dcid); + rsp.dcid = cpu_to_le16(chan->scid); rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); l2cap_send_cmd(conn, chan->ident, @@ -2085,14 +2087,14 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd l2cap_sock_init(sk, parent); bacpy(&bt_sk(sk)->src, conn->src); bacpy(&bt_sk(sk)->dst, conn->dst); - l2cap_pi(sk)->psm = psm; - l2cap_pi(sk)->dcid = scid; + chan->psm = psm; + chan->dcid = scid; bt_accept_enqueue(parent, sk); __l2cap_chan_add(conn, chan); - dcid = l2cap_pi(sk)->scid; + dcid = chan->scid; l2cap_sock_set_timer(sk, sk->sk_sndtimeo); @@ -2190,7 +2192,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd case L2CAP_CR_SUCCESS: sk->sk_state = BT_CONFIG; chan->ident = 0; - l2cap_pi(sk)->dcid = dcid; + chan->dcid = dcid; chan->conf_state &= ~L2CAP_CONF_CONNECT_PEND; if (chan->conf_state & L2CAP_CONF_REQ_SENT) @@ -2270,7 +2272,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr len = cmd_len - sizeof(*req); if (chan->conf_len + len > sizeof(chan->conf_req)) { l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, - l2cap_build_conf_rsp(sk, rsp, + l2cap_build_conf_rsp(chan, rsp, L2CAP_CONF_REJECT, flags), rsp); goto unlock; } @@ -2282,7 +2284,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr if (flags & 0x0001) { /* Incomplete config. Send empty response. */ l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, - l2cap_build_conf_rsp(sk, rsp, + l2cap_build_conf_rsp(chan, rsp, L2CAP_CONF_SUCCESS, 0x0001), rsp); goto unlock; } @@ -2432,8 +2434,8 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd sk = chan->sk; - rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); - rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); + rsp.dcid = cpu_to_le16(chan->scid); + rsp.scid = cpu_to_le16(chan->dcid); l2cap_send_cmd(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp); sk->sk_shutdown = SHUTDOWN_MASK; @@ -3920,8 +3922,8 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) if (sk->sk_state == BT_CONNECT) { if (!status) { struct l2cap_conn_req req; - req.scid = cpu_to_le16(l2cap_pi(sk)->scid); - req.psm = l2cap_pi(sk)->psm; + req.scid = cpu_to_le16(chan->scid); + req.psm = chan->psm; chan->ident = l2cap_get_ident(conn); chan->conf_state |= L2CAP_CONF_CONNECT_PEND; @@ -3945,8 +3947,8 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) result = L2CAP_CR_SEC_BLOCK; } - rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); - rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); + rsp.scid = cpu_to_le16(chan->dcid); + rsp.dcid = cpu_to_le16(chan->scid); rsp.result = cpu_to_le16(result); rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, @@ -4086,8 +4088,8 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p) seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n", batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), - sk->sk_state, __le16_to_cpu(pi->psm), - pi->scid, pi->dcid, + sk->sk_state, __le16_to_cpu(chan->psm), + chan->scid, chan->dcid, chan->imtu, chan->omtu, chan->sec_level, chan->mode); } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index eef33b179f02..f5a27737c151 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -141,7 +141,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) } else { /* Save source address */ bacpy(&bt_sk(sk)->src, &la.l2_bdaddr); - l2cap_pi(sk)->psm = la.l2_psm; + chan->psm = la.l2_psm; chan->sport = la.l2_psm; sk->sk_state = BT_BOUND; @@ -151,7 +151,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) } if (la.l2_cid) - l2cap_pi(sk)->scid = la.l2_cid; + chan->scid = la.l2_cid; write_unlock_bh(&l2cap_sk_list.lock); @@ -232,8 +232,8 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al /* Set destination address and psm */ bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr); - l2cap_pi(sk)->psm = la.l2_psm; - l2cap_pi(sk)->dcid = la.l2_cid; + chan->psm = la.l2_psm; + chan->dcid = la.l2_cid; err = l2cap_chan_connect(l2cap_pi(sk)->chan); if (err) @@ -276,7 +276,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) goto done; } - if (!l2cap_pi(sk)->psm && !l2cap_pi(sk)->scid) { + if (!chan->psm && !chan->scid) { bdaddr_t *src = &bt_sk(sk)->src; u16 psm; @@ -286,7 +286,7 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) for (psm = 0x1001; psm < 0x1100; psm += 2) if (!__l2cap_get_sock_by_addr(cpu_to_le16(psm), src)) { - l2cap_pi(sk)->psm = cpu_to_le16(psm); + chan->psm = cpu_to_le16(psm); chan->sport = cpu_to_le16(psm); err = 0; break; @@ -375,13 +375,13 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l *len = sizeof(struct sockaddr_l2); if (peer) { - la->l2_psm = l2cap_pi(sk)->psm; + la->l2_psm = chan->psm; bacpy(&la->l2_bdaddr, &bt_sk(sk)->dst); - la->l2_cid = cpu_to_le16(l2cap_pi(sk)->dcid); + la->l2_cid = cpu_to_le16(chan->dcid); } else { la->l2_psm = chan->sport; bacpy(&la->l2_bdaddr, &bt_sk(sk)->src); - la->l2_cid = cpu_to_le16(l2cap_pi(sk)->scid); + la->l2_cid = cpu_to_le16(chan->scid); } return 0; @@ -737,7 +737,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms /* Connectionless channel */ if (sk->sk_type == SOCK_DGRAM) { - skb = l2cap_create_connless_pdu(sk, msg, len); + skb = l2cap_create_connless_pdu(chan, msg, len); if (IS_ERR(skb)) { err = PTR_ERR(skb); } else { @@ -756,7 +756,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms } /* Create a basic PDU */ - skb = l2cap_create_basic_pdu(sk, msg, len); + skb = l2cap_create_basic_pdu(chan, msg, len); if (IS_ERR(skb)) { err = PTR_ERR(skb); goto done; @@ -911,8 +911,8 @@ void __l2cap_sock_close(struct sock *sk, int reason) else result = L2CAP_CR_BAD_PSM; - rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid); - rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid); + rsp.scid = cpu_to_le16(chan->dcid); + rsp.dcid = cpu_to_le16(chan->scid); rsp.result = cpu_to_le16(result); rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO); l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, -- cgit v1.2.3 From 8c1d787be4b62d2d1b6f04953eca4bcf7c839d44 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 13 Apr 2011 20:23:55 -0300 Subject: Bluetooth: Move conn to struct l2cap_chan There is no need to the socket deal directly with the channel, most of the time it cares about the channel only. Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 7 ++-- net/bluetooth/l2cap_core.c | 92 +++++++++++++++++++------------------------ net/bluetooth/l2cap_sock.c | 12 +++--- net/bluetooth/rfcomm/core.c | 8 ++-- net/bluetooth/rfcomm/sock.c | 5 ++- 5 files changed, 59 insertions(+), 65 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index fd199cda752c..3de90a91a4e4 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -284,6 +284,9 @@ struct srej_list { struct l2cap_chan { struct sock *sk; + + struct l2cap_conn *conn; + __le16 psm; __u16 dcid; __u16 scid; @@ -385,8 +388,6 @@ struct l2cap_conn { struct l2cap_pinfo { struct bt_sock bt; - - struct l2cap_conn *conn; struct l2cap_chan *chan; }; @@ -447,7 +448,7 @@ int l2cap_init_sockets(void); void l2cap_cleanup_sockets(void); void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data); -void __l2cap_connect_rsp_defer(struct sock *sk); +void __l2cap_connect_rsp_defer(struct l2cap_chan *chan); int __l2cap_wait_ack(struct sock *sk); struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index dd726bdd6e02..8562ac1ba947 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -169,7 +169,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) conn->disc_reason = 0x13; - l2cap_pi(sk)->conn = conn; + chan->conn = conn; if (sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM) { if (conn->hcon->type == LE_LINK) { @@ -204,7 +204,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) void l2cap_chan_del(struct l2cap_chan *chan, int err) { struct sock *sk = chan->sk; - struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_conn *conn = chan->conn; struct sock *parent = bt_sk(sk)->parent; l2cap_sock_clear_timer(sk); @@ -218,7 +218,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) write_unlock_bh(&conn->chan_lock); __sock_put(sk); - l2cap_pi(sk)->conn = NULL; + chan->conn = NULL; hci_conn_put(conn->hcon); } @@ -296,7 +296,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) /* Service level security */ static inline int l2cap_check_security(struct l2cap_chan *chan) { - struct l2cap_conn *conn = l2cap_pi(chan->sk)->conn; + struct l2cap_conn *conn = chan->conn; __u8 auth_type; auth_type = l2cap_get_auth_type(chan); @@ -349,7 +349,7 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control) struct sk_buff *skb; struct l2cap_hdr *lh; struct l2cap_pinfo *pi = l2cap_pi(chan->sk); - struct l2cap_conn *conn = pi->conn; + struct l2cap_conn *conn = chan->conn; struct sock *sk = (struct sock *)pi; int count, hlen = L2CAP_HDR_SIZE + 2; u8 flags; @@ -394,7 +394,7 @@ static inline void l2cap_send_sframe(struct l2cap_chan *chan, u16 control) else flags = ACL_START; - hci_send_acl(pi->conn->hcon, skb, flags); + hci_send_acl(chan->conn->hcon, skb, flags); } static inline void l2cap_send_rr_or_rnr(struct l2cap_chan *chan, u16 control) @@ -417,8 +417,7 @@ static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan) static void l2cap_do_start(struct l2cap_chan *chan) { - struct sock *sk = chan->sk; - struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_conn *conn = chan->conn; if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) { if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)) @@ -920,12 +919,13 @@ done: int __l2cap_wait_ack(struct sock *sk) { + struct l2cap_chan *chan = l2cap_pi(sk)->chan; DECLARE_WAITQUEUE(wait, current); int err = 0; int timeo = HZ/5; add_wait_queue(sk_sleep(sk), &wait); - while ((l2cap_pi(sk)->chan->unacked_frames > 0 && l2cap_pi(sk)->conn)) { + while ((chan->unacked_frames > 0 && chan->conn)) { set_current_state(TASK_INTERRUPTIBLE); if (!timeo) @@ -958,7 +958,7 @@ static void l2cap_monitor_timeout(unsigned long arg) bh_lock_sock(sk); if (chan->retry_count >= chan->remote_max_tx) { - l2cap_send_disconn_req(l2cap_pi(sk)->conn, chan, ECONNABORTED); + l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); bh_unlock_sock(sk); return; } @@ -1008,8 +1008,7 @@ static void l2cap_drop_acked_frames(struct l2cap_chan *chan) void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb) { - struct sock *sk = chan->sk; - struct hci_conn *hcon = l2cap_pi(sk)->conn->hcon; + struct hci_conn *hcon = chan->conn->hcon; u16 flags; BT_DBG("chan %p, skb %p len %d", chan, skb, skb->len); @@ -1045,8 +1044,6 @@ void l2cap_streaming_send(struct l2cap_chan *chan) static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) { - struct sock *sk = chan->sk; - struct l2cap_pinfo *pi = l2cap_pi(sk); struct sk_buff *skb, *tx_skb; u16 control, fcs; @@ -1065,7 +1062,7 @@ static void l2cap_retransmit_one_frame(struct l2cap_chan *chan, u8 tx_seq) if (chan->remote_max_tx && bt_cb(skb)->retries == chan->remote_max_tx) { - l2cap_send_disconn_req(pi->conn, chan, ECONNABORTED); + l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); return; } @@ -1096,7 +1093,6 @@ int l2cap_ertm_send(struct l2cap_chan *chan) { struct sk_buff *skb, *tx_skb; struct sock *sk = chan->sk; - struct l2cap_pinfo *pi = l2cap_pi(sk); u16 control, fcs; int nsent = 0; @@ -1107,7 +1103,7 @@ int l2cap_ertm_send(struct l2cap_chan *chan) if (chan->remote_max_tx && bt_cb(skb)->retries == chan->remote_max_tx) { - l2cap_send_disconn_req(pi->conn, chan, ECONNABORTED); + l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED); break; } @@ -1203,7 +1199,7 @@ static void l2cap_send_srejtail(struct l2cap_chan *chan) static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, int len, int count, struct sk_buff *skb) { - struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn; struct sk_buff **frag; int err, sent = 0; @@ -1236,7 +1232,7 @@ static inline int l2cap_skbuff_fromiovec(struct sock *sk, struct msghdr *msg, in struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) { struct sock *sk = chan->sk; - struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; int err, count, hlen = L2CAP_HDR_SIZE + 2; struct l2cap_hdr *lh; @@ -1266,7 +1262,7 @@ struct sk_buff *l2cap_create_connless_pdu(struct l2cap_chan *chan, struct msghdr struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len) { struct sock *sk = chan->sk; - struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; int err, count, hlen = L2CAP_HDR_SIZE; struct l2cap_hdr *lh; @@ -1295,7 +1291,7 @@ struct sk_buff *l2cap_create_basic_pdu(struct l2cap_chan *chan, struct msghdr *m struct sk_buff *l2cap_create_iframe_pdu(struct l2cap_chan *chan, struct msghdr *msg, size_t len, u16 control, u16 sdulen) { struct sock *sk = chan->sk; - struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_conn *conn = chan->conn; struct sk_buff *skb; int err, count, hlen = L2CAP_HDR_SIZE + 2; struct l2cap_hdr *lh; @@ -1611,7 +1607,6 @@ static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask) static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) { - struct l2cap_pinfo *pi = l2cap_pi(chan->sk); struct l2cap_conf_req *req = data; struct l2cap_conf_rfc rfc = { .mode = chan->mode }; void *ptr = req->data; @@ -1629,7 +1624,7 @@ static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data) /* fall through */ default: - chan->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask); + chan->mode = l2cap_select_mode(rfc.mode, chan->conn->feat_mask); break; } @@ -1639,8 +1634,8 @@ done: switch (chan->mode) { case L2CAP_MODE_BASIC: - if (!(pi->conn->feat_mask & L2CAP_FEAT_ERTM) && - !(pi->conn->feat_mask & L2CAP_FEAT_STREAMING)) + if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) && + !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING)) break; rfc.mode = L2CAP_MODE_BASIC; @@ -1661,13 +1656,13 @@ done: 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 > pi->conn->mtu - 10) - rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10); + if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10) + rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10); l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), (unsigned long) &rfc); - if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS)) + if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS)) break; if (chan->fcs == L2CAP_FCS_NONE || @@ -1684,13 +1679,13 @@ done: 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 > pi->conn->mtu - 10) - rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10); + if (L2CAP_DEFAULT_MAX_PDU_SIZE > chan->conn->mtu - 10) + rfc.max_pdu_size = cpu_to_le16(chan->conn->mtu - 10); l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc), (unsigned long) &rfc); - if (!(pi->conn->feat_mask & L2CAP_FEAT_FCS)) + if (!(chan->conn->feat_mask & L2CAP_FEAT_FCS)) break; if (chan->fcs == L2CAP_FCS_NONE || @@ -1709,7 +1704,6 @@ done: static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data) { - struct l2cap_pinfo *pi = l2cap_pi(chan->sk); struct l2cap_conf_rsp *rsp = data; void *ptr = rsp->data; void *req = chan->conf_req; @@ -1769,7 +1763,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data) case L2CAP_MODE_ERTM: if (!(chan->conf_state & L2CAP_CONF_STATE2_DEVICE)) { chan->mode = l2cap_select_mode(rfc.mode, - pi->conn->feat_mask); + chan->conn->feat_mask); break; } @@ -1814,8 +1808,8 @@ done: chan->remote_tx_win = rfc.txwin_size; chan->remote_max_tx = rfc.max_transmit; - if (le16_to_cpu(rfc.max_pdu_size) > pi->conn->mtu - 10) - rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10); + 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); @@ -1832,8 +1826,8 @@ done: break; case L2CAP_MODE_STREAMING: - if (le16_to_cpu(rfc.max_pdu_size) > pi->conn->mtu - 10) - rfc.max_pdu_size = cpu_to_le16(pi->conn->mtu - 10); + 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); @@ -1943,15 +1937,12 @@ static int l2cap_build_conf_rsp(struct l2cap_chan *chan, void *data, u16 result, return ptr - data; } -void __l2cap_connect_rsp_defer(struct sock *sk) +void __l2cap_connect_rsp_defer(struct l2cap_chan *chan) { struct l2cap_conn_rsp rsp; - struct l2cap_conn *conn = l2cap_pi(sk)->conn; - struct l2cap_chan *chan = l2cap_pi(sk)->chan; + struct l2cap_conn *conn = chan->conn; u8 buf[128]; - sk->sk_state = BT_CONFIG; - rsp.scid = cpu_to_le16(chan->dcid); rsp.dcid = cpu_to_le16(chan->scid); rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS); @@ -2856,7 +2847,6 @@ static int l2cap_add_to_srej_queue(struct l2cap_chan *chan, struct sk_buff *skb, static int l2cap_ertm_reassembly_sdu(struct l2cap_chan *chan, struct sk_buff *skb, u16 control) { - struct l2cap_pinfo *pi = l2cap_pi(chan->sk); struct sk_buff *_skb; int err; @@ -2957,7 +2947,7 @@ drop: chan->sdu = NULL; disconnect: - l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); kfree_skb(skb); return 0; } @@ -3018,7 +3008,7 @@ static void l2cap_busy_work(struct work_struct *work) if (n_tries++ > L2CAP_LOCAL_BUSY_TRIES) { err = -EBUSY; - l2cap_send_disconn_req(l2cap_pi(sk)->conn, chan, EBUSY); + l2cap_send_disconn_req(chan->conn, chan, EBUSY); break; } @@ -3236,7 +3226,6 @@ static void l2cap_send_srejframe(struct l2cap_chan *chan, u8 tx_seq) static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_control, struct sk_buff *skb) { - struct l2cap_pinfo *pi = l2cap_pi(chan->sk); u8 tx_seq = __get_txseq(rx_control); u8 req_seq = __get_reqseq(rx_control); u8 sar = rx_control >> L2CAP_CTRL_SAR_SHIFT; @@ -3267,7 +3256,7 @@ static inline int l2cap_data_channel_iframe(struct l2cap_chan *chan, u16 rx_cont /* invalid tx_seq */ if (tx_seq_offset >= chan->tx_win) { - l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); goto drop; } @@ -3534,7 +3523,6 @@ 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; - struct l2cap_pinfo *pi = l2cap_pi(sk); u16 control; u8 req_seq; int len, next_tx_seq_offset, req_seq_offset; @@ -3558,7 +3546,7 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) len -= 2; if (len > chan->mps) { - l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); goto drop; } @@ -3574,13 +3562,13 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) /* check for invalid req-seq */ if (req_seq_offset > next_tx_seq_offset) { - l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); goto drop; } if (__is_iframe(control)) { if (len < 0) { - l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); goto drop; } @@ -3588,7 +3576,7 @@ static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb) } else { if (len != 0) { BT_ERR("%d", len); - l2cap_send_disconn_req(pi->conn, chan, ECONNRESET); + l2cap_send_disconn_req(chan->conn, chan, ECONNRESET); goto drop; } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index f5a27737c151..61d93f6c36c8 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -455,8 +455,8 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us break; } - cinfo.hci_handle = l2cap_pi(sk)->conn->hcon->handle; - memcpy(cinfo.dev_class, l2cap_pi(sk)->conn->hcon->dev_class, 3); + cinfo.hci_handle = chan->conn->hcon->handle; + memcpy(cinfo.dev_class, chan->conn->hcon->dev_class, 3); len = min_t(unsigned int, len, sizeof(cinfo)); if (copy_to_user(optval, (char *) &cinfo, len)) @@ -690,7 +690,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch } if (opt == BT_FLUSHABLE_OFF) { - struct l2cap_conn *conn = l2cap_pi(sk)->conn; + struct l2cap_conn *conn = chan->conn; /* proceed futher only when we have l2cap_conn and No Flush support in the LM */ if (!conn || !lmp_no_flush_capable(conn->hcon->hdev)) { @@ -823,7 +823,9 @@ static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct ms lock_sock(sk); if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) { - __l2cap_connect_rsp_defer(sk); + sk->sk_state = BT_CONFIG; + + __l2cap_connect_rsp_defer(l2cap_pi(sk)->chan); release_sock(sk); return 0; } @@ -878,8 +880,8 @@ static void l2cap_sock_cleanup_listen(struct sock *parent) void __l2cap_sock_close(struct sock *sk, int reason) { - struct l2cap_conn *conn = l2cap_pi(sk)->conn; struct l2cap_chan *chan = l2cap_pi(sk)->chan; + struct l2cap_conn *conn = chan->conn; BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket); diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index fdd8f5ab18c1..121a5c13b989 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -232,6 +232,8 @@ static int rfcomm_l2sock_create(struct socket **sock) static inline int rfcomm_check_security(struct rfcomm_dlc *d) { struct sock *sk = d->session->sock->sk; + struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn; + __u8 auth_type; switch (d->sec_level) { @@ -246,8 +248,7 @@ static inline int rfcomm_check_security(struct rfcomm_dlc *d) break; } - return hci_conn_security(l2cap_pi(sk)->conn->hcon, d->sec_level, - auth_type); + return hci_conn_security(conn->hcon, d->sec_level, auth_type); } static void rfcomm_session_timeout(unsigned long arg) @@ -1241,6 +1242,7 @@ static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci) void rfcomm_dlc_accept(struct rfcomm_dlc *d) { struct sock *sk = d->session->sock->sk; + struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn; BT_DBG("dlc %p", d); @@ -1254,7 +1256,7 @@ void rfcomm_dlc_accept(struct rfcomm_dlc *d) rfcomm_dlc_unlock(d); if (d->role_switch) - hci_conn_switch_role(l2cap_pi(sk)->conn->hcon, 0x00); + hci_conn_switch_role(conn->hcon, 0x00); rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig); } diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 66cc1f0c3df8..386cfaffd4b7 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -743,6 +743,7 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u struct sock *sk = sock->sk; struct sock *l2cap_sk; struct rfcomm_conninfo cinfo; + struct l2cap_conn *conn = l2cap_pi(sk)->chan->conn; int len, err = 0; u32 opt; @@ -787,8 +788,8 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u l2cap_sk = rfcomm_pi(sk)->dlc->session->sock->sk; - cinfo.hci_handle = l2cap_pi(l2cap_sk)->conn->hcon->handle; - memcpy(cinfo.dev_class, l2cap_pi(l2cap_sk)->conn->hcon->dev_class, 3); + cinfo.hci_handle = conn->hcon->handle; + memcpy(cinfo.dev_class, conn->hcon->dev_class, 3); len = min_t(unsigned int, len, sizeof(cinfo)); if (copy_to_user(optval, (char *) &cinfo, len)) -- cgit v1.2.3 From 6ff5abbf4e4aa88feb9c2367d4fbd9ea081bf98c Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 25 Apr 2011 15:10:41 -0300 Subject: Bluetooth: Fix memory leak with L2CAP channels A new l2cap_chan_free() is added to free the channels. Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 1 + net/bluetooth/l2cap_core.c | 10 ++++++---- net/bluetooth/l2cap_sock.c | 2 ++ 3 files changed, 9 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 3de90a91a4e4..0a0134161b1b 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -469,6 +469,7 @@ struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err); struct l2cap_chan *l2cap_chan_alloc(struct sock *sk); void l2cap_chan_del(struct l2cap_chan *chan, int err); +void l2cap_chan_free(struct l2cap_chan *chan); int l2cap_chan_connect(struct l2cap_chan *chan); #endif /* __L2CAP_H */ diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 8562ac1ba947..338d8c3eedab 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -160,6 +160,11 @@ struct l2cap_chan *l2cap_chan_alloc(struct sock *sk) return chan; } +void l2cap_chan_free(struct l2cap_chan *chan) +{ + kfree(chan); +} + static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan) { struct sock *sk = chan->sk; @@ -236,7 +241,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE && chan->conf_state & L2CAP_CONF_INPUT_DONE)) - goto free; + return; skb_queue_purge(&chan->tx_q); @@ -255,9 +260,6 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err) kfree(l); } } - -free: - kfree(chan); } static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 61d93f6c36c8..0e23ebdf7c8f 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -849,6 +849,8 @@ void l2cap_sock_kill(struct sock *sk) BT_DBG("sk %p state %d", sk, sk->sk_state); /* Kill poor orphan */ + + l2cap_chan_free(l2cap_pi(sk)->chan); bt_sock_unlink(&l2cap_sk_list, sk); sock_set_flag(sk, SOCK_DEAD); sock_put(sk); -- cgit v1.2.3 From cf2f90f59bbf2c2a539d171cde6e1dfe72048555 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 27 Apr 2011 18:40:39 -0300 Subject: Bluetooth: Don't export l2cap_sock_ops l2cap_sk_ops can be static, it's not used outside l2cap_sock.c Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 1 - net/bluetooth/l2cap_sock.c | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 0a0134161b1b..c34b1c126363 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -441,7 +441,6 @@ static inline int l2cap_tx_window_full(struct l2cap_chan *ch) #define __is_sar_start(ctrl) (((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START) extern int disable_ertm; -extern const struct proto_ops l2cap_sock_ops; extern struct bt_sock_list l2cap_sk_list; int l2cap_init_sockets(void); diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 0e23ebdf7c8f..09cc7a005349 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -30,6 +30,8 @@ #include #include +static const struct proto_ops l2cap_sock_ops; + /* ---- L2CAP timers ---- */ static void l2cap_sock_timeout(unsigned long arg) { @@ -1106,7 +1108,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol, return 0; } -const struct proto_ops l2cap_sock_ops = { +static const struct proto_ops l2cap_sock_ops = { .family = PF_BLUETOOTH, .owner = THIS_MODULE, .release = l2cap_sock_release, -- cgit v1.2.3 From 14a53664138a8407382745bb470045d1817b7801 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 27 Apr 2011 10:29:56 -0400 Subject: Bluetooth: Add basic discovery commands to the management interface This patch adds start_discovery and stop_discovery commands to the management interface. Right now their implementation is fairly simplistic and the parameters are fixed to what user space has defaulted to so far. This is the very initial phase for discovery implementation into the kernel. Next steps include name resolution, LE scanning and bdaddr type handling. Signed-off-by: Johan Hedberg Signed-off-by: Anderson Briglia Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/mgmt.h | 4 +++ net/bluetooth/mgmt.c | 76 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 79 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 6b6ff92ab499..be93dd0eb962 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -195,6 +195,10 @@ struct mgmt_cp_remove_remote_oob_data { bdaddr_t bdaddr; } __packed; +#define MGMT_OP_START_DISCOVERY 0x001B + +#define MGMT_OP_STOP_DISCOVERY 0x001C + #define MGMT_EV_CMD_COMPLETE 0x0001 struct mgmt_ev_cmd_complete { __le16 opcode; diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index c304688252b8..dbc248f27b1b 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1569,6 +1569,75 @@ static int remove_remote_oob_data(struct sock *sk, u16 index, return err; } +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; + + BT_DBG("hci%u", index); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_START_DISCOVERY, ENODEV); + + hci_dev_lock_bh(hdev); + + cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, index, 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); + if (err < 0) + mgmt_pending_remove(cmd); + +failed: + hci_dev_unlock_bh(hdev); + hci_dev_put(hdev); + + return err; +} + +static int stop_discovery(struct sock *sk, u16 index) +{ + struct hci_dev *hdev; + struct pending_cmd *cmd; + int err; + + BT_DBG("hci%u", index); + + hdev = hci_dev_get(index); + if (!hdev) + return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY, ENODEV); + + hci_dev_lock_bh(hdev); + + cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, index, NULL, 0); + if (!cmd) { + err = -ENOMEM; + goto failed; + } + + err = hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL); + if (err < 0) + mgmt_pending_remove(cmd); + +failed: + hci_dev_unlock_bh(hdev); + hci_dev_put(hdev); + + return err; +} + int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) { unsigned char *buf; @@ -1677,7 +1746,12 @@ int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen) err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr), len); break; - + case MGMT_OP_START_DISCOVERY: + err = start_discovery(sk, index); + break; + case MGMT_OP_STOP_DISCOVERY: + err = stop_discovery(sk, index); + break; default: BT_DBG("Unknown op %u", opcode); err = cmd_status(sk, index, opcode, 0x01); -- cgit v1.2.3 From 314b2381a79c6bfe3ddc4ba3806ecb6aec27a3db Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Wed, 27 Apr 2011 10:29:57 -0400 Subject: Bluetooth: Add discovering event to the Management interface This patch adds a new event to the Management interface to track when local adapters are discovering remote devices. For now this only tracks BR/EDR discovery procedures. Signed-off-by: Johan Hedberg Signed-off-by: Anderson Briglia Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 1 + include/net/bluetooth/mgmt.h | 2 ++ net/bluetooth/hci_event.c | 40 ++++++++++++++++++++++++++++++++++------ net/bluetooth/mgmt.c | 6 ++++++ 4 files changed, 43 insertions(+), 6 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 4093133c1283..69967e540c96 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -790,6 +790,7 @@ int mgmt_read_local_oob_data_reply_complete(u16 index, u8 *hash, u8 *randomizer, 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); /* HCI info for socket */ #define hci_pi(sk) ((struct hci_pinfo *) sk) diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index be93dd0eb962..743440615349 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -285,3 +285,5 @@ struct mgmt_ev_remote_name { bdaddr_t bdaddr; __u8 name[MGMT_MAX_NAME_LENGTH]; } __packed; + +#define MGMT_EV_DISCOVERING 0x0014 diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index cb25628c0583..e64a3de70d77 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -56,7 +56,9 @@ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb) if (status) return; - clear_bit(HCI_INQUIRY, &hdev->flags); + if (test_bit(HCI_MGMT, &hdev->flags) && + test_and_clear_bit(HCI_INQUIRY, &hdev->flags)) + mgmt_discovering(hdev->id, 0); hci_req_complete(hdev, HCI_OP_INQUIRY_CANCEL, status); @@ -72,7 +74,9 @@ static void hci_cc_exit_periodic_inq(struct hci_dev *hdev, struct sk_buff *skb) if (status) return; - clear_bit(HCI_INQUIRY, &hdev->flags); + if (test_bit(HCI_MGMT, &hdev->flags) && + test_and_clear_bit(HCI_INQUIRY, &hdev->flags)) + mgmt_discovering(hdev->id, 0); hci_conn_check_pending(hdev); } @@ -841,10 +845,14 @@ 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); - } else - set_bit(HCI_INQUIRY, &hdev->flags); + return; + } + + if (test_bit(HCI_MGMT, &hdev->flags) && + !test_and_set_bit(HCI_INQUIRY, + &hdev->flags)) + mgmt_discovering(hdev->id, 1); } static inline void hci_cs_create_conn(struct hci_dev *hdev, __u8 status) @@ -1208,7 +1216,9 @@ static inline void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff BT_DBG("%s status %d", hdev->name, status); - clear_bit(HCI_INQUIRY, &hdev->flags); + if (test_bit(HCI_MGMT, &hdev->flags) && + test_and_clear_bit(HCI_INQUIRY, &hdev->flags)) + mgmt_discovering(hdev->id, 0); hci_req_complete(hdev, HCI_OP_INQUIRY, status); @@ -1228,6 +1238,12 @@ 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; @@ -2158,6 +2174,12 @@ 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); @@ -2320,6 +2342,12 @@ 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++) { diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index dbc248f27b1b..4542396fc856 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -2149,3 +2149,9 @@ int mgmt_remote_name(u16 index, bdaddr_t *bdaddr, u8 *name) return mgmt_event(MGMT_EV_REMOTE_NAME, index, &ev, sizeof(ev), NULL); } + +int mgmt_discovering(u16 index, u8 discovering) +{ + return mgmt_event(MGMT_EV_DISCOVERING, index, &discovering, + sizeof(discovering), NULL); +} -- cgit v1.2.3 From b6020ba055c7f1ca901dc8751ecc7c9de58164db Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Thu, 28 Apr 2011 12:07:53 +0200 Subject: Bluetooth: Add definitions for link key types Introduce the link key types defs and use them instead of magic numbers. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci.h | 9 +++++++++ net/bluetooth/hci_core.c | 2 +- net/bluetooth/hci_event.c | 7 ++++--- 3 files changed, 14 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 6138e313d175..e0a3cf1234b2 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -246,6 +246,15 @@ enum { #define HCI_AT_GENERAL_BONDING 0x04 #define HCI_AT_GENERAL_BONDING_MITM 0x05 +/* Link Key types */ +#define HCI_LK_COMBINATION 0x00 +#define HCI_LK_LOCAL_UNIT 0x01 +#define HCI_LK_REMOTE_UNIT 0x02 +#define HCI_LK_DEBUG_COMBINATION 0x03 +#define HCI_LK_UNAUTH_COMBINATION 0x04 +#define HCI_LK_AUTH_COMBINATION 0x05 +#define HCI_LK_CHANGED_COMBINATION 0x06 + /* ----- HCI Commands ---- */ #define HCI_OP_NOP 0x0000 diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 98aa24b92c58..07d0ba35b9a5 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1050,7 +1050,7 @@ int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, if (new_key) mgmt_new_key(hdev->id, key, old_key_type); - if (type == 0x06) + if (type == HCI_LK_CHANGED_COMBINATION) key->type = old_key_type; return 0; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index e64a3de70d77..fbbb63f8a897 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2053,15 +2053,16 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff BT_DBG("%s found key type %u for %s", hdev->name, key->type, batostr(&ev->bdaddr)); - if (!test_bit(HCI_DEBUG_KEYS, &hdev->flags) && key->type == 0x03) { + if (!test_bit(HCI_DEBUG_KEYS, &hdev->flags) && + key->type == HCI_LK_DEBUG_COMBINATION) { BT_DBG("%s ignoring debug key", hdev->name); goto not_found; } conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); - if (key->type == 0x04 && conn && conn->auth_type != 0xff && - (conn->auth_type & 0x01)) { + if (key->type == HCI_LK_UNAUTH_COMBINATION && conn && + conn->auth_type != 0xff && (conn->auth_type & 0x01)) { BT_DBG("%s ignoring unauthenticated key", hdev->name); goto not_found; } -- cgit v1.2.3 From 9003c4e220c2954a53c5da0d739ed15a46c13429 Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Thu, 28 Apr 2011 12:07:54 +0200 Subject: Bluetooth: Don't modify sec_level if auth failed If authentication fails the security level should stay as it was set before the process has started. Setting BT_SECURITY_LOW can hide real security level on a link eg. having BT_SECURITY_MEDIUM on the link, re-authenticate with failure to get BT_SECURITY_HIGH, as a result we get BT_SECURITY_LOW on the link while the real security is still medium. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_event.c | 1 - 1 file changed, 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index fbbb63f8a897..35f98980070c 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1459,7 +1459,6 @@ 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); - conn->sec_level = BT_SECURITY_LOW; } clear_bit(HCI_CONN_AUTH_PEND, &conn->pend); -- cgit v1.2.3 From 13d39315c22b128f4796fc008b04914a7c32bb1a Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Thu, 28 Apr 2011 12:07:55 +0200 Subject: Bluetooth: Map sec_level to link key requirements Keep the link key type together with connection and use it to map security level to link key requirements. Authenticate and/or encrypt connection if the link is insufficiently secure. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_conn.c | 61 +++++++++++++++++++++++++++++++++------- net/bluetooth/hci_event.c | 4 +++ 3 files changed, 56 insertions(+), 10 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 69967e540c96..2da2eb9f53ac 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -226,6 +226,7 @@ struct hci_conn { __u16 pkt_type; __u16 link_policy; __u32 link_mode; + __u8 key_type; __u8 auth_type; __u8 sec_level; __u8 pending_sec_level; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 7a6f56b2f49d..74cd755b38a7 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -287,6 +287,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) conn->auth_type = HCI_AT_GENERAL_BONDING; conn->io_capability = hdev->io_capability; conn->remote_auth = 0xff; + conn->key_type = 0xff; conn->power_save = 1; conn->disc_timeout = HCI_DISCONN_TIMEOUT; @@ -535,32 +536,72 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) return 0; } +/* Encrypt the the link */ +static void hci_conn_encrypt(struct hci_conn *conn) +{ + BT_DBG("conn %p", conn); + + if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) { + struct hci_cp_set_conn_encrypt cp; + cp.handle = cpu_to_le16(conn->handle); + cp.encrypt = 0x01; + hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), + &cp); + } +} + /* Enable security */ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type) { BT_DBG("conn %p", conn); + /* For sdp we don't need the link key. */ if (sec_level == BT_SECURITY_SDP) return 1; + /* For non 2.1 devices and low security level we don't need the link + key. */ if (sec_level == BT_SECURITY_LOW && (!conn->ssp_mode || !conn->hdev->ssp_mode)) return 1; - if (conn->link_mode & HCI_LM_ENCRYPT) - return hci_conn_auth(conn, sec_level, auth_type); - + /* For other security levels we need the link key. */ + if (!(conn->link_mode & HCI_LM_AUTH)) + goto auth; + + /* An authenticated combination key has sufficient security for any + security level. */ + if (conn->key_type == HCI_LK_AUTH_COMBINATION) + goto encrypt; + + /* An unauthenticated combination key has sufficient security for + security level 1 and 2. */ + if (conn->key_type == HCI_LK_UNAUTH_COMBINATION && + (sec_level == BT_SECURITY_MEDIUM || + sec_level == BT_SECURITY_LOW)) + goto encrypt; + + /* A combination key has always sufficient security for the security + levels 1 or 2. High security level requires the combination key + is generated using maximum PIN code length (16). + For pre 2.1 units. */ + if (conn->key_type == HCI_LK_COMBINATION && + (sec_level != BT_SECURITY_HIGH || + conn->pin_length == 16)) + goto encrypt; + +auth: if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) return 0; - if (hci_conn_auth(conn, sec_level, auth_type)) { - struct hci_cp_set_conn_encrypt cp; - cp.handle = cpu_to_le16(conn->handle); - cp.encrypt = 1; - hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, - sizeof(cp), &cp); - } + hci_conn_auth(conn, sec_level, auth_type); + return 0; + +encrypt: + if (conn->link_mode & HCI_LM_ENCRYPT) + return 1; + hci_conn_encrypt(conn); return 0; } EXPORT_SYMBOL(hci_conn_security); diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 35f98980070c..655af8bc60e2 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2095,6 +2095,10 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff hci_conn_hold(conn); conn->disc_timeout = HCI_DISCONN_TIMEOUT; pin_len = conn->pin_length; + + if (ev->key_type != HCI_LK_CHANGED_COMBINATION) + conn->key_type = ev->key_type; + hci_conn_put(conn); } -- cgit v1.2.3 From 60b83f571cf17a7a8ca9ddf2090db63e6a594571 Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Thu, 28 Apr 2011 12:07:56 +0200 Subject: Bluetooth: Ignore key unauthenticated for high security High security level for pre v2.1 devices requires combination link key authenticated by at least 16 digit PIN code. It's also necessary to update key_type and pin_length when the key exists and is sufficently secured for the connection as there will be no link key notify event in that case. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_event.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 655af8bc60e2..40e96cd79e4a 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2059,11 +2059,23 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff } conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); + if (conn) { + if (key->type == HCI_LK_UNAUTH_COMBINATION && + conn->auth_type != 0xff && + (conn->auth_type & 0x01)) { + BT_DBG("%s ignoring unauthenticated key", hdev->name); + goto not_found; + } - if (key->type == HCI_LK_UNAUTH_COMBINATION && conn && - conn->auth_type != 0xff && (conn->auth_type & 0x01)) { - BT_DBG("%s ignoring unauthenticated key", hdev->name); - goto not_found; + if (key->type == HCI_LK_COMBINATION && key->pin_len < 16 && + conn->pending_sec_level == BT_SECURITY_HIGH) { + BT_DBG("%s ignoring key unauthenticated for high \ + security", hdev->name); + goto not_found; + } + + conn->key_type = key->type; + conn->pin_length = key->pin_len; } bacpy(&cp.bdaddr, &ev->bdaddr); -- cgit v1.2.3 From 58797bf77234154a84827186bda316a1205bde05 Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Thu, 28 Apr 2011 12:07:58 +0200 Subject: Bluetooth: Respect local MITM req in io_cap reply If host requires MITM protection notify that to controller in io capabilities reply even if the remote device requires no bonding. If it is not respected, host can get an unauthenticated link key while it expects authenticated one. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 40e96cd79e4a..9d50e90993ca 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2397,7 +2397,7 @@ static inline u8 hci_get_auth_req(struct hci_conn *conn) /* If remote requests no-bonding follow that lead */ if (conn->remote_auth == 0x00 || conn->remote_auth == 0x01) - return 0x00; + return conn->remote_auth | (conn->auth_type & 0x01); return conn->auth_type; } -- cgit v1.2.3 From a770bb5aea84ee2509d4775f9959665f96da3b9d Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Thu, 28 Apr 2011 12:07:59 +0200 Subject: Bluetooth: Add secure flag for mgmt_pin_code_req Extend the mgmt_pin_code_request interface to require secure pin code (16 digit) for authentication. This is a kernel part of the secure pin code requirement notification to user space agent. Code styling fix by Johan Hedberg. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 2 +- include/net/bluetooth/mgmt.h | 1 + net/bluetooth/hci_event.c | 12 ++++++++++-- net/bluetooth/mgmt.c | 3 ++- 4 files changed, 14 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 2da2eb9f53ac..2995e2e63512 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -777,7 +777,7 @@ int mgmt_connected(u16 index, bdaddr_t *bdaddr); 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); +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); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 743440615349..0e7de636035d 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -253,6 +253,7 @@ struct mgmt_ev_connect_failed { #define MGMT_EV_PIN_CODE_REQUEST 0x000E struct mgmt_ev_pin_code_request { bdaddr_t bdaddr; + __u8 secure; } __packed; #define MGMT_EV_USER_CONFIRM_REQUEST 0x000F diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 9d50e90993ca..577d638600df 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2022,8 +2022,16 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(ev->bdaddr), &ev->bdaddr); - if (test_bit(HCI_MGMT, &hdev->flags)) - mgmt_pin_code_request(hdev->id, &ev->bdaddr); + if (test_bit(HCI_MGMT, &hdev->flags)) { + u8 secure; + + if (conn->pending_sec_level == BT_SECURITY_HIGH) + secure = 1; + else + secure = 0; + + mgmt_pin_code_request(hdev->id, &ev->bdaddr, secure); + } hci_dev_unlock(hdev); } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 4542396fc856..a7b4937d761c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1942,11 +1942,12 @@ int mgmt_connect_failed(u16 index, bdaddr_t *bdaddr, u8 status) return mgmt_event(MGMT_EV_CONNECT_FAILED, index, &ev, sizeof(ev), NULL); } -int mgmt_pin_code_request(u16 index, bdaddr_t *bdaddr) +int mgmt_pin_code_request(u16 index, 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), NULL); -- cgit v1.2.3 From 7a828908a026d801c6192fd32cfb35d6843f1539 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 28 Apr 2011 11:28:53 -0700 Subject: Bluetooth: Add automated SSP user confirmation responses This patch adds automated negative and positive (auto-accept) responses for Secure Simple Pairing user confirmation requests. The responses are only sent if the HCI_MGMT flag is set in order not to confuse older user space versions (without management interface support). Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_event.c | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 577d638600df..514e10e1e0ff 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2483,14 +2483,47 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_user_confirm_req *ev = (void *) skb->data; + int loc_mitm, rem_mitm; + struct hci_conn *conn; BT_DBG("%s", hdev->name); hci_dev_lock(hdev); - if (test_bit(HCI_MGMT, &hdev->flags)) - mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey); + if (!test_bit(HCI_MGMT, &hdev->flags)) + goto unlock; + conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); + if (!conn) + goto unlock; + + loc_mitm = (conn->auth_type & 0x01); + rem_mitm = (conn->remote_auth & 0x01); + + /* If we require MITM but the remote device can't provide that + * (it has NoInputNoOutput) then reject the confirmation + * request. The only exception is when we're dedicated bonding + * initiators (connect_cfm_cb set) since then we always have the MITM + * bit set. */ + if (!conn->connect_cfm_cb && loc_mitm && conn->remote_cap == 0x03) { + BT_DBG("Rejecting request: remote device can't provide MITM"); + hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_NEG_REPLY, + sizeof(ev->bdaddr), &ev->bdaddr); + goto unlock; + } + + /* If no side requires MITM protection; auto-accept */ + if ((!loc_mitm || conn->remote_cap == 0x03) && + (!rem_mitm || conn->io_capability == 0x03)) { + BT_DBG("Auto-accept of user confirmation"); + hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY, + sizeof(ev->bdaddr), &ev->bdaddr); + goto unlock; + } + + mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey); + +unlock: hci_dev_unlock(hdev); } -- cgit v1.2.3 From 9f61656a60c9506e3e4cd41af5efbcf6a30ee3b9 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 28 Apr 2011 11:28:54 -0700 Subject: Bluetooth: Add variable SSP auto-accept delay support Some test systems require an arbitrary delay to the auto-accept test cases for Secure Simple Pairing in order for the tests to pass. Previously when this was handled in user space it was worked around by code modifications and recompilation, but now that it's on the kernel side it's more convenient if there's a debugfs interface for it. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 3 +++ net/bluetooth/hci_conn.c | 17 +++++++++++++++++ net/bluetooth/hci_event.c | 10 +++++++++- net/bluetooth/hci_sysfs.c | 31 +++++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 2995e2e63512..09b9dd61e370 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -126,6 +126,8 @@ struct hci_dev { __u16 sniff_min_interval; __u16 sniff_max_interval; + unsigned int auto_accept_delay; + unsigned long quirks; atomic_t cmd_cnt; @@ -246,6 +248,7 @@ struct hci_conn { struct timer_list disc_timer; struct timer_list idle_timer; + struct timer_list auto_accept_timer; struct work_struct work_add; struct work_struct work_del; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 74cd755b38a7..7f5ad8a2b22d 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -269,6 +269,19 @@ static void hci_conn_idle(unsigned long arg) hci_conn_enter_sniff_mode(conn); } +static void hci_conn_auto_accept(unsigned long arg) +{ + struct hci_conn *conn = (void *) arg; + struct hci_dev *hdev = conn->hdev; + + hci_dev_lock(hdev); + + hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY, sizeof(conn->dst), + &conn->dst); + + hci_dev_unlock(hdev); +} + struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) { struct hci_conn *conn; @@ -312,6 +325,8 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) 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, + (unsigned long) conn); atomic_set(&conn->refcnt, 0); @@ -342,6 +357,8 @@ int hci_conn_del(struct hci_conn *conn) del_timer(&conn->disc_timer); + del_timer(&conn->auto_accept_timer); + if (conn->type == ACL_LINK) { struct hci_conn *sco = conn->link; if (sco) diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 514e10e1e0ff..a479389668ef 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2515,7 +2515,15 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev, /* If no side requires MITM protection; auto-accept */ if ((!loc_mitm || conn->remote_cap == 0x03) && (!rem_mitm || conn->io_capability == 0x03)) { - BT_DBG("Auto-accept of user confirmation"); + BT_DBG("Auto-accept of user confirmation with %ums delay", + hdev->auto_accept_delay); + + if (hdev->auto_accept_delay > 0) { + int delay = msecs_to_jiffies(hdev->auto_accept_delay); + mod_timer(&conn->auto_accept_timer, jiffies + delay); + goto unlock; + } + hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY, sizeof(ev->bdaddr), &ev->bdaddr); goto unlock; diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index 8775933ea837..a6c3aa8be1f7 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -511,6 +511,35 @@ static const struct file_operations uuids_fops = { .release = single_release, }; +static int auto_accept_delay_set(void *data, u64 val) +{ + struct hci_dev *hdev = data; + + hci_dev_lock_bh(hdev); + + hdev->auto_accept_delay = val; + + hci_dev_unlock_bh(hdev); + + return 0; +} + +static int auto_accept_delay_get(void *data, u64 *val) +{ + struct hci_dev *hdev = data; + + hci_dev_lock_bh(hdev); + + *val = hdev->auto_accept_delay; + + hci_dev_unlock_bh(hdev); + + return 0; +} + +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) { struct device *dev = &hdev->dev; @@ -545,6 +574,8 @@ int hci_register_sysfs(struct hci_dev *hdev) debugfs_create_file("uuids", 0444, hdev->debugfs, hdev, &uuids_fops); + debugfs_create_file("auto_accept_delay", 0444, hdev->debugfs, hdev, + &auto_accept_delay_fops); return 0; } -- cgit v1.2.3 From 79c6c70cbe35c270e7b59207ab76b44183a1030a Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 28 Apr 2011 11:28:55 -0700 Subject: Bluetooth: Fix HCI_CONN_AUTH_PEND flag for all authentication requests The HCI_CONN_AUTH_PEND flag should be set whenever requesting authentication so that multiple pending requests can't occur. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_event.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index a479389668ef..ce8e09955834 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1021,12 +1021,19 @@ static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status) hci_dev_lock(hdev); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); - if (conn && hci_outgoing_auth_needed(hdev, conn)) { + if (!conn) + goto unlock; + + if (!hci_outgoing_auth_needed(hdev, conn)) + goto unlock; + + if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { struct hci_cp_auth_requested cp; cp.handle = __cpu_to_le16(conn->handle); hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); } +unlock: hci_dev_unlock(hdev); } @@ -1516,12 +1523,19 @@ static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb mgmt_remote_name(hdev->id, &ev->bdaddr, ev->name); conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr); - if (conn && hci_outgoing_auth_needed(hdev, conn)) { + if (!conn) + goto unlock; + + if (!hci_outgoing_auth_needed(hdev, conn)) + goto unlock; + + if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { struct hci_cp_auth_requested cp; cp.handle = __cpu_to_le16(conn->handle); hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp); } +unlock: hci_dev_unlock(hdev); } -- cgit v1.2.3 From 55bc1a378cc35f21a26e07af2ff2b71820808cd4 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 28 Apr 2011 11:28:56 -0700 Subject: Bluetooth: Add confirm_hint parameter to user confirmation requests When accepting a pairing request which fulfills the SSP auto-accept criteria we need to push the request all the way to the user for confirmation. This patch adds a new hint to the user_confirm_request management event so user space can know when to show a numeric comparison dialog and when to show a simple yes/no confirmation dialog. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 3 ++- include/net/bluetooth/mgmt.h | 1 + net/bluetooth/hci_event.c | 16 ++++++++++++++-- net/bluetooth/mgmt.c | 4 +++- 4 files changed, 20 insertions(+), 4 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 09b9dd61e370..135dfac1be12 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -783,7 +783,8 @@ 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); +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, u8 status); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 0e7de636035d..c444a2b87e72 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -259,6 +259,7 @@ struct mgmt_ev_pin_code_request { #define MGMT_EV_USER_CONFIRM_REQUEST 0x000F struct mgmt_ev_user_confirm_request { bdaddr_t bdaddr; + __u8 confirm_hint; __le32 value; } __packed; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index ce8e09955834..29310c78ebb3 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2497,7 +2497,7 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_user_confirm_req *ev = (void *) skb->data; - int loc_mitm, rem_mitm; + int loc_mitm, rem_mitm, confirm_hint = 0; struct hci_conn *conn; BT_DBG("%s", hdev->name); @@ -2529,6 +2529,16 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev, /* If no side requires MITM protection; auto-accept */ if ((!loc_mitm || conn->remote_cap == 0x03) && (!rem_mitm || conn->io_capability == 0x03)) { + + /* If we're not the initiators request authorization to + * proceed from user space (mgmt_user_confirm with + * confirm_hint set to 1). */ + if (!test_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { + BT_DBG("Confirming auto-accept as acceptor"); + confirm_hint = 1; + goto confirm; + } + BT_DBG("Auto-accept of user confirmation with %ums delay", hdev->auto_accept_delay); @@ -2543,7 +2553,9 @@ static inline void hci_user_confirm_request_evt(struct hci_dev *hdev, goto unlock; } - mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey); +confirm: + mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey, + confirm_hint); unlock: hci_dev_unlock(hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a7b4937d761c..a1b0ec4e5178 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1995,13 +1995,15 @@ 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) +int mgmt_user_confirm_request(u16 index, bdaddr_t *bdaddr, __le32 value, + u8 confirm_hint) { struct mgmt_ev_user_confirm_request ev; BT_DBG("hci%u", index); 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), -- cgit v1.2.3 From be77159c3f37e73a18ecc5c1eab3c67e07c6ce22 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 28 Apr 2011 11:28:57 -0700 Subject: Bluetooth: Fix reason code for pairing rejection "Pairing not allowed" is 0x18 and not 0x16. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_event.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 29310c78ebb3..d535ea4ccbed 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2462,7 +2462,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 = 0x16; /* Pairing not allowed */ + cp.reason = 0x18; /* Pairing not allowed */ hci_send_cmd(hdev, HCI_OP_IO_CAPABILITY_NEG_REPLY, sizeof(cp), &cp); -- cgit v1.2.3 From 582fbe9ef9d6fc089ff20956595f046d4899e74e Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 28 Apr 2011 11:28:58 -0700 Subject: Bluetooth: Fix logic in hci_pin_code_request_evt The mgmt_ev_pin_code_request event should not be sent to user space if the request gets rejected by the kernel due to the pairable flag not being set. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_event.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d535ea4ccbed..ebbaa6c8d015 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2035,8 +2035,7 @@ static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff if (!test_bit(HCI_PAIRABLE, &hdev->flags)) hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(ev->bdaddr), &ev->bdaddr); - - if (test_bit(HCI_MGMT, &hdev->flags)) { + else if (test_bit(HCI_MGMT, &hdev->flags)) { u8 secure; if (conn->pending_sec_level == BT_SECURITY_HIGH) -- cgit v1.2.3 From d25e28abe58d2bcedf6025a6ccc532c29a19046f Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 28 Apr 2011 11:28:59 -0700 Subject: Bluetooth: Fix link key persistent storage criteria Link keys should only be stored if very specific criteria of the authentication process are fulfilled. This patch essentially copies the criteria that user space has so far been using to the kernel side so that the management interface works properly. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 4 +-- net/bluetooth/hci_core.c | 54 ++++++++++++++++++++++++++++++++++++++-- net/bluetooth/hci_event.c | 2 +- net/bluetooth/mgmt.c | 2 +- 4 files changed, 56 insertions(+), 6 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 135dfac1be12..3a3f7b453803 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -515,8 +515,8 @@ int hci_uuids_clear(struct hci_dev *hdev); int hci_link_keys_clear(struct hci_dev *hdev); struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); -int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, - u8 *key, u8 type, u8 pin_len); +int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, + bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len); int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr); int hci_remote_oob_data_clear(struct hci_dev *hdev); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 07d0ba35b9a5..5f55aef63e20 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1022,8 +1022,44 @@ struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) return NULL; } -int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, - u8 *val, u8 type, u8 pin_len) +static int hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn, + u8 key_type, u8 old_key_type) +{ + /* Legacy key */ + if (key_type < 0x03) + return 1; + + /* Debug keys are insecure so don't store them persistently */ + if (key_type == HCI_LK_DEBUG_COMBINATION) + return 0; + + /* Changed combination key and there's no previous one */ + if (key_type == HCI_LK_CHANGED_COMBINATION && old_key_type == 0xff) + return 0; + + /* Security mode 3 case */ + if (!conn) + return 1; + + /* Neither local nor remote side had no-bonding as requirement */ + if (conn->auth_type > 0x01 && conn->remote_auth > 0x01) + return 1; + + /* Local side had dedicated bonding as requirement */ + if (conn->auth_type == 0x02 || conn->auth_type == 0x03) + return 1; + + /* Remote side had dedicated bonding as requirement */ + if (conn->remote_auth == 0x02 || conn->remote_auth == 0x03) + return 1; + + /* If none of the above criteria match, then don't store the key + * persistently */ + return 0; +} + +int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, + bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len) { struct link_key *key, *old_key; u8 old_key_type; @@ -1042,6 +1078,20 @@ int hci_add_link_key(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, BT_DBG("%s key for %s type %u", hdev->name, batostr(bdaddr), type); + /* Some buggy controller combinations generate a changed + * combination key for legacy pairing even when there's no + * previous key */ + if (type == HCI_LK_CHANGED_COMBINATION && + (!conn || conn->remote_auth == 0xff) && + old_key_type == 0xff) + type = HCI_LK_COMBINATION; + + if (new_key && !hci_persistent_key(hdev, conn, type, old_key_type)) { + list_del(&key->list); + kfree(key); + return 0; + } + bacpy(&key->bdaddr, bdaddr); memcpy(key->val, val, 16); key->type = type; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index ebbaa6c8d015..8a63d3a463f7 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2136,7 +2136,7 @@ static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff } if (test_bit(HCI_LINK_KEYS, &hdev->flags)) - hci_add_link_key(hdev, 1, &ev->bdaddr, ev->link_key, + hci_add_link_key(hdev, conn, 1, &ev->bdaddr, ev->link_key, ev->key_type, pin_len); hci_dev_unlock(hdev); diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index a1b0ec4e5178..e1384fc6016c 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -945,7 +945,7 @@ static int load_keys(struct sock *sk, u16 index, unsigned char *data, u16 len) for (i = 0; i < key_count; i++) { struct mgmt_key_info *key = &cp->keys[i]; - hci_add_link_key(hdev, 0, &key->bdaddr, key->val, key->type, + hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type, key->pin_len); } -- cgit v1.2.3 From 12adcf3a953c3aa4006d855aa638133bf018ceac Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 28 Apr 2011 11:29:00 -0700 Subject: Bluetooth: Fix old_key_type logic for non-persistent keys Even if there's no previous key stored the connection might still be secured with a non-persistent key and in that case the key type in the hci_conn struct should be checked. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 5f55aef63e20..2ac6036b70c3 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1069,7 +1069,7 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, old_key_type = old_key->type; key = old_key; } else { - old_key_type = 0xff; + old_key_type = conn ? conn->key_type : 0xff; key = kzalloc(sizeof(*key), GFP_ATOMIC); if (!key) return -ENOMEM; -- cgit v1.2.3 From 655fe6ece7e71b37c17577ae485d11bf701c95f7 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 28 Apr 2011 11:29:01 -0700 Subject: Bluetooth: Fix connection key type updating for buggy controllers If a controller generates a changed combination key as its first key the connection key type will not be correctly set. In these situations make sure the update the connection key type when such a buggy controller is detected. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 2ac6036b70c3..59ca4755b6b3 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1083,8 +1083,11 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, * previous key */ if (type == HCI_LK_CHANGED_COMBINATION && (!conn || conn->remote_auth == 0xff) && - old_key_type == 0xff) + old_key_type == 0xff) { type = HCI_LK_COMBINATION; + if (conn) + conn->key_type = type; + } if (new_key && !hci_persistent_key(hdev, conn, type, old_key_type)) { list_del(&key->list); -- cgit v1.2.3 From 4748fed2d1a2a7a816277754498b8aa70850e051 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 28 Apr 2011 11:29:02 -0700 Subject: Bluetooth: Remove old_key_type from mgmt_ev_new_key User space shouldn't have any need for the old key type so remove it from the corresponding Management interface event. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 2 +- include/net/bluetooth/mgmt.h | 1 - net/bluetooth/hci_core.c | 9 +++++---- net/bluetooth/mgmt.c | 3 +-- 4 files changed, 7 insertions(+), 8 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 3a3f7b453803..88c2cd92eaea 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -775,7 +775,7 @@ 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 old_key_type); +int mgmt_new_key(u16 index, struct link_key *key); int mgmt_connected(u16 index, bdaddr_t *bdaddr); int mgmt_disconnected(u16 index, bdaddr_t *bdaddr); int mgmt_disconnect_failed(u16 index); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index c444a2b87e72..353a85dc2de0 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -231,7 +231,6 @@ struct mgmt_ev_controller_error { #define MGMT_EV_NEW_KEY 0x000A struct mgmt_ev_new_key { struct mgmt_key_info key; - __u8 old_key_type; } __packed; #define MGMT_EV_CONNECTED 0x000B diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 59ca4755b6b3..60260cae3a04 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1097,14 +1097,15 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, bacpy(&key->bdaddr, bdaddr); memcpy(key->val, val, 16); - key->type = type; key->pin_len = pin_len; - if (new_key) - mgmt_new_key(hdev->id, key, old_key_type); - if (type == HCI_LK_CHANGED_COMBINATION) key->type = old_key_type; + else + key->type = type; + + if (new_key) + mgmt_new_key(hdev->id, key); return 0; } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index e1384fc6016c..232ea8bfff19 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1858,7 +1858,7 @@ int mgmt_connectable(u16 index, u8 connectable) return ret; } -int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type) +int mgmt_new_key(u16 index, struct link_key *key) { struct mgmt_ev_new_key ev; @@ -1868,7 +1868,6 @@ int mgmt_new_key(u16 index, struct link_key *key, u8 old_key_type) ev.key.type = key->type; memcpy(ev.key.val, key->val, 16); ev.key.pin_len = key->pin_len; - ev.old_key_type = old_key_type; return mgmt_event(MGMT_EV_NEW_KEY, index, &ev, sizeof(ev), NULL); } -- cgit v1.2.3 From 4df378a10e31698df1679f3329301d773a654b61 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 28 Apr 2011 11:29:03 -0700 Subject: Bluetooth: Add store_hint parameter to mgmt_new_key Even for keys that shouldn't be stored some use cases require the knowledge of a new key having been created so that the conclusion of a successful pairing can be made. Therefore, always send the mgmt_new_key event but add a store_hint parameter to it to indicate to user space whether the key should be stored or not. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 2 +- include/net/bluetooth/mgmt.h | 1 + net/bluetooth/hci_core.c | 21 ++++++++++++--------- net/bluetooth/mgmt.c | 3 ++- 4 files changed, 16 insertions(+), 11 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 88c2cd92eaea..14cc3249c1eb 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -775,7 +775,7 @@ 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); +int mgmt_new_key(u16 index, struct link_key *key, u8 persistent); int mgmt_connected(u16 index, bdaddr_t *bdaddr); int mgmt_disconnected(u16 index, bdaddr_t *bdaddr); int mgmt_disconnect_failed(u16 index); diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h index 353a85dc2de0..4899286ed4e4 100644 --- a/include/net/bluetooth/mgmt.h +++ b/include/net/bluetooth/mgmt.h @@ -230,6 +230,7 @@ struct mgmt_ev_controller_error { #define MGMT_EV_NEW_KEY 0x000A struct mgmt_ev_new_key { + __u8 store_hint; struct mgmt_key_info key; } __packed; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 60260cae3a04..b6bda3fac10e 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1062,7 +1062,7 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len) { struct link_key *key, *old_key; - u8 old_key_type; + u8 old_key_type, persistent; old_key = hci_find_link_key(hdev, bdaddr); if (old_key) { @@ -1089,12 +1089,6 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, conn->key_type = type; } - if (new_key && !hci_persistent_key(hdev, conn, type, old_key_type)) { - list_del(&key->list); - kfree(key); - return 0; - } - bacpy(&key->bdaddr, bdaddr); memcpy(key->val, val, 16); key->pin_len = pin_len; @@ -1104,8 +1098,17 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, else key->type = type; - if (new_key) - mgmt_new_key(hdev->id, key); + if (!new_key) + return 0; + + persistent = hci_persistent_key(hdev, conn, type, old_key_type); + + mgmt_new_key(hdev->id, key, persistent); + + if (!persistent) { + list_del(&key->list); + kfree(key); + } return 0; } diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 232ea8bfff19..2481d257ed98 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1858,12 +1858,13 @@ int mgmt_connectable(u16 index, u8 connectable) return ret; } -int mgmt_new_key(u16 index, struct link_key *key) +int mgmt_new_key(u16 index, struct link_key *key, u8 persistent) { struct mgmt_ev_new_key ev; memset(&ev, 0, sizeof(ev)); + ev.store_hint = persistent; bacpy(&ev.key.bdaddr, &key->bdaddr); ev.key.type = key->type; memcpy(ev.key.val, key->val, 16); -- cgit v1.2.3 From 7cbc9bd99542752ff570abca79d0027669a01fb8 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Thu, 28 Apr 2011 11:29:04 -0700 Subject: Bluetooth: Fix updating conn->auth_type in hci_io_capa_request_evt In some circumstances hci_get_auth_req will return a value different from the current conn->auth_type. In these cases update conn->auth_type so that when a user confirm request comes it doesn't falsely trigger auto-accept. Signed-off-by: Johan Hedberg Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_event.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 8a63d3a463f7..d5aa97ee6ffa 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2447,7 +2447,8 @@ static inline void hci_io_capa_request_evt(struct hci_dev *hdev, struct sk_buff bacpy(&cp.bdaddr, &ev->bdaddr); cp.capability = conn->io_capability; - cp.authentication = hci_get_auth_req(conn); + conn->auth_type = hci_get_auth_req(conn); + cp.authentication = conn->auth_type; if ((conn->out == 0x01 || conn->remote_oob == 0x01) && hci_find_remote_oob_data(hdev, &conn->dst)) -- cgit v1.2.3 From 9e4425fff9e0a0fb6a8c705777ed861f991f8747 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 18 Apr 2011 18:38:43 -0300 Subject: Bluetooth: Add l2cap_add_psm() and l2cap_add_scid() The intention is to get rid of the l2cap_sk_list usage inside l2cap_core.c. l2cap_sk_list will soon be replaced by a list that does not depend on socket usage. Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 4 ++++ net/bluetooth/l2cap_core.c | 44 +++++++++++++++++++++++++++++++++++++++++++ net/bluetooth/l2cap_sock.c | 44 +++++++++++-------------------------------- 3 files changed, 59 insertions(+), 33 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index c34b1c126363..f5f3c2cf8a3e 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -458,6 +458,10 @@ void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb); void l2cap_streaming_send(struct l2cap_chan *chan); int l2cap_ertm_send(struct l2cap_chan *chan); +struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src); +int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm); +int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid); + void l2cap_sock_set_timer(struct sock *sk, long timeout); void l2cap_sock_clear_timer(struct sock *sk); void __l2cap_sock_close(struct sock *sk, int reason); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 338d8c3eedab..98ddd867cfd4 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -135,6 +135,50 @@ static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn return c; } +struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src) +{ + struct sock *sk; + struct hlist_node *node; + sk_for_each(sk, node, &l2cap_sk_list.head) { + struct l2cap_chan *chan = l2cap_pi(sk)->chan; + + if (chan->sport == psm && !bacmp(&bt_sk(sk)->src, src)) + goto found; + } + + sk = NULL; +found: + return sk; +} + +int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm) +{ + write_lock_bh(&l2cap_sk_list.lock); + + if (__l2cap_get_sock_by_addr(psm, src)) { + write_unlock_bh(&l2cap_sk_list.lock); + return -EADDRINUSE; + } + + chan->psm = psm; + chan->sport = psm; + + write_unlock_bh(&l2cap_sk_list.lock); + + return 0; +} + +int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid) +{ + write_lock_bh(&l2cap_sk_list.lock); + + chan->scid = scid; + + write_unlock_bh(&l2cap_sk_list.lock); + + return 0; +} + static u16 l2cap_alloc_cid(struct l2cap_conn *conn) { u16 cid = L2CAP_CID_DYN_START; diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 09cc7a005349..2156dcecec0b 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -78,22 +78,6 @@ void l2cap_sock_clear_timer(struct sock *sk) sk_stop_timer(sk, &sk->sk_timer); } -static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src) -{ - struct sock *sk; - struct hlist_node *node; - sk_for_each(sk, node, &l2cap_sk_list.head) { - struct l2cap_chan *chan = l2cap_pi(sk)->chan; - - if (chan->sport == psm && !bacmp(&bt_sk(sk)->src, src)) - goto found; - } - - sk = NULL; -found: - return sk; -} - static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) { struct sock *sk = sock->sk; @@ -136,26 +120,20 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen) } } - write_lock_bh(&l2cap_sk_list.lock); + if (la.l2_cid) + err = l2cap_add_scid(chan, la.l2_cid); + else + err = l2cap_add_psm(chan, &la.l2_bdaddr, la.l2_psm); - if (la.l2_psm && __l2cap_get_sock_by_addr(la.l2_psm, &la.l2_bdaddr)) { - err = -EADDRINUSE; - } else { - /* Save source address */ - bacpy(&bt_sk(sk)->src, &la.l2_bdaddr); - chan->psm = la.l2_psm; - chan->sport = la.l2_psm; - sk->sk_state = BT_BOUND; - - if (__le16_to_cpu(la.l2_psm) == 0x0001 || - __le16_to_cpu(la.l2_psm) == 0x0003) - chan->sec_level = BT_SECURITY_SDP; - } + if (err < 0) + goto done; - if (la.l2_cid) - chan->scid = la.l2_cid; + if (__le16_to_cpu(la.l2_psm) == 0x0001 || + __le16_to_cpu(la.l2_psm) == 0x0003) + chan->sec_level = BT_SECURITY_SDP; - write_unlock_bh(&l2cap_sk_list.lock); + bacpy(&bt_sk(sk)->src, &la.l2_bdaddr); + sk->sk_state = BT_BOUND; done: release_sock(sk); -- cgit v1.2.3 From 73b2ec18532f45e9028ce4c7bc8d7f8818eabd2a Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Mon, 18 Apr 2011 19:36:44 -0300 Subject: Bluetooth: Handle psm == 0 case inside l2cap_add_psm() When the user doesn't specify a psm we have the choose one for the channel. Now we do this inside l2cap_add_psm(). Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 1 - net/bluetooth/l2cap_core.c | 32 ++++++++++++++++++++++++-------- net/bluetooth/l2cap_sock.c | 22 ---------------------- 3 files changed, 24 insertions(+), 31 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index f5f3c2cf8a3e..fb3f90eaaaa4 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -458,7 +458,6 @@ void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb); void l2cap_streaming_send(struct l2cap_chan *chan); int l2cap_ertm_send(struct l2cap_chan *chan); -struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src); int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm); int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid); diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 98ddd867cfd4..9e3f64f05d49 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -135,7 +135,7 @@ static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn return c; } -struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src) +static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src) { struct sock *sk; struct hlist_node *node; @@ -153,19 +153,35 @@ found: int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm) { + int err; + write_lock_bh(&l2cap_sk_list.lock); - if (__l2cap_get_sock_by_addr(psm, src)) { - write_unlock_bh(&l2cap_sk_list.lock); - return -EADDRINUSE; + if (psm && __l2cap_get_sock_by_addr(psm, src)) { + err = -EADDRINUSE; + goto done; } - chan->psm = psm; - chan->sport = psm; + if (psm) { + chan->psm = psm; + chan->sport = psm; + err = 0; + } else { + u16 p; - write_unlock_bh(&l2cap_sk_list.lock); + err = -EINVAL; + for (p = 0x1001; p < 0x1100; p += 2) + if (!__l2cap_get_sock_by_addr(cpu_to_le16(p), src)) { + chan->psm = cpu_to_le16(p); + chan->sport = cpu_to_le16(p); + err = 0; + break; + } + } - return 0; +done: + write_unlock_bh(&l2cap_sk_list.lock); + return err; } int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid) diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index 2156dcecec0b..aca99cd5377d 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -256,28 +256,6 @@ static int l2cap_sock_listen(struct socket *sock, int backlog) goto done; } - if (!chan->psm && !chan->scid) { - bdaddr_t *src = &bt_sk(sk)->src; - u16 psm; - - err = -EINVAL; - - write_lock_bh(&l2cap_sk_list.lock); - - for (psm = 0x1001; psm < 0x1100; psm += 2) - if (!__l2cap_get_sock_by_addr(cpu_to_le16(psm), src)) { - chan->psm = cpu_to_le16(psm); - chan->sport = cpu_to_le16(psm); - err = 0; - break; - } - - write_unlock_bh(&l2cap_sk_list.lock); - - if (err < 0) - goto done; - } - sk->sk_max_ack_backlog = backlog; sk->sk_ack_backlog = 0; sk->sk_state = BT_LISTEN; -- cgit v1.2.3 From 23691d75cdc69c3b285211b4d77746aa20a17d18 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 27 Apr 2011 18:26:32 -0300 Subject: Bluetooth: Remove l2cap_sk_list A new list was added to replace the socket based one. This new list doesn't depent on sock and then fits better inside l2cap_core.c code. It also rename l2cap_chan_alloc() to l2cap_chan_create() and l2cap_chan_free() to l2cap_chan_destroy) Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/l2cap.h | 6 +- net/bluetooth/l2cap_core.c | 165 +++++++++++++++++++++++------------------- net/bluetooth/l2cap_sock.c | 6 +- 3 files changed, 95 insertions(+), 82 deletions(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index fb3f90eaaaa4..d09c9b1118e3 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -350,6 +350,7 @@ struct l2cap_chan { struct list_head srej_l; struct list_head list; + struct list_head global_l; }; struct l2cap_conn { @@ -441,7 +442,6 @@ static inline int l2cap_tx_window_full(struct l2cap_chan *ch) #define __is_sar_start(ctrl) (((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START) extern int disable_ertm; -extern struct bt_sock_list l2cap_sk_list; int l2cap_init_sockets(void); void l2cap_cleanup_sockets(void); @@ -469,9 +469,9 @@ void l2cap_sock_init(struct sock *sk, struct sock *parent); struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio); void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err); -struct l2cap_chan *l2cap_chan_alloc(struct sock *sk); +struct l2cap_chan *l2cap_chan_create(struct sock *sk); void l2cap_chan_del(struct l2cap_chan *chan, int err); -void l2cap_chan_free(struct l2cap_chan *chan); +void l2cap_chan_destroy(struct l2cap_chan *chan); int l2cap_chan_connect(struct l2cap_chan *chan); #endif /* __L2CAP_H */ diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 9e3f64f05d49..d0769a83cb58 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -62,9 +62,8 @@ static u8 l2cap_fixed_chan[8] = { 0x02, }; static struct workqueue_struct *_busy_wq; -struct bt_sock_list l2cap_sk_list = { - .lock = __RW_LOCK_UNLOCKED(l2cap_sk_list.lock) -}; +LIST_HEAD(chan_list); +DEFINE_RWLOCK(chan_list_lock); static void l2cap_busy_work(struct work_struct *work); @@ -135,29 +134,27 @@ static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn return c; } -static struct sock *__l2cap_get_sock_by_addr(__le16 psm, bdaddr_t *src) +static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src) { - struct sock *sk; - struct hlist_node *node; - sk_for_each(sk, node, &l2cap_sk_list.head) { - struct l2cap_chan *chan = l2cap_pi(sk)->chan; + struct l2cap_chan *c; - if (chan->sport == psm && !bacmp(&bt_sk(sk)->src, src)) + list_for_each_entry(c, &chan_list, global_l) { + if (c->sport == psm && !bacmp(&bt_sk(c->sk)->src, src)) goto found; } - sk = NULL; + c = NULL; found: - return sk; + return c; } int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm) { int err; - write_lock_bh(&l2cap_sk_list.lock); + write_lock_bh(&chan_list_lock); - if (psm && __l2cap_get_sock_by_addr(psm, src)) { + if (psm && __l2cap_global_chan_by_addr(psm, src)) { err = -EADDRINUSE; goto done; } @@ -171,7 +168,7 @@ int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm) err = -EINVAL; for (p = 0x1001; p < 0x1100; p += 2) - if (!__l2cap_get_sock_by_addr(cpu_to_le16(p), src)) { + if (!__l2cap_global_chan_by_addr(cpu_to_le16(p), src)) { chan->psm = cpu_to_le16(p); chan->sport = cpu_to_le16(p); err = 0; @@ -180,17 +177,17 @@ int l2cap_add_psm(struct l2cap_chan *chan, bdaddr_t *src, __le16 psm) } done: - write_unlock_bh(&l2cap_sk_list.lock); + write_unlock_bh(&chan_list_lock); return err; } int l2cap_add_scid(struct l2cap_chan *chan, __u16 scid) { - write_lock_bh(&l2cap_sk_list.lock); + write_lock_bh(&chan_list_lock); chan->scid = scid; - write_unlock_bh(&l2cap_sk_list.lock); + write_unlock_bh(&chan_list_lock); return 0; } @@ -207,7 +204,7 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn) return 0; } -struct l2cap_chan *l2cap_chan_alloc(struct sock *sk) +struct l2cap_chan *l2cap_chan_create(struct sock *sk) { struct l2cap_chan *chan; @@ -217,11 +214,19 @@ struct l2cap_chan *l2cap_chan_alloc(struct sock *sk) chan->sk = sk; + write_lock_bh(&chan_list_lock); + list_add(&chan->global_l, &chan_list); + write_unlock_bh(&chan_list_lock); + return chan; } -void l2cap_chan_free(struct l2cap_chan *chan) +void l2cap_chan_destroy(struct l2cap_chan *chan) { + write_lock_bh(&chan_list_lock); + list_del(&chan->global_l); + write_unlock_bh(&chan_list_lock); + kfree(chan); } @@ -651,48 +656,51 @@ static void l2cap_conn_start(struct l2cap_conn *conn) /* Find socket with cid and source bdaddr. * Returns closest match, locked. */ -static struct sock *l2cap_get_sock_by_scid(int state, __le16 cid, bdaddr_t *src) +static struct l2cap_chan *l2cap_global_chan_by_scid(int state, __le16 cid, bdaddr_t *src) { - struct sock *sk = NULL, *sk1 = NULL; - struct hlist_node *node; + struct l2cap_chan *c, *c1 = NULL; - read_lock(&l2cap_sk_list.lock); + read_lock(&chan_list_lock); - sk_for_each(sk, node, &l2cap_sk_list.head) { - struct l2cap_chan *chan = l2cap_pi(sk)->chan; + list_for_each_entry(c, &chan_list, global_l) { + struct sock *sk = c->sk; if (state && sk->sk_state != state) continue; - if (chan->scid == cid) { + if (c->scid == cid) { /* Exact match. */ - if (!bacmp(&bt_sk(sk)->src, src)) - break; + if (!bacmp(&bt_sk(sk)->src, src)) { + read_unlock(&chan_list_lock); + return c; + } /* Closest match */ if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) - sk1 = sk; + c1 = c; } } - read_unlock(&l2cap_sk_list.lock); + read_unlock(&chan_list_lock); - return node ? sk : sk1; + return c1; } static void l2cap_le_conn_ready(struct l2cap_conn *conn) { struct sock *parent, *sk; - struct l2cap_chan *chan; + struct l2cap_chan *chan, *pchan; BT_DBG(""); /* Check if we have socket listening on cid */ - parent = l2cap_get_sock_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA, + pchan = l2cap_global_chan_by_scid(BT_LISTEN, L2CAP_CID_LE_DATA, conn->src); - if (!parent) + if (!pchan) return; + parent = pchan->sk; + bh_lock_sock(parent); /* Check for backlog size */ @@ -705,7 +713,7 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn) if (!sk) goto clean; - chan = l2cap_chan_alloc(sk); + chan = l2cap_chan_create(sk); if (!chan) { l2cap_sock_kill(sk); goto clean; @@ -883,33 +891,34 @@ static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *ch /* Find socket with psm and source bdaddr. * Returns closest match. */ -static struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src) +static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr_t *src) { - struct sock *sk = NULL, *sk1 = NULL; - struct hlist_node *node; + struct l2cap_chan *c, *c1 = NULL; - read_lock(&l2cap_sk_list.lock); + read_lock(&chan_list_lock); - sk_for_each(sk, node, &l2cap_sk_list.head) { - struct l2cap_chan *chan = l2cap_pi(sk)->chan; + list_for_each_entry(c, &chan_list, global_l) { + struct sock *sk = c->sk; if (state && sk->sk_state != state) continue; - if (chan->psm == psm) { + if (c->psm == psm) { /* Exact match. */ - if (!bacmp(&bt_sk(sk)->src, src)) - break; + if (!bacmp(&bt_sk(sk)->src, src)) { + read_unlock_bh(&chan_list_lock); + return c; + } /* Closest match */ if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) - sk1 = sk; + c1 = c; } } - read_unlock(&l2cap_sk_list.lock); + read_unlock(&chan_list_lock); - return node ? sk : sk1; + return c1; } int l2cap_chan_connect(struct l2cap_chan *chan) @@ -2079,22 +2088,26 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd { struct l2cap_conn_req *req = (struct l2cap_conn_req *) data; struct l2cap_conn_rsp rsp; - struct l2cap_chan *chan = NULL; + struct l2cap_chan *chan = NULL, *pchan; struct sock *parent, *sk = NULL; int result, status = L2CAP_CS_NO_INFO; u16 dcid = 0, scid = __le16_to_cpu(req->scid); __le16 psm = req->psm; - BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid); + BT_ERR("psm 0x%2.2x scid 0x%4.4x", psm, scid); /* Check if we have socket listening on psm */ - parent = l2cap_get_sock_by_psm(BT_LISTEN, psm, conn->src); - if (!parent) { + pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src); + if (!pchan) { result = L2CAP_CR_BAD_PSM; goto sendresp; } + BT_ERR("%p 0x%2.2x", pchan, pchan->psm); + + parent = pchan->sk; + bh_lock_sock(parent); /* Check if the ACL is secure enough (if not SDP) */ @@ -2117,7 +2130,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd if (!sk) goto response; - chan = l2cap_chan_alloc(sk); + chan = l2cap_chan_create(sk); if (!chan) { l2cap_sock_kill(sk); goto response; @@ -3745,11 +3758,14 @@ done: static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb) { struct sock *sk; + struct l2cap_chan *chan; - sk = l2cap_get_sock_by_psm(0, psm, conn->src); - if (!sk) + chan = l2cap_global_chan_by_psm(0, psm, conn->src); + if (!chan) goto drop; + sk = chan->sk; + bh_lock_sock(sk); BT_DBG("sk %p, len %d", sk, skb->len); @@ -3775,11 +3791,14 @@ done: static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb) { struct sock *sk; + struct l2cap_chan *chan; - sk = l2cap_get_sock_by_scid(0, cid, conn->src); - if (!sk) + chan = l2cap_global_chan_by_scid(0, cid, conn->src); + if (!chan) goto drop; + sk = chan->sk; + bh_lock_sock(sk); BT_DBG("sk %p, len %d", sk, skb->len); @@ -3846,8 +3865,7 @@ static void l2cap_recv_frame(struct l2cap_conn *conn, struct sk_buff *skb) static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) { int exact = 0, lm1 = 0, lm2 = 0; - register struct sock *sk; - struct hlist_node *node; + struct l2cap_chan *c; if (type != ACL_LINK) return -EINVAL; @@ -3855,25 +3873,25 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type) BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr)); /* Find listening sockets and check their link_mode */ - read_lock(&l2cap_sk_list.lock); - sk_for_each(sk, node, &l2cap_sk_list.head) { - struct l2cap_chan *chan = l2cap_pi(sk)->chan; + read_lock(&chan_list_lock); + list_for_each_entry(c, &chan_list, global_l) { + struct sock *sk = c->sk; if (sk->sk_state != BT_LISTEN) continue; if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) { lm1 |= HCI_LM_ACCEPT; - if (chan->role_switch) + if (c->role_switch) lm1 |= HCI_LM_MASTER; exact++; } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) { lm2 |= HCI_LM_ACCEPT; - if (chan->role_switch) + if (c->role_switch) lm2 |= HCI_LM_MASTER; } } - read_unlock(&l2cap_sk_list.lock); + read_unlock(&chan_list_lock); return exact ? lm1 : lm2; } @@ -4126,25 +4144,22 @@ drop: static int l2cap_debugfs_show(struct seq_file *f, void *p) { - struct sock *sk; - struct hlist_node *node; + struct l2cap_chan *c; - read_lock_bh(&l2cap_sk_list.lock); + read_lock_bh(&chan_list_lock); - sk_for_each(sk, node, &l2cap_sk_list.head) { - struct l2cap_pinfo *pi = l2cap_pi(sk); - struct l2cap_chan *chan = pi->chan; + list_for_each_entry(c, &chan_list, global_l) { + struct sock *sk = c->sk; seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n", batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), - sk->sk_state, __le16_to_cpu(chan->psm), - chan->scid, chan->dcid, - chan->imtu, chan->omtu, chan->sec_level, - chan->mode); + sk->sk_state, __le16_to_cpu(c->psm), + c->scid, c->dcid, c->imtu, c->omtu, + c->sec_level, c->mode); } - read_unlock_bh(&l2cap_sk_list.lock); + read_unlock_bh(&chan_list_lock); return 0; } diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c index aca99cd5377d..c98360d40b84 100644 --- a/net/bluetooth/l2cap_sock.c +++ b/net/bluetooth/l2cap_sock.c @@ -808,8 +808,7 @@ void l2cap_sock_kill(struct sock *sk) /* Kill poor orphan */ - l2cap_chan_free(l2cap_pi(sk)->chan); - bt_sock_unlink(&l2cap_sk_list, sk); + l2cap_chan_destroy(l2cap_pi(sk)->chan); sock_set_flag(sk, SOCK_DEAD); sock_put(sk); } @@ -1025,7 +1024,6 @@ struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, g setup_timer(&sk->sk_timer, l2cap_sock_timeout, (unsigned long) sk); - bt_sock_link(&l2cap_sk_list, sk); return sk; } @@ -1052,7 +1050,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol, if (!sk) return -ENOMEM; - chan = l2cap_chan_alloc(sk); + chan = l2cap_chan_create(sk); if (!chan) { l2cap_sock_kill(sk); return -ENOMEM; -- cgit v1.2.3 From b3b1b061583ba4909b59a2f736825d86495fe956 Mon Sep 17 00:00:00 2001 From: Waldemar Rymarkiewicz Date: Fri, 6 May 2011 09:42:31 +0200 Subject: Bluetooth: Double check sec req for pre 2.1 device In case of pre v2.1 devices authentication request will return success immediately if the link key already exists without any authentication process. That means, it's not possible to re-authenticate the link if you already have combination key and for instance want to re-authenticate to get the high security (use 16 digit pin). Therefore, it's necessary to check security requirements on auth complete event to prevent not enough secure connection. Signed-off-by: Waldemar Rymarkiewicz Signed-off-by: Gustavo F. Padovan --- include/net/bluetooth/hci_core.h | 1 + net/bluetooth/hci_conn.c | 17 +++++++++++++++++ net/bluetooth/rfcomm/core.c | 2 +- 3 files changed, 19 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 14cc3249c1eb..6c994c004d15 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -422,6 +422,7 @@ void hci_conn_check_pending(struct hci_dev *hdev); 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); +int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level); int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type); int hci_conn_change_link_key(struct hci_conn *conn); int hci_conn_switch_role(struct hci_conn *conn, __u8 role); diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 7f5ad8a2b22d..3163330cd4f1 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -623,6 +623,23 @@ encrypt: } EXPORT_SYMBOL(hci_conn_security); +/* Check secure link requirement */ +int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level) +{ + BT_DBG("conn %p", conn); + + if (sec_level != BT_SECURITY_HIGH) + return 1; /* Accept if non-secure is required */ + + if (conn->key_type == HCI_LK_AUTH_COMBINATION || + (conn->key_type == HCI_LK_COMBINATION && + conn->pin_length == 16)) + return 1; + + return 0; /* Reject not secure link */ +} +EXPORT_SYMBOL(hci_conn_check_secure); + /* Change link key */ int hci_conn_change_link_key(struct hci_conn *conn) { diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index 121a5c13b989..5759bb7054f7 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -2096,7 +2096,7 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt) if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags)) continue; - if (!status) + if (!status && hci_conn_check_secure(conn, d->sec_level)) set_bit(RFCOMM_AUTH_ACCEPT, &d->flags); else set_bit(RFCOMM_AUTH_REJECT, &d->flags); -- cgit v1.2.3 From 83bc71b4102d2a288edaf9ee398b330b88a88086 Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Fri, 6 May 2011 18:41:43 -0300 Subject: Bluetooth: Add support for sending connection events for LE links We need to be able for receive events notifying that the connection was established, the connection attempt failed or that disconnection happened. Signed-off-by: Vinicius Costa Gomes Signed-off-by: Gustavo F. Padovan --- net/bluetooth/hci_event.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index d5aa97ee6ffa..f13ddbf858ba 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -1440,7 +1440,7 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff conn->state = BT_CLOSED; - if (conn->type == ACL_LINK) + if (conn->type == ACL_LINK || conn->type == LE_LINK) mgmt_disconnected(hdev->id, &conn->dst); hci_proto_disconn_cfm(conn, ev->reason); @@ -2659,12 +2659,15 @@ 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); hci_proto_connect_cfm(conn, ev->status); conn->state = BT_CLOSED; hci_conn_del(conn); goto unlock; } + mgmt_connected(hdev->id, &ev->bdaddr); + conn->handle = __le16_to_cpu(ev->handle); conn->state = BT_CONNECTED; -- cgit v1.2.3 From 365227e5fdf3d117e096416d9d3cc148959a829e Mon Sep 17 00:00:00 2001 From: Vinicius Costa Gomes Date: Fri, 6 May 2011 18:41:44 -0300 Subject: Bluetooth: Add support for disconnecting LE links via mgmt If we can't find a ACL link between the devices, we search the connection list one second time looking for LE links. Signed-off-by: Vinicius Costa Gomes Signed-off-by: Gustavo F. Padovan --- net/bluetooth/mgmt.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'net/bluetooth') diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 2481d257ed98..dae382ce7020 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -1033,6 +1033,9 @@ static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len) } conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr); + if (!conn) + conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr); + if (!conn) { err = cmd_status(sk, index, MGMT_OP_DISCONNECT, ENOTCONN); goto failed; -- cgit v1.2.3 From 55183d06cd1bd939ceccdad628b0aae12c86b803 Mon Sep 17 00:00:00 2001 From: "Gustavo F. Padovan" Date: Wed, 11 May 2011 19:26:06 -0300 Subject: Bluetooth: Remove leftover debug messages They were added by me while testing and I forgot to remove. Signed-off-by: Gustavo F. Padovan --- net/bluetooth/l2cap_core.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index d0769a83cb58..a5ab4a29ae31 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -2095,7 +2095,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd u16 dcid = 0, scid = __le16_to_cpu(req->scid); __le16 psm = req->psm; - BT_ERR("psm 0x%2.2x scid 0x%4.4x", psm, scid); + BT_DBG("psm 0x%2.2x scid 0x%4.4x", psm, scid); /* Check if we have socket listening on psm */ pchan = l2cap_global_chan_by_psm(BT_LISTEN, psm, conn->src); @@ -2104,8 +2104,6 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd goto sendresp; } - BT_ERR("%p 0x%2.2x", pchan, pchan->psm); - parent = pchan->sk; bh_lock_sock(parent); -- cgit v1.2.3 From 6dcae1eaee2b437536b2fe928a609f9589691ebf Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 16 May 2011 23:09:26 -0400 Subject: bluetooth: Fix warnings in l2cap_core.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit net/bluetooth/l2cap_core.c: In function ‘l2cap_recv_frame’: net/bluetooth/l2cap_core.c:3758:15: warning: ‘sk’ may be used uninitialized in this function net/bluetooth/l2cap_core.c:3758:15: note: ‘sk’ was declared here net/bluetooth/l2cap_core.c:3791:15: warning: ‘sk’ may be used uninitialized in this function net/bluetooth/l2cap_core.c:3791:15: note: ‘sk’ was declared here Signed-off-by: David S. Miller --- net/bluetooth/l2cap_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net/bluetooth') diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c index 4f3bc741183c..a86f9ba4f05c 100644 --- a/net/bluetooth/l2cap_core.c +++ b/net/bluetooth/l2cap_core.c @@ -3755,7 +3755,7 @@ done: static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, struct sk_buff *skb) { - struct sock *sk; + struct sock *sk = NULL; struct l2cap_chan *chan; chan = l2cap_global_chan_by_psm(0, psm, conn->src); @@ -3788,7 +3788,7 @@ done: static inline int l2cap_att_channel(struct l2cap_conn *conn, __le16 cid, struct sk_buff *skb) { - struct sock *sk; + struct sock *sk = NULL; struct l2cap_chan *chan; chan = l2cap_global_chan_by_scid(0, cid, conn->src); -- cgit v1.2.3