]> git.proxmox.com Git - mirror_ubuntu-eoan-kernel.git/commitdiff
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth...
authorJohn W. Linville <linville@tuxdriver.com>
Fri, 19 Oct 2012 19:22:27 +0000 (15:22 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Fri, 19 Oct 2012 19:22:27 +0000 (15:22 -0400)
28 files changed:
drivers/bluetooth/btmrvl_sdio.c
include/net/bluetooth/a2mp.h
include/net/bluetooth/amp.h [new file with mode: 0644]
include/net/bluetooth/bluetooth.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/l2cap.h
net/bluetooth/Kconfig
net/bluetooth/Makefile
net/bluetooth/a2mp.c
net/bluetooth/af_bluetooth.c
net/bluetooth/amp.c [new file with mode: 0644]
net/bluetooth/bnep/core.c
net/bluetooth/cmtp/core.c
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sysfs.c
net/bluetooth/hidp/core.c
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_sock.c
net/bluetooth/lib.c
net/bluetooth/mgmt.c
net/bluetooth/rfcomm/core.c
net/bluetooth/rfcomm/sock.c
net/bluetooth/rfcomm/tty.c
net/bluetooth/sco.c
net/bluetooth/smp.c

index 3f4bfc814dc7d5a0382635dbe16a41af413e59fe..9959d4cb23dcc2ddad7deefa008def72ac513925 100644 (file)
@@ -492,7 +492,7 @@ done:
 static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
 {
        u16 buf_len = 0;
-       int ret, buf_block_len, blksz;
+       int ret, num_blocks, blksz;
        struct sk_buff *skb = NULL;
        u32 type;
        u8 *payload = NULL;
@@ -514,18 +514,17 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
        }
 
        blksz = SDIO_BLOCK_SIZE;
-       buf_block_len = (buf_len + blksz - 1) / blksz;
+       num_blocks = DIV_ROUND_UP(buf_len, blksz);
 
        if (buf_len <= SDIO_HEADER_LEN
-                       || (buf_block_len * blksz) > ALLOC_BUF_SIZE) {
+           || (num_blocks * blksz) > ALLOC_BUF_SIZE) {
                BT_ERR("invalid packet length: %d", buf_len);
                ret = -EINVAL;
                goto exit;
        }
 
        /* Allocate buffer */
-       skb = bt_skb_alloc(buf_block_len * blksz + BTSDIO_DMA_ALIGN,
-                                                               GFP_ATOMIC);
+       skb = bt_skb_alloc(num_blocks * blksz + BTSDIO_DMA_ALIGN, GFP_ATOMIC);
        if (skb == NULL) {
                BT_ERR("No free skb");
                goto exit;
@@ -541,7 +540,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
        payload = skb->data;
 
        ret = sdio_readsb(card->func, payload, card->ioport,
-                         buf_block_len * blksz);
+                         num_blocks * blksz);
        if (ret < 0) {
                BT_ERR("readsb failed: %d", ret);
                ret = -EIO;
@@ -553,7 +552,16 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
         */
 
        buf_len = payload[0];
-       buf_len |= (u16) payload[1] << 8;
+       buf_len |= payload[1] << 8;
+       buf_len |= payload[2] << 16;
+
+       if (buf_len > blksz * num_blocks) {
+               BT_ERR("Skip incorrect packet: hdrlen %d buffer %d",
+                      buf_len, blksz * num_blocks);
+               ret = -EIO;
+               goto exit;
+       }
+
        type = payload[3];
 
        switch (type) {
@@ -589,8 +597,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv)
 
        default:
                BT_ERR("Unknown packet type:%d", type);
-               print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, payload,
-                                               blksz * buf_block_len);
+               BT_ERR("hex: %*ph", blksz * num_blocks, payload);
 
                kfree_skb(skb);
                skb = NULL;
@@ -849,8 +856,7 @@ static int btmrvl_sdio_host_to_card(struct btmrvl_private *priv,
                if (ret < 0) {
                        i++;
                        BT_ERR("i=%d writesb failed: %d", i, ret);
-                       print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,
-                                               payload, nb);
+                       BT_ERR("hex: %*ph", nb, payload);
                        ret = -EIO;
                        if (i > MAX_WRITE_IOMEM_RETRY)
                                goto exit;
index 6a76e0a0705eff9926c3558c3120f6cfab71eb71..42f21766c538b4bfeab6d140aaaa0fcada8e1f16 100644 (file)
 
 #define A2MP_FEAT_EXT  0x8000
 
+enum amp_mgr_state {
+       READ_LOC_AMP_INFO,
+       READ_LOC_AMP_ASSOC,
+       READ_LOC_AMP_ASSOC_FINAL,
+};
+
 struct amp_mgr {
+       struct list_head        list;
        struct l2cap_conn       *l2cap_conn;
        struct l2cap_chan       *a2mp_chan;
+       struct l2cap_chan       *bredr_chan;
        struct kref             kref;
        __u8                    ident;
        __u8                    handle;
+       enum amp_mgr_state      state;
        unsigned long           flags;
+
+       struct list_head        amp_ctrls;
+       struct mutex            amp_ctrls_lock;
 };
 
 struct a2mp_cmd {
@@ -118,9 +130,19 @@ struct a2mp_physlink_rsp {
 #define A2MP_STATUS_PHYS_LINK_EXISTS           0x05
 #define A2MP_STATUS_SECURITY_VIOLATION         0x06
 
-void amp_mgr_get(struct amp_mgr *mgr);
+extern struct list_head amp_mgr_list;
+extern struct mutex amp_mgr_list_lock;
+
+struct amp_mgr *amp_mgr_get(struct amp_mgr *mgr);
 int amp_mgr_put(struct amp_mgr *mgr);
+u8 __next_ident(struct amp_mgr *mgr);
 struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
                                       struct sk_buff *skb);
+struct amp_mgr *amp_mgr_lookup_by_state(u8 state);
+void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data);
+void a2mp_discover_amp(struct l2cap_chan *chan);
+void a2mp_send_getinfo_rsp(struct hci_dev *hdev);
+void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status);
+void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status);
 
 #endif /* __A2MP_H */
diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h
new file mode 100644 (file)
index 0000000..2e7c79e
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+   Copyright (c) 2011,2012 Intel Corp.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 and
+   only version 2 as published by the Free Software Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+*/
+
+#ifndef __AMP_H
+#define __AMP_H
+
+struct amp_ctrl {
+       struct list_head        list;
+       struct kref             kref;
+       __u8                    id;
+       __u16                   assoc_len_so_far;
+       __u16                   assoc_rem_len;
+       __u16                   assoc_len;
+       __u8                    *assoc;
+};
+
+int amp_ctrl_put(struct amp_ctrl *ctrl);
+void amp_ctrl_get(struct amp_ctrl *ctrl);
+struct amp_ctrl *amp_ctrl_add(struct amp_mgr *mgr, u8 id);
+struct amp_ctrl *amp_ctrl_lookup(struct amp_mgr *mgr, u8 id);
+void amp_ctrl_list_flush(struct amp_mgr *mgr);
+
+struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr,
+                            u8 remote_id, bool out);
+
+int phylink_gen_key(struct hci_conn *hcon, u8 *data, u8 *len, u8 *type);
+
+void amp_read_loc_info(struct hci_dev *hdev, struct amp_mgr *mgr);
+void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle);
+void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr);
+void amp_read_loc_assoc_final_data(struct hci_dev *hdev,
+                                  struct hci_conn *hcon);
+void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
+                       struct hci_conn *hcon);
+void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
+                       struct hci_conn *hcon);
+void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle);
+void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle);
+
+#endif /* __AMP_H */
index ede036977ae8b6debe3ee4560f7e93905bd92f9a..2554b3f5222ae0fa32b7f6fce650fb65327a65db 100644 (file)
@@ -180,7 +180,6 @@ static inline void bacpy(bdaddr_t *dst, bdaddr_t *src)
 }
 
 void baswap(bdaddr_t *dst, bdaddr_t *src);
-char *batostr(bdaddr_t *ba);
 
 /* Common socket structures and functions */
 
index 76b2b6bdcf36a281d558925a2a7a707ca2e1dddf..88cbbda6102777eb67e1ae33fbec458f17aec918 100644 (file)
@@ -33,6 +33,8 @@
 #define HCI_LINK_KEY_SIZE      16
 #define HCI_AMP_LINK_KEY_SIZE  (2 * HCI_LINK_KEY_SIZE)
 
+#define HCI_MAX_AMP_ASSOC_SIZE 672
+
 /* HCI dev events */
 #define HCI_DEV_REG                    1
 #define HCI_DEV_UNREG                  2
@@ -196,6 +198,7 @@ enum {
 #define ACL_START_NO_FLUSH     0x00
 #define ACL_CONT               0x01
 #define ACL_START              0x02
+#define ACL_COMPLETE           0x03
 #define ACL_ACTIVE_BCAST       0x04
 #define ACL_PICO_BCAST         0x08
 
@@ -205,6 +208,7 @@ enum {
 #define ESCO_LINK      0x02
 /* Low Energy links do not have defined link type. Use invented one */
 #define LE_LINK                0x80
+#define AMP_LINK       0x81
 
 /* LMP features */
 #define LMP_3SLOT      0x01
@@ -556,12 +560,46 @@ struct hci_cp_accept_phy_link {
        __u8     key[HCI_AMP_LINK_KEY_SIZE];
 } __packed;
 
-#define HCI_OP_DISCONN_PHY_LINK        0x0437
+#define HCI_OP_DISCONN_PHY_LINK                0x0437
 struct hci_cp_disconn_phy_link {
        __u8     phy_handle;
        __u8     reason;
 } __packed;
 
+struct ext_flow_spec {
+       __u8       id;
+       __u8       stype;
+       __le16     msdu;
+       __le32     sdu_itime;
+       __le32     acc_lat;
+       __le32     flush_to;
+} __packed;
+
+#define HCI_OP_CREATE_LOGICAL_LINK     0x0438
+#define HCI_OP_ACCEPT_LOGICAL_LINK     0x0439
+struct hci_cp_create_accept_logical_link {
+       __u8                  phy_handle;
+       struct ext_flow_spec  tx_flow_spec;
+       struct ext_flow_spec  rx_flow_spec;
+} __packed;
+
+#define HCI_OP_DISCONN_LOGICAL_LINK    0x043a
+struct hci_cp_disconn_logical_link {
+       __le16   log_handle;
+} __packed;
+
+#define HCI_OP_LOGICAL_LINK_CANCEL     0x043b
+struct hci_cp_logical_link_cancel {
+       __u8     phy_handle;
+       __u8     flow_spec_id;
+} __packed;
+
+struct hci_rp_logical_link_cancel {
+       __u8     status;
+       __u8     phy_handle;
+       __u8     flow_spec_id;
+} __packed;
+
 #define HCI_OP_SNIFF_MODE              0x0803
 struct hci_cp_sniff_mode {
        __le16   handle;
index e7d454609881a30d929ec8aa613390df157c8b43..9fe8e2dec870c57073d24aaf1b0ff6ebfbfc1801 100644 (file)
@@ -73,6 +73,7 @@ struct discovery_state {
 struct hci_conn_hash {
        struct list_head list;
        unsigned int     acl_num;
+       unsigned int     amp_num;
        unsigned int     sco_num;
        unsigned int     le_num;
 };
@@ -124,6 +125,14 @@ struct le_scan_params {
 
 #define HCI_MAX_SHORT_NAME_LENGTH      10
 
+struct amp_assoc {
+       __u16   len;
+       __u16   offset;
+       __u16   rem_len;
+       __u16   len_so_far;
+       __u8    data[HCI_MAX_AMP_ASSOC_SIZE];
+};
+
 #define NUM_REASSEMBLY 4
 struct hci_dev {
        struct list_head list;
@@ -177,6 +186,8 @@ struct hci_dev {
        __u32           amp_max_flush_to;
        __u32           amp_be_flush_to;
 
+       struct amp_assoc        loc_assoc;
+
        __u8            flow_ctl_mode;
 
        unsigned int    auto_accept_delay;
@@ -252,8 +263,6 @@ struct hci_dev {
 
        struct sk_buff_head     driver_init;
 
-       void                    *core_data;
-
        atomic_t                promisc;
 
        struct dentry           *debugfs;
@@ -277,6 +286,8 @@ struct hci_dev {
        int (*ioctl)(struct hci_dev *hdev, unsigned int cmd, unsigned long arg);
 };
 
+#define HCI_PHY_HANDLE(handle) (handle & 0xff)
+
 struct hci_conn {
        struct list_head list;
 
@@ -310,6 +321,7 @@ struct hci_conn {
 
        __u8            remote_cap;
        __u8            remote_auth;
+       __u8            remote_id;
        bool            flush_key;
 
        unsigned int    sent;
@@ -339,7 +351,7 @@ struct hci_conn {
 
 struct hci_chan {
        struct list_head list;
-
+       __u16 handle;
        struct hci_conn *conn;
        struct sk_buff_head data_q;
        unsigned int    sent;
@@ -438,6 +450,9 @@ static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
        case ACL_LINK:
                h->acl_num++;
                break;
+       case AMP_LINK:
+               h->amp_num++;
+               break;
        case LE_LINK:
                h->le_num++;
                break;
@@ -459,6 +474,9 @@ static inline void hci_conn_hash_del(struct hci_dev *hdev, struct hci_conn *c)
        case ACL_LINK:
                h->acl_num--;
                break;
+       case AMP_LINK:
+               h->amp_num--;
+               break;
        case LE_LINK:
                h->le_num--;
                break;
@@ -475,6 +493,8 @@ static inline unsigned int hci_conn_num(struct hci_dev *hdev, __u8 type)
        switch (type) {
        case ACL_LINK:
                return h->acl_num;
+       case AMP_LINK:
+               return h->amp_num;
        case LE_LINK:
                return h->le_num;
        case SCO_LINK:
@@ -556,6 +576,7 @@ void hci_conn_check_pending(struct hci_dev *hdev);
 struct hci_chan *hci_chan_create(struct hci_conn *conn);
 void hci_chan_del(struct hci_chan *chan);
 void hci_chan_list_flush(struct hci_conn *conn);
+struct hci_chan *hci_chan_lookup_handle(struct hci_dev *hdev, __u16 handle);
 
 struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
                             __u8 dst_type, __u8 sec_level, __u8 auth_type);
@@ -584,7 +605,10 @@ static inline void hci_conn_put(struct hci_conn *conn)
 
        if (atomic_dec_and_test(&conn->refcnt)) {
                unsigned long timeo;
-               if (conn->type == ACL_LINK || conn->type == LE_LINK) {
+
+               switch (conn->type) {
+               case ACL_LINK:
+               case LE_LINK:
                        del_timer(&conn->idle_timer);
                        if (conn->state == BT_CONNECTED) {
                                timeo = conn->disc_timeout;
@@ -593,12 +617,20 @@ static inline void hci_conn_put(struct hci_conn *conn)
                        } else {
                                timeo = msecs_to_jiffies(10);
                        }
-               } else {
+                       break;
+
+               case AMP_LINK:
+                       timeo = conn->disc_timeout;
+                       break;
+
+               default:
                        timeo = msecs_to_jiffies(10);
+                       break;
                }
+
                cancel_delayed_work(&conn->disc_work);
                queue_delayed_work(conn->hdev->workqueue,
-                                       &conn->disc_work, timeo);
+                                  &conn->disc_work, timeo);
        }
 }
 
@@ -789,6 +821,10 @@ static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason)
                sco_disconn_cfm(conn, reason);
                break;
 
+       /* L2CAP would be handled for BREDR chan */
+       case AMP_LINK:
+               break;
+
        default:
                BT_ERR("unknown link type %d", conn->type);
                break;
index 7ed8e356425a16dc33c5afd5e4a80eaafdd6ea64..6e23afdf65c1c64a625c6763a1144383ccc5341d 100644 (file)
 /* L2CAP defaults */
 #define L2CAP_DEFAULT_MTU              672
 #define L2CAP_DEFAULT_MIN_MTU          48
-#define L2CAP_DEFAULT_FLUSH_TO         0xffff
+#define L2CAP_DEFAULT_FLUSH_TO         0xFFFF
+#define L2CAP_EFS_DEFAULT_FLUSH_TO     0xFFFFFFFF
 #define L2CAP_DEFAULT_TX_WINDOW                63
 #define L2CAP_DEFAULT_EXT_WINDOW       0x3FFF
 #define L2CAP_DEFAULT_MAX_TX           3
 #define L2CAP_DEFAULT_RETRANS_TO       2000    /* 2 seconds */
 #define L2CAP_DEFAULT_MONITOR_TO       12000   /* 12 seconds */
-#define L2CAP_DEFAULT_MAX_PDU_SIZE     1009    /* Sized for 3-DH5 packet */
+#define L2CAP_DEFAULT_MAX_PDU_SIZE     1492    /* Sized for AMP packet */
 #define L2CAP_DEFAULT_ACK_TO           200
 #define L2CAP_DEFAULT_MAX_SDU_SIZE     0xFFFF
 #define L2CAP_DEFAULT_SDU_ITIME                0xFFFFFFFF
@@ -508,6 +509,8 @@ struct l2cap_chan {
        __u32           remote_acc_lat;
        __u32           remote_flush_to;
 
+       __u8            ctrl_id;
+
        struct delayed_work     chan_timer;
        struct delayed_work     retrans_timer;
        struct delayed_work     monitor_timer;
@@ -538,6 +541,7 @@ struct l2cap_ops {
        void                    (*state_change) (struct l2cap_chan *chan,
                                                 int state);
        void                    (*ready) (struct l2cap_chan *chan);
+       void                    (*defer) (struct l2cap_chan *chan);
        struct sk_buff          *(*alloc_skb) (struct l2cap_chan *chan,
                                               unsigned long len, int nb);
 };
@@ -745,6 +749,10 @@ static inline void l2cap_chan_no_ready(struct l2cap_chan *chan)
 {
 }
 
+static inline void l2cap_chan_no_defer(struct l2cap_chan *chan)
+{
+}
+
 extern bool disable_ertm;
 
 int l2cap_init_sockets(void);
@@ -767,6 +775,8 @@ int l2cap_chan_check_security(struct l2cap_chan *chan);
 void l2cap_chan_set_defaults(struct l2cap_chan *chan);
 int l2cap_ertm_init(struct l2cap_chan *chan);
 void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
+void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
 void l2cap_chan_del(struct l2cap_chan *chan, int err);
+void l2cap_send_conn_req(struct l2cap_chan *chan);
 
 #endif /* __L2CAP_H */
index 3537d385035e61fc090e9094b83850243268f992..1c11d0dcd863951c400cb55156b11b9446582fee 100644 (file)
@@ -11,6 +11,7 @@ menuconfig BT
        select CRYPTO_BLKCIPHER
        select CRYPTO_AES
        select CRYPTO_ECB
+       select CRYPTO_SHA256
        help
          Bluetooth is low-cost, low-power, short-range wireless technology.
          It was designed as a replacement for cables and other short-range
index fa6d94a4602a8352a6f2aa9ed13ed18ff7e6c08a..dea6a287daca88b666eaee999043a3abf6dd853a 100644 (file)
@@ -10,4 +10,4 @@ obj-$(CONFIG_BT_HIDP) += hidp/
 
 bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
        hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
-       a2mp.o
+       a2mp.o amp.o
index 0760d1fed6f08bb13404a11622b83cf3dcf02484..d5136cfb57e2e33276b93947d7b64aa3b4d98fa8 100644 (file)
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/a2mp.h>
+#include <net/bluetooth/amp.h>
+
+/* Global AMP Manager list */
+LIST_HEAD(amp_mgr_list);
+DEFINE_MUTEX(amp_mgr_list_lock);
 
 /* A2MP build & send command helper functions */
 static struct a2mp_cmd *__a2mp_build(u8 code, u8 ident, u16 len, void *data)
@@ -37,8 +42,7 @@ static struct a2mp_cmd *__a2mp_build(u8 code, u8 ident, u16 len, void *data)
        return cmd;
 }
 
-static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
-                     void *data)
+void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data)
 {
        struct l2cap_chan *chan = mgr->a2mp_chan;
        struct a2mp_cmd *cmd;
@@ -63,6 +67,14 @@ static void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len,
        kfree(cmd);
 }
 
+u8 __next_ident(struct amp_mgr *mgr)
+{
+       if (++mgr->ident == 0)
+               mgr->ident = 1;
+
+       return mgr->ident;
+}
+
 static inline void __a2mp_cl_bredr(struct a2mp_cl *cl)
 {
        cl->id = 0;
@@ -161,6 +173,83 @@ static int a2mp_discover_req(struct amp_mgr *mgr, struct sk_buff *skb,
        return 0;
 }
 
+static int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
+                            struct a2mp_cmd *hdr)
+{
+       struct a2mp_discov_rsp *rsp = (void *) skb->data;
+       u16 len = le16_to_cpu(hdr->len);
+       struct a2mp_cl *cl;
+       u16 ext_feat;
+       bool found = false;
+
+       if (len < sizeof(*rsp))
+               return -EINVAL;
+
+       len -= sizeof(*rsp);
+       skb_pull(skb, sizeof(*rsp));
+
+       ext_feat = le16_to_cpu(rsp->ext_feat);
+
+       BT_DBG("mtu %d efm 0x%4.4x", le16_to_cpu(rsp->mtu), ext_feat);
+
+       /* check that packet is not broken for now */
+       while (ext_feat & A2MP_FEAT_EXT) {
+               if (len < sizeof(ext_feat))
+                       return -EINVAL;
+
+               ext_feat = get_unaligned_le16(skb->data);
+               BT_DBG("efm 0x%4.4x", ext_feat);
+               len -= sizeof(ext_feat);
+               skb_pull(skb, sizeof(ext_feat));
+       }
+
+       cl = (void *) skb->data;
+       while (len >= sizeof(*cl)) {
+               BT_DBG("Remote AMP id %d type %d status %d", cl->id, cl->type,
+                      cl->status);
+
+               if (cl->id != HCI_BREDR_ID && cl->type == HCI_AMP) {
+                       struct a2mp_info_req req;
+
+                       found = true;
+                       req.id = cl->id;
+                       a2mp_send(mgr, A2MP_GETINFO_REQ, __next_ident(mgr),
+                                 sizeof(req), &req);
+               }
+
+               len -= sizeof(*cl);
+               cl = (void *) skb_pull(skb, sizeof(*cl));
+       }
+
+       /* Fall back to L2CAP init sequence */
+       if (!found) {
+               struct l2cap_conn *conn = mgr->l2cap_conn;
+               struct l2cap_chan *chan;
+
+               mutex_lock(&conn->chan_lock);
+
+               list_for_each_entry(chan, &conn->chan_l, list) {
+
+                       BT_DBG("chan %p state %s", chan,
+                              state_to_string(chan->state));
+
+                       if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP)
+                               continue;
+
+                       l2cap_chan_lock(chan);
+
+                       if (chan->state == BT_CONNECT)
+                               l2cap_send_conn_req(chan);
+
+                       l2cap_chan_unlock(chan);
+               }
+
+               mutex_unlock(&conn->chan_lock);
+       }
+
+       return 0;
+}
+
 static int a2mp_change_notify(struct amp_mgr *mgr, struct sk_buff *skb,
                              struct a2mp_cmd *hdr)
 {
@@ -181,7 +270,6 @@ static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
                            struct a2mp_cmd *hdr)
 {
        struct a2mp_info_req *req  = (void *) skb->data;
-       struct a2mp_info_rsp rsp;
        struct hci_dev *hdev;
 
        if (le16_to_cpu(hdr->len) < sizeof(*req))
@@ -189,53 +277,93 @@ static int a2mp_getinfo_req(struct amp_mgr *mgr, struct sk_buff *skb,
 
        BT_DBG("id %d", req->id);
 
-       rsp.id = req->id;
-       rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
-
        hdev = hci_dev_get(req->id);
-       if (hdev && hdev->amp_type != HCI_BREDR) {
-               rsp.status = 0;
-               rsp.total_bw = cpu_to_le32(hdev->amp_total_bw);
-               rsp.max_bw = cpu_to_le32(hdev->amp_max_bw);
-               rsp.min_latency = cpu_to_le32(hdev->amp_min_latency);
-               rsp.pal_cap = cpu_to_le16(hdev->amp_pal_cap);
-               rsp.assoc_size = cpu_to_le16(hdev->amp_assoc_size);
+       if (!hdev || hdev->dev_type != HCI_AMP) {
+               struct a2mp_info_rsp rsp;
+
+               rsp.id = req->id;
+               rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+
+               a2mp_send(mgr, A2MP_GETINFO_RSP, hdr->ident, sizeof(rsp),
+                         &rsp);
+
+               goto done;
        }
 
+       mgr->state = READ_LOC_AMP_INFO;
+       hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_INFO, 0, NULL);
+
+done:
        if (hdev)
                hci_dev_put(hdev);
 
-       a2mp_send(mgr, A2MP_GETINFO_RSP, hdr->ident, sizeof(rsp), &rsp);
-
        skb_pull(skb, sizeof(*req));
        return 0;
 }
 
+static int a2mp_getinfo_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
+                           struct a2mp_cmd *hdr)
+{
+       struct a2mp_info_rsp *rsp = (struct a2mp_info_rsp *) skb->data;
+       struct a2mp_amp_assoc_req req;
+       struct amp_ctrl *ctrl;
+
+       if (le16_to_cpu(hdr->len) < sizeof(*rsp))
+               return -EINVAL;
+
+       BT_DBG("id %d status 0x%2.2x", rsp->id, rsp->status);
+
+       if (rsp->status)
+               return -EINVAL;
+
+       ctrl = amp_ctrl_add(mgr, rsp->id);
+       if (!ctrl)
+               return -ENOMEM;
+
+       req.id = rsp->id;
+       a2mp_send(mgr, A2MP_GETAMPASSOC_REQ, __next_ident(mgr), sizeof(req),
+                 &req);
+
+       skb_pull(skb, sizeof(*rsp));
+       return 0;
+}
+
 static int a2mp_getampassoc_req(struct amp_mgr *mgr, struct sk_buff *skb,
                                struct a2mp_cmd *hdr)
 {
        struct a2mp_amp_assoc_req *req = (void *) skb->data;
        struct hci_dev *hdev;
+       struct amp_mgr *tmp;
 
        if (le16_to_cpu(hdr->len) < sizeof(*req))
                return -EINVAL;
 
        BT_DBG("id %d", req->id);
 
+       /* Make sure that other request is not processed */
+       tmp = amp_mgr_lookup_by_state(READ_LOC_AMP_ASSOC);
+
        hdev = hci_dev_get(req->id);
-       if (!hdev || hdev->amp_type == HCI_BREDR) {
+       if (!hdev || hdev->amp_type == HCI_BREDR || tmp) {
                struct a2mp_amp_assoc_rsp rsp;
                rsp.id = req->id;
-               rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+
+               if (tmp) {
+                       rsp.status = A2MP_STATUS_COLLISION_OCCURED;
+                       amp_mgr_put(tmp);
+               } else {
+                       rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+               }
 
                a2mp_send(mgr, A2MP_GETAMPASSOC_RSP, hdr->ident, sizeof(rsp),
                          &rsp);
-               goto clean;
+
+               goto done;
        }
 
-       /* Placeholder for HCI Read AMP Assoc */
+       amp_read_loc_assoc(hdev, mgr);
 
-clean:
+done:
        if (hdev)
                hci_dev_put(hdev);
 
@@ -243,6 +371,68 @@ clean:
        return 0;
 }
 
+static int a2mp_getampassoc_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
+                               struct a2mp_cmd *hdr)
+{
+       struct a2mp_amp_assoc_rsp *rsp = (void *) skb->data;
+       u16 len = le16_to_cpu(hdr->len);
+       struct hci_dev *hdev;
+       struct amp_ctrl *ctrl;
+       struct hci_conn *hcon;
+       size_t assoc_len;
+
+       if (len < sizeof(*rsp))
+               return -EINVAL;
+
+       assoc_len = len - sizeof(*rsp);
+
+       BT_DBG("id %d status 0x%2.2x assoc len %zu", rsp->id, rsp->status,
+              assoc_len);
+
+       if (rsp->status)
+               return -EINVAL;
+
+       /* Save remote ASSOC data */
+       ctrl = amp_ctrl_lookup(mgr, rsp->id);
+       if (ctrl) {
+               u8 *assoc;
+
+               assoc = kzalloc(assoc_len, GFP_KERNEL);
+               if (!assoc) {
+                       amp_ctrl_put(ctrl);
+                       return -ENOMEM;
+               }
+
+               memcpy(assoc, rsp->amp_assoc, assoc_len);
+               ctrl->assoc = assoc;
+               ctrl->assoc_len = assoc_len;
+               ctrl->assoc_rem_len = assoc_len;
+               ctrl->assoc_len_so_far = 0;
+
+               amp_ctrl_put(ctrl);
+       }
+
+       /* Create Phys Link */
+       hdev = hci_dev_get(rsp->id);
+       if (!hdev)
+               return -EINVAL;
+
+       hcon = phylink_add(hdev, mgr, rsp->id, true);
+       if (!hcon)
+               goto done;
+
+       BT_DBG("Created hcon %p: loc:%d -> rem:%d", hcon, hdev->id, rsp->id);
+
+       mgr->bredr_chan->ctrl_id = rsp->id;
+
+       amp_create_phylink(hdev, mgr, hcon);
+
+done:
+       hci_dev_put(hdev);
+       skb_pull(skb, len);
+       return 0;
+}
+
 static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
                                   struct a2mp_cmd *hdr)
 {
@@ -250,6 +440,8 @@ static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
 
        struct a2mp_physlink_rsp rsp;
        struct hci_dev *hdev;
+       struct hci_conn *hcon;
+       struct amp_ctrl *ctrl;
 
        if (le16_to_cpu(hdr->len) < sizeof(*req))
                return -EINVAL;
@@ -265,9 +457,43 @@ static int a2mp_createphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
                goto send_rsp;
        }
 
-       /* TODO process physlink create */
+       ctrl = amp_ctrl_lookup(mgr, rsp.remote_id);
+       if (!ctrl) {
+               ctrl = amp_ctrl_add(mgr, rsp.remote_id);
+               if (ctrl) {
+                       amp_ctrl_get(ctrl);
+               } else {
+                       rsp.status = A2MP_STATUS_UNABLE_START_LINK_CREATION;
+                       goto send_rsp;
+               }
+       }
 
-       rsp.status = A2MP_STATUS_SUCCESS;
+       if (ctrl) {
+               size_t assoc_len = le16_to_cpu(hdr->len) - sizeof(*req);
+               u8 *assoc;
+
+               assoc = kzalloc(assoc_len, GFP_KERNEL);
+               if (!assoc) {
+                       amp_ctrl_put(ctrl);
+                       return -ENOMEM;
+               }
+
+               memcpy(assoc, req->amp_assoc, assoc_len);
+               ctrl->assoc = assoc;
+               ctrl->assoc_len = assoc_len;
+               ctrl->assoc_rem_len = assoc_len;
+               ctrl->assoc_len_so_far = 0;
+
+               amp_ctrl_put(ctrl);
+       }
+
+       hcon = phylink_add(hdev, mgr, req->local_id, false);
+       if (hcon) {
+               amp_accept_phylink(hdev, mgr, hcon);
+               rsp.status = A2MP_STATUS_SUCCESS;
+       } else {
+               rsp.status = A2MP_STATUS_UNABLE_START_LINK_CREATION;
+       }
 
 send_rsp:
        if (hdev)
@@ -286,6 +512,7 @@ static int a2mp_discphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
        struct a2mp_physlink_req *req = (void *) skb->data;
        struct a2mp_physlink_rsp rsp;
        struct hci_dev *hdev;
+       struct hci_conn *hcon;
 
        if (le16_to_cpu(hdr->len) < sizeof(*req))
                return -EINVAL;
@@ -296,14 +523,22 @@ static int a2mp_discphyslink_req(struct amp_mgr *mgr, struct sk_buff *skb,
        rsp.remote_id = req->local_id;
        rsp.status = A2MP_STATUS_SUCCESS;
 
-       hdev = hci_dev_get(req->local_id);
+       hdev = hci_dev_get(req->remote_id);
        if (!hdev) {
                rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
                goto send_rsp;
        }
 
+       hcon = hci_conn_hash_lookup_ba(hdev, AMP_LINK, mgr->l2cap_conn->dst);
+       if (!hcon) {
+               BT_ERR("No phys link exist");
+               rsp.status = A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS;
+               goto clean;
+       }
+
        /* TODO Disconnect Phys Link here */
 
+clean:
        hci_dev_put(hdev);
 
 send_rsp:
@@ -377,10 +612,19 @@ static int a2mp_chan_recv_cb(struct l2cap_chan *chan, struct sk_buff *skb)
                        err = a2mp_discphyslink_req(mgr, skb, hdr);
                        break;
 
-               case A2MP_CHANGE_RSP:
                case A2MP_DISCOVER_RSP:
+                       err = a2mp_discover_rsp(mgr, skb, hdr);
+                       break;
+
                case A2MP_GETINFO_RSP:
+                       err = a2mp_getinfo_rsp(mgr, skb, hdr);
+                       break;
+
                case A2MP_GETAMPASSOC_RSP:
+                       err = a2mp_getampassoc_rsp(mgr, skb, hdr);
+                       break;
+
+               case A2MP_CHANGE_RSP:
                case A2MP_CREATEPHYSLINK_RSP:
                case A2MP_DISCONNPHYSLINK_RSP:
                        err = a2mp_cmd_rsp(mgr, skb, hdr);
@@ -455,9 +699,10 @@ static struct l2cap_ops a2mp_chan_ops = {
        .new_connection = l2cap_chan_no_new_connection,
        .teardown = l2cap_chan_no_teardown,
        .ready = l2cap_chan_no_ready,
+       .defer = l2cap_chan_no_defer,
 };
 
-static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
+static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn, bool locked)
 {
        struct l2cap_chan *chan;
        int err;
@@ -492,7 +737,10 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
 
        chan->conf_state = 0;
 
-       l2cap_chan_add(conn, chan);
+       if (locked)
+               __l2cap_chan_add(conn, chan);
+       else
+               l2cap_chan_add(conn, chan);
 
        chan->remote_mps = chan->omtu;
        chan->mps = chan->omtu;
@@ -503,11 +751,13 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
 }
 
 /* AMP Manager functions */
-void amp_mgr_get(struct amp_mgr *mgr)
+struct amp_mgr *amp_mgr_get(struct amp_mgr *mgr)
 {
        BT_DBG("mgr %p orig refcnt %d", mgr, atomic_read(&mgr->kref.refcount));
 
        kref_get(&mgr->kref);
+
+       return mgr;
 }
 
 static void amp_mgr_destroy(struct kref *kref)
@@ -516,6 +766,11 @@ static void amp_mgr_destroy(struct kref *kref)
 
        BT_DBG("mgr %p", mgr);
 
+       mutex_lock(&amp_mgr_list_lock);
+       list_del(&mgr->list);
+       mutex_unlock(&amp_mgr_list_lock);
+
+       amp_ctrl_list_flush(mgr);
        kfree(mgr);
 }
 
@@ -526,7 +781,7 @@ int amp_mgr_put(struct amp_mgr *mgr)
        return kref_put(&mgr->kref, &amp_mgr_destroy);
 }
 
-static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
+static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn, bool locked)
 {
        struct amp_mgr *mgr;
        struct l2cap_chan *chan;
@@ -539,7 +794,7 @@ static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
 
        mgr->l2cap_conn = conn;
 
-       chan = a2mp_chan_open(conn);
+       chan = a2mp_chan_open(conn, locked);
        if (!chan) {
                kfree(mgr);
                return NULL;
@@ -552,6 +807,14 @@ static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
 
        kref_init(&mgr->kref);
 
+       /* Remote AMP ctrl list initialization */
+       INIT_LIST_HEAD(&mgr->amp_ctrls);
+       mutex_init(&mgr->amp_ctrls_lock);
+
+       mutex_lock(&amp_mgr_list_lock);
+       list_add(&mgr->list, &amp_mgr_list);
+       mutex_unlock(&amp_mgr_list_lock);
+
        return mgr;
 }
 
@@ -560,7 +823,7 @@ struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
 {
        struct amp_mgr *mgr;
 
-       mgr = amp_mgr_create(conn);
+       mgr = amp_mgr_create(conn, false);
        if (!mgr) {
                BT_ERR("Could not create AMP manager");
                return NULL;
@@ -570,3 +833,139 @@ struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
 
        return mgr->a2mp_chan;
 }
+
+struct amp_mgr *amp_mgr_lookup_by_state(u8 state)
+{
+       struct amp_mgr *mgr;
+
+       mutex_lock(&amp_mgr_list_lock);
+       list_for_each_entry(mgr, &amp_mgr_list, list) {
+               if (mgr->state == state) {
+                       amp_mgr_get(mgr);
+                       mutex_unlock(&amp_mgr_list_lock);
+                       return mgr;
+               }
+       }
+       mutex_unlock(&amp_mgr_list_lock);
+
+       return NULL;
+}
+
+void a2mp_send_getinfo_rsp(struct hci_dev *hdev)
+{
+       struct amp_mgr *mgr;
+       struct a2mp_info_rsp rsp;
+
+       mgr = amp_mgr_lookup_by_state(READ_LOC_AMP_INFO);
+       if (!mgr)
+               return;
+
+       BT_DBG("%s mgr %p", hdev->name, mgr);
+
+       rsp.id = hdev->id;
+       rsp.status = A2MP_STATUS_INVALID_CTRL_ID;
+
+       if (hdev->amp_type != HCI_BREDR) {
+               rsp.status = 0;
+               rsp.total_bw = cpu_to_le32(hdev->amp_total_bw);
+               rsp.max_bw = cpu_to_le32(hdev->amp_max_bw);
+               rsp.min_latency = cpu_to_le32(hdev->amp_min_latency);
+               rsp.pal_cap = cpu_to_le16(hdev->amp_pal_cap);
+               rsp.assoc_size = cpu_to_le16(hdev->amp_assoc_size);
+       }
+
+       a2mp_send(mgr, A2MP_GETINFO_RSP, mgr->ident, sizeof(rsp), &rsp);
+       amp_mgr_put(mgr);
+}
+
+void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status)
+{
+       struct amp_mgr *mgr;
+       struct amp_assoc *loc_assoc = &hdev->loc_assoc;
+       struct a2mp_amp_assoc_rsp *rsp;
+       size_t len;
+
+       mgr = amp_mgr_lookup_by_state(READ_LOC_AMP_ASSOC);
+       if (!mgr)
+               return;
+
+       BT_DBG("%s mgr %p", hdev->name, mgr);
+
+       len = sizeof(struct a2mp_amp_assoc_rsp) + loc_assoc->len;
+       rsp = kzalloc(len, GFP_KERNEL);
+       if (!rsp) {
+               amp_mgr_put(mgr);
+               return;
+       }
+
+       rsp->id = hdev->id;
+
+       if (status) {
+               rsp->status = A2MP_STATUS_INVALID_CTRL_ID;
+       } else {
+               rsp->status = A2MP_STATUS_SUCCESS;
+               memcpy(rsp->amp_assoc, loc_assoc->data, loc_assoc->len);
+       }
+
+       a2mp_send(mgr, A2MP_GETAMPASSOC_RSP, mgr->ident, len, rsp);
+       amp_mgr_put(mgr);
+       kfree(rsp);
+}
+
+void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status)
+{
+       struct amp_mgr *mgr;
+       struct amp_assoc *loc_assoc = &hdev->loc_assoc;
+       struct a2mp_physlink_req *req;
+       struct l2cap_chan *bredr_chan;
+       size_t len;
+
+       mgr = amp_mgr_lookup_by_state(READ_LOC_AMP_ASSOC_FINAL);
+       if (!mgr)
+               return;
+
+       len = sizeof(*req) + loc_assoc->len;
+
+       BT_DBG("%s mgr %p assoc_len %zu", hdev->name, mgr, len);
+
+       req = kzalloc(len, GFP_KERNEL);
+       if (!req) {
+               amp_mgr_put(mgr);
+               return;
+       }
+
+       bredr_chan = mgr->bredr_chan;
+       if (!bredr_chan)
+               goto clean;
+
+       req->local_id = hdev->id;
+       req->remote_id = bredr_chan->ctrl_id;
+       memcpy(req->amp_assoc, loc_assoc->data, loc_assoc->len);
+
+       a2mp_send(mgr, A2MP_CREATEPHYSLINK_REQ, __next_ident(mgr), len, req);
+
+clean:
+       amp_mgr_put(mgr);
+       kfree(req);
+}
+
+void a2mp_discover_amp(struct l2cap_chan *chan)
+{
+       struct l2cap_conn *conn = chan->conn;
+       struct amp_mgr *mgr = conn->hcon->amp_mgr;
+       struct a2mp_discov_req req;
+
+       BT_DBG("chan %p conn %p mgr %p", chan, conn, mgr);
+
+       if (!mgr) {
+               mgr = amp_mgr_create(conn, true);
+               if (!mgr)
+                       return;
+       }
+
+       mgr->bredr_chan = chan;
+
+       req.mtu = cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU);
+       req.ext_feat = 0;
+       a2mp_send(mgr, A2MP_DISCOVER_REQ, 1, sizeof(req), &req);
+}
index ba033f09196ee45d7d6fbd170386a0d62af1d4ac..5355df63d39b673d246d131564a1e17dc116c27d 100644 (file)
@@ -569,7 +569,6 @@ static int bt_seq_show(struct seq_file *seq, void *v)
 {
        struct bt_seq_state *s = seq->private;
        struct bt_sock_list *l = s->l;
-       bdaddr_t src_baswapped, dst_baswapped;
 
        if (v == SEQ_START_TOKEN) {
                seq_puts(seq ,"sk               RefCnt Rmem   Wmem   User   Inode  Src Dst Parent");
@@ -583,18 +582,17 @@ static int bt_seq_show(struct seq_file *seq, void *v)
        } else {
                struct sock *sk = sk_entry(v);
                struct bt_sock *bt = bt_sk(sk);
-               baswap(&src_baswapped, &bt->src);
-               baswap(&dst_baswapped, &bt->dst);
 
-               seq_printf(seq, "%pK %-6d %-6u %-6u %-6u %-6lu %pM %pM %-6lu",
+               seq_printf(seq,
+                          "%pK %-6d %-6u %-6u %-6u %-6lu %pMR %pMR %-6lu",
                           sk,
                           atomic_read(&sk->sk_refcnt),
                           sk_rmem_alloc_get(sk),
                           sk_wmem_alloc_get(sk),
                           from_kuid(seq_user_ns(seq), sock_i_uid(sk)),
                           sock_i_ino(sk),
-                          &src_baswapped,
-                          &dst_baswapped,
+                          &bt->src,
+                          &bt->dst,
                           bt->parent? sock_i_ino(bt->parent): 0LU);
 
                if (l->custom_seq_show) {
diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c
new file mode 100644 (file)
index 0000000..231d7ef
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+   Copyright (c) 2011,2012 Intel Corp.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License version 2 and
+   only version 2 as published by the Free Software Foundation.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+*/
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/a2mp.h>
+#include <net/bluetooth/amp.h>
+#include <crypto/hash.h>
+
+/* Remote AMP Controllers interface */
+void amp_ctrl_get(struct amp_ctrl *ctrl)
+{
+       BT_DBG("ctrl %p orig refcnt %d", ctrl,
+              atomic_read(&ctrl->kref.refcount));
+
+       kref_get(&ctrl->kref);
+}
+
+static void amp_ctrl_destroy(struct kref *kref)
+{
+       struct amp_ctrl *ctrl = container_of(kref, struct amp_ctrl, kref);
+
+       BT_DBG("ctrl %p", ctrl);
+
+       kfree(ctrl->assoc);
+       kfree(ctrl);
+}
+
+int amp_ctrl_put(struct amp_ctrl *ctrl)
+{
+       BT_DBG("ctrl %p orig refcnt %d", ctrl,
+              atomic_read(&ctrl->kref.refcount));
+
+       return kref_put(&ctrl->kref, &amp_ctrl_destroy);
+}
+
+struct amp_ctrl *amp_ctrl_add(struct amp_mgr *mgr, u8 id)
+{
+       struct amp_ctrl *ctrl;
+
+       ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
+       if (!ctrl)
+               return NULL;
+
+       kref_init(&ctrl->kref);
+       ctrl->id = id;
+
+       mutex_lock(&mgr->amp_ctrls_lock);
+       list_add(&ctrl->list, &mgr->amp_ctrls);
+       mutex_unlock(&mgr->amp_ctrls_lock);
+
+       BT_DBG("mgr %p ctrl %p", mgr, ctrl);
+
+       return ctrl;
+}
+
+void amp_ctrl_list_flush(struct amp_mgr *mgr)
+{
+       struct amp_ctrl *ctrl, *n;
+
+       BT_DBG("mgr %p", mgr);
+
+       mutex_lock(&mgr->amp_ctrls_lock);
+       list_for_each_entry_safe(ctrl, n, &mgr->amp_ctrls, list) {
+               list_del(&ctrl->list);
+               amp_ctrl_put(ctrl);
+       }
+       mutex_unlock(&mgr->amp_ctrls_lock);
+}
+
+struct amp_ctrl *amp_ctrl_lookup(struct amp_mgr *mgr, u8 id)
+{
+       struct amp_ctrl *ctrl;
+
+       BT_DBG("mgr %p id %d", mgr, id);
+
+       mutex_lock(&mgr->amp_ctrls_lock);
+       list_for_each_entry(ctrl, &mgr->amp_ctrls, list) {
+               if (ctrl->id == id) {
+                       amp_ctrl_get(ctrl);
+                       mutex_unlock(&mgr->amp_ctrls_lock);
+                       return ctrl;
+               }
+       }
+       mutex_unlock(&mgr->amp_ctrls_lock);
+
+       return NULL;
+}
+
+/* Physical Link interface */
+static u8 __next_handle(struct amp_mgr *mgr)
+{
+       if (++mgr->handle == 0)
+               mgr->handle = 1;
+
+       return mgr->handle;
+}
+
+struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr,
+                            u8 remote_id, bool out)
+{
+       bdaddr_t *dst = mgr->l2cap_conn->dst;
+       struct hci_conn *hcon;
+
+       hcon = hci_conn_add(hdev, AMP_LINK, dst);
+       if (!hcon)
+               return NULL;
+
+       BT_DBG("hcon %p dst %pMR", hcon, dst);
+
+       hcon->state = BT_CONNECT;
+       hcon->attempt++;
+       hcon->handle = __next_handle(mgr);
+       hcon->remote_id = remote_id;
+       hcon->amp_mgr = amp_mgr_get(mgr);
+       hcon->out = out;
+
+       return hcon;
+}
+
+/* AMP crypto key generation interface */
+static int hmac_sha256(u8 *key, u8 ksize, char *plaintext, u8 psize, u8 *output)
+{
+       int ret = 0;
+       struct crypto_shash *tfm;
+
+       if (!ksize)
+               return -EINVAL;
+
+       tfm = crypto_alloc_shash("hmac(sha256)", 0, 0);
+       if (IS_ERR(tfm)) {
+               BT_DBG("crypto_alloc_ahash failed: err %ld", PTR_ERR(tfm));
+               return PTR_ERR(tfm);
+       }
+
+       ret = crypto_shash_setkey(tfm, key, ksize);
+       if (ret) {
+               BT_DBG("crypto_ahash_setkey failed: err %d", ret);
+       } else {
+               struct {
+                       struct shash_desc shash;
+                       char ctx[crypto_shash_descsize(tfm)];
+               } desc;
+
+               desc.shash.tfm = tfm;
+               desc.shash.flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+               ret = crypto_shash_digest(&desc.shash, plaintext, psize,
+                                         output);
+       }
+
+       crypto_free_shash(tfm);
+       return ret;
+}
+
+int phylink_gen_key(struct hci_conn *conn, u8 *data, u8 *len, u8 *type)
+{
+       struct hci_dev *hdev = conn->hdev;
+       struct link_key *key;
+       u8 keybuf[HCI_AMP_LINK_KEY_SIZE];
+       u8 gamp_key[HCI_AMP_LINK_KEY_SIZE];
+       int err;
+
+       if (!hci_conn_check_link_mode(conn))
+               return -EACCES;
+
+       BT_DBG("conn %p key_type %d", conn, conn->key_type);
+
+       /* Legacy key */
+       if (conn->key_type < 3) {
+               BT_ERR("Legacy key type %d", conn->key_type);
+               return -EACCES;
+       }
+
+       *type = conn->key_type;
+       *len = HCI_AMP_LINK_KEY_SIZE;
+
+       key = hci_find_link_key(hdev, &conn->dst);
+       if (!key) {
+               BT_DBG("No Link key for conn %p dst %pMR", conn, &conn->dst);
+               return -EACCES;
+       }
+
+       /* BR/EDR Link Key concatenated together with itself */
+       memcpy(&keybuf[0], key->val, HCI_LINK_KEY_SIZE);
+       memcpy(&keybuf[HCI_LINK_KEY_SIZE], key->val, HCI_LINK_KEY_SIZE);
+
+       /* Derive Generic AMP Link Key (gamp) */
+       err = hmac_sha256(keybuf, HCI_AMP_LINK_KEY_SIZE, "gamp", 4, gamp_key);
+       if (err) {
+               BT_ERR("Could not derive Generic AMP Key: err %d", err);
+               return err;
+       }
+
+       if (conn->key_type == HCI_LK_DEBUG_COMBINATION) {
+               BT_DBG("Use Generic AMP Key (gamp)");
+               memcpy(data, gamp_key, HCI_AMP_LINK_KEY_SIZE);
+               return err;
+       }
+
+       /* Derive Dedicated AMP Link Key: "802b" is 802.11 PAL keyID */
+       return hmac_sha256(gamp_key, HCI_AMP_LINK_KEY_SIZE, "802b", 4, data);
+}
+
+void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle)
+{
+       struct hci_cp_read_local_amp_assoc cp;
+       struct amp_assoc *loc_assoc = &hdev->loc_assoc;
+
+       BT_DBG("%s handle %d", hdev->name, phy_handle);
+
+       cp.phy_handle = phy_handle;
+       cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
+       cp.len_so_far = cpu_to_le16(loc_assoc->offset);
+
+       hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
+}
+
+void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr)
+{
+       struct hci_cp_read_local_amp_assoc cp;
+
+       memset(&hdev->loc_assoc, 0, sizeof(struct amp_assoc));
+       memset(&cp, 0, sizeof(cp));
+
+       cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
+
+       mgr->state = READ_LOC_AMP_ASSOC;
+       hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
+}
+
+void amp_read_loc_assoc_final_data(struct hci_dev *hdev,
+                                  struct hci_conn *hcon)
+{
+       struct hci_cp_read_local_amp_assoc cp;
+       struct amp_mgr *mgr = hcon->amp_mgr;
+
+       cp.phy_handle = hcon->handle;
+       cp.len_so_far = cpu_to_le16(0);
+       cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
+
+       mgr->state = READ_LOC_AMP_ASSOC_FINAL;
+
+       /* Read Local AMP Assoc final link information data */
+       hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
+}
+
+/* Write AMP Assoc data fragments, returns true with last fragment written*/
+static bool amp_write_rem_assoc_frag(struct hci_dev *hdev,
+                                    struct hci_conn *hcon)
+{
+       struct hci_cp_write_remote_amp_assoc *cp;
+       struct amp_mgr *mgr = hcon->amp_mgr;
+       struct amp_ctrl *ctrl;
+       u16 frag_len, len;
+
+       ctrl = amp_ctrl_lookup(mgr, hcon->remote_id);
+       if (!ctrl)
+               return false;
+
+       if (!ctrl->assoc_rem_len) {
+               BT_DBG("all fragments are written");
+               ctrl->assoc_rem_len = ctrl->assoc_len;
+               ctrl->assoc_len_so_far = 0;
+
+               amp_ctrl_put(ctrl);
+               return true;
+       }
+
+       frag_len = min_t(u16, 248, ctrl->assoc_rem_len);
+       len = frag_len + sizeof(*cp);
+
+       cp = kzalloc(len, GFP_KERNEL);
+       if (!cp) {
+               amp_ctrl_put(ctrl);
+               return false;
+       }
+
+       BT_DBG("hcon %p ctrl %p frag_len %u assoc_len %u rem_len %u",
+              hcon, ctrl, frag_len, ctrl->assoc_len, ctrl->assoc_rem_len);
+
+       cp->phy_handle = hcon->handle;
+       cp->len_so_far = cpu_to_le16(ctrl->assoc_len_so_far);
+       cp->rem_len = cpu_to_le16(ctrl->assoc_rem_len);
+       memcpy(cp->frag, ctrl->assoc, frag_len);
+
+       ctrl->assoc_len_so_far += frag_len;
+       ctrl->assoc_rem_len -= frag_len;
+
+       amp_ctrl_put(ctrl);
+
+       hci_send_cmd(hdev, HCI_OP_WRITE_REMOTE_AMP_ASSOC, len, cp);
+
+       kfree(cp);
+
+       return false;
+}
+
+void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle)
+{
+       struct hci_conn *hcon;
+
+       BT_DBG("%s phy handle 0x%2.2x", hdev->name, handle);
+
+       hcon = hci_conn_hash_lookup_handle(hdev, handle);
+       if (!hcon)
+               return;
+
+       amp_write_rem_assoc_frag(hdev, hcon);
+}
+
+void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle)
+{
+       struct hci_conn *hcon;
+
+       BT_DBG("%s phy handle 0x%2.2x", hdev->name, handle);
+
+       hcon = hci_conn_hash_lookup_handle(hdev, handle);
+       if (!hcon)
+               return;
+
+       BT_DBG("%s phy handle 0x%2.2x hcon %p", hdev->name, handle, hcon);
+
+       amp_write_rem_assoc_frag(hdev, hcon);
+}
+
+void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
+                       struct hci_conn *hcon)
+{
+       struct hci_cp_create_phy_link cp;
+
+       cp.phy_handle = hcon->handle;
+
+       BT_DBG("%s hcon %p phy handle 0x%2.2x", hdev->name, hcon,
+              hcon->handle);
+
+       if (phylink_gen_key(mgr->l2cap_conn->hcon, cp.key, &cp.key_len,
+                           &cp.key_type)) {
+               BT_DBG("Cannot create link key");
+               return;
+       }
+
+       hci_send_cmd(hdev, HCI_OP_CREATE_PHY_LINK, sizeof(cp), &cp);
+}
+
+void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
+                       struct hci_conn *hcon)
+{
+       struct hci_cp_accept_phy_link cp;
+
+       cp.phy_handle = hcon->handle;
+
+       BT_DBG("%s hcon %p phy handle 0x%2.2x", hdev->name, hcon,
+              hcon->handle);
+
+       if (phylink_gen_key(mgr->l2cap_conn->hcon, cp.key, &cp.key_len,
+                           &cp.key_type)) {
+               BT_DBG("Cannot create link key");
+               return;
+       }
+
+       hci_send_cmd(hdev, HCI_OP_ACCEPT_PHY_LINK, sizeof(cp), &cp);
+}
index 4a6620bc1570901c34a1c406ffb83909c27d3348..a5b639702637404d5c1955b36163a3c459fe174c 100644 (file)
@@ -182,8 +182,7 @@ static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
                        a2 = data;
                        data += ETH_ALEN;
 
-                       BT_DBG("mc filter %s -> %s",
-                               batostr((void *) a1), batostr((void *) a2));
+                       BT_DBG("mc filter %pMR -> %pMR", a1, a2);
 
                        /* Iterate from a1 to a2 */
                        set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
index 6c9c1fd601cac41e879c3e041f103ee645ebd458..e0a6ebf2baa6fecd58a0cc13ea6f2906c6614a46 100644 (file)
@@ -353,7 +353,7 @@ int cmtp_add_connection(struct cmtp_connadd_req *req, struct socket *sock)
 
        BT_DBG("mtu %d", session->mtu);
 
-       sprintf(session->name, "%s", batostr(&bt_sk(sock->sk)->dst));
+       sprintf(session->name, "%pMR", &bt_sk(sock->sk)->dst);
 
        session->sock  = sock;
        session->state = BT_CONFIG;
index b9196a44f7598bf33b0c2bff6d0764eeeba8fc11..fe646211c61f5f0a056884e34bdff6c0336f9043 100644 (file)
@@ -130,6 +130,20 @@ void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
        hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp);
 }
 
+static void hci_amp_disconn(struct hci_conn *conn, __u8 reason)
+{
+       struct hci_cp_disconn_phy_link cp;
+
+       BT_DBG("hcon %p", conn);
+
+       conn->state = BT_DISCONN;
+
+       cp.phy_handle = HCI_PHY_HANDLE(conn->handle);
+       cp.reason = reason;
+       hci_send_cmd(conn->hdev, HCI_OP_DISCONN_PHY_LINK,
+                    sizeof(cp), &cp);
+}
+
 static void hci_add_sco(struct hci_conn *conn, __u16 handle)
 {
        struct hci_dev *hdev = conn->hdev;
@@ -230,11 +244,24 @@ void hci_sco_setup(struct hci_conn *conn, __u8 status)
        }
 }
 
+static void hci_conn_disconnect(struct hci_conn *conn)
+{
+       __u8 reason = hci_proto_disconn_ind(conn);
+
+       switch (conn->type) {
+       case ACL_LINK:
+               hci_acl_disconn(conn, reason);
+               break;
+       case AMP_LINK:
+               hci_amp_disconn(conn, reason);
+               break;
+       }
+}
+
 static void hci_conn_timeout(struct work_struct *work)
 {
        struct hci_conn *conn = container_of(work, struct hci_conn,
                                             disc_work.work);
-       __u8 reason;
 
        BT_DBG("hcon %p state %s", conn, state_to_string(conn->state));
 
@@ -253,8 +280,7 @@ static void hci_conn_timeout(struct work_struct *work)
                break;
        case BT_CONFIG:
        case BT_CONNECTED:
-               reason = hci_proto_disconn_ind(conn);
-               hci_acl_disconn(conn, reason);
+               hci_conn_disconnect(conn);
                break;
        default:
                conn->state = BT_CLOSED;
@@ -320,7 +346,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
 {
        struct hci_conn *conn;
 
-       BT_DBG("%s dst %s", hdev->name, batostr(dst));
+       BT_DBG("%s dst %pMR", hdev->name, dst);
 
        conn = kzalloc(sizeof(struct hci_conn), GFP_KERNEL);
        if (!conn)
@@ -437,7 +463,7 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
        int use_src = bacmp(src, BDADDR_ANY);
        struct hci_dev *hdev = NULL, *d;
 
-       BT_DBG("%s -> %s", batostr(src), batostr(dst));
+       BT_DBG("%pMR -> %pMR", src, dst);
 
        read_lock(&hci_dev_list_lock);
 
@@ -567,7 +593,7 @@ static struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type,
 struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst,
                             __u8 dst_type, __u8 sec_level, __u8 auth_type)
 {
-       BT_DBG("%s dst %s type 0x%x", hdev->name, batostr(dst), type);
+       BT_DBG("%s dst %pMR type 0x%x", hdev->name, dst, type);
 
        switch (type) {
        case LE_LINK:
@@ -963,3 +989,35 @@ void hci_chan_list_flush(struct hci_conn *conn)
        list_for_each_entry_safe(chan, n, &conn->chan_list, list)
                hci_chan_del(chan);
 }
+
+static struct hci_chan *__hci_chan_lookup_handle(struct hci_conn *hcon,
+                                                __u16 handle)
+{
+       struct hci_chan *hchan;
+
+       list_for_each_entry(hchan, &hcon->chan_list, list) {
+               if (hchan->handle == handle)
+                       return hchan;
+       }
+
+       return NULL;
+}
+
+struct hci_chan *hci_chan_lookup_handle(struct hci_dev *hdev, __u16 handle)
+{
+       struct hci_conn_hash *h = &hdev->conn_hash;
+       struct hci_conn *hcon;
+       struct hci_chan *hchan = NULL;
+
+       rcu_read_lock();
+
+       list_for_each_entry_rcu(hcon, &h->list, list) {
+               hchan = __hci_chan_lookup_handle(hcon, handle);
+               if (hchan)
+                       break;
+       }
+
+       rcu_read_unlock();
+
+       return hchan;
+}
index 8a0ce706aebd624ae7fd1c50b9670780dc4f6761..5a3f941b610f8d4a3653b8df5997f04a96fc5432 100644 (file)
@@ -405,7 +405,7 @@ struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev,
        struct discovery_state *cache = &hdev->discovery;
        struct inquiry_entry *e;
 
-       BT_DBG("cache %p, %s", cache, batostr(bdaddr));
+       BT_DBG("cache %p, %pMR", cache, bdaddr);
 
        list_for_each_entry(e, &cache->all, all) {
                if (!bacmp(&e->data.bdaddr, bdaddr))
@@ -421,7 +421,7 @@ struct inquiry_entry *hci_inquiry_cache_lookup_unknown(struct hci_dev *hdev,
        struct discovery_state *cache = &hdev->discovery;
        struct inquiry_entry *e;
 
-       BT_DBG("cache %p, %s", cache, batostr(bdaddr));
+       BT_DBG("cache %p, %pMR", cache, bdaddr);
 
        list_for_each_entry(e, &cache->unknown, list) {
                if (!bacmp(&e->data.bdaddr, bdaddr))
@@ -438,7 +438,7 @@ struct inquiry_entry *hci_inquiry_cache_lookup_resolve(struct hci_dev *hdev,
        struct discovery_state *cache = &hdev->discovery;
        struct inquiry_entry *e;
 
-       BT_DBG("cache %p bdaddr %s state %d", cache, batostr(bdaddr), state);
+       BT_DBG("cache %p bdaddr %pMR state %d", cache, bdaddr, state);
 
        list_for_each_entry(e, &cache->resolve, list) {
                if (!bacmp(bdaddr, BDADDR_ANY) && e->name_state == state)
@@ -475,7 +475,7 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
        struct discovery_state *cache = &hdev->discovery;
        struct inquiry_entry *ie;
 
-       BT_DBG("cache %p, %s", cache, batostr(&data->bdaddr));
+       BT_DBG("cache %p, %pMR", cache, &data->bdaddr);
 
        if (ssp)
                *ssp = data->ssp_mode;
@@ -1259,7 +1259,7 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key,
                list_add(&key->list, &hdev->link_keys);
        }
 
-       BT_DBG("%s key for %s type %u", hdev->name, batostr(bdaddr), type);
+       BT_DBG("%s key for %pMR type %u", hdev->name, bdaddr, type);
 
        /* Some buggy controller combinations generate a changed
         * combination key for legacy pairing even when there's no
@@ -1338,7 +1338,7 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
        if (!key)
                return -ENOENT;
 
-       BT_DBG("%s removing %s", hdev->name, batostr(bdaddr));
+       BT_DBG("%s removing %pMR", hdev->name, bdaddr);
 
        list_del(&key->list);
        kfree(key);
@@ -1354,7 +1354,7 @@ int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr)
                if (bacmp(bdaddr, &k->bdaddr))
                        continue;
 
-               BT_DBG("%s removing %s", hdev->name, batostr(bdaddr));
+               BT_DBG("%s removing %pMR", hdev->name, bdaddr);
 
                list_del(&k->list);
                kfree(k);
@@ -1401,7 +1401,7 @@ int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr)
        if (!data)
                return -ENOENT;
 
-       BT_DBG("%s removing %s", hdev->name, batostr(bdaddr));
+       BT_DBG("%s removing %pMR", hdev->name, bdaddr);
 
        list_del(&data->list);
        kfree(data);
@@ -1440,7 +1440,7 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
        memcpy(data->hash, hash, sizeof(data->hash));
        memcpy(data->randomizer, randomizer, sizeof(data->randomizer));
 
-       BT_DBG("%s for %s", hdev->name, batostr(bdaddr));
+       BT_DBG("%s for %pMR", hdev->name, bdaddr);
 
        return 0;
 }
@@ -2153,9 +2153,10 @@ static void hci_add_acl_hdr(struct sk_buff *skb, __u16 handle, __u16 flags)
        hdr->dlen   = cpu_to_le16(len);
 }
 
-static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
+static void hci_queue_acl(struct hci_chan *chan, struct sk_buff_head *queue,
                          struct sk_buff *skb, __u16 flags)
 {
+       struct hci_conn *conn = chan->conn;
        struct hci_dev *hdev = conn->hdev;
        struct sk_buff *list;
 
@@ -2163,7 +2164,18 @@ static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
        skb->data_len = 0;
 
        bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
-       hci_add_acl_hdr(skb, conn->handle, flags);
+
+       switch (hdev->dev_type) {
+       case HCI_BREDR:
+               hci_add_acl_hdr(skb, conn->handle, flags);
+               break;
+       case HCI_AMP:
+               hci_add_acl_hdr(skb, chan->handle, flags);
+               break;
+       default:
+               BT_ERR("%s unknown dev_type %d", hdev->name, hdev->dev_type);
+               return;
+       }
 
        list = skb_shinfo(skb)->frag_list;
        if (!list) {
@@ -2202,14 +2214,13 @@ static void hci_queue_acl(struct hci_conn *conn, struct sk_buff_head *queue,
 
 void hci_send_acl(struct hci_chan *chan, struct sk_buff *skb, __u16 flags)
 {
-       struct hci_conn *conn = chan->conn;
-       struct hci_dev *hdev = conn->hdev;
+       struct hci_dev *hdev = chan->conn->hdev;
 
        BT_DBG("%s chan %p flags 0x%4.4x", hdev->name, chan, flags);
 
        skb->dev = (void *) hdev;
 
-       hci_queue_acl(conn, &chan->data_q, skb, flags);
+       hci_queue_acl(chan, &chan->data_q, skb, flags);
 
        queue_work(hdev->workqueue, &hdev->tx_work);
 }
@@ -2311,8 +2322,8 @@ static void hci_link_tx_to(struct hci_dev *hdev, __u8 type)
        /* Kill stalled connections */
        list_for_each_entry_rcu(c, &h->list, list) {
                if (c->type == type && c->sent) {
-                       BT_ERR("%s killing stalled connection %s",
-                              hdev->name, batostr(&c->dst));
+                       BT_ERR("%s killing stalled connection %pMR",
+                              hdev->name, &c->dst);
                        hci_acl_disconn(c, HCI_ERROR_REMOTE_USER_TERM);
                }
        }
@@ -2381,6 +2392,9 @@ static struct hci_chan *hci_chan_sent(struct hci_dev *hdev, __u8 type,
        case ACL_LINK:
                cnt = hdev->acl_cnt;
                break;
+       case AMP_LINK:
+               cnt = hdev->block_cnt;
+               break;
        case SCO_LINK:
        case ESCO_LINK:
                cnt = hdev->sco_cnt;
@@ -2510,11 +2524,19 @@ static void hci_sched_acl_blk(struct hci_dev *hdev)
        struct hci_chan *chan;
        struct sk_buff *skb;
        int quote;
+       u8 type;
 
        __check_timeout(hdev, cnt);
 
+       BT_DBG("%s", hdev->name);
+
+       if (hdev->dev_type == HCI_AMP)
+               type = AMP_LINK;
+       else
+               type = ACL_LINK;
+
        while (hdev->block_cnt > 0 &&
-              (chan = hci_chan_sent(hdev, ACL_LINK, &quote))) {
+              (chan = hci_chan_sent(hdev, type, &quote))) {
                u32 priority = (skb_peek(&chan->data_q))->priority;
                while (quote > 0 && (skb = skb_peek(&chan->data_q))) {
                        int blocks;
@@ -2547,14 +2569,19 @@ static void hci_sched_acl_blk(struct hci_dev *hdev)
        }
 
        if (cnt != hdev->block_cnt)
-               hci_prio_recalculate(hdev, ACL_LINK);
+               hci_prio_recalculate(hdev, type);
 }
 
 static void hci_sched_acl(struct hci_dev *hdev)
 {
        BT_DBG("%s", hdev->name);
 
-       if (!hci_conn_num(hdev, ACL_LINK))
+       /* No ACL link over BR/EDR controller */
+       if (!hci_conn_num(hdev, ACL_LINK) && hdev->dev_type == HCI_BREDR)
+               return;
+
+       /* No AMP link over AMP controller */
+       if (!hci_conn_num(hdev, AMP_LINK) && hdev->dev_type == HCI_AMP)
                return;
 
        switch (hdev->flow_ctl_mode) {
index 2022b43c7353ee98d7546d6c9e0ef67c43811d3f..0383635f91fbc18991abe090c6a637d5d12d96e7 100644 (file)
@@ -30,6 +30,8 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/mgmt.h>
+#include <net/bluetooth/a2mp.h>
+#include <net/bluetooth/amp.h>
 
 /* Handle HCI Event packets */
 
@@ -846,7 +848,7 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
        BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
        if (rp->status)
-               return;
+               goto a2mp_rsp;
 
        hdev->amp_status = rp->amp_status;
        hdev->amp_total_bw = __le32_to_cpu(rp->total_bw);
@@ -860,6 +862,46 @@ static void hci_cc_read_local_amp_info(struct hci_dev *hdev,
        hdev->amp_max_flush_to = __le32_to_cpu(rp->max_flush_to);
 
        hci_req_complete(hdev, HCI_OP_READ_LOCAL_AMP_INFO, rp->status);
+
+a2mp_rsp:
+       a2mp_send_getinfo_rsp(hdev);
+}
+
+static void hci_cc_read_local_amp_assoc(struct hci_dev *hdev,
+                                       struct sk_buff *skb)
+{
+       struct hci_rp_read_local_amp_assoc *rp = (void *) skb->data;
+       struct amp_assoc *assoc = &hdev->loc_assoc;
+       size_t rem_len, frag_len;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+       if (rp->status)
+               goto a2mp_rsp;
+
+       frag_len = skb->len - sizeof(*rp);
+       rem_len = __le16_to_cpu(rp->rem_len);
+
+       if (rem_len > frag_len) {
+               BT_DBG("frag_len %zu rem_len %zu", frag_len, rem_len);
+
+               memcpy(assoc->data + assoc->offset, rp->frag, frag_len);
+               assoc->offset += frag_len;
+
+               /* Read other fragments */
+               amp_read_loc_assoc_frag(hdev, rp->phy_handle);
+
+               return;
+       }
+
+       memcpy(assoc->data + assoc->offset, rp->frag, rem_len);
+       assoc->len = assoc->offset + rem_len;
+       assoc->offset = 0;
+
+a2mp_rsp:
+       /* Send A2MP Rsp when all fragments are received */
+       a2mp_send_getampassoc_rsp(hdev, rp->status);
+       a2mp_send_create_phy_link_req(hdev, rp->status);
 }
 
 static void hci_cc_delete_stored_link_key(struct hci_dev *hdev,
@@ -1174,6 +1216,20 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
        hci_req_complete(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, status);
 }
 
+static void hci_cc_write_remote_amp_assoc(struct hci_dev *hdev,
+                                         struct sk_buff *skb)
+{
+       struct hci_rp_write_remote_amp_assoc *rp = (void *) skb->data;
+
+       BT_DBG("%s status 0x%2.2x phy_handle 0x%2.2x",
+              hdev->name, rp->status, rp->phy_handle);
+
+       if (rp->status)
+               return;
+
+       amp_write_rem_assoc_continue(hdev, rp->phy_handle);
+}
+
 static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
 {
        BT_DBG("%s status 0x%2.2x", hdev->name, status);
@@ -1210,7 +1266,7 @@ static void hci_cs_create_conn(struct hci_dev *hdev, __u8 status)
 
        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
 
-       BT_DBG("%s bdaddr %s hcon %p", hdev->name, batostr(&cp->bdaddr), conn);
+       BT_DBG("%s bdaddr %pMR hcon %p", hdev->name, &cp->bdaddr, conn);
 
        if (status) {
                if (conn && conn->state == BT_CONNECT) {
@@ -1639,8 +1695,7 @@ static void hci_cs_le_create_conn(struct hci_dev *hdev, __u8 status)
                        return;
                }
 
-               BT_DBG("%s bdaddr %s conn %p", hdev->name, batostr(&conn->dst),
-                      conn);
+               BT_DBG("%s bdaddr %pMR conn %p", hdev->name, &conn->dst, conn);
 
                conn->state = BT_CLOSED;
                mgmt_connect_failed(hdev, &conn->dst, conn->type,
@@ -1657,6 +1712,38 @@ static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status)
        BT_DBG("%s status 0x%2.2x", hdev->name, status);
 }
 
+static void hci_cs_create_phylink(struct hci_dev *hdev, u8 status)
+{
+       struct hci_cp_create_phy_link *cp;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       if (status)
+               return;
+
+       cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_PHY_LINK);
+       if (!cp)
+               return;
+
+       amp_write_remote_assoc(hdev, cp->phy_handle);
+}
+
+static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status)
+{
+       struct hci_cp_accept_phy_link *cp;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       if (status)
+               return;
+
+       cp = hci_sent_cmd_data(hdev, HCI_OP_ACCEPT_PHY_LINK);
+       if (!cp)
+               return;
+
+       amp_write_remote_assoc(hdev, cp->phy_handle);
+}
+
 static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        __u8 status = *((__u8 *) skb->data);
@@ -1822,7 +1909,7 @@ static void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
        struct hci_ev_conn_request *ev = (void *) skb->data;
        int mask = hdev->link_mode;
 
-       BT_DBG("%s bdaddr %s type 0x%x", hdev->name, batostr(&ev->bdaddr),
+       BT_DBG("%s bdaddr %pMR type 0x%x", hdev->name, &ev->bdaddr,
               ev->link_type);
 
        mask |= hci_proto_connect_ind(hdev, &ev->bdaddr, ev->link_type);
@@ -2314,6 +2401,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                hci_cc_read_local_amp_info(hdev, skb);
                break;
 
+       case HCI_OP_READ_LOCAL_AMP_ASSOC:
+               hci_cc_read_local_amp_assoc(hdev, skb);
+               break;
+
        case HCI_OP_DELETE_STORED_LINK_KEY:
                hci_cc_delete_stored_link_key(hdev, skb);
                break;
@@ -2386,6 +2477,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                hci_cc_write_le_host_supported(hdev, skb);
                break;
 
+       case HCI_OP_WRITE_REMOTE_AMP_ASSOC:
+               hci_cc_write_remote_amp_assoc(hdev, skb);
+               break;
+
        default:
                BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);
                break;
@@ -2467,6 +2562,14 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
                hci_cs_le_start_enc(hdev, ev->status);
                break;
 
+       case HCI_OP_CREATE_PHY_LINK:
+               hci_cs_create_phylink(hdev, ev->status);
+               break;
+
+       case HCI_OP_ACCEPT_PHY_LINK:
+               hci_cs_accept_phylink(hdev, ev->status);
+               break;
+
        default:
                BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);
                break;
@@ -2574,6 +2677,27 @@ static void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
        queue_work(hdev->workqueue, &hdev->tx_work);
 }
 
+static struct hci_conn *__hci_conn_lookup_handle(struct hci_dev *hdev,
+                                                __u16 handle)
+{
+       struct hci_chan *chan;
+
+       switch (hdev->dev_type) {
+       case HCI_BREDR:
+               return hci_conn_hash_lookup_handle(hdev, handle);
+       case HCI_AMP:
+               chan = hci_chan_lookup_handle(hdev, handle);
+               if (chan)
+                       return chan->conn;
+               break;
+       default:
+               BT_ERR("%s unknown dev_type %d", hdev->name, hdev->dev_type);
+               break;
+       }
+
+       return NULL;
+}
+
 static void hci_num_comp_blocks_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_num_comp_blocks *ev = (void *) skb->data;
@@ -2595,13 +2719,13 @@ static void hci_num_comp_blocks_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
        for (i = 0; i < ev->num_hndl; i++) {
                struct hci_comp_blocks_info *info = &ev->handles[i];
-               struct hci_conn *conn;
+               struct hci_conn *conn = NULL;
                __u16  handle, block_count;
 
                handle = __le16_to_cpu(info->handle);
                block_count = __le16_to_cpu(info->blocks);
 
-               conn = hci_conn_hash_lookup_handle(hdev, handle);
+               conn = __hci_conn_lookup_handle(hdev, handle);
                if (!conn)
                        continue;
 
@@ -2609,6 +2733,7 @@ static void hci_num_comp_blocks_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
                switch (conn->type) {
                case ACL_LINK:
+               case AMP_LINK:
                        hdev->block_cnt += block_count;
                        if (hdev->block_cnt > hdev->num_blocks)
                                hdev->block_cnt = hdev->num_blocks;
@@ -2705,13 +2830,13 @@ static void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
 
        key = hci_find_link_key(hdev, &ev->bdaddr);
        if (!key) {
-               BT_DBG("%s link key not found for %s", hdev->name,
-                      batostr(&ev->bdaddr));
+               BT_DBG("%s link key not found for %pMR", hdev->name,
+                      &ev->bdaddr);
                goto not_found;
        }
 
-       BT_DBG("%s found key type %u for %s", hdev->name, key->type,
-              batostr(&ev->bdaddr));
+       BT_DBG("%s found key type %u for %pMR", hdev->name, key->type,
+              &ev->bdaddr);
 
        if (!test_bit(HCI_DEBUG_KEYS, &hdev->dev_flags) &&
            key->type == HCI_LK_DEBUG_COMBINATION) {
@@ -3558,6 +3683,22 @@ static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb)
        }
 }
 
+static void hci_chan_selected_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_ev_channel_selected *ev = (void *) skb->data;
+       struct hci_conn *hcon;
+
+       BT_DBG("%s handle 0x%2.2x", hdev->name, ev->phy_handle);
+
+       skb_pull(skb, sizeof(*ev));
+
+       hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle);
+       if (!hcon)
+               return;
+
+       amp_read_loc_assoc_final_data(hdev, hcon);
+}
+
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_event_hdr *hdr = (void *) skb->data;
@@ -3722,6 +3863,10 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
                hci_le_meta_evt(hdev, skb);
                break;
 
+       case HCI_EV_CHANNEL_SELECTED:
+               hci_chan_selected_evt(hdev, skb);
+               break;
+
        case HCI_EV_REMOTE_OOB_DATA_REQUEST:
                hci_remote_oob_data_request_evt(hdev, skb);
                break;
index a20e61c3653dbf84f3c567977757f61239fd2a82..55cceee02a840598d8b8f49d9f6b0ad989719ba8 100644 (file)
@@ -38,7 +38,7 @@ static ssize_t show_link_address(struct device *dev,
                                 struct device_attribute *attr, char *buf)
 {
        struct hci_conn *conn = to_hci_conn(dev);
-       return sprintf(buf, "%s\n", batostr(&conn->dst));
+       return sprintf(buf, "%pMR\n", &conn->dst);
 }
 
 static ssize_t show_link_features(struct device *dev,
@@ -224,7 +224,7 @@ static ssize_t show_address(struct device *dev,
                            struct device_attribute *attr, char *buf)
 {
        struct hci_dev *hdev = to_hci_dev(dev);
-       return sprintf(buf, "%s\n", batostr(&hdev->bdaddr));
+       return sprintf(buf, "%pMR\n", &hdev->bdaddr);
 }
 
 static ssize_t show_features(struct device *dev,
@@ -406,8 +406,8 @@ static int inquiry_cache_show(struct seq_file *f, void *p)
 
        list_for_each_entry(e, &cache->all, all) {
                struct inquiry_data *data = &e->data;
-               seq_printf(f, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n",
-                          batostr(&data->bdaddr),
+               seq_printf(f, "%pMR %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n",
+                          &data->bdaddr,
                           data->pscan_rep_mode, data->pscan_period_mode,
                           data->pscan_mode, data->dev_class[2],
                           data->dev_class[1], data->dev_class[0],
@@ -440,7 +440,7 @@ static int blacklist_show(struct seq_file *f, void *p)
        hci_dev_lock(hdev);
 
        list_for_each_entry(b, &hdev->blacklist, list)
-               seq_printf(f, "%s\n", batostr(&b->bdaddr));
+               seq_printf(f, "%pMR\n", &b->bdaddr);
 
        hci_dev_unlock(hdev);
 
index ccd985da65180656d7df83a986655c4b82258220..0c0028463fa3479f5448053772b14fe11360fa49 100644 (file)
@@ -932,8 +932,12 @@ static int hidp_setup_hid(struct hidp_session *session,
        hid->country = req->country;
 
        strncpy(hid->name, req->name, 128);
-       strncpy(hid->phys, batostr(&bt_sk(session->ctrl_sock->sk)->src), 64);
-       strncpy(hid->uniq, batostr(&bt_sk(session->ctrl_sock->sk)->dst), 64);
+
+       snprintf(hid->phys, sizeof(hid->phys), "%pMR",
+                &bt_sk(session->ctrl_sock->sk)->src);
+
+       snprintf(hid->uniq, sizeof(hid->uniq), "%pMR",
+                &bt_sk(session->ctrl_sock->sk)->dst);
 
        hid->dev.parent = &session->conn->dev;
        hid->ll_driver = &hidp_hid_driver;
index a91239dcda417f5a862346c981bb941aba44d086..08efc256c9313382bbc666335ea645670eab087e 100644 (file)
@@ -48,19 +48,20 @@ static LIST_HEAD(chan_list);
 static DEFINE_RWLOCK(chan_list_lock);
 
 static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
-                               u8 code, u8 ident, u16 dlen, void *data);
+                                      u8 code, u8 ident, u16 dlen, void *data);
 static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
-                                                               void *data);
+                          void *data);
 static int l2cap_build_conf_req(struct l2cap_chan *chan, void *data);
 static void l2cap_send_disconn_req(struct l2cap_conn *conn,
                                   struct l2cap_chan *chan, int err);
 
 static void l2cap_tx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
-                   struct sk_buff_head *skbs, u8 event);
+                    struct sk_buff_head *skbs, u8 event);
 
 /* ---- L2CAP channels ---- */
 
-static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
+static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn,
+                                                  u16 cid)
 {
        struct l2cap_chan *c;
 
@@ -71,7 +72,8 @@ static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16
        return NULL;
 }
 
-static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
+static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn,
+                                                  u16 cid)
 {
        struct l2cap_chan *c;
 
@@ -84,7 +86,8 @@ static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16
 
 /* Find channel with given SCID.
  * Returns locked channel. */
-static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
+static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn,
+                                                u16 cid)
 {
        struct l2cap_chan *c;
 
@@ -97,7 +100,8 @@ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 ci
        return c;
 }
 
-static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
+static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn,
+                                                   u8 ident)
 {
        struct l2cap_chan *c;
 
@@ -178,7 +182,7 @@ static u16 l2cap_alloc_cid(struct l2cap_conn *conn)
 static void __l2cap_state_change(struct l2cap_chan *chan, int state)
 {
        BT_DBG("chan %p %s -> %s", chan, state_to_string(chan->state),
-                                               state_to_string(state));
+              state_to_string(state));
 
        chan->state = state;
        chan->ops->state_change(chan, state);
@@ -361,7 +365,7 @@ static void l2cap_seq_list_append(struct l2cap_seq_list *seq_list, u16 seq)
 static void l2cap_chan_timeout(struct work_struct *work)
 {
        struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
-                                                       chan_timer.work);
+                                              chan_timer.work);
        struct l2cap_conn *conn = chan->conn;
        int reason;
 
@@ -373,7 +377,7 @@ static void l2cap_chan_timeout(struct work_struct *work)
        if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
                reason = ECONNREFUSED;
        else if (chan->state == BT_CONNECT &&
-                                       chan->sec_level != BT_SECURITY_SDP)
+                chan->sec_level != BT_SECURITY_SDP)
                reason = ECONNREFUSED;
        else
                reason = ETIMEDOUT;
@@ -455,7 +459,7 @@ void l2cap_chan_set_defaults(struct l2cap_chan *chan)
        set_bit(FLAG_FORCE_ACTIVE, &chan->flags);
 }
 
-static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
+void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
 {
        BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
               __le16_to_cpu(chan->psm), chan->dcid);
@@ -504,7 +508,7 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
        chan->local_msdu        = L2CAP_DEFAULT_MAX_SDU_SIZE;
        chan->local_sdu_itime   = L2CAP_DEFAULT_SDU_ITIME;
        chan->local_acc_lat     = L2CAP_DEFAULT_ACC_LAT;
-       chan->local_flush_to    = L2CAP_DEFAULT_FLUSH_TO;
+       chan->local_flush_to    = L2CAP_EFS_DEFAULT_FLUSH_TO;
 
        l2cap_chan_hold(chan);
 
@@ -527,6 +531,7 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
        BT_DBG("chan %p, conn %p, err %d", chan, conn, err);
 
        if (conn) {
+               struct amp_mgr *mgr = conn->hcon->amp_mgr;
                /* Delete from channel list */
                list_del(&chan->list);
 
@@ -536,10 +541,12 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
 
                if (chan->chan_type != L2CAP_CHAN_CONN_FIX_A2MP)
                        hci_conn_put(conn->hcon);
+
+               if (mgr && mgr->bredr_chan == chan)
+                       mgr->bredr_chan = NULL;
        }
 
-       if (chan->ops->teardown)
-               chan->ops->teardown(chan, err);
+       chan->ops->teardown(chan, err);
 
        if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state))
                return;
@@ -573,19 +580,18 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
        struct l2cap_conn *conn = chan->conn;
        struct sock *sk = chan->sk;
 
-       BT_DBG("chan %p state %s sk %p", chan,
-                                       state_to_string(chan->state), sk);
+       BT_DBG("chan %p state %s sk %p", chan, state_to_string(chan->state),
+              sk);
 
        switch (chan->state) {
        case BT_LISTEN:
-               if (chan->ops->teardown)
-                       chan->ops->teardown(chan, 0);
+               chan->ops->teardown(chan, 0);
                break;
 
        case BT_CONNECTED:
        case BT_CONFIG:
                if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
-                                       conn->hcon->type == ACL_LINK) {
+                   conn->hcon->type == ACL_LINK) {
                        __set_chan_timer(chan, sk->sk_sndtimeo);
                        l2cap_send_disconn_req(conn, chan, reason);
                } else
@@ -594,7 +600,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
 
        case BT_CONNECT2:
                if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED &&
-                                       conn->hcon->type == ACL_LINK) {
+                   conn->hcon->type == ACL_LINK) {
                        struct l2cap_conn_rsp rsp;
                        __u16 result;
 
@@ -609,7 +615,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
                        rsp.result = cpu_to_le16(result);
                        rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
                        l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
-                                                       sizeof(rsp), &rsp);
+                                      sizeof(rsp), &rsp);
                }
 
                l2cap_chan_del(chan, reason);
@@ -621,8 +627,7 @@ void l2cap_chan_close(struct l2cap_chan *chan, int reason)
                break;
 
        default:
-               if (chan->ops->teardown)
-                       chan->ops->teardown(chan, 0);
+               chan->ops->teardown(chan, 0);
                break;
        }
 }
@@ -691,7 +696,8 @@ static u8 l2cap_get_ident(struct l2cap_conn *conn)
        return id;
 }
 
-static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len, void *data)
+static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
+                          void *data)
 {
        struct sk_buff *skb = l2cap_build_cmd(conn, code, ident, len, data);
        u8 flags;
@@ -718,10 +724,10 @@ static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
        u16 flags;
 
        BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,
-                                                       skb->priority);
+              skb->priority);
 
        if (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
-                                       lmp_no_flush_capable(hcon->hdev))
+           lmp_no_flush_capable(hcon->hdev))
                flags = ACL_START_NO_FLUSH;
        else
                flags = ACL_START;
@@ -946,7 +952,19 @@ static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
        return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
 }
 
-static void l2cap_send_conn_req(struct l2cap_chan *chan)
+static bool __amp_capable(struct l2cap_chan *chan)
+{
+       struct l2cap_conn *conn = chan->conn;
+
+       if (enable_hs &&
+           chan->chan_policy == BT_CHANNEL_POLICY_AMP_PREFERRED &&
+           conn->fixed_chan_mask & L2CAP_FC_A2MP)
+               return true;
+       else
+               return false;
+}
+
+void l2cap_send_conn_req(struct l2cap_chan *chan)
 {
        struct l2cap_conn *conn = chan->conn;
        struct l2cap_conn_req req;
@@ -972,6 +990,16 @@ static void l2cap_chan_ready(struct l2cap_chan *chan)
        chan->ops->ready(chan);
 }
 
+static void l2cap_start_connection(struct l2cap_chan *chan)
+{
+       if (__amp_capable(chan)) {
+               BT_DBG("chan %p AMP capable: discover AMPs", chan);
+               a2mp_discover_amp(chan);
+       } else {
+               l2cap_send_conn_req(chan);
+       }
+}
+
 static void l2cap_do_start(struct l2cap_chan *chan)
 {
        struct l2cap_conn *conn = chan->conn;
@@ -986,8 +1014,9 @@ static void l2cap_do_start(struct l2cap_chan *chan)
                        return;
 
                if (l2cap_chan_check_security(chan) &&
-                               __l2cap_no_conn_pending(chan))
-                       l2cap_send_conn_req(chan);
+                   __l2cap_no_conn_pending(chan)) {
+                       l2cap_start_connection(chan);
+               }
        } else {
                struct l2cap_info_req req;
                req.type = __constant_cpu_to_le16(L2CAP_IT_FEAT_MASK);
@@ -997,8 +1026,8 @@ static void l2cap_do_start(struct l2cap_chan *chan)
 
                schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
 
-               l2cap_send_cmd(conn, conn->info_ident,
-                                       L2CAP_INFO_REQ, sizeof(req), &req);
+               l2cap_send_cmd(conn, conn->info_ident, L2CAP_INFO_REQ,
+                              sizeof(req), &req);
        }
 }
 
@@ -1018,7 +1047,8 @@ static inline int l2cap_mode_supported(__u8 mode, __u32 feat_mask)
        }
 }
 
-static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *chan, int err)
+static void l2cap_send_disconn_req(struct l2cap_conn *conn,
+                                  struct l2cap_chan *chan, int err)
 {
        struct sock *sk = chan->sk;
        struct l2cap_disconn_req req;
@@ -1033,14 +1063,14 @@ static void l2cap_send_disconn_req(struct l2cap_conn *conn, struct l2cap_chan *c
        }
 
        if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP) {
-               __l2cap_state_change(chan, BT_DISCONN);
+               l2cap_state_change(chan, BT_DISCONN);
                return;
        }
 
        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);
+       l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_DISCONN_REQ,
+                      sizeof(req), &req);
 
        lock_sock(sk);
        __l2cap_state_change(chan, BT_DISCONN);
@@ -1069,20 +1099,20 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
 
                if (chan->state == BT_CONNECT) {
                        if (!l2cap_chan_check_security(chan) ||
-                                       !__l2cap_no_conn_pending(chan)) {
+                           !__l2cap_no_conn_pending(chan)) {
                                l2cap_chan_unlock(chan);
                                continue;
                        }
 
                        if (!l2cap_mode_supported(chan->mode, conn->feat_mask)
-                                       && test_bit(CONF_STATE2_DEVICE,
+                           && test_bit(CONF_STATE2_DEVICE,
                                        &chan->conf_state)) {
                                l2cap_chan_close(chan, ECONNRESET);
                                l2cap_chan_unlock(chan);
                                continue;
                        }
 
-                       l2cap_send_conn_req(chan);
+                       l2cap_start_connection(chan);
 
                } else if (chan->state == BT_CONNECT2) {
                        struct l2cap_conn_rsp rsp;
@@ -1094,11 +1124,9 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
                                lock_sock(sk);
                                if (test_bit(BT_SK_DEFER_SETUP,
                                             &bt_sk(sk)->flags)) {
-                                       struct sock *parent = bt_sk(sk)->parent;
                                        rsp.result = __constant_cpu_to_le16(L2CAP_CR_PEND);
                                        rsp.status = __constant_cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
-                                       if (parent)
-                                               parent->sk_data_ready(parent, 0);
+                                       chan->ops->defer(chan);
 
                                } else {
                                        __l2cap_state_change(chan, BT_CONFIG);
@@ -1112,17 +1140,17 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
                        }
 
                        l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
-                                                       sizeof(rsp), &rsp);
+                                      sizeof(rsp), &rsp);
 
                        if (test_bit(CONF_REQ_SENT, &chan->conf_state) ||
-                                       rsp.result != L2CAP_CR_SUCCESS) {
+                           rsp.result != L2CAP_CR_SUCCESS) {
                                l2cap_chan_unlock(chan);
                                continue;
                        }
 
                        set_bit(CONF_REQ_SENT, &chan->conf_state);
                        l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
-                                               l2cap_build_conf_req(chan, buf), buf);
+                                      l2cap_build_conf_req(chan, buf), buf);
                        chan->num_conf_req++;
                }
 
@@ -1204,8 +1232,6 @@ static void l2cap_le_conn_ready(struct l2cap_conn *conn)
        bacpy(&bt_sk(sk)->src, conn->src);
        bacpy(&bt_sk(sk)->dst, conn->dst);
 
-       bt_accept_enqueue(parent, sk);
-
        l2cap_chan_add(conn, chan);
 
        l2cap_chan_ready(chan);
@@ -1270,7 +1296,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
 
        list_for_each_entry(chan, &conn->chan_l, list) {
                if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
-                       __l2cap_chan_set_err(chan, err);
+                       l2cap_chan_set_err(chan, err);
        }
 
        mutex_unlock(&conn->chan_lock);
@@ -1279,7 +1305,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
 static void l2cap_info_timeout(struct work_struct *work)
 {
        struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
-                                                       info_timer.work);
+                                              info_timer.work);
 
        conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
        conn->info_ident = 0;
@@ -1333,7 +1359,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
 static void security_timeout(struct work_struct *work)
 {
        struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
-                                               security_timer.work);
+                                              security_timer.work);
 
        BT_DBG("conn %p", conn);
 
@@ -1355,7 +1381,7 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
        if (!hchan)
                return NULL;
 
-       conn = kzalloc(sizeof(struct l2cap_conn), GFP_ATOMIC);
+       conn = kzalloc(sizeof(struct l2cap_conn), GFP_KERNEL);
        if (!conn) {
                hci_chan_del(hchan);
                return NULL;
@@ -1367,10 +1393,22 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
 
        BT_DBG("hcon %p conn %p hchan %p", hcon, conn, hchan);
 
-       if (hcon->hdev->le_mtu && hcon->type == LE_LINK)
-               conn->mtu = hcon->hdev->le_mtu;
-       else
+       switch (hcon->type) {
+       case AMP_LINK:
+               conn->mtu = hcon->hdev->block_mtu;
+               break;
+
+       case LE_LINK:
+               if (hcon->hdev->le_mtu) {
+                       conn->mtu = hcon->hdev->le_mtu;
+                       break;
+               }
+               /* fall through */
+
+       default:
                conn->mtu = hcon->hdev->acl_mtu;
+               break;
+       }
 
        conn->src = &hcon->hdev->bdaddr;
        conn->dst = &hcon->dst;
@@ -1448,7 +1486,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
        __u8 auth_type;
        int err;
 
-       BT_DBG("%s -> %s (type %u) psm 0x%2.2x", batostr(src), batostr(dst),
+       BT_DBG("%pMR -> %pMR (type %u) psm 0x%2.2x", src, dst,
               dst_type, __le16_to_cpu(psm));
 
        hdev = hci_get_route(dst, src);
@@ -1461,7 +1499,7 @@ int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
 
        /* PSM must be odd and lsb of upper byte must be 0 */
        if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid &&
-                                       chan->chan_type != L2CAP_CHAN_RAW) {
+           chan->chan_type != L2CAP_CHAN_RAW) {
                err = -EINVAL;
                goto done;
        }
@@ -1770,7 +1808,7 @@ static void l2cap_ertm_resend(struct l2cap_chan *chan)
                skb = l2cap_ertm_seq_in_queue(&chan->tx_q, seq);
                if (!skb) {
                        BT_DBG("Error: Can't retransmit seq %d, frame missing",
-                               seq);
+                              seq);
                        continue;
                }
 
@@ -1795,9 +1833,9 @@ static void l2cap_ertm_resend(struct l2cap_chan *chan)
                        /* Cloned sk_buffs are read-only, so we need a
                         * writeable copy
                         */
-                       tx_skb = skb_copy(skb, GFP_ATOMIC);
+                       tx_skb = skb_copy(skb, GFP_KERNEL);
                } else {
-                       tx_skb = skb_clone(skb, GFP_ATOMIC);
+                       tx_skb = skb_clone(skb, GFP_KERNEL);
                }
 
                if (!tx_skb) {
@@ -1855,7 +1893,7 @@ static void l2cap_retransmit_all(struct l2cap_chan *chan,
        if (chan->unacked_frames) {
                skb_queue_walk(&chan->tx_q, skb) {
                        if (bt_cb(skb)->control.txseq == control->reqseq ||
-                               skb == chan->tx_send_head)
+                           skb == chan->tx_send_head)
                                break;
                }
 
@@ -2156,7 +2194,7 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan,
 }
 
 int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
-                                                               u32 priority)
+                   u32 priority)
 {
        struct sk_buff *skb;
        int err;
@@ -2543,7 +2581,7 @@ static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
                /* Don't send frame to the socket it came from */
                if (skb->sk == sk)
                        continue;
-               nskb = skb_clone(skb, GFP_ATOMIC);
+               nskb = skb_clone(skb, GFP_KERNEL);
                if (!nskb)
                        continue;
 
@@ -2569,7 +2607,7 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, u8 code,
        len = L2CAP_HDR_SIZE + L2CAP_CMD_HDR_SIZE + dlen;
        count = min_t(unsigned int, conn->mtu, len);
 
-       skb = bt_skb_alloc(count, GFP_ATOMIC);
+       skb = bt_skb_alloc(count, GFP_KERNEL);
        if (!skb)
                return NULL;
 
@@ -2599,7 +2637,7 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn, u8 code,
        while (len) {
                count = min_t(unsigned int, conn->mtu, len);
 
-               *frag = bt_skb_alloc(count, GFP_ATOMIC);
+               *frag = bt_skb_alloc(count, GFP_KERNEL);
                if (!*frag)
                        goto fail;
 
@@ -2618,7 +2656,8 @@ fail:
        return NULL;
 }
 
-static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen, unsigned long *val)
+static inline int l2cap_get_conf_opt(void **ptr, int *type, int *olen,
+                                    unsigned long *val)
 {
        struct l2cap_conf_opt *opt = *ptr;
        int len;
@@ -2692,7 +2731,7 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
                efs.msdu        = cpu_to_le16(chan->local_msdu);
                efs.sdu_itime   = cpu_to_le32(chan->local_sdu_itime);
                efs.acc_lat     = __constant_cpu_to_le32(L2CAP_DEFAULT_ACC_LAT);
-               efs.flush_to    = __constant_cpu_to_le32(L2CAP_DEFAULT_FLUSH_TO);
+               efs.flush_to    = __constant_cpu_to_le32(L2CAP_EFS_DEFAULT_FLUSH_TO);
                break;
 
        case L2CAP_MODE_STREAMING:
@@ -2709,7 +2748,7 @@ static void l2cap_add_opt_efs(void **ptr, struct l2cap_chan *chan)
        }
 
        l2cap_add_conf_opt(ptr, L2CAP_CONF_EFS, sizeof(efs),
-                                                       (unsigned long) &efs);
+                          (unsigned long) &efs);
 }
 
 static void l2cap_ack_timeout(struct work_struct *work)
@@ -2798,13 +2837,13 @@ static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
 static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
 {
        if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
-                                               __l2cap_ews_supported(chan)) {
+           __l2cap_ews_supported(chan)) {
                /* use extended control field */
                set_bit(FLAG_EXT_CTRL, &chan->flags);
                chan->tx_win_max = L2CAP_DEFAULT_EXT_WINDOW;
        } else {
                chan->tx_win = min_t(u16, chan->tx_win,
-                                               L2CAP_DEFAULT_TX_WINDOW);
+                                    L2CAP_DEFAULT_TX_WINDOW);
                chan->tx_win_max = L2CAP_DEFAULT_TX_WINDOW;
        }
        chan->ack_win = chan->tx_win;
@@ -2844,7 +2883,7 @@ done:
        switch (chan->mode) {
        case L2CAP_MODE_BASIC:
                if (!(chan->conn->feat_mask & L2CAP_FEAT_ERTM) &&
-                               !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
+                   !(chan->conn->feat_mask & L2CAP_FEAT_STREAMING))
                        break;
 
                rfc.mode            = L2CAP_MODE_BASIC;
@@ -2855,7 +2894,7 @@ done:
                rfc.max_pdu_size    = 0;
 
                l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
-                                                       (unsigned long) &rfc);
+                                  (unsigned long) &rfc);
                break;
 
        case L2CAP_MODE_ERTM:
@@ -2865,18 +2904,17 @@ done:
                rfc.monitor_timeout = 0;
 
                size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
-                                               L2CAP_EXT_HDR_SIZE -
-                                               L2CAP_SDULEN_SIZE -
-                                               L2CAP_FCS_SIZE);
+                            L2CAP_EXT_HDR_SIZE - L2CAP_SDULEN_SIZE -
+                            L2CAP_FCS_SIZE);
                rfc.max_pdu_size = cpu_to_le16(size);
 
                l2cap_txwin_setup(chan);
 
                rfc.txwin_size = min_t(u16, chan->tx_win,
-                                               L2CAP_DEFAULT_TX_WINDOW);
+                                      L2CAP_DEFAULT_TX_WINDOW);
 
                l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
-                                                       (unsigned long) &rfc);
+                                  (unsigned long) &rfc);
 
                if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
                        l2cap_add_opt_efs(&ptr, chan);
@@ -2885,14 +2923,14 @@ done:
                        break;
 
                if (chan->fcs == L2CAP_FCS_NONE ||
-                               test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
+                   test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
                        chan->fcs = L2CAP_FCS_NONE;
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
                }
 
                if (test_bit(FLAG_EXT_CTRL, &chan->flags))
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_EWS, 2,
-                                                               chan->tx_win);
+                                          chan->tx_win);
                break;
 
        case L2CAP_MODE_STREAMING:
@@ -2904,13 +2942,12 @@ done:
                rfc.monitor_timeout = 0;
 
                size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
-                                               L2CAP_EXT_HDR_SIZE -
-                                               L2CAP_SDULEN_SIZE -
-                                               L2CAP_FCS_SIZE);
+                            L2CAP_EXT_HDR_SIZE - L2CAP_SDULEN_SIZE -
+                            L2CAP_FCS_SIZE);
                rfc.max_pdu_size = cpu_to_le16(size);
 
                l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
-                                                       (unsigned long) &rfc);
+                                  (unsigned long) &rfc);
 
                if (test_bit(FLAG_EFS_ENABLE, &chan->flags))
                        l2cap_add_opt_efs(&ptr, chan);
@@ -2919,7 +2956,7 @@ done:
                        break;
 
                if (chan->fcs == L2CAP_FCS_NONE ||
-                               test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
+                   test_bit(CONF_NO_FCS_RECV, &chan->conf_state)) {
                        chan->fcs = L2CAP_FCS_NONE;
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_FCS, 1, chan->fcs);
                }
@@ -3011,7 +3048,7 @@ static int l2cap_parse_conf_req(struct l2cap_chan *chan, void *data)
        case L2CAP_MODE_ERTM:
                if (!test_bit(CONF_STATE2_DEVICE, &chan->conf_state)) {
                        chan->mode = l2cap_select_mode(rfc.mode,
-                                       chan->conn->feat_mask);
+                                                      chan->conn->feat_mask);
                        break;
                }
 
@@ -3036,8 +3073,8 @@ done:
                if (chan->num_conf_rsp == 1)
                        return -ECONNREFUSED;
 
-               l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
-                                       sizeof(rfc), (unsigned long) &rfc);
+               l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
+                                  (unsigned long) &rfc);
        }
 
        if (result == L2CAP_CONF_SUCCESS) {
@@ -3054,8 +3091,8 @@ done:
 
                if (remote_efs) {
                        if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
-                                       efs.stype != L2CAP_SERV_NOTRAFIC &&
-                                       efs.stype != chan->local_stype) {
+                           efs.stype != L2CAP_SERV_NOTRAFIC &&
+                           efs.stype != chan->local_stype) {
 
                                result = L2CAP_CONF_UNACCEPT;
 
@@ -3063,8 +3100,8 @@ done:
                                        return -ECONNREFUSED;
 
                                l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
-                                                       sizeof(efs),
-                                                       (unsigned long) &efs);
+                                                  sizeof(efs),
+                                                  (unsigned long) &efs);
                        } else {
                                /* Send PENDING Conf Rsp */
                                result = L2CAP_CONF_PENDING;
@@ -3087,10 +3124,8 @@ done:
                        chan->remote_max_tx = rfc.max_transmit;
 
                        size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
-                                               chan->conn->mtu -
-                                               L2CAP_EXT_HDR_SIZE -
-                                               L2CAP_SDULEN_SIZE -
-                                               L2CAP_FCS_SIZE);
+                                    chan->conn->mtu - L2CAP_EXT_HDR_SIZE -
+                                    L2CAP_SDULEN_SIZE - L2CAP_FCS_SIZE);
                        rfc.max_pdu_size = cpu_to_le16(size);
                        chan->remote_mps = size;
 
@@ -3102,36 +3137,35 @@ done:
                        set_bit(CONF_MODE_DONE, &chan->conf_state);
 
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
-                                       sizeof(rfc), (unsigned long) &rfc);
+                                          sizeof(rfc), (unsigned long) &rfc);
 
                        if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
                                chan->remote_id = efs.id;
                                chan->remote_stype = efs.stype;
                                chan->remote_msdu = le16_to_cpu(efs.msdu);
                                chan->remote_flush_to =
-                                               le32_to_cpu(efs.flush_to);
+                                       le32_to_cpu(efs.flush_to);
                                chan->remote_acc_lat =
-                                               le32_to_cpu(efs.acc_lat);
+                                       le32_to_cpu(efs.acc_lat);
                                chan->remote_sdu_itime =
                                        le32_to_cpu(efs.sdu_itime);
                                l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
-                                       sizeof(efs), (unsigned long) &efs);
+                                                  sizeof(efs),
+                                                  (unsigned long) &efs);
                        }
                        break;
 
                case L2CAP_MODE_STREAMING:
                        size = min_t(u16, le16_to_cpu(rfc.max_pdu_size),
-                                               chan->conn->mtu -
-                                               L2CAP_EXT_HDR_SIZE -
-                                               L2CAP_SDULEN_SIZE -
-                                               L2CAP_FCS_SIZE);
+                                    chan->conn->mtu - L2CAP_EXT_HDR_SIZE -
+                                    L2CAP_SDULEN_SIZE - L2CAP_FCS_SIZE);
                        rfc.max_pdu_size = cpu_to_le16(size);
                        chan->remote_mps = size;
 
                        set_bit(CONF_MODE_DONE, &chan->conf_state);
 
-                       l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
-                                       sizeof(rfc), (unsigned long) &rfc);
+                       l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC, sizeof(rfc),
+                                          (unsigned long) &rfc);
 
                        break;
 
@@ -3152,7 +3186,8 @@ done:
        return ptr - data;
 }
 
-static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, 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_conf_req *req = data;
        void *ptr = req->data;
@@ -3179,7 +3214,7 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
                case L2CAP_CONF_FLUSH_TO:
                        chan->flush_to = val;
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_FLUSH_TO,
-                                                       2, chan->flush_to);
+                                          2, chan->flush_to);
                        break;
 
                case L2CAP_CONF_RFC:
@@ -3187,13 +3222,13 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
                                memcpy(&rfc, (void *)val, olen);
 
                        if (test_bit(CONF_STATE2_DEVICE, &chan->conf_state) &&
-                                                       rfc.mode != chan->mode)
+                           rfc.mode != chan->mode)
                                return -ECONNREFUSED;
 
                        chan->fcs = 0;
 
                        l2cap_add_conf_opt(&ptr, L2CAP_CONF_RFC,
-                                       sizeof(rfc), (unsigned long) &rfc);
+                                          sizeof(rfc), (unsigned long) &rfc);
                        break;
 
                case L2CAP_CONF_EWS:
@@ -3207,12 +3242,12 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
                                memcpy(&efs, (void *)val, olen);
 
                        if (chan->local_stype != L2CAP_SERV_NOTRAFIC &&
-                                       efs.stype != L2CAP_SERV_NOTRAFIC &&
-                                       efs.stype != chan->local_stype)
+                           efs.stype != L2CAP_SERV_NOTRAFIC &&
+                           efs.stype != chan->local_stype)
                                return -ECONNREFUSED;
 
-                       l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS,
-                                       sizeof(efs), (unsigned long) &efs);
+                       l2cap_add_conf_opt(&ptr, L2CAP_CONF_EFS, sizeof(efs),
+                                          (unsigned long) &efs);
                        break;
                }
        }
@@ -3235,10 +3270,10 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
                        if (test_bit(FLAG_EFS_ENABLE, &chan->flags)) {
                                chan->local_msdu = le16_to_cpu(efs.msdu);
                                chan->local_sdu_itime =
-                                               le32_to_cpu(efs.sdu_itime);
+                                       le32_to_cpu(efs.sdu_itime);
                                chan->local_acc_lat = le32_to_cpu(efs.acc_lat);
                                chan->local_flush_to =
-                                               le32_to_cpu(efs.flush_to);
+                                       le32_to_cpu(efs.flush_to);
                        }
                        break;
 
@@ -3253,7 +3288,8 @@ static int l2cap_parse_conf_rsp(struct l2cap_chan *chan, void *rsp, int len, voi
        return ptr - data;
 }
 
-static int l2cap_build_conf_rsp(struct l2cap_chan *chan, 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;
@@ -3277,14 +3313,13 @@ void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
        rsp.dcid   = cpu_to_le16(chan->scid);
        rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS);
        rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
-       l2cap_send_cmd(conn, chan->ident,
-                               L2CAP_CONN_RSP, sizeof(rsp), &rsp);
+       l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
 
        if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
                return;
 
        l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
-                       l2cap_build_conf_req(chan, buf), buf);
+                      l2cap_build_conf_req(chan, buf), buf);
        chan->num_conf_req++;
 }
 
@@ -3339,7 +3374,8 @@ static void l2cap_conf_rfc_get(struct l2cap_chan *chan, void *rsp, int len)
        }
 }
 
-static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+static inline int l2cap_command_rej(struct l2cap_conn *conn,
+                                   struct l2cap_cmd_hdr *cmd, u8 *data)
 {
        struct l2cap_cmd_rej_unk *rej = (struct l2cap_cmd_rej_unk *) data;
 
@@ -3347,7 +3383,7 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd
                return 0;
 
        if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
-                                       cmd->ident == conn->info_ident) {
+           cmd->ident == conn->info_ident) {
                cancel_delayed_work(&conn->info_timer);
 
                conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
@@ -3359,7 +3395,8 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd
        return 0;
 }
 
-static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
+                         u8 *data, u8 rsp_code, u8 amp_id)
 {
        struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
        struct l2cap_conn_rsp rsp;
@@ -3386,7 +3423,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
 
        /* Check if the ACL is secure enough (if not SDP) */
        if (psm != __constant_cpu_to_le16(L2CAP_PSM_SDP) &&
-                               !hci_conn_check_link_mode(conn->hcon)) {
+           !hci_conn_check_link_mode(conn->hcon)) {
                conn->disc_reason = HCI_ERROR_AUTH_FAILURE;
                result = L2CAP_CR_SEC_BLOCK;
                goto response;
@@ -3411,8 +3448,6 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
        chan->psm  = psm;
        chan->dcid = scid;
 
-       bt_accept_enqueue(parent, sk);
-
        __l2cap_chan_add(conn, chan);
 
        dcid = chan->scid;
@@ -3427,7 +3462,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
                                __l2cap_state_change(chan, BT_CONNECT2);
                                result = L2CAP_CR_PEND;
                                status = L2CAP_CS_AUTHOR_PEND;
-                               parent->sk_data_ready(parent, 0);
+                               chan->ops->defer(chan);
                        } else {
                                __l2cap_state_change(chan, BT_CONFIG);
                                result = L2CAP_CR_SUCCESS;
@@ -3453,7 +3488,7 @@ sendresp:
        rsp.dcid   = cpu_to_le16(dcid);
        rsp.result = cpu_to_le16(result);
        rsp.status = cpu_to_le16(status);
-       l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
+       l2cap_send_cmd(conn, cmd->ident, rsp_code, sizeof(rsp), &rsp);
 
        if (result == L2CAP_CR_PEND && status == L2CAP_CS_NO_INFO) {
                struct l2cap_info_req info;
@@ -3464,23 +3499,29 @@ sendresp:
 
                schedule_delayed_work(&conn->info_timer, L2CAP_INFO_TIMEOUT);
 
-               l2cap_send_cmd(conn, conn->info_ident,
-                                       L2CAP_INFO_REQ, sizeof(info), &info);
+               l2cap_send_cmd(conn, conn->info_ident, L2CAP_INFO_REQ,
+                              sizeof(info), &info);
        }
 
        if (chan && !test_bit(CONF_REQ_SENT, &chan->conf_state) &&
-                               result == L2CAP_CR_SUCCESS) {
+           result == L2CAP_CR_SUCCESS) {
                u8 buf[128];
                set_bit(CONF_REQ_SENT, &chan->conf_state);
                l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
-                                       l2cap_build_conf_req(chan, buf), buf);
+                              l2cap_build_conf_req(chan, buf), buf);
                chan->num_conf_req++;
        }
+}
 
+static int l2cap_connect_req(struct l2cap_conn *conn,
+                            struct l2cap_cmd_hdr *cmd, u8 *data)
+{
+       l2cap_connect(conn, cmd, data, L2CAP_CONN_RSP, 0);
        return 0;
 }
 
-static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+static inline int l2cap_connect_rsp(struct l2cap_conn *conn,
+                                   struct l2cap_cmd_hdr *cmd, u8 *data)
 {
        struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
        u16 scid, dcid, result, status;
@@ -3494,7 +3535,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
        status = __le16_to_cpu(rsp->status);
 
        BT_DBG("dcid 0x%4.4x scid 0x%4.4x result 0x%2.2x status 0x%2.2x",
-                                               dcid, scid, result, status);
+              dcid, scid, result, status);
 
        mutex_lock(&conn->chan_lock);
 
@@ -3527,7 +3568,7 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
                        break;
 
                l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
-                                       l2cap_build_conf_req(chan, req), req);
+                              l2cap_build_conf_req(chan, req), req);
                chan->num_conf_req++;
                break;
 
@@ -3559,7 +3600,25 @@ static inline void set_default_fcs(struct l2cap_chan *chan)
                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)
+static void l2cap_send_efs_conf_rsp(struct l2cap_chan *chan, void *data,
+                                   u8 ident, u16 flags)
+{
+       struct l2cap_conn *conn = chan->conn;
+
+       BT_DBG("conn %p chan %p ident %d flags 0x%4.4x", conn, chan, ident,
+              flags);
+
+       clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
+       set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
+
+       l2cap_send_cmd(conn, ident, L2CAP_CONF_RSP,
+                      l2cap_build_conf_rsp(chan, data,
+                                           L2CAP_CONF_SUCCESS, flags), data);
+}
+
+static inline int l2cap_config_req(struct l2cap_conn *conn,
+                                  struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+                                  u8 *data)
 {
        struct l2cap_conf_req *req = (struct l2cap_conf_req *) data;
        u16 dcid, flags;
@@ -3584,7 +3643,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
                rej.dcid = cpu_to_le16(chan->dcid);
 
                l2cap_send_cmd(conn, cmd->ident, L2CAP_COMMAND_REJ,
-                               sizeof(rej), &rej);
+                              sizeof(rej), &rej);
                goto unlock;
        }
 
@@ -3592,8 +3651,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        len = cmd_len - sizeof(*req);
        if (len < 0 || chan->conf_len + len > sizeof(chan->conf_req)) {
                l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
-                               l2cap_build_conf_rsp(chan, rsp,
-                                       L2CAP_CONF_REJECT, flags), rsp);
+                              l2cap_build_conf_rsp(chan, rsp,
+                              L2CAP_CONF_REJECT, flags), rsp);
                goto unlock;
        }
 
@@ -3604,8 +3663,8 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        if (flags & L2CAP_CONF_FLAG_CONTINUATION) {
                /* Incomplete config. Send empty response. */
                l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
-                               l2cap_build_conf_rsp(chan, rsp,
-                                       L2CAP_CONF_SUCCESS, flags), rsp);
+                              l2cap_build_conf_rsp(chan, rsp,
+                              L2CAP_CONF_SUCCESS, flags), rsp);
                goto unlock;
        }
 
@@ -3643,23 +3702,22 @@ static inline int l2cap_config_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr
        if (!test_and_set_bit(CONF_REQ_SENT, &chan->conf_state)) {
                u8 buf[64];
                l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
-                                       l2cap_build_conf_req(chan, buf), buf);
+                              l2cap_build_conf_req(chan, buf), buf);
                chan->num_conf_req++;
        }
 
        /* Got Conf Rsp PENDING from remote side and asume we sent
           Conf Rsp PENDING in the code above */
        if (test_bit(CONF_REM_CONF_PEND, &chan->conf_state) &&
-                       test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
+           test_bit(CONF_LOC_CONF_PEND, &chan->conf_state)) {
 
                /* check compatibility */
 
-               clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
-               set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
-
-               l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
-                                       l2cap_build_conf_rsp(chan, rsp,
-                                       L2CAP_CONF_SUCCESS, flags), rsp);
+               /* Send rsp for BR/EDR channel */
+               if (!chan->ctrl_id)
+                       l2cap_send_efs_conf_rsp(chan, rsp, cmd->ident, flags);
+               else
+                       chan->ident = cmd->ident;
        }
 
 unlock:
@@ -3667,7 +3725,8 @@ unlock:
        return err;
 }
 
-static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+static inline int l2cap_config_rsp(struct l2cap_conn *conn,
+                                  struct l2cap_cmd_hdr *cmd, u8 *data)
 {
        struct l2cap_conf_rsp *rsp = (struct l2cap_conf_rsp *)data;
        u16 scid, flags, result;
@@ -3699,7 +3758,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
                        char buf[64];
 
                        len = l2cap_parse_conf_rsp(chan, rsp->data, len,
-                                                               buf, &result);
+                                                  buf, &result);
                        if (len < 0) {
                                l2cap_send_disconn_req(conn, chan, ECONNRESET);
                                goto done;
@@ -3707,12 +3766,11 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
 
                        /* check compatibility */
 
-                       clear_bit(CONF_LOC_CONF_PEND, &chan->conf_state);
-                       set_bit(CONF_OUTPUT_DONE, &chan->conf_state);
-
-                       l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP,
-                                               l2cap_build_conf_rsp(chan, buf,
-                                               L2CAP_CONF_SUCCESS, 0x0000), buf);
+                       if (!chan->ctrl_id)
+                               l2cap_send_efs_conf_rsp(chan, buf, cmd->ident,
+                                                       0);
+                       else
+                               chan->ident = cmd->ident;
                }
                goto done;
 
@@ -3728,14 +3786,14 @@ 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(chan, rsp->data, len,
-                                                               req, &result);
+                                                  req, &result);
                        if (len < 0) {
                                l2cap_send_disconn_req(conn, chan, ECONNRESET);
                                goto done;
                        }
 
                        l2cap_send_cmd(conn, l2cap_get_ident(conn),
-                                               L2CAP_CONF_REQ, len, req);
+                                      L2CAP_CONF_REQ, len, req);
                        chan->num_conf_req++;
                        if (result != L2CAP_CONF_SUCCESS)
                                goto done;
@@ -3773,7 +3831,8 @@ done:
        return err;
 }
 
-static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+static inline int l2cap_disconnect_req(struct l2cap_conn *conn,
+                                      struct l2cap_cmd_hdr *cmd, u8 *data)
 {
        struct l2cap_disconn_req *req = (struct l2cap_disconn_req *) data;
        struct l2cap_disconn_rsp rsp;
@@ -3819,7 +3878,8 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
        return 0;
 }
 
-static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn,
+                                      struct l2cap_cmd_hdr *cmd, u8 *data)
 {
        struct l2cap_disconn_rsp *rsp = (struct l2cap_disconn_rsp *) data;
        u16 dcid, scid;
@@ -3853,7 +3913,8 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
        return 0;
 }
 
-static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+static inline int l2cap_information_req(struct l2cap_conn *conn,
+                                       struct l2cap_cmd_hdr *cmd, u8 *data)
 {
        struct l2cap_info_req *req = (struct l2cap_info_req *) data;
        u16 type;
@@ -3870,14 +3931,14 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm
                rsp->result = __constant_cpu_to_le16(L2CAP_IR_SUCCESS);
                if (!disable_ertm)
                        feat_mask |= L2CAP_FEAT_ERTM | L2CAP_FEAT_STREAMING
-                                                        | L2CAP_FEAT_FCS;
+                               | L2CAP_FEAT_FCS;
                if (enable_hs)
                        feat_mask |= L2CAP_FEAT_EXT_FLOW
-                                               | L2CAP_FEAT_EXT_WINDOW;
+                               | L2CAP_FEAT_EXT_WINDOW;
 
                put_unaligned_le32(feat_mask, rsp->data);
-               l2cap_send_cmd(conn, cmd->ident,
-                                       L2CAP_INFO_RSP, sizeof(buf), buf);
+               l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(buf),
+                              buf);
        } else if (type == L2CAP_IT_FIXED_CHAN) {
                u8 buf[12];
                struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
@@ -3890,20 +3951,21 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm
                rsp->type   = __constant_cpu_to_le16(L2CAP_IT_FIXED_CHAN);
                rsp->result = __constant_cpu_to_le16(L2CAP_IR_SUCCESS);
                memcpy(rsp->data, l2cap_fixed_chan, sizeof(l2cap_fixed_chan));
-               l2cap_send_cmd(conn, cmd->ident,
-                                       L2CAP_INFO_RSP, sizeof(buf), buf);
+               l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(buf),
+                              buf);
        } else {
                struct l2cap_info_rsp rsp;
                rsp.type   = cpu_to_le16(type);
                rsp.result = __constant_cpu_to_le16(L2CAP_IR_NOTSUPP);
-               l2cap_send_cmd(conn, cmd->ident,
-                                       L2CAP_INFO_RSP, sizeof(rsp), &rsp);
+               l2cap_send_cmd(conn, cmd->ident, L2CAP_INFO_RSP, sizeof(rsp),
+                              &rsp);
        }
 
        return 0;
 }
 
-static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd, u8 *data)
+static inline int l2cap_information_rsp(struct l2cap_conn *conn,
+                                       struct l2cap_cmd_hdr *cmd, u8 *data)
 {
        struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) data;
        u16 type, result;
@@ -3915,7 +3977,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
 
        /* L2CAP Info req/rsp are unbound to channels, add extra checks */
        if (cmd->ident != conn->info_ident ||
-                       conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
+           conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
                return 0;
 
        cancel_delayed_work(&conn->info_timer);
@@ -3940,7 +4002,7 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
                        conn->info_ident = l2cap_get_ident(conn);
 
                        l2cap_send_cmd(conn, conn->info_ident,
-                                       L2CAP_INFO_REQ, sizeof(req), &req);
+                                      L2CAP_INFO_REQ, sizeof(req), &req);
                } else {
                        conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
                        conn->info_ident = 0;
@@ -3962,8 +4024,8 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
 }
 
 static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
-                                       struct l2cap_cmd_hdr *cmd, u16 cmd_len,
-                                       void *data)
+                                          struct l2cap_cmd_hdr *cmd,
+                                          u16 cmd_len, void *data)
 {
        struct l2cap_create_chan_req *req = data;
        struct l2cap_create_chan_rsp rsp;
@@ -3993,7 +4055,8 @@ static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
 }
 
 static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
-                                       struct l2cap_cmd_hdr *cmd, void *data)
+                                          struct l2cap_cmd_hdr *cmd,
+                                          void *data)
 {
        BT_DBG("conn %p", conn);
 
@@ -4126,7 +4189,7 @@ static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
 }
 
 static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
-                                                       u16 to_multiplier)
+                                        u16 to_multiplier)
 {
        u16 max_latency;
 
@@ -4147,7 +4210,8 @@ static inline int l2cap_check_conn_param(u16 min, u16 max, u16 latency,
 }
 
 static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
-                                       struct l2cap_cmd_hdr *cmd, u8 *data)
+                                             struct l2cap_cmd_hdr *cmd,
+                                             u8 *data)
 {
        struct hci_conn *hcon = conn->hcon;
        struct l2cap_conn_param_update_req *req;
@@ -4169,7 +4233,7 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
        to_multiplier   = __le16_to_cpu(req->to_multiplier);
 
        BT_DBG("min 0x%4.4x max 0x%4.4x latency: 0x%4.4x Timeout: 0x%4.4x",
-                                               min, max, latency, to_multiplier);
+              min, max, latency, to_multiplier);
 
        memset(&rsp, 0, sizeof(rsp));
 
@@ -4180,7 +4244,7 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
                rsp.result = __constant_cpu_to_le16(L2CAP_CONN_PARAM_ACCEPTED);
 
        l2cap_send_cmd(conn, cmd->ident, L2CAP_CONN_PARAM_UPDATE_RSP,
-                                                       sizeof(rsp), &rsp);
+                      sizeof(rsp), &rsp);
 
        if (!err)
                hci_le_conn_update(hcon, min, max, latency, to_multiplier);
@@ -4189,7 +4253,8 @@ static inline int l2cap_conn_param_update_req(struct l2cap_conn *conn,
 }
 
 static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
-                       struct l2cap_cmd_hdr *cmd, u16 cmd_len, u8 *data)
+                                     struct l2cap_cmd_hdr *cmd, u16 cmd_len,
+                                     u8 *data)
 {
        int err = 0;
 
@@ -4203,6 +4268,7 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
                break;
 
        case L2CAP_CONN_RSP:
+       case L2CAP_CREATE_CHAN_RSP:
                err = l2cap_connect_rsp(conn, cmd, data);
                break;
 
@@ -4241,10 +4307,6 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
                err = l2cap_create_channel_req(conn, cmd, cmd_len, data);
                break;
 
-       case L2CAP_CREATE_CHAN_RSP:
-               err = l2cap_create_channel_rsp(conn, cmd, data);
-               break;
-
        case L2CAP_MOVE_CHAN_REQ:
                err = l2cap_move_channel_req(conn, cmd, cmd_len, data);
                break;
@@ -4271,7 +4333,7 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
 }
 
 static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
-                                       struct l2cap_cmd_hdr *cmd, u8 *data)
+                                  struct l2cap_cmd_hdr *cmd, u8 *data)
 {
        switch (cmd->code) {
        case L2CAP_COMMAND_REJ:
@@ -4290,7 +4352,7 @@ static inline int l2cap_le_sig_cmd(struct l2cap_conn *conn,
 }
 
 static inline void l2cap_sig_channel(struct l2cap_conn *conn,
-                                                       struct sk_buff *skb)
+                                    struct sk_buff *skb)
 {
        u8 *data = skb->data;
        int len = skb->len;
@@ -4307,7 +4369,8 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
 
                cmd_len = le16_to_cpu(cmd.len);
 
-               BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd_len, cmd.ident);
+               BT_DBG("code 0x%2.2x len %d id 0x%2.2x", cmd.code, cmd_len,
+                      cmd.ident);
 
                if (cmd_len > len || !cmd.ident) {
                        BT_DBG("corrupted command");
@@ -4326,7 +4389,8 @@ static inline void l2cap_sig_channel(struct l2cap_conn *conn,
 
                        /* FIXME: Map err to a valid reason */
                        rej.reason = __constant_cpu_to_le16(L2CAP_REJ_NOT_UNDERSTOOD);
-                       l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ, sizeof(rej), &rej);
+                       l2cap_send_cmd(conn, cmd.ident, L2CAP_COMMAND_REJ,
+                                      sizeof(rej), &rej);
                }
 
                data += cmd_len;
@@ -4391,8 +4455,8 @@ static void l2cap_send_i_or_rr_or_rnr(struct l2cap_chan *chan)
        }
 }
 
-static void append_skb_frag(struct sk_buff *skb,
-                       struct sk_buff *new_frag, struct sk_buff **last_frag)
+static void append_skb_frag(struct sk_buff *skb, struct sk_buff *new_frag,
+                           struct sk_buff **last_frag)
 {
        /* skb->len reflects data in skb as well as all fragments
         * skb->data_len reflects only data in fragments
@@ -4641,7 +4705,7 @@ static u8 l2cap_classify_txseq(struct l2cap_chan *chan, u16 txseq)
 
        if (chan->rx_state == L2CAP_RX_STATE_SREJ_SENT) {
                if (__seq_offset(chan, txseq, chan->last_acked_seq) >=
-                                                               chan->tx_win) {
+                   chan->tx_win) {
                        /* See notes below regarding "double poll" and
                         * invalid packets.
                         */
@@ -4682,8 +4746,7 @@ static u8 l2cap_classify_txseq(struct l2cap_chan *chan, u16 txseq)
        }
 
        if (__seq_offset(chan, txseq, chan->last_acked_seq) <
-               __seq_offset(chan, chan->expected_tx_seq,
-                            chan->last_acked_seq)){
+           __seq_offset(chan, chan->expected_tx_seq, chan->last_acked_seq)) {
                BT_DBG("Duplicate - expected_tx_seq later than txseq");
                return L2CAP_TXSEQ_DUPLICATE;
        }
@@ -5323,7 +5386,7 @@ int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
        int exact = 0, lm1 = 0, lm2 = 0;
        struct l2cap_chan *c;
 
-       BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
+       BT_DBG("hdev %s, bdaddr %pMR", hdev->name, bdaddr);
 
        /* Find listening sockets and check their link_mode */
        read_lock(&chan_list_lock);
@@ -5353,7 +5416,7 @@ void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
 {
        struct l2cap_conn *conn;
 
-       BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
+       BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status);
 
        if (!status) {
                conn = l2cap_conn_add(hcon, status);
@@ -5443,7 +5506,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                }
 
                if (!status && (chan->state == BT_CONNECTED ||
-                                               chan->state == BT_CONFIG)) {
+                               chan->state == BT_CONFIG)) {
                        struct sock *sk = chan->sk;
 
                        clear_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags);
@@ -5456,7 +5519,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 
                if (chan->state == BT_CONNECT) {
                        if (!status) {
-                               l2cap_send_conn_req(chan);
+                               l2cap_start_connection(chan);
                        } else {
                                __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
                        }
@@ -5470,11 +5533,9 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                        if (!status) {
                                if (test_bit(BT_SK_DEFER_SETUP,
                                             &bt_sk(sk)->flags)) {
-                                       struct sock *parent = bt_sk(sk)->parent;
                                        res = L2CAP_CR_PEND;
                                        stat = L2CAP_CS_AUTHOR_PEND;
-                                       if (parent)
-                                               parent->sk_data_ready(parent, 0);
+                                       chan->ops->defer(chan);
                                } else {
                                        __l2cap_state_change(chan, BT_CONFIG);
                                        res = L2CAP_CR_SUCCESS;
@@ -5494,7 +5555,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                        rsp.result = cpu_to_le16(res);
                        rsp.status = cpu_to_le16(stat);
                        l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP,
-                                                       sizeof(rsp), &rsp);
+                                      sizeof(rsp), &rsp);
 
                        if (!test_bit(CONF_REQ_SENT, &chan->conf_state) &&
                            res == L2CAP_CR_SUCCESS) {
@@ -5519,6 +5580,12 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
 {
        struct l2cap_conn *conn = hcon->l2cap_data;
+       struct l2cap_hdr *hdr;
+       int len;
+
+       /* For AMP controller do not create l2cap conn */
+       if (!conn && hcon->hdev->dev_type != HCI_BREDR)
+               goto drop;
 
        if (!conn)
                conn = l2cap_conn_add(hcon, 0);
@@ -5528,10 +5595,10 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
 
        BT_DBG("conn %p len %d flags 0x%x", conn, skb->len, flags);
 
-       if (!(flags & ACL_CONT)) {
-               struct l2cap_hdr *hdr;
-               int len;
-
+       switch (flags) {
+       case ACL_START:
+       case ACL_START_NO_FLUSH:
+       case ACL_COMPLETE:
                if (conn->rx_len) {
                        BT_ERR("Unexpected start frame (len %d)", skb->len);
                        kfree_skb(conn->rx_skb);
@@ -5560,20 +5627,22 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
 
                if (skb->len > len) {
                        BT_ERR("Frame is too long (len %d, expected len %d)",
-                               skb->len, len);
+                              skb->len, len);
                        l2cap_conn_unreliable(conn, ECOMM);
                        goto drop;
                }
 
                /* Allocate skb for the complete frame (with header) */
-               conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC);
+               conn->rx_skb = bt_skb_alloc(len, GFP_KERNEL);
                if (!conn->rx_skb)
                        goto drop;
 
                skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
-                                                               skb->len);
+                                         skb->len);
                conn->rx_len = len - skb->len;
-       } else {
+               break;
+
+       case ACL_CONT:
                BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
 
                if (!conn->rx_len) {
@@ -5584,7 +5653,7 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
 
                if (skb->len > conn->rx_len) {
                        BT_ERR("Fragment is too long (len %d, expected %d)",
-                                       skb->len, conn->rx_len);
+                              skb->len, conn->rx_len);
                        kfree_skb(conn->rx_skb);
                        conn->rx_skb = NULL;
                        conn->rx_len = 0;
@@ -5593,7 +5662,7 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
                }
 
                skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
-                                                               skb->len);
+                                         skb->len);
                conn->rx_len -= skb->len;
 
                if (!conn->rx_len) {
@@ -5601,6 +5670,7 @@ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
                        l2cap_recv_frame(conn, conn->rx_skb);
                        conn->rx_skb = NULL;
                }
+               break;
        }
 
 drop:
@@ -5617,12 +5687,11 @@ static int l2cap_debugfs_show(struct seq_file *f, void *p)
        list_for_each_entry(c, &chan_list, global_l) {
                struct sock *sk = c->sk;
 
-               seq_printf(f, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n",
-                                       batostr(&bt_sk(sk)->src),
-                                       batostr(&bt_sk(sk)->dst),
-                                       c->state, __le16_to_cpu(c->psm),
-                                       c->scid, c->dcid, c->imtu, c->omtu,
-                                       c->sec_level, c->mode);
+               seq_printf(f, "%pMR %pMR %d %d 0x%4.4x 0x%4.4x %d %d %d %d\n",
+                          &bt_sk(sk)->src, &bt_sk(sk)->dst,
+                          c->state, __le16_to_cpu(c->psm),
+                          c->scid, c->dcid, c->imtu, c->omtu,
+                          c->sec_level, c->mode);
        }
 
        read_unlock(&chan_list_lock);
@@ -5653,8 +5722,8 @@ int __init l2cap_init(void)
                return err;
 
        if (bt_debugfs) {
-               l2cap_debugfs = debugfs_create_file("l2cap", 0444,
-                                       bt_debugfs, NULL, &l2cap_debugfs_fops);
+               l2cap_debugfs = debugfs_create_file("l2cap", 0444, bt_debugfs,
+                                                   NULL, &l2cap_debugfs_fops);
                if (!l2cap_debugfs)
                        BT_ERR("Failed to create L2CAP debug file");
        }
index 083f2bf065d4d788e59702d29b71b39aaa7bd688..89f1472939ecfba8658c668506f8ce980f9a9866 100644 (file)
@@ -40,7 +40,8 @@ static struct bt_sock_list l2cap_sk_list = {
 
 static const struct proto_ops l2cap_sock_ops;
 static void l2cap_sock_init(struct sock *sk, struct sock *parent);
-static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio);
+static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
+                                    int proto, gfp_t prio);
 
 static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
 {
@@ -106,7 +107,8 @@ done:
        return err;
 }
 
-static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
+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;
@@ -134,7 +136,7 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
        lock_sock(sk);
 
        err = bt_sock_wait_state(sk, BT_CONNECTED,
-                       sock_sndtimeo(sk, flags & O_NONBLOCK));
+                                sock_sndtimeo(sk, flags & O_NONBLOCK));
 
        release_sock(sk);
 
@@ -185,7 +187,8 @@ done:
        return err;
 }
 
-static int l2cap_sock_accept(struct socket *sock, struct socket *newsock, int flags)
+static int l2cap_sock_accept(struct socket *sock, struct socket *newsock,
+                            int flags)
 {
        DECLARE_WAITQUEUE(wait, current);
        struct sock *sk = sock->sk, *nsk;
@@ -241,7 +244,8 @@ done:
        return err;
 }
 
-static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *len, int peer)
+static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr,
+                             int *len, int peer)
 {
        struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
        struct sock *sk = sock->sk;
@@ -266,7 +270,8 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l
        return 0;
 }
 
-static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
+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;
@@ -309,7 +314,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
                        break;
                case BT_SECURITY_HIGH:
                        opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT |
-                                                       L2CAP_LM_SECURE;
+                             L2CAP_LM_SECURE;
                        break;
                default:
                        opt = 0;
@@ -353,7 +358,8 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __us
        return err;
 }
 
-static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
+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;
@@ -377,19 +383,20 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
        switch (optname) {
        case BT_SECURITY:
                if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED &&
-                                       chan->chan_type != L2CAP_CHAN_RAW) {
+                   chan->chan_type != L2CAP_CHAN_RAW) {
                        err = -EINVAL;
                        break;
                }
 
                memset(&sec, 0, sizeof(sec));
-               if (chan->conn)
+               if (chan->conn) {
                        sec.level = chan->conn->hcon->sec_level;
-               else
-                       sec.level = chan->sec_level;
 
-               if (sk->sk_state == BT_CONNECTED)
-                       sec.key_size = chan->conn->hcon->enc_key_size;
+                       if (sk->sk_state == BT_CONNECTED)
+                               sec.key_size = chan->conn->hcon->enc_key_size;
+               } else {
+                       sec.level = chan->sec_level;
+               }
 
                len = min_t(unsigned int, len, sizeof(sec));
                if (copy_to_user(optval, (char *) &sec, len))
@@ -411,14 +418,14 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
 
        case BT_FLUSHABLE:
                if (put_user(test_bit(FLAG_FLUSHABLE, &chan->flags),
-                                               (u32 __user *) optval))
+                            (u32 __user *) optval))
                        err = -EFAULT;
 
                break;
 
        case BT_POWER:
                if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_STREAM
-                               && sk->sk_type != SOCK_RAW) {
+                   && sk->sk_type != SOCK_RAW) {
                        err = -EINVAL;
                        break;
                }
@@ -466,7 +473,8 @@ static bool l2cap_valid_mtu(struct l2cap_chan *chan, u16 mtu)
        return true;
 }
 
-static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, unsigned int optlen)
+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;
@@ -529,6 +537,7 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
                chan->fcs  = opts.fcs;
                chan->max_tx = opts.max_tx;
                chan->tx_win = opts.txwin_size;
+               chan->flush_to = opts.flush_to;
                break;
 
        case L2CAP_LM:
@@ -564,7 +573,8 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __us
        return err;
 }
 
-static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen)
+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;
@@ -587,7 +597,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
        switch (optname) {
        case BT_SECURITY:
                if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED &&
-                                       chan->chan_type != L2CAP_CHAN_RAW) {
+                   chan->chan_type != L2CAP_CHAN_RAW) {
                        err = -EINVAL;
                        break;
                }
@@ -601,7 +611,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
                }
 
                if (sec.level < BT_SECURITY_LOW ||
-                                       sec.level > BT_SECURITY_HIGH) {
+                   sec.level > BT_SECURITY_HIGH) {
                        err = -EINVAL;
                        break;
                }
@@ -627,7 +637,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
 
                /* or for ACL link */
                } else if ((sk->sk_state == BT_CONNECT2 &&
-                          test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) ||
+                           test_bit(BT_SK_DEFER_SETUP, &bt_sk(sk)->flags)) ||
                           sk->sk_state == BT_CONNECTED) {
                        if (!l2cap_chan_check_security(chan))
                                set_bit(BT_SK_SUSPEND, &bt_sk(sk)->flags);
@@ -684,7 +694,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
 
        case BT_POWER:
                if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED &&
-                                       chan->chan_type != L2CAP_CHAN_RAW) {
+                   chan->chan_type != L2CAP_CHAN_RAW) {
                        err = -EINVAL;
                        break;
                }
@@ -720,7 +730,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
                }
 
                if (chan->mode != L2CAP_MODE_ERTM &&
-                               chan->mode != L2CAP_MODE_STREAMING) {
+                   chan->mode != L2CAP_MODE_STREAMING) {
                        err = -EOPNOTSUPP;
                        break;
                }
@@ -737,7 +747,8 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
        return err;
 }
 
-static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len)
+static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
+                             struct msghdr *msg, size_t len)
 {
        struct sock *sk = sock->sk;
        struct l2cap_chan *chan = l2cap_pi(sk)->chan;
@@ -762,7 +773,8 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
        return err;
 }
 
-static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags)
+static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
+                             struct msghdr *msg, size_t len, int flags)
 {
        struct sock *sk = sock->sk;
        struct l2cap_pinfo *pi = l2cap_pi(sk);
@@ -866,7 +878,7 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
 
                if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
                        err = bt_sock_wait_state(sk, BT_CLOSED,
-                                                       sk->sk_lingertime);
+                                                sk->sk_lingertime);
        }
 
        if (!err && sk->sk_err)
@@ -930,7 +942,7 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan)
        }
 
        sk = l2cap_sock_alloc(sock_net(parent), NULL, BTPROTO_L2CAP,
-                                                               GFP_ATOMIC);
+                             GFP_ATOMIC);
        if (!sk)
                return NULL;
 
@@ -938,6 +950,8 @@ static struct l2cap_chan *l2cap_sock_new_connection_cb(struct l2cap_chan *chan)
 
        l2cap_sock_init(sk, parent);
 
+       bt_accept_enqueue(parent, sk);
+
        return l2cap_pi(sk)->chan;
 }
 
@@ -1068,6 +1082,15 @@ static void l2cap_sock_ready_cb(struct l2cap_chan *chan)
        release_sock(sk);
 }
 
+static void l2cap_sock_defer_cb(struct l2cap_chan *chan)
+{
+       struct sock *sk = chan->data;
+       struct sock *parent = bt_sk(sk)->parent;
+
+       if (parent)
+               parent->sk_data_ready(parent, 0);
+}
+
 static struct l2cap_ops l2cap_chan_ops = {
        .name           = "L2CAP Socket Interface",
        .new_connection = l2cap_sock_new_connection_cb,
@@ -1076,6 +1099,7 @@ static struct l2cap_ops l2cap_chan_ops = {
        .teardown       = l2cap_sock_teardown_cb,
        .state_change   = l2cap_sock_state_change_cb,
        .ready          = l2cap_sock_ready_cb,
+       .defer          = l2cap_sock_defer_cb,
        .alloc_skb      = l2cap_sock_alloc_skb_cb,
 };
 
@@ -1083,7 +1107,8 @@ static void l2cap_sock_destruct(struct sock *sk)
 {
        BT_DBG("sk %p", sk);
 
-       l2cap_chan_put(l2cap_pi(sk)->chan);
+       if (l2cap_pi(sk)->chan)
+               l2cap_chan_put(l2cap_pi(sk)->chan);
        if (l2cap_pi(sk)->rx_busy_skb) {
                kfree_skb(l2cap_pi(sk)->rx_busy_skb);
                l2cap_pi(sk)->rx_busy_skb = NULL;
@@ -1159,7 +1184,8 @@ static struct proto l2cap_proto = {
        .obj_size       = sizeof(struct l2cap_pinfo)
 };
 
-static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int proto, gfp_t prio)
+static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock,
+                                    int proto, gfp_t prio)
 {
        struct sock *sk;
        struct l2cap_chan *chan;
@@ -1204,7 +1230,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol,
        sock->state = SS_UNCONNECTED;
 
        if (sock->type != SOCK_SEQPACKET && sock->type != SOCK_STREAM &&
-                       sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
+           sock->type != SOCK_DGRAM && sock->type != SOCK_RAW)
                return -ESOCKTNOSUPPORT;
 
        if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW))
@@ -1261,7 +1287,8 @@ int __init l2cap_init_sockets(void)
                goto error;
        }
 
-       err = bt_procfs_init(THIS_MODULE, &init_net, "l2cap", &l2cap_sk_list, NULL);
+       err = bt_procfs_init(THIS_MODULE, &init_net, "l2cap", &l2cap_sk_list,
+                            NULL);
        if (err < 0) {
                BT_ERR("Failed to create L2CAP proc file");
                bt_sock_unregister(BTPROTO_L2CAP);
index e1c97527e16ca352d4e55016b3a1f70b3e40d5b6..b3fbc73516c415ee1654eb6f2aa38d5e390fb00b 100644 (file)
@@ -41,20 +41,6 @@ void baswap(bdaddr_t *dst, bdaddr_t *src)
 }
 EXPORT_SYMBOL(baswap);
 
-char *batostr(bdaddr_t *ba)
-{
-       static char str[2][18];
-       static int i = 1;
-
-       i ^= 1;
-       sprintf(str[i], "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
-               ba->b[5], ba->b[4], ba->b[3],
-               ba->b[2], ba->b[1], ba->b[0]);
-
-       return str[i];
-}
-EXPORT_SYMBOL(batostr);
-
 /* Bluetooth error codes to Unix errno mapping */
 int bt_to_errno(__u16 code)
 {
index aa2ea0a8142cc0d6c7378ced06be1257b2f846d7..399e5024b5bdb70e1b4c9ff4c409a0cc9d9b435a 100644 (file)
@@ -3125,6 +3125,9 @@ int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
        struct pending_cmd *cmd;
        int err;
 
+       mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
+                            hdev);
+
        cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
        if (!cmd)
                return -ENOENT;
@@ -3137,8 +3140,6 @@ int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
 
        mgmt_pending_remove(cmd);
 
-       mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
-                            hdev);
        return err;
 }
 
index c75107ef89204877315ea8d61248c2fa4e2bddd2..201fdf73720933f9fbbbb3bea3bedd1db6d5bbcf 100644 (file)
@@ -377,8 +377,8 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst,
        int err = 0;
        u8 dlci;
 
-       BT_DBG("dlc %p state %ld %s %s channel %d",
-                       d, d->state, batostr(src), batostr(dst), channel);
+       BT_DBG("dlc %p state %ld %pMR -> %pMR channel %d",
+              d, d->state, src, dst, channel);
 
        if (channel < 1 || channel > 30)
                return -EINVAL;
@@ -676,7 +676,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
        struct socket *sock;
        struct sock *sk;
 
-       BT_DBG("%s %s", batostr(src), batostr(dst));
+       BT_DBG("%pMR -> %pMR", src, dst);
 
        *err = rfcomm_l2sock_create(&sock);
        if (*err < 0)
@@ -709,7 +709,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src,
 
        bacpy(&addr.l2_bdaddr, dst);
        addr.l2_family = AF_BLUETOOTH;
-       addr.l2_psm    = cpu_to_le16(RFCOMM_PSM);
+       addr.l2_psm    = __constant_cpu_to_le16(RFCOMM_PSM);
        addr.l2_cid    = 0;
        *err = kernel_connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK);
        if (*err == 0 || *err == -EINPROGRESS)
@@ -1987,7 +1987,7 @@ static int rfcomm_add_listener(bdaddr_t *ba)
        /* Bind socket */
        bacpy(&addr.l2_bdaddr, ba);
        addr.l2_family = AF_BLUETOOTH;
-       addr.l2_psm    = cpu_to_le16(RFCOMM_PSM);
+       addr.l2_psm    = __constant_cpu_to_le16(RFCOMM_PSM);
        addr.l2_cid    = 0;
        err = kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr));
        if (err < 0) {
@@ -2125,11 +2125,10 @@ static int rfcomm_dlc_debugfs_show(struct seq_file *f, void *x)
                list_for_each_entry(d, &s->dlcs, list) {
                        struct sock *sk = s->sock->sk;
 
-                       seq_printf(f, "%s %s %ld %d %d %d %d\n",
-                                               batostr(&bt_sk(sk)->src),
-                                               batostr(&bt_sk(sk)->dst),
-                                               d->state, d->dlci, d->mtu,
-                                               d->rx_credits, d->tx_credits);
+                       seq_printf(f, "%pMR %pMR %ld %d %d %d %d\n",
+                                  &bt_sk(sk)->src, &bt_sk(sk)->dst,
+                                  d->state, d->dlci, d->mtu,
+                                  d->rx_credits, d->tx_credits);
                }
        }
 
index b3226f3658cfda1142c7484b110324115dccc85b..4ddef57d03a7f4ee31c80035270d0cfb93a8a71e 100644 (file)
@@ -334,7 +334,7 @@ static int rfcomm_sock_bind(struct socket *sock, struct sockaddr *addr, int addr
        struct sock *sk = sock->sk;
        int err = 0;
 
-       BT_DBG("sk %p %s", sk, batostr(&sa->rc_bdaddr));
+       BT_DBG("sk %p %pMR", sk, &sa->rc_bdaddr);
 
        if (!addr || addr->sa_family != AF_BLUETOOTH)
                return -EINVAL;
@@ -975,10 +975,9 @@ static int rfcomm_sock_debugfs_show(struct seq_file *f, void *p)
        read_lock(&rfcomm_sk_list.lock);
 
        sk_for_each(sk, node, &rfcomm_sk_list.head) {
-               seq_printf(f, "%s %s %d %d\n",
-                               batostr(&bt_sk(sk)->src),
-                               batostr(&bt_sk(sk)->dst),
-                               sk->sk_state, rfcomm_pi(sk)->channel);
+               seq_printf(f, "%pMR %pMR %d %d\n",
+                          &bt_sk(sk)->src, &bt_sk(sk)->dst,
+                          sk->sk_state, rfcomm_pi(sk)->channel);
        }
 
        read_unlock(&rfcomm_sk_list.lock);
index ccc248791d50239c24fce5c0635245f33f654fa3..bd6fd0f43d2b36f3652127d51f5bdf7e797add58 100644 (file)
@@ -166,7 +166,7 @@ static struct device *rfcomm_get_device(struct rfcomm_dev *dev)
 static ssize_t show_address(struct device *tty_dev, struct device_attribute *attr, char *buf)
 {
        struct rfcomm_dev *dev = dev_get_drvdata(tty_dev);
-       return sprintf(buf, "%s\n", batostr(&dev->dst));
+       return sprintf(buf, "%pMR\n", &dev->dst);
 }
 
 static ssize_t show_channel(struct device *tty_dev, struct device_attribute *attr, char *buf)
@@ -663,8 +663,8 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
        if (!dev)
                return -ENODEV;
 
-       BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst),
-                               dev->channel, dev->port.count);
+       BT_DBG("dev %p dst %pMR channel %d opened %d", dev, &dev->dst,
+              dev->channel, dev->port.count);
 
        spin_lock_irqsave(&dev->port.lock, flags);
        if (++dev->port.count > 1) {
index dc42b917aaafad3f050177694c438648af2b22bb..450cdcd88e5c9a624372927639433f67fc2fde1d 100644 (file)
@@ -172,7 +172,7 @@ static int sco_connect(struct sock *sk)
        struct hci_dev  *hdev;
        int err, type;
 
-       BT_DBG("%s -> %s", batostr(src), batostr(dst));
+       BT_DBG("%pMR -> %pMR", src, dst);
 
        hdev = hci_get_route(dst, src);
        if (!hdev)
@@ -460,7 +460,7 @@ static int sco_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
        struct sock *sk = sock->sk;
        int err = 0;
 
-       BT_DBG("sk %p %s", sk, batostr(&sa->sco_bdaddr));
+       BT_DBG("sk %p %pMR", sk, &sa->sco_bdaddr);
 
        if (!addr || addr->sa_family != AF_BLUETOOTH)
                return -EINVAL;
@@ -893,7 +893,7 @@ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
        struct hlist_node *node;
        int lm = 0;
 
-       BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
+       BT_DBG("hdev %s, bdaddr %pMR", hdev->name, bdaddr);
 
        /* Find listening sockets */
        read_lock(&sco_sk_list.lock);
@@ -914,7 +914,7 @@ int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
 
 void sco_connect_cfm(struct hci_conn *hcon, __u8 status)
 {
-       BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
+       BT_DBG("hcon %p bdaddr %pMR status %d", hcon, &hcon->dst, status);
        if (!status) {
                struct sco_conn *conn;
 
@@ -959,8 +959,8 @@ static int sco_debugfs_show(struct seq_file *f, void *p)
        read_lock(&sco_sk_list.lock);
 
        sk_for_each(sk, node, &sco_sk_list.head) {
-               seq_printf(f, "%s %s %d\n", batostr(&bt_sk(sk)->src),
-                          batostr(&bt_sk(sk)->dst), sk->sk_state);
+               seq_printf(f, "%pMR %pMR %d\n", &bt_sk(sk)->src,
+                          &bt_sk(sk)->dst, sk->sk_state);
        }
 
        read_unlock(&sco_sk_list.lock);
index 8c225ef349cd733614dfeaca0f2f1bceccdae064..9b54fea080c9648ae4b022d51e60cff85af36016 100644 (file)
@@ -165,7 +165,7 @@ static struct sk_buff *smp_build_cmd(struct l2cap_conn *conn, u8 code,
 
        lh = (struct l2cap_hdr *) skb_put(skb, L2CAP_HDR_SIZE);
        lh->len = cpu_to_le16(sizeof(code) + dlen);
-       lh->cid = cpu_to_le16(L2CAP_CID_SMP);
+       lh->cid = __constant_cpu_to_le16(L2CAP_CID_SMP);
 
        memcpy(skb_put(skb, sizeof(code)), &code, sizeof(code));