summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2011-05-05 14:09:28 -0700
committerDavid S. Miller <davem@davemloft.net>2011-05-05 14:09:28 -0700
commit90864fbc7639d7a2300c67a18c9fb9fbcf7d51d2 (patch)
tree6951c8d0e529dbfc7c4cec75d4cec63350e39b7c /net
parent228e548e602061b08ee8e8966f567c12aa079682 (diff)
parenta70171dce9cd44cb06c7d299eba9fa87a8933045 (diff)
downloadop-kernel-dev-90864fbc7639d7a2300c67a18c9fb9fbcf7d51d2.zip
op-kernel-dev-90864fbc7639d7a2300c67a18c9fb9fbcf7d51d2.tar.gz
Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'net')
-rw-r--r--net/bluetooth/cmtp/core.c3
-rw-r--r--net/bluetooth/hci_conn.c78
-rw-r--r--net/bluetooth/hci_core.c75
-rw-r--r--net/bluetooth/hci_event.c163
-rw-r--r--net/bluetooth/hci_sysfs.c31
-rw-r--r--net/bluetooth/hidp/core.c6
-rw-r--r--net/bluetooth/l2cap_core.c588
-rw-r--r--net/bluetooth/l2cap_sock.c242
-rw-r--r--net/bluetooth/mgmt.c95
-rw-r--r--net/bluetooth/rfcomm/core.c21
-rw-r--r--net/bluetooth/rfcomm/sock.c5
-rw-r--r--net/mac80211/aes_ccm.c6
-rw-r--r--net/mac80211/cfg.c15
-rw-r--r--net/mac80211/driver-ops.h18
-rw-r--r--net/mac80211/driver-trace.h27
-rw-r--r--net/mac80211/ibss.c7
-rw-r--r--net/mac80211/ieee80211_i.h3
-rw-r--r--net/mac80211/key.c21
-rw-r--r--net/mac80211/main.c18
-rw-r--r--net/mac80211/mesh.c3
-rw-r--r--net/mac80211/mesh_hwmp.c4
-rw-r--r--net/mac80211/pm.c16
-rw-r--r--net/mac80211/rx.c49
-rw-r--r--net/mac80211/sta_info.c2
-rw-r--r--net/mac80211/status.c8
-rw-r--r--net/mac80211/tx.c15
-rw-r--r--net/mac80211/work.c6
-rw-r--r--net/mac80211/wpa.c62
-rw-r--r--net/wireless/core.c17
-rw-r--r--net/wireless/reg.c3
30 files changed, 1008 insertions, 599 deletions
diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c
index cce99b0..c5b11af 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/hci_conn.c b/net/bluetooth/hci_conn.c
index 7a6f56b..7f5ad8a 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;
@@ -287,6 +300,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;
@@ -311,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);
@@ -341,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)
@@ -535,32 +553,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_core.c b/net/bluetooth/hci_core.c
index e057d12..815269b 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -1020,18 +1020,54 @@ 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;
+ u8 old_key_type, persistent;
old_key = hci_find_link_key(hdev, bdaddr);
if (old_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;
@@ -1040,16 +1076,37 @@ 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 (conn)
+ conn->key_type = type;
+ }
+
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 == 0x06)
+ if (type == HCI_LK_CHANGED_COMBINATION)
key->type = old_key_type;
+ else
+ key->type = type;
+
+ 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/hci_event.c b/net/bluetooth/hci_event.c
index cb25628..d5aa97e 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)
@@ -1013,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);
}
@@ -1208,7 +1223,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 +1245,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;
@@ -1443,7 +1466,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);
@@ -1501,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);
}
@@ -2006,9 +2035,16 @@ 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);
+ else if (test_bit(HCI_MGMT, &hdev->flags)) {
+ u8 secure;
- if (test_bit(HCI_MGMT, &hdev->flags))
- mgmt_pin_code_request(hdev->id, &ev->bdaddr);
+ 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);
}
@@ -2037,17 +2073,30 @@ 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 (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 == 0x04 && 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);
@@ -2079,11 +2128,15 @@ 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);
}
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);
@@ -2158,6 +2211,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 +2379,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++) {
@@ -2353,7 +2418,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;
}
@@ -2382,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))
@@ -2396,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);
@@ -2431,14 +2497,67 @@ 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, confirm_hint = 0;
+ 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)) {
+ /* 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);
+
+ 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;
+ }
+
+confirm:
+ mgmt_user_confirm_request(hdev->id, &ev->bdaddr, ev->passkey,
+ confirm_hint);
+
+unlock:
hci_dev_unlock(hdev);
}
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 8775933..a6c3aa8 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;
}
diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c
index ae6ebc6..c405a95 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 fd3c1f3..a378acc 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;
@@ -149,7 +147,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;
@@ -162,38 +160,43 @@ static 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;
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;
- 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) {
/* LE connection */
- l2cap_pi(sk)->omtu = L2CAP_LE_DEFAULT_MTU;
- l2cap_pi(sk)->scid = L2CAP_CID_LE_DATA;
- l2cap_pi(sk)->dcid = L2CAP_CID_LE_DATA;
+ chan->omtu = L2CAP_LE_DEFAULT_MTU;
+ 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);
- l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
+ 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;
- l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
+ 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;
- l2cap_pi(sk)->omtu = L2CAP_DEFAULT_MTU;
+ chan->scid = L2CAP_CID_SIGNALING;
+ chan->dcid = L2CAP_CID_SIGNALING;
+ chan->omtu = L2CAP_DEFAULT_MTU;
}
sock_hold(sk);
@@ -206,7 +209,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);
@@ -220,7 +223,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);
}
@@ -236,13 +239,13 @@ 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;
+ if (!(chan->conf_state & L2CAP_CONF_OUTPUT_DONE &&
+ chan->conf_state & L2CAP_CONF_INPUT_DONE))
+ return;
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);
@@ -257,15 +260,14 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
kfree(l);
}
}
-
-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:
@@ -273,16 +275,16 @@ static inline u8 l2cap_get_auth_type(struct sock *sk)
default:
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;
+ } else if (chan->psm == cpu_to_le16(0x0001)) {
+ 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 = chan->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)
@@ -350,7 +351,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;
@@ -358,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);
@@ -382,10 +383,10 @@ 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 (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));
}
@@ -395,7 +396,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)
@@ -411,27 +412,27 @@ 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)
{
- 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))
return;
- if (l2cap_check_security(sk) && __l2cap_no_conn_pending(sk)) {
+ 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);
- 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);
@@ -477,14 +478,14 @@ 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);
}
- 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);
@@ -515,15 +516,15 @@ 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) ||
- !__l2cap_no_conn_pending(sk)) {
+ if (!l2cap_check_security(chan) ||
+ !__l2cap_no_conn_pending(chan)) {
bh_unlock_sock(sk);
continue;
}
- if (!l2cap_mode_supported(l2cap_pi(sk)->mode,
+ if (!l2cap_mode_supported(chan->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 */
@@ -534,11 +535,11 @@ 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);
- 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);
@@ -546,10 +547,10 @@ 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(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);
@@ -569,13 +570,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++;
@@ -598,10 +599,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;
@@ -648,6 +651,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 +666,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;
@@ -722,7 +725,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;
}
@@ -828,10 +831,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;
@@ -847,19 +852,19 @@ 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_chan_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;
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)
@@ -867,14 +872,14 @@ int l2cap_do_connect(struct sock *sk)
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)
+ if (chan->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);
@@ -888,20 +893,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);
@@ -909,7 +905,7 @@ int l2cap_do_connect(struct sock *sk)
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);
@@ -925,12 +921,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)
@@ -963,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, chan, ECONNABORTED);
+ l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
bh_unlock_sock(sk);
return;
}
@@ -1011,15 +1008,14 @@ 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 hci_conn *hcon = chan->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;
@@ -1029,9 +1025,7 @@ void l2cap_do_send(struct sock *sk, 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))) {
@@ -1039,12 +1033,12 @@ 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);
}
- l2cap_do_send(sk, skb);
+ l2cap_do_send(chan, skb);
chan->next_tx_seq = (chan->next_tx_seq + 1) % 64;
}
@@ -1052,8 +1046,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;
@@ -1072,7 +1064,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;
}
@@ -1091,19 +1083,18 @@ 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);
}
- l2cap_do_send(sk, tx_skb);
+ l2cap_do_send(chan, tx_skb);
}
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;
@@ -1114,7 +1105,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;
}
@@ -1134,12 +1125,12 @@ 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);
}
- l2cap_do_send(sk, tx_skb);
+ l2cap_do_send(chan, tx_skb);
__mod_retrans_timer();
@@ -1210,7 +1201,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;
@@ -1240,9 +1231,10 @@ 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 l2cap_conn *conn = l2cap_pi(sk)->conn;
+ struct sock *sk = chan->sk;
+ struct l2cap_conn *conn = chan->conn;
struct sk_buff *skb;
int err, count, hlen = L2CAP_HDR_SIZE + 2;
struct l2cap_hdr *lh;
@@ -1257,9 +1249,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)) {
@@ -1269,9 +1261,10 @@ 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 l2cap_conn *conn = l2cap_pi(sk)->conn;
+ struct sock *sk = chan->sk;
+ struct l2cap_conn *conn = chan->conn;
struct sk_buff *skb;
int err, count, hlen = L2CAP_HDR_SIZE;
struct l2cap_hdr *lh;
@@ -1286,7 +1279,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);
@@ -1297,9 +1290,10 @@ 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 l2cap_conn *conn = l2cap_pi(sk)->conn;
+ struct sock *sk = chan->sk;
+ struct l2cap_conn *conn = chan->conn;
struct sk_buff *skb;
int err, count, hlen = L2CAP_HDR_SIZE + 2;
struct l2cap_hdr *lh;
@@ -1312,7 +1306,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);
@@ -1323,7 +1317,7 @@ struct sk_buff *l2cap_create_iframe_pdu(struct sock *sk, struct msghdr *msg, siz
/* 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)
@@ -1335,7 +1329,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;
@@ -1344,7 +1338,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;
@@ -1352,7 +1345,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);
@@ -1371,7 +1364,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);
@@ -1391,10 +1384,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) {
@@ -1615,9 +1609,8 @@ 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 = pi->mode };
+ struct l2cap_conf_rfc rfc = { .mode = chan->mode };
void *ptr = req->data;
BT_DBG("chan %p", chan);
@@ -1625,26 +1618,26 @@ 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 (pi->conf_state & L2CAP_CONF_STATE2_DEVICE)
+ if (chan->conf_state & L2CAP_CONF_STATE2_DEVICE)
break;
/* fall through */
default:
- pi->mode = l2cap_select_mode(rfc.mode, pi->conn->feat_mask);
+ chan->mode = l2cap_select_mode(rfc.mode, chan->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))
+ if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
+ !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
break;
rfc.mode = L2CAP_MODE_BASIC;
@@ -1660,24 +1653,24 @@ 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);
- 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 (pi->fcs == L2CAP_FCS_NONE ||
- pi->conf_state & L2CAP_CONF_NO_FCS_RECV) {
- pi->fcs = L2CAP_FCS_NONE;
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, pi->fcs);
+ if (chan->fcs == L2CAP_FCS_NONE ||
+ chan->conf_state & L2CAP_CONF_NO_FCS_RECV) {
+ chan->fcs = L2CAP_FCS_NONE;
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
}
break;
@@ -1688,24 +1681,24 @@ 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 (pi->fcs == L2CAP_FCS_NONE ||
- pi->conf_state & L2CAP_CONF_NO_FCS_RECV) {
- pi->fcs = L2CAP_FCS_NONE;
- l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, pi->fcs);
+ if (chan->fcs == L2CAP_FCS_NONE ||
+ chan->conf_state & L2CAP_CONF_NO_FCS_RECV) {
+ chan->fcs = L2CAP_FCS_NONE;
+ l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
}
break;
}
- req->dcid = cpu_to_le16(pi->dcid);
+ req->dcid = cpu_to_le16(chan->dcid);
req->flags = cpu_to_le16(0);
return ptr - data;
@@ -1713,7 +1706,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;
@@ -1738,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:
@@ -1751,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;
@@ -1768,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 (!(pi->conf_state & L2CAP_CONF_STATE2_DEVICE)) {
- pi->mode = l2cap_select_mode(rfc.mode,
- pi->conn->feat_mask);
+ if (!(chan->conf_state & L2CAP_CONF_STATE2_DEVICE)) {
+ chan->mode = l2cap_select_mode(rfc.mode,
+ chan->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;
@@ -1803,23 +1795,23 @@ done:
if (mtu < L2CAP_DEFAULT_MIN_MTU)
result = L2CAP_CONF_UNACCEPT;
else {
- pi->omtu = mtu;
- pi->conf_state |= L2CAP_CONF_MTU_DONE;
+ 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:
- pi->fcs = L2CAP_FCS_NONE;
- pi->conf_state |= L2CAP_CONF_MODE_DONE;
+ chan->fcs = L2CAP_FCS_NONE;
+ chan->conf_state |= L2CAP_CONF_MODE_DONE;
break;
case L2CAP_MODE_ERTM:
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);
@@ -1828,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);
@@ -1836,12 +1828,12 @@ 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);
- 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);
@@ -1852,29 +1844,28 @@ done:
result = L2CAP_CONF_UNACCEPT;
memset(&rfc, 0, sizeof(rfc));
- rfc.mode = pi->mode;
+ rfc.mode = chan->mode;
}
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->scid = cpu_to_le16(chan->dcid);
rsp->result = cpu_to_le16(result);
rsp->flags = cpu_to_le16(0x0000);
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 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);
@@ -1883,27 +1874,27 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data,
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:
if (olen == sizeof(rfc))
memcpy(&rfc, (void *)val, olen);
- if ((pi->conf_state & L2CAP_CONF_STATE2_DEVICE) &&
- rfc.mode != pi->mode)
+ if ((chan->conf_state & L2CAP_CONF_STATE2_DEVICE) &&
+ rfc.mode != chan->mode)
return -ECONNREFUSED;
- pi->fcs = 0;
+ chan->fcs = 0;
l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
sizeof(rfc), (unsigned long) &rfc);
@@ -1911,78 +1902,74 @@ static int l2cap_parse_conf_rsp(struct sock *sk, void *rsp, int len, void *data,
}
}
- 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) {
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);
}
}
- 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);
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(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,
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++;
}
-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);
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))
+ if ((chan->mode != L2CAP_MODE_ERTM) && (chan->mode != L2CAP_MODE_STREAMING))
return;
while (len >= L2CAP_CONF_OPT_SIZE) {
@@ -1999,12 +1986,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);
}
}
@@ -2076,6 +2063,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 */
@@ -2091,23 +2080,21 @@ 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);
- l2cap_pi(sk)->chan = chan;
-
- dcid = l2cap_pi(sk)->scid;
+ dcid = chan->scid;
l2cap_sock_set_timer(sk, sk->sk_sndtimeo);
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;
@@ -2155,10 +2142,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++;
@@ -2198,13 +2185,13 @@ 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;
- l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_CONNECT_PEND;
+ chan->dcid = dcid;
+ 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);
@@ -2212,7 +2199,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:
@@ -2232,15 +2219,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;
- else if (!(pi->conf_state & L2CAP_CONF_NO_FCS_RECV))
- pi->fcs = L2CAP_FCS_CRC16;
+ 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;
}
static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
@@ -2276,7 +2265,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;
}
@@ -2288,7 +2277,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;
}
@@ -2306,27 +2295,27 @@ 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) {
- set_default_fcs(l2cap_pi(sk));
+ if (chan->conf_state & L2CAP_CONF_INPUT_DONE) {
+ set_default_fcs(chan);
sk->sk_state = BT_CONNECTED;
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);
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++;
@@ -2360,7 +2349,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:
@@ -2374,8 +2363,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;
@@ -2399,16 +2388,16 @@ 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) {
- set_default_fcs(l2cap_pi(sk));
+ if (chan->conf_state & L2CAP_CONF_OUTPUT_DONE) {
+ set_default_fcs(chan);
sk->sk_state = BT_CONNECTED;
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);
@@ -2438,8 +2427,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;
@@ -2774,12 +2763,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);
@@ -2860,7 +2849,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;
@@ -2881,7 +2869,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);
@@ -2924,7 +2912,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)
@@ -2961,7 +2949,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;
}
@@ -3022,7 +3010,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;
}
@@ -3092,7 +3080,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;
@@ -3123,7 +3110,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;
}
@@ -3164,7 +3151,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) {
@@ -3241,12 +3228,11 @@ 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;
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,
@@ -3271,8 +3257,8 @@ 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) {
- l2cap_send_disconn_req(pi->conn, chan, ECONNRESET);
+ if (tx_seq_offset >= chan->tx_win) {
+ l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
goto drop;
}
@@ -3539,7 +3525,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;
@@ -3553,17 +3538,17 @@ 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) {
- l2cap_send_disconn_req(pi->conn, chan, ECONNRESET);
+ if (len > chan->mps) {
+ l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
goto drop;
}
@@ -3579,13 +3564,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;
}
@@ -3593,7 +3578,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;
}
@@ -3630,14 +3615,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))
@@ -3659,16 +3644,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);
@@ -3683,7 +3668,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;
}
@@ -3712,7 +3697,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))
@@ -3742,7 +3727,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))
@@ -3812,17 +3797,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;
}
}
@@ -3874,19 +3861,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,14 +3897,14 @@ 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;
}
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;
}
@@ -3923,11 +3912,11 @@ 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);
- 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);
@@ -3948,8 +3937,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,
@@ -4021,10 +4010,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;
@@ -4084,14 +4073,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->sec_level,
- pi->mode);
+ sk->sk_state, __le16_to_cpu(chan->psm),
+ chan->scid, chan->dcid,
+ 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 47394a1..7c4a9ae 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -30,6 +30,8 @@
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
+static const struct proto_ops l2cap_sock_ops;
+
/* ---- L2CAP timers ---- */
static void l2cap_sock_timeout(unsigned long arg)
{
@@ -51,7 +53,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;
@@ -80,9 +82,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;
@@ -91,6 +97,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;
@@ -136,17 +143,17 @@ 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;
- l2cap_pi(sk)->sport = la.l2_psm;
+ 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)
- l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
+ chan->sec_level = BT_SECURITY_SDP;
}
if (la.l2_cid)
- l2cap_pi(sk)->scid = la.l2_cid;
+ chan->scid = la.l2_cid;
write_unlock_bh(&l2cap_sk_list.lock);
@@ -158,6 +165,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;
@@ -182,7 +190,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:
@@ -226,10 +234,10 @@ 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_do_connect(sk);
+ err = l2cap_chan_connect(l2cap_pi(sk)->chan);
if (err)
goto done;
@@ -244,6 +252,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);
@@ -256,7 +265,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:
@@ -269,7 +278,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;
@@ -279,8 +288,8 @@ 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->psm = cpu_to_le16(psm);
+ chan->sport = cpu_to_le16(psm);
err = 0;
break;
}
@@ -360,6 +369,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);
@@ -367,13 +377,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 = 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);
+ la->l2_cid = cpu_to_le16(chan->scid);
}
return 0;
@@ -382,6 +392,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;
@@ -397,13 +408,13 @@ 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.fcs = l2cap_pi(sk)->fcs;
- opts.max_tx = l2cap_pi(sk)->max_tx;
- opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win;
+ 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;
len = min_t(unsigned int, len, sizeof(opts));
if (copy_to_user(optval, (char *) &opts, len))
@@ -412,7 +423,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 +439,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))
@@ -446,8 +457,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))
@@ -467,6 +478,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 +503,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 +523,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;
@@ -528,6 +540,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;
@@ -543,13 +556,13 @@ 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.fcs = l2cap_pi(sk)->fcs;
- opts.max_tx = l2cap_pi(sk)->max_tx;
- opts.txwin_size = (__u16)l2cap_pi(sk)->tx_win;
+ 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;
len = min_t(unsigned int, sizeof(opts), optlen);
if (copy_from_user((char *) &opts, optval, len)) {
@@ -562,10 +575,10 @@ 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:
- 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:
@@ -577,11 +590,11 @@ 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;
- l2cap_pi(sk)->fcs = opts.fcs;
- l2cap_pi(sk)->max_tx = opts.max_tx;
- l2cap_pi(sk)->tx_win = (__u8)opts.txwin_size;
+ 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;
break;
case L2CAP_LM:
@@ -591,14 +604,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:
@@ -613,6 +626,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;
@@ -649,7 +663,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:
@@ -678,7 +692,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 further only when we have l2cap_conn and
No Flush support in the LM */
if (!conn || !lmp_no_flush_capable(conn->hcon->hdev)) {
@@ -687,7 +701,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
}
}
- l2cap_pi(sk)->flushable = opt;
+ chan->flushable = opt;
break;
default:
@@ -702,7 +716,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;
@@ -725,76 +739,77 @@ 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 {
- l2cap_do_send(sk, 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;
}
/* 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;
}
- l2cap_do_send(sk, 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(sk, 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;
}
@@ -810,7 +825,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;
}
@@ -834,6 +851,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);
@@ -865,8 +884,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);
@@ -898,8 +917,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,
@@ -923,6 +942,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);
@@ -932,7 +952,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;
@@ -979,44 +999,47 @@ 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;
- 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;
- 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->imtu = pchan->imtu;
+ chan->omtu = pchan->omtu;
+ chan->conf_state = pchan->conf_state;
+ chan->mode = pchan->mode;
+ 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;
+ 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;
- pi->conf_state |= L2CAP_CONF_STATE2_DEVICE;
+ chan->mode = L2CAP_MODE_ERTM;
+ chan->conf_state |= L2CAP_CONF_STATE2_DEVICE;
} else {
- pi->mode = L2CAP_MODE_BASIC;
+ chan->mode = L2CAP_MODE_BASIC;
}
- 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->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;
+ chan->flushable = BT_FLUSHABLE_OFF;
}
/* Default config options */
- pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
+ chan->flush_to = L2CAP_DEFAULT_FLUSH_TO;
}
static struct proto l2cap_proto = {
@@ -1054,6 +1077,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,11 +1096,19 @@ 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;
}
-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,
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index c304688..2481d25 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);
}
@@ -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);
@@ -1784,17 +1858,17 @@ 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, 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);
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);
}
@@ -1868,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);
@@ -1920,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),
@@ -2075,3 +2152,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);
+}
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index c997393..121a5c1 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)
@@ -710,10 +711,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)->sec_level = sec_level;
+ 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);
@@ -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);
}
@@ -1890,7 +1892,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 +1912,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 +1995,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 */
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 66cc1f0..386cfaf 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))
diff --git a/net/mac80211/aes_ccm.c b/net/mac80211/aes_ccm.c
index 4bd6ef0..b9b595c 100644
--- a/net/mac80211/aes_ccm.c
+++ b/net/mac80211/aes_ccm.c
@@ -54,13 +54,12 @@ void ieee80211_aes_ccm_encrypt(struct crypto_cipher *tfm, u8 *scratch,
u8 *cdata, u8 *mic)
{
int i, j, last_len, num_blocks;
- u8 *pos, *cpos, *b, *s_0, *e, *b_0, *aad;
+ u8 *pos, *cpos, *b, *s_0, *e, *b_0;
b = scratch;
s_0 = scratch + AES_BLOCK_LEN;
e = scratch + 2 * AES_BLOCK_LEN;
b_0 = scratch + 3 * AES_BLOCK_LEN;
- aad = scratch + 4 * AES_BLOCK_LEN;
num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
last_len = data_len % AES_BLOCK_LEN;
@@ -94,13 +93,12 @@ int ieee80211_aes_ccm_decrypt(struct crypto_cipher *tfm, u8 *scratch,
u8 *cdata, size_t data_len, u8 *mic, u8 *data)
{
int i, j, last_len, num_blocks;
- u8 *pos, *cpos, *b, *s_0, *a, *b_0, *aad;
+ u8 *pos, *cpos, *b, *s_0, *a, *b_0;
b = scratch;
s_0 = scratch + AES_BLOCK_LEN;
a = scratch + 2 * AES_BLOCK_LEN;
b_0 = scratch + 3 * AES_BLOCK_LEN;
- aad = scratch + 4 * AES_BLOCK_LEN;
num_blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN);
last_len = data_len % AES_BLOCK_LEN;
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index a9ddaf6..12d52ce 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -1633,16 +1633,13 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
{
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
- int i;
-
- /*
- * This _could_ be supported by providing a hook for
- * drivers for this function, but at this point it
- * doesn't seem worth bothering.
- */
- if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL)
- return -EOPNOTSUPP;
+ int i, ret;
+ if (local->hw.flags & IEEE80211_HW_HAS_RATE_CONTROL) {
+ ret = drv_set_bitrate_mask(local, sdata, mask);
+ if (ret)
+ return ret;
+ }
for (i = 0; i < IEEE80211_NUM_BANDS; i++)
sdata->rc_rateidx_mask[i] = mask->control[i].legacy;
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 00a0685..2ddb56e 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -565,4 +565,22 @@ static inline bool drv_tx_frames_pending(struct ieee80211_local *local)
return ret;
}
+
+static inline int drv_set_bitrate_mask(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ const struct cfg80211_bitrate_mask *mask)
+{
+ int ret = -EOPNOTSUPP;
+
+ might_sleep();
+
+ trace_drv_set_bitrate_mask(local, sdata, mask);
+ if (local->ops->set_bitrate_mask)
+ ret = local->ops->set_bitrate_mask(&local->hw,
+ &sdata->vif, mask);
+ trace_drv_return_int(local, ret);
+
+ return ret;
+}
+
#endif /* __MAC80211_DRIVER_OPS */
diff --git a/net/mac80211/driver-trace.h b/net/mac80211/driver-trace.h
index c8c934d..191e834 100644
--- a/net/mac80211/driver-trace.h
+++ b/net/mac80211/driver-trace.h
@@ -989,6 +989,33 @@ DEFINE_EVENT(local_only_evt, drv_offchannel_tx_cancel_wait,
TP_ARGS(local)
);
+TRACE_EVENT(drv_set_bitrate_mask,
+ TP_PROTO(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ const struct cfg80211_bitrate_mask *mask),
+
+ TP_ARGS(local, sdata, mask),
+
+ TP_STRUCT__entry(
+ LOCAL_ENTRY
+ VIF_ENTRY
+ __field(u32, legacy_2g)
+ __field(u32, legacy_5g)
+ ),
+
+ TP_fast_assign(
+ LOCAL_ASSIGN;
+ VIF_ASSIGN;
+ __entry->legacy_2g = mask->control[IEEE80211_BAND_2GHZ].legacy;
+ __entry->legacy_5g = mask->control[IEEE80211_BAND_5GHZ].legacy;
+ ),
+
+ TP_printk(
+ LOCAL_PR_FMT VIF_PR_FMT " 2G Mask:0x%x 5G Mask:0x%x",
+ LOCAL_PR_ARG, VIF_PR_ARG, __entry->legacy_2g, __entry->legacy_5g
+ )
+);
+
/*
* Tracing for API calls that drivers call.
*/
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 1488396..b81860c 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -40,7 +40,7 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mgmt *mgmt,
size_t len)
{
- u16 auth_alg, auth_transaction, status_code;
+ u16 auth_alg, auth_transaction;
lockdep_assert_held(&sdata->u.ibss.mtx);
@@ -49,7 +49,6 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
- status_code = le16_to_cpu(mgmt->u.auth.status_code);
/*
* IEEE 802.11 standard does not require authentication in IBSS
@@ -527,8 +526,6 @@ static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_supported_band *sband;
u8 bssid[ETH_ALEN];
u16 capability;
int i;
@@ -551,8 +548,6 @@ static void ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n",
sdata->name, bssid);
- sband = local->hw.wiphy->bands[ifibss->channel->band];
-
capability = WLAN_CAPABILITY_IBSS;
if (ifibss->privacy)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index a778499..027c046 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -766,6 +766,9 @@ struct ieee80211_local {
int tx_headroom; /* required headroom for hardware/radiotap */
+ /* count for keys needing tailroom space allocation */
+ int crypto_tx_tailroom_needed_cnt;
+
/* Tasklet and skb queue to process calls from IRQ mode. All frames
* added to skb_queue will be processed, but frames in
* skb_queue_unreliable may be dropped if the total length of these
diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index af3c564..b510721 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -101,6 +101,11 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
if (!ret) {
key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
+
+ if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
+ (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)))
+ key->local->crypto_tx_tailroom_needed_cnt--;
+
return 0;
}
@@ -156,6 +161,10 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
+
+ if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
+ (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)))
+ key->local->crypto_tx_tailroom_needed_cnt++;
}
void ieee80211_key_removed(struct ieee80211_key_conf *key_conf)
@@ -388,8 +397,10 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key)
ieee80211_aes_key_free(key->u.ccmp.tfm);
if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC)
ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
- if (key->local)
+ if (key->local) {
ieee80211_debugfs_key_remove(key);
+ key->local->crypto_tx_tailroom_needed_cnt--;
+ }
kfree(key);
}
@@ -451,6 +462,8 @@ int ieee80211_key_link(struct ieee80211_key *key,
ieee80211_debugfs_key_add(key);
+ key->local->crypto_tx_tailroom_needed_cnt++;
+
ret = ieee80211_key_enable_hw_accel(key);
mutex_unlock(&sdata->local->key_mtx);
@@ -492,8 +505,12 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
mutex_lock(&sdata->local->key_mtx);
- list_for_each_entry(key, &sdata->key_list, list)
+ sdata->local->crypto_tx_tailroom_needed_cnt = 0;
+
+ list_for_each_entry(key, &sdata->key_list, list) {
+ sdata->local->crypto_tx_tailroom_needed_cnt++;
ieee80211_key_enable_hw_accel(key);
+ }
mutex_unlock(&sdata->local->key_mtx);
}
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 0ab2a8d..6187766 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -33,12 +33,6 @@
#include "cfg.h"
#include "debugfs.h"
-
-static bool ieee80211_disable_40mhz_24ghz;
-module_param(ieee80211_disable_40mhz_24ghz, bool, 0644);
-MODULE_PARM_DESC(ieee80211_disable_40mhz_24ghz,
- "Disable 40MHz support in the 2.4GHz band");
-
static struct lock_class_key ieee80211_rx_skb_queue_class;
void ieee80211_configure_filter(struct ieee80211_local *local)
@@ -728,18 +722,6 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
}
channels += sband->n_channels;
- /*
- * Since ieee80211_disable_40mhz_24ghz is global, we can
- * modify the sband's ht data even if the driver uses a
- * global structure for that.
- */
- if (ieee80211_disable_40mhz_24ghz &&
- band == IEEE80211_BAND_2GHZ &&
- sband->ht_cap.ht_supported) {
- sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
- sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40;
- }
-
if (max_bitrates < sband->n_bitrates)
max_bitrates = sband->n_bitrates;
supp_ht = supp_ht || sband->ht_cap.ht_supported;
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 1120797..c1299e2 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -613,12 +613,9 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb)
{
struct ieee80211_rx_status *rx_status;
- struct ieee80211_if_mesh *ifmsh;
struct ieee80211_mgmt *mgmt;
u16 stype;
- ifmsh = &sdata->u.mesh;
-
rx_status = IEEE80211_SKB_RXCB(skb);
mgmt = (struct ieee80211_mgmt *) skb->data;
stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE;
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 5bf64d7..e57f2e7 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -633,7 +633,6 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
struct mesh_path *mpath;
u8 ttl;
u8 *ta, *target_addr;
- u8 target_flags;
u32 target_sn;
u16 target_rcode;
@@ -644,7 +643,6 @@ static void hwmp_perr_frame_process(struct ieee80211_sub_if_data *sdata,
return;
}
ttl--;
- target_flags = PERR_IE_TARGET_FLAGS(perr_elem);
target_addr = PERR_IE_TARGET_ADDR(perr_elem);
target_sn = PERR_IE_TARGET_SN(perr_elem);
target_rcode = PERR_IE_TARGET_RCODE(perr_elem);
@@ -675,12 +673,10 @@ static void hwmp_rann_frame_process(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
struct mesh_path *mpath;
- u8 *ta;
u8 ttl, flags, hopcount;
u8 *orig_addr;
u32 orig_sn, metric;
- ta = mgmt->sa;
ttl = rann->rann_ttl;
if (ttl <= 1) {
ifmsh->mshstats.dropped_frames_ttl++;
diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index e373551..0424617 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -14,12 +14,23 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
ieee80211_scan_cancel(local);
+ if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
+ mutex_lock(&local->sta_mtx);
+ list_for_each_entry(sta, &local->sta_list, list) {
+ set_sta_flags(sta, WLAN_STA_BLOCK_BA);
+ ieee80211_sta_tear_down_BA_sessions(sta, true);
+ }
+ mutex_unlock(&local->sta_mtx);
+ }
+
ieee80211_stop_queues_by_reason(hw,
IEEE80211_QUEUE_STOP_REASON_SUSPEND);
/* flush out all packets */
synchronize_net();
+ drv_flush(local, false);
+
local->quiescing = true;
/* make quiescing visible to timers everywhere */
mb();
@@ -43,11 +54,6 @@ int __ieee80211_suspend(struct ieee80211_hw *hw)
/* tear down aggregation sessions and remove STAs */
mutex_lock(&local->sta_mtx);
list_for_each_entry(sta, &local->sta_list, list) {
- if (hw->flags & IEEE80211_HW_AMPDU_AGGREGATION) {
- set_sta_flags(sta, WLAN_STA_BLOCK_BA);
- ieee80211_sta_tear_down_BA_sessions(sta, true);
- }
-
if (sta->uploaded) {
sdata = sta->sdata;
if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index a864890..13a6697 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -652,7 +652,7 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
set_release_timer:
mod_timer(&tid_agg_rx->reorder_timer,
- tid_agg_rx->reorder_time[j] +
+ tid_agg_rx->reorder_time[j] + 1 +
HT_RX_REORDER_BUF_TIMEOUT);
} else {
del_timer(&tid_agg_rx->reorder_timer);
@@ -2368,47 +2368,6 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
return RX_QUEUED;
}
-static void ieee80211_rx_michael_mic_report(struct ieee80211_hdr *hdr,
- struct ieee80211_rx_data *rx)
-{
- int keyidx;
- unsigned int hdrlen;
-
- hdrlen = ieee80211_hdrlen(hdr->frame_control);
- if (rx->skb->len >= hdrlen + 4)
- keyidx = rx->skb->data[hdrlen + 3] >> 6;
- else
- keyidx = -1;
-
- if (!rx->sta) {
- /*
- * Some hardware seem to generate incorrect Michael MIC
- * reports; ignore them to avoid triggering countermeasures.
- */
- return;
- }
-
- if (!ieee80211_has_protected(hdr->frame_control))
- return;
-
- if (rx->sdata->vif.type == NL80211_IFTYPE_AP && keyidx) {
- /*
- * APs with pairwise keys should never receive Michael MIC
- * errors for non-zero keyidx because these are reserved for
- * group keys and only the AP is sending real multicast
- * frames in the BSS.
- */
- return;
- }
-
- if (!ieee80211_is_data(hdr->frame_control) &&
- !ieee80211_is_auth(hdr->frame_control))
- return;
-
- mac80211_ev_michael_mic_failure(rx->sdata, keyidx, hdr, NULL,
- GFP_ATOMIC);
-}
-
/* TODO: use IEEE80211_RX_FRAGMENTED */
static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
struct ieee80211_rate *rate)
@@ -2752,12 +2711,6 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx,
if (!prepares)
return false;
- if (status->flag & RX_FLAG_MMIC_ERROR) {
- if (status->rx_flags & IEEE80211_RX_RA_MATCH)
- ieee80211_rx_michael_mic_report(hdr, rx);
- return false;
- }
-
if (!consume) {
skb = skb_copy(skb, GFP_ATOMIC);
if (!skb) {
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index a03d8a3..d9e6e81 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -587,7 +587,6 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
{
unsigned long flags;
struct sk_buff *skb;
- struct ieee80211_sub_if_data *sdata;
if (skb_queue_empty(&sta->ps_tx_buf))
return false;
@@ -604,7 +603,6 @@ static bool sta_info_cleanup_expire_buffered(struct ieee80211_local *local,
if (!skb)
break;
- sdata = sta->sdata;
local->total_ps_buffered--;
#ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG
printk(KERN_DEBUG "Buffered frame expired (STA %pM)\n",
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 3ed3c83..1658efa 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -446,3 +446,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
dev_kfree_skb(skb);
}
EXPORT_SYMBOL(ieee80211_tx_status);
+
+void ieee80211_report_low_ack(struct ieee80211_sta *pubsta, u32 num_packets)
+{
+ struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
+ cfg80211_cqm_pktloss_notify(sta->sdata->dev, sta->sta.addr,
+ num_packets, GFP_ATOMIC);
+}
+EXPORT_SYMBOL(ieee80211_report_low_ack);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 17b10be..e3e3aa1 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1036,14 +1036,11 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
struct ieee80211_radiotap_iterator iterator;
struct ieee80211_radiotap_header *rthdr =
(struct ieee80211_radiotap_header *) skb->data;
- struct ieee80211_supported_band *sband;
bool hw_frag;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
NULL);
- sband = tx->local->hw.wiphy->bands[tx->channel->band];
-
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
tx->flags &= ~IEEE80211_TX_FRAGMENTED;
@@ -1442,11 +1439,8 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
struct ieee80211_tx_data tx;
ieee80211_tx_result res_prepare;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- u16 queue;
bool result = true;
- queue = skb_get_queue_mapping(skb);
-
if (unlikely(skb->len < 10)) {
dev_kfree_skb(skb);
return true;
@@ -1482,12 +1476,7 @@ static int ieee80211_skb_resize(struct ieee80211_local *local,
{
int tail_need = 0;
- /*
- * This could be optimised, devices that do full hardware
- * crypto (including TKIP MMIC) need no tailroom... But we
- * have no drivers for such devices currently.
- */
- if (may_encrypt) {
+ if (may_encrypt && local->crypto_tx_tailroom_needed_cnt) {
tail_need = IEEE80211_ENCRYPT_TAILROOM;
tail_need -= skb_tailroom(skb);
tail_need = max_t(int, tail_need, 0);
@@ -2485,7 +2474,6 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
{
struct ieee80211_local *local = hw_to_local(hw);
struct sk_buff *skb = NULL;
- struct sta_info *sta;
struct ieee80211_tx_data tx;
struct ieee80211_sub_if_data *sdata;
struct ieee80211_if_ap *bss = NULL;
@@ -2527,7 +2515,6 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
info = IEEE80211_SKB_CB(skb);
- sta = tx.sta;
tx.flags |= IEEE80211_TX_PS_BUFFERED;
tx.channel = local->hw.conf.channel;
info->band = tx.channel->band;
diff --git a/net/mac80211/work.c b/net/mac80211/work.c
index e73c8ca..a94b312 100644
--- a/net/mac80211/work.c
+++ b/net/mac80211/work.c
@@ -198,9 +198,8 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb;
struct ieee80211_mgmt *mgmt;
u8 *pos, qos_info;
- const u8 *ies;
size_t offset = 0, noffset;
- int i, len, count, rates_len, supp_rates_len;
+ int i, count, rates_len, supp_rates_len;
u16 capab;
struct ieee80211_supported_band *sband;
u32 rates = 0;
@@ -285,7 +284,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
}
/* SSID */
- ies = pos = skb_put(skb, 2 + wk->assoc.ssid_len);
+ pos = skb_put(skb, 2 + wk->assoc.ssid_len);
*pos++ = WLAN_EID_SSID;
*pos++ = wk->assoc.ssid_len;
memcpy(pos, wk->assoc.ssid, wk->assoc.ssid_len);
@@ -295,7 +294,6 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
if (supp_rates_len > 8)
supp_rates_len = 8;
- len = sband->n_bitrates;
pos = skb_put(skb, supp_rates_len + 2);
*pos++ = WLAN_EID_SUPP_RATES;
*pos++ = supp_rates_len;
diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c
index f1765de..9dc3b5f 100644
--- a/net/mac80211/wpa.c
+++ b/net/mac80211/wpa.c
@@ -87,42 +87,76 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx)
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- /* No way to verify the MIC if the hardware stripped it */
- if (status->flag & RX_FLAG_MMIC_STRIPPED)
+ /*
+ * it makes no sense to check for MIC errors on anything other
+ * than data frames.
+ */
+ if (!ieee80211_is_data_present(hdr->frame_control))
+ return RX_CONTINUE;
+
+ /*
+ * No way to verify the MIC if the hardware stripped it or
+ * the IV with the key index. In this case we have solely rely
+ * on the driver to set RX_FLAG_MMIC_ERROR in the event of a
+ * MIC failure report.
+ */
+ if (status->flag & (RX_FLAG_MMIC_STRIPPED | RX_FLAG_IV_STRIPPED)) {
+ if (status->flag & RX_FLAG_MMIC_ERROR)
+ goto mic_fail;
+
+ if (!(status->flag & RX_FLAG_IV_STRIPPED))
+ goto update_iv;
+
return RX_CONTINUE;
+ }
+ /*
+ * Some hardware seems to generate Michael MIC failure reports; even
+ * though, the frame was not encrypted with TKIP and therefore has no
+ * MIC. Ignore the flag them to avoid triggering countermeasures.
+ */
if (!rx->key || rx->key->conf.cipher != WLAN_CIPHER_SUITE_TKIP ||
- !ieee80211_has_protected(hdr->frame_control) ||
- !ieee80211_is_data_present(hdr->frame_control))
+ !(status->flag & RX_FLAG_DECRYPTED))
return RX_CONTINUE;
+ if (rx->sdata->vif.type == NL80211_IFTYPE_AP && rx->key->conf.keyidx) {
+ /*
+ * APs with pairwise keys should never receive Michael MIC
+ * errors for non-zero keyidx because these are reserved for
+ * group keys and only the AP is sending real multicast
+ * frames in the BSS. (
+ */
+ return RX_DROP_UNUSABLE;
+ }
+
+ if (status->flag & RX_FLAG_MMIC_ERROR)
+ goto mic_fail;
+
hdrlen = ieee80211_hdrlen(hdr->frame_control);
if (skb->len < hdrlen + MICHAEL_MIC_LEN)
return RX_DROP_UNUSABLE;
data = skb->data + hdrlen;
data_len = skb->len - hdrlen - MICHAEL_MIC_LEN;
-
key = &rx->key->conf.key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY];
michael_mic(key, hdr, data, data_len, mic);
- if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0) {
- if (!(status->rx_flags & IEEE80211_RX_RA_MATCH))
- return RX_DROP_UNUSABLE;
-
- mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx,
- (void *) skb->data, NULL,
- GFP_ATOMIC);
- return RX_DROP_UNUSABLE;
- }
+ if (memcmp(mic, data + data_len, MICHAEL_MIC_LEN) != 0)
+ goto mic_fail;
/* remove Michael MIC from payload */
skb_trim(skb, skb->len - MICHAEL_MIC_LEN);
+update_iv:
/* update IV in key information to be able to detect replays */
rx->key->u.tkip.rx[rx->queue].iv32 = rx->tkip_iv32;
rx->key->u.tkip.rx[rx->queue].iv16 = rx->tkip_iv16;
return RX_CONTINUE;
+
+mic_fail:
+ mac80211_ev_michael_mic_failure(rx->sdata, rx->key->conf.keyidx,
+ (void *) skb->data, NULL, GFP_ATOMIC);
+ return RX_DROP_UNUSABLE;
}
diff --git a/net/wireless/core.c b/net/wireless/core.c
index fe01de2..bbf1fa1 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -46,6 +46,11 @@ static struct dentry *ieee80211_debugfs_dir;
/* for the cleanup, scan and event works */
struct workqueue_struct *cfg80211_wq;
+static bool cfg80211_disable_40mhz_24ghz;
+module_param(cfg80211_disable_40mhz_24ghz, bool, 0644);
+MODULE_PARM_DESC(cfg80211_disable_40mhz_24ghz,
+ "Disable 40MHz support in the 2.4GHz band");
+
/* requires cfg80211_mutex to be held! */
struct cfg80211_registered_device *cfg80211_rdev_by_wiphy_idx(int wiphy_idx)
{
@@ -451,6 +456,18 @@ int wiphy_register(struct wiphy *wiphy)
return -EINVAL;
/*
+ * Since cfg80211_disable_40mhz_24ghz is global, we can
+ * modify the sband's ht data even if the driver uses a
+ * global structure for that.
+ */
+ if (cfg80211_disable_40mhz_24ghz &&
+ band == IEEE80211_BAND_2GHZ &&
+ sband->ht_cap.ht_supported) {
+ sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+ sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40;
+ }
+
+ /*
* Since we use a u32 for rate bitmaps in
* ieee80211_get_response_rate, we cannot
* have more than 32 legacy rates.
diff --git a/net/wireless/reg.c b/net/wireless/reg.c
index 58d6995..1613080 100644
--- a/net/wireless/reg.c
+++ b/net/wireless/reg.c
@@ -1455,7 +1455,8 @@ static void reg_process_hint(struct regulatory_request *reg_request)
* We only time out user hints, given that they should be the only
* source of bogus requests.
*/
- if (reg_request->initiator == NL80211_REGDOM_SET_BY_USER)
+ if (r != -EALREADY &&
+ reg_request->initiator == NL80211_REGDOM_SET_BY_USER)
schedule_delayed_work(&reg_timeout, msecs_to_jiffies(3142));
}
OpenPOWER on IntegriCloud