mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
Bluetooth: Added AMP manager and support for use of AMP channels.
Bluetooth 3.0+HS depends on an AMP manager to coordinate the setup and teardown of AMP physical and logical links using the A2MP protocol. There are also new L2CAP signals that allow two Bluetooth devices to move L2CAP channels to and from a high-speed link, and a new socket option for applications to use to control the type of Bluetooth link used for L2CAP traffic. Change-Id: I98067e0781b31f5d694e7b7da5cf5006dc21f514 Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
This commit is contained in:
parent
582ddfaab0
commit
4b46819f6c
7 changed files with 3950 additions and 33 deletions
296
include/net/bluetooth/amp.h
Normal file
296
include/net/bluetooth/amp.h
Normal file
|
@ -0,0 +1,296 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2010-2011 Code Aurora Forum. All rights reserved.
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
/* AMP defaults */
|
||||||
|
|
||||||
|
#define A2MP_RSP_TIMEOUT (20000) /* 20 seconds */
|
||||||
|
|
||||||
|
/* A2MP Protocol */
|
||||||
|
|
||||||
|
/* A2MP command codes */
|
||||||
|
#define A2MP_COMMAND_REJ 0x01
|
||||||
|
#define A2MP_DISCOVER_REQ 0x02
|
||||||
|
#define A2MP_DISCOVER_RSP 0x03
|
||||||
|
#define A2MP_CHANGE_NOTIFY 0x04
|
||||||
|
#define A2MP_CHANGE_RSP 0x05
|
||||||
|
#define A2MP_GETINFO_REQ 0x06
|
||||||
|
#define A2MP_GETINFO_RSP 0x07
|
||||||
|
#define A2MP_GETAMPASSOC_REQ 0x08
|
||||||
|
#define A2MP_GETAMPASSOC_RSP 0x09
|
||||||
|
#define A2MP_CREATEPHYSLINK_REQ 0x0A
|
||||||
|
#define A2MP_CREATEPHYSLINK_RSP 0x0B
|
||||||
|
#define A2MP_DISCONNPHYSLINK_REQ 0x0C
|
||||||
|
#define A2MP_DISCONNPHYSLINK_RSP 0x0D
|
||||||
|
|
||||||
|
struct a2mp_cmd_hdr {
|
||||||
|
__u8 code;
|
||||||
|
__u8 ident;
|
||||||
|
__le16 len;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct a2mp_cmd_rej {
|
||||||
|
__le16 reason;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
#define HCI_A2MP_ID(id) ((id)+0x10) /* convert HCI dev index to AMP ID */
|
||||||
|
#define A2MP_HCI_ID(id) ((id)-0x10) /* convert AMP ID to HCI dev index */
|
||||||
|
|
||||||
|
struct a2mp_discover_req {
|
||||||
|
__le16 mtu;
|
||||||
|
__le16 ext_feat;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct a2mp_cl {
|
||||||
|
__u8 id;
|
||||||
|
__u8 type;
|
||||||
|
__u8 status;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct a2mp_discover_rsp {
|
||||||
|
__le16 mtu;
|
||||||
|
__le16 ext_feat;
|
||||||
|
struct a2mp_cl cl[0];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct a2mp_getinfo_req {
|
||||||
|
__u8 id;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct a2mp_getinfo_rsp {
|
||||||
|
__u8 id;
|
||||||
|
__u8 status;
|
||||||
|
__le32 total_bw;
|
||||||
|
__le32 max_bw;
|
||||||
|
__le32 min_latency;
|
||||||
|
__le16 pal_cap;
|
||||||
|
__le16 assoc_size;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct a2mp_getampassoc_req {
|
||||||
|
__u8 id;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct a2mp_getampassoc_rsp {
|
||||||
|
__u8 id;
|
||||||
|
__u8 status;
|
||||||
|
__u8 amp_assoc[0];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct a2mp_createphyslink_req {
|
||||||
|
__u8 local_id;
|
||||||
|
__u8 remote_id;
|
||||||
|
__u8 amp_assoc[0];
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct a2mp_createphyslink_rsp {
|
||||||
|
__u8 local_id;
|
||||||
|
__u8 remote_id;
|
||||||
|
__u8 status;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct a2mp_disconnphyslink_req {
|
||||||
|
__u8 local_id;
|
||||||
|
__u8 remote_id;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
struct a2mp_disconnphyslink_rsp {
|
||||||
|
__u8 local_id;
|
||||||
|
__u8 remote_id;
|
||||||
|
__u8 status;
|
||||||
|
} __packed;
|
||||||
|
|
||||||
|
|
||||||
|
/* L2CAP-AMP module interface */
|
||||||
|
int amp_init(void);
|
||||||
|
void amp_exit(void);
|
||||||
|
|
||||||
|
/* L2CAP-AMP fixed channel interface */
|
||||||
|
void amp_conn_ind(struct l2cap_conn *conn, struct sk_buff *skb);
|
||||||
|
|
||||||
|
/* L2CAP-AMP link interface */
|
||||||
|
void amp_create_physical(struct l2cap_conn *conn, struct sock *sk);
|
||||||
|
void amp_accept_physical(struct l2cap_conn *conn, u8 id, struct sock *sk);
|
||||||
|
|
||||||
|
/* AMP manager internals */
|
||||||
|
struct amp_ctrl {
|
||||||
|
struct amp_mgr *mgr;
|
||||||
|
__u8 id;
|
||||||
|
__u8 type;
|
||||||
|
__u8 status;
|
||||||
|
__u32 total_bw;
|
||||||
|
__u32 max_bw;
|
||||||
|
__u32 min_latency;
|
||||||
|
__u16 pal_cap;
|
||||||
|
__u16 max_assoc_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct amp_mgr {
|
||||||
|
struct list_head list;
|
||||||
|
__u8 discovered;
|
||||||
|
__u8 next_ident;
|
||||||
|
struct l2cap_conn *l2cap_conn;
|
||||||
|
struct socket *a2mp_sock;
|
||||||
|
struct list_head ctx_list;
|
||||||
|
rwlock_t ctx_list_lock;
|
||||||
|
struct amp_ctrl *ctrls; /* @@ TODO s.b. list of controllers */
|
||||||
|
struct sk_buff *skb;
|
||||||
|
__u8 connected;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* AMP Manager signalling contexts */
|
||||||
|
#define AMP_GETAMPASSOC 1
|
||||||
|
#define AMP_CREATEPHYSLINK 2
|
||||||
|
#define AMP_ACCEPTPHYSLINK 3
|
||||||
|
#define AMP_CREATELOGLINK 4
|
||||||
|
#define AMP_ACCEPTLOGLINK 5
|
||||||
|
|
||||||
|
/* Get AMP Assoc sequence */
|
||||||
|
#define AMP_GAA_INIT 0
|
||||||
|
#define AMP_GAA_RLAA_COMPLETE 1
|
||||||
|
struct amp_gaa_state {
|
||||||
|
__u8 req_ident;
|
||||||
|
__u16 len_so_far;
|
||||||
|
__u8 *assoc;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Create Physical Link sequence */
|
||||||
|
#define AMP_CPL_INIT 0
|
||||||
|
#define AMP_CPL_DISC_RSP 1
|
||||||
|
#define AMP_CPL_GETINFO_RSP 2
|
||||||
|
#define AMP_CPL_GAA_RSP 3
|
||||||
|
#define AMP_CPL_CPL_STATUS 4
|
||||||
|
#define AMP_CPL_WRA_COMPLETE 5
|
||||||
|
#define AMP_CPL_CHANNEL_SELECT 6
|
||||||
|
#define AMP_CPL_RLA_COMPLETE 7
|
||||||
|
#define AMP_CPL_PL_COMPLETE 8
|
||||||
|
#define AMP_CPL_PL_CANCEL 9
|
||||||
|
struct amp_cpl_state {
|
||||||
|
__u8 remote_id;
|
||||||
|
__u16 max_len;
|
||||||
|
__u8 *remote_assoc;
|
||||||
|
__u8 *local_assoc;
|
||||||
|
__u16 len_so_far;
|
||||||
|
__u16 rem_len;
|
||||||
|
__u8 phy_handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Accept Physical Link sequence */
|
||||||
|
#define AMP_APL_INIT 0
|
||||||
|
#define AMP_APL_APL_STATUS 1
|
||||||
|
#define AMP_APL_WRA_COMPLETE 2
|
||||||
|
#define AMP_APL_PL_COMPLETE 3
|
||||||
|
struct amp_apl_state {
|
||||||
|
__u8 remote_id;
|
||||||
|
__u8 req_ident;
|
||||||
|
__u8 *remote_assoc;
|
||||||
|
__u16 len_so_far;
|
||||||
|
__u16 rem_len;
|
||||||
|
__u8 phy_handle;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Create/Accept Logical Link sequence */
|
||||||
|
#define AMP_LOG_INIT 0
|
||||||
|
#define AMP_LOG_LL_STATUS 1
|
||||||
|
#define AMP_LOG_LL_COMPLETE 2
|
||||||
|
struct amp_log_state {
|
||||||
|
__u8 remote_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Possible event types a context may wait for */
|
||||||
|
#define AMP_INIT 0x01
|
||||||
|
#define AMP_HCI_EVENT 0x02
|
||||||
|
#define AMP_HCI_CMD_CMPLT 0x04
|
||||||
|
#define AMP_HCI_CMD_STATUS 0x08
|
||||||
|
#define AMP_A2MP_RSP 0x10
|
||||||
|
#define AMP_KILLED 0x20
|
||||||
|
#define AMP_CANCEL 0x40
|
||||||
|
struct amp_ctx {
|
||||||
|
struct list_head list;
|
||||||
|
struct amp_mgr *mgr;
|
||||||
|
struct hci_dev *hdev;
|
||||||
|
__u8 type;
|
||||||
|
__u8 state;
|
||||||
|
union {
|
||||||
|
struct amp_gaa_state gaa;
|
||||||
|
struct amp_cpl_state cpl;
|
||||||
|
struct amp_apl_state apl;
|
||||||
|
} d;
|
||||||
|
__u8 evt_type;
|
||||||
|
__u8 evt_code;
|
||||||
|
__u16 opcode;
|
||||||
|
__u8 id;
|
||||||
|
__u8 rsp_ident;
|
||||||
|
|
||||||
|
struct sock *sk;
|
||||||
|
struct amp_ctx *deferred;
|
||||||
|
struct timer_list timer;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* AMP work */
|
||||||
|
struct amp_work_pl_timeout {
|
||||||
|
struct work_struct work;
|
||||||
|
struct amp_ctrl *ctrl;
|
||||||
|
};
|
||||||
|
struct amp_work_ctx_timeout {
|
||||||
|
struct work_struct work;
|
||||||
|
struct amp_ctx *ctx;
|
||||||
|
};
|
||||||
|
struct amp_work_data_ready {
|
||||||
|
struct work_struct work;
|
||||||
|
struct sock *sk;
|
||||||
|
int bytes;
|
||||||
|
};
|
||||||
|
struct amp_work_state_change {
|
||||||
|
struct work_struct work;
|
||||||
|
struct sock *sk;
|
||||||
|
};
|
||||||
|
struct amp_work_conn_ind {
|
||||||
|
struct work_struct work;
|
||||||
|
struct l2cap_conn *conn;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
};
|
||||||
|
struct amp_work_create_physical {
|
||||||
|
struct work_struct work;
|
||||||
|
struct l2cap_conn *conn;
|
||||||
|
u8 id;
|
||||||
|
struct sock *sk;
|
||||||
|
};
|
||||||
|
struct amp_work_accept_physical {
|
||||||
|
struct work_struct work;
|
||||||
|
struct l2cap_conn *conn;
|
||||||
|
u8 id;
|
||||||
|
struct sock *sk;
|
||||||
|
};
|
||||||
|
struct amp_work_cmd_cmplt {
|
||||||
|
struct work_struct work;
|
||||||
|
struct hci_dev *hdev;
|
||||||
|
u16 opcode;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
};
|
||||||
|
struct amp_work_cmd_status {
|
||||||
|
struct work_struct work;
|
||||||
|
struct hci_dev *hdev;
|
||||||
|
u16 opcode;
|
||||||
|
u8 status;
|
||||||
|
};
|
||||||
|
struct amp_work_event {
|
||||||
|
struct work_struct work;
|
||||||
|
struct hci_dev *hdev;
|
||||||
|
u8 event;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* __AMP_H */
|
|
@ -70,6 +70,33 @@ struct bt_power {
|
||||||
__u8 force_active;
|
__u8 force_active;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define BT_AMP_POLICY 9
|
||||||
|
|
||||||
|
/* Require BR/EDR (default policy)
|
||||||
|
* AMP controllers cannot be used
|
||||||
|
* Channel move requests from the remote device are denied
|
||||||
|
* If the L2CAP channel is currently using AMP, move the channel to BR/EDR
|
||||||
|
*/
|
||||||
|
#define BT_AMP_POLICY_REQUIRE_BR_EDR 0
|
||||||
|
|
||||||
|
/* Prefer AMP
|
||||||
|
* Allow use of AMP controllers
|
||||||
|
* If the L2CAP channel is currently on BR/EDR and AMP controller
|
||||||
|
* resources are available, initiate a channel move to AMP
|
||||||
|
* Channel move requests from the remote device are allowed
|
||||||
|
* If the L2CAP socket has not been connected yet, try to create
|
||||||
|
* and configure the channel directly on an AMP controller rather
|
||||||
|
* than BR/EDR
|
||||||
|
*/
|
||||||
|
#define BT_AMP_POLICY_PREFER_AMP 1
|
||||||
|
|
||||||
|
/* Prefer BR/EDR
|
||||||
|
* Allow use of AMP controllers
|
||||||
|
* If the L2CAP channel is currently on AMP, move it to BR/EDR
|
||||||
|
* Channel move requests from the remote device are allowed
|
||||||
|
*/
|
||||||
|
#define BT_AMP_POLICY_PREFER_BR_EDR 2
|
||||||
|
|
||||||
#define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg)
|
#define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg)
|
||||||
#define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg)
|
#define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg)
|
||||||
#define BT_DBG(fmt, arg...) pr_debug("%s: " fmt "\n" , __func__ , ## arg)
|
#define BT_DBG(fmt, arg...) pr_debug("%s: " fmt "\n" , __func__ , ## arg)
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
#define L2CAP_DEFAULT_MAX_TX 3
|
#define L2CAP_DEFAULT_MAX_TX 3
|
||||||
#define L2CAP_DEFAULT_RETRANS_TO 2000 /* 2 seconds */
|
#define L2CAP_DEFAULT_RETRANS_TO 2000 /* 2 seconds */
|
||||||
#define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */
|
#define L2CAP_DEFAULT_MONITOR_TO 12000 /* 12 seconds */
|
||||||
#define L2CAP_DEFAULT_MAX_PDU_SIZE 1009 /* Sized for 3-DH5 packet */
|
#define L2CAP_DEFAULT_MAX_PDU_SIZE 1482 /* Sized for AMP or BR/EDR */
|
||||||
#define L2CAP_DEFAULT_ACK_TO 200
|
#define L2CAP_DEFAULT_ACK_TO 200
|
||||||
#define L2CAP_BREDR_MAX_PAYLOAD 1019 /* 3-DH5 packet */
|
#define L2CAP_BREDR_MAX_PAYLOAD 1019 /* 3-DH5 packet */
|
||||||
#define L2CAP_MAX_ERTM_QUEUED 5
|
#define L2CAP_MAX_ERTM_QUEUED 5
|
||||||
|
@ -48,6 +48,8 @@
|
||||||
|
|
||||||
#define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */
|
#define L2CAP_CONN_TIMEOUT (40000) /* 40 seconds */
|
||||||
#define L2CAP_INFO_TIMEOUT (4000) /* 4 seconds */
|
#define L2CAP_INFO_TIMEOUT (4000) /* 4 seconds */
|
||||||
|
#define L2CAP_MOVE_TIMEOUT (2000) /* 2 seconds */
|
||||||
|
#define L2CAP_MOVE_ERTX_TIMEOUT (60000) /* 60 seconds */
|
||||||
|
|
||||||
/* L2CAP socket address */
|
/* L2CAP socket address */
|
||||||
struct sockaddr_l2 {
|
struct sockaddr_l2 {
|
||||||
|
@ -85,17 +87,23 @@ struct l2cap_conninfo {
|
||||||
#define L2CAP_LM_FLUSHABLE 0x0040
|
#define L2CAP_LM_FLUSHABLE 0x0040
|
||||||
|
|
||||||
/* L2CAP command codes */
|
/* L2CAP command codes */
|
||||||
#define L2CAP_COMMAND_REJ 0x01
|
#define L2CAP_COMMAND_REJ 0x01
|
||||||
#define L2CAP_CONN_REQ 0x02
|
#define L2CAP_CONN_REQ 0x02
|
||||||
#define L2CAP_CONN_RSP 0x03
|
#define L2CAP_CONN_RSP 0x03
|
||||||
#define L2CAP_CONF_REQ 0x04
|
#define L2CAP_CONF_REQ 0x04
|
||||||
#define L2CAP_CONF_RSP 0x05
|
#define L2CAP_CONF_RSP 0x05
|
||||||
#define L2CAP_DISCONN_REQ 0x06
|
#define L2CAP_DISCONN_REQ 0x06
|
||||||
#define L2CAP_DISCONN_RSP 0x07
|
#define L2CAP_DISCONN_RSP 0x07
|
||||||
#define L2CAP_ECHO_REQ 0x08
|
#define L2CAP_ECHO_REQ 0x08
|
||||||
#define L2CAP_ECHO_RSP 0x09
|
#define L2CAP_ECHO_RSP 0x09
|
||||||
#define L2CAP_INFO_REQ 0x0a
|
#define L2CAP_INFO_REQ 0x0a
|
||||||
#define L2CAP_INFO_RSP 0x0b
|
#define L2CAP_INFO_RSP 0x0b
|
||||||
|
#define L2CAP_CREATE_CHAN_REQ 0x0c
|
||||||
|
#define L2CAP_CREATE_CHAN_RSP 0x0d
|
||||||
|
#define L2CAP_MOVE_CHAN_REQ 0x0e
|
||||||
|
#define L2CAP_MOVE_CHAN_RSP 0x0f
|
||||||
|
#define L2CAP_MOVE_CHAN_CFM 0x10
|
||||||
|
#define L2CAP_MOVE_CHAN_CFM_RSP 0x11
|
||||||
#define L2CAP_CONN_PARAM_UPDATE_REQ 0x12
|
#define L2CAP_CONN_PARAM_UPDATE_REQ 0x12
|
||||||
#define L2CAP_CONN_PARAM_UPDATE_RSP 0x13
|
#define L2CAP_CONN_PARAM_UPDATE_RSP 0x13
|
||||||
|
|
||||||
|
@ -199,6 +207,7 @@ struct l2cap_conn_rsp {
|
||||||
/* channel indentifier */
|
/* channel indentifier */
|
||||||
#define L2CAP_CID_SIGNALING 0x0001
|
#define L2CAP_CID_SIGNALING 0x0001
|
||||||
#define L2CAP_CID_CONN_LESS 0x0002
|
#define L2CAP_CID_CONN_LESS 0x0002
|
||||||
|
#define L2CAP_CID_A2MP 0x0003
|
||||||
#define L2CAP_CID_LE_DATA 0x0004
|
#define L2CAP_CID_LE_DATA 0x0004
|
||||||
#define L2CAP_CID_LE_SIGNALING 0x0005
|
#define L2CAP_CID_LE_SIGNALING 0x0005
|
||||||
#define L2CAP_CID_SMP 0x0006
|
#define L2CAP_CID_SMP 0x0006
|
||||||
|
@ -297,6 +306,79 @@ struct l2cap_info_rsp {
|
||||||
__u8 data[0];
|
__u8 data[0];
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
|
struct l2cap_create_chan_req {
|
||||||
|
__le16 psm;
|
||||||
|
__le16 scid;
|
||||||
|
__u8 amp_id;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct l2cap_create_chan_rsp {
|
||||||
|
__le16 dcid;
|
||||||
|
__le16 scid;
|
||||||
|
__le16 result;
|
||||||
|
__le16 status;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#define L2CAP_CREATE_CHAN_SUCCESS (0x0000)
|
||||||
|
#define L2CAP_CREATE_CHAN_PENDING (0x0001)
|
||||||
|
#define L2CAP_CREATE_CHAN_REFUSED_PSM (0x0002)
|
||||||
|
#define L2CAP_CREATE_CHAN_REFUSED_SECURITY (0x0003)
|
||||||
|
#define L2CAP_CREATE_CHAN_REFUSED_RESOURCES (0x0004)
|
||||||
|
#define L2CAP_CREATE_CHAN_REFUSED_CONTROLLER (0x0005)
|
||||||
|
|
||||||
|
#define L2CAP_CREATE_CHAN_STATUS_NONE (0x0000)
|
||||||
|
#define L2CAP_CREATE_CHAN_STATUS_AUTHENTICATION (0x0001)
|
||||||
|
#define L2CAP_CREATE_CHAN_STATUS_AUTHORIZATION (0x0002)
|
||||||
|
|
||||||
|
struct l2cap_move_chan_req {
|
||||||
|
__le16 icid;
|
||||||
|
__u8 dest_amp_id;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct l2cap_move_chan_rsp {
|
||||||
|
__le16 icid;
|
||||||
|
__le16 result;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#define L2CAP_MOVE_CHAN_SUCCESS (0x0000)
|
||||||
|
#define L2CAP_MOVE_CHAN_PENDING (0x0001)
|
||||||
|
#define L2CAP_MOVE_CHAN_REFUSED_CONTROLLER (0x0002)
|
||||||
|
#define L2CAP_MOVE_CHAN_REFUSED_SAME_ID (0x0003)
|
||||||
|
#define L2CAP_MOVE_CHAN_REFUSED_CONFIG (0x0004)
|
||||||
|
#define L2CAP_MOVE_CHAN_REFUSED_COLLISION (0x0005)
|
||||||
|
#define L2CAP_MOVE_CHAN_REFUSED_NOT_ALLOWED (0x0006)
|
||||||
|
|
||||||
|
struct l2cap_move_chan_cfm {
|
||||||
|
__le16 icid;
|
||||||
|
__le16 result;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
#define L2CAP_MOVE_CHAN_CONFIRMED (0x0000)
|
||||||
|
#define L2CAP_MOVE_CHAN_UNCONFIRMED (0x0001)
|
||||||
|
|
||||||
|
struct l2cap_move_chan_cfm_rsp {
|
||||||
|
__le16 icid;
|
||||||
|
} __attribute__ ((packed));
|
||||||
|
|
||||||
|
struct l2cap_amp_signal_work {
|
||||||
|
struct work_struct work;
|
||||||
|
struct l2cap_cmd_hdr cmd;
|
||||||
|
struct l2cap_conn *conn;
|
||||||
|
struct sk_buff *skb;
|
||||||
|
u8 *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct l2cap_resegment_work {
|
||||||
|
struct work_struct work;
|
||||||
|
struct sock *sk;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct l2cap_logical_link_work {
|
||||||
|
struct work_struct work;
|
||||||
|
struct hci_chan *chan;
|
||||||
|
u8 status;
|
||||||
|
};
|
||||||
|
|
||||||
/* info type */
|
/* info type */
|
||||||
#define L2CAP_IT_CL_MTU 0x0001
|
#define L2CAP_IT_CL_MTU 0x0001
|
||||||
#define L2CAP_IT_FEAT_MASK 0x0002
|
#define L2CAP_IT_FEAT_MASK 0x0002
|
||||||
|
@ -337,6 +419,7 @@ struct l2cap_conn {
|
||||||
|
|
||||||
__u32 feat_mask;
|
__u32 feat_mask;
|
||||||
__u8 fc_mask;
|
__u8 fc_mask;
|
||||||
|
struct amp_mgr *mgr;
|
||||||
|
|
||||||
__u8 info_state;
|
__u8 info_state;
|
||||||
__u8 info_ident;
|
__u8 info_ident;
|
||||||
|
@ -413,6 +496,14 @@ struct l2cap_pinfo {
|
||||||
__u8 tx_state;
|
__u8 tx_state;
|
||||||
__u8 rx_state;
|
__u8 rx_state;
|
||||||
|
|
||||||
|
__u8 amp_id;
|
||||||
|
__u8 amp_move_id;
|
||||||
|
__u8 amp_move_state;
|
||||||
|
__u8 amp_move_role;
|
||||||
|
__u8 amp_move_cmd_ident;
|
||||||
|
__u16 amp_move_reqseq;
|
||||||
|
__u16 amp_move_event;
|
||||||
|
|
||||||
__u16 next_tx_seq;
|
__u16 next_tx_seq;
|
||||||
__u16 expected_ack_seq;
|
__u16 expected_ack_seq;
|
||||||
__u16 expected_tx_seq;
|
__u16 expected_tx_seq;
|
||||||
|
@ -434,6 +525,7 @@ struct l2cap_pinfo {
|
||||||
__u16 tx_win;
|
__u16 tx_win;
|
||||||
__u16 tx_win_max;
|
__u16 tx_win_max;
|
||||||
__u8 max_tx;
|
__u8 max_tx;
|
||||||
|
__u8 amp_pref;
|
||||||
__u16 remote_tx_win;
|
__u16 remote_tx_win;
|
||||||
__u8 remote_max_tx;
|
__u8 remote_max_tx;
|
||||||
__u8 extended_control;
|
__u8 extended_control;
|
||||||
|
@ -452,6 +544,8 @@ struct l2cap_pinfo {
|
||||||
struct sk_buff_head srej_queue;
|
struct sk_buff_head srej_queue;
|
||||||
struct l2cap_seq_list srej_list;
|
struct l2cap_seq_list srej_list;
|
||||||
struct l2cap_seq_list retrans_list;
|
struct l2cap_seq_list retrans_list;
|
||||||
|
struct hci_conn *ampcon;
|
||||||
|
struct hci_chan *ampchan;
|
||||||
struct l2cap_conn *conn;
|
struct l2cap_conn *conn;
|
||||||
struct sock *next_c;
|
struct sock *next_c;
|
||||||
struct sock *prev_c;
|
struct sock *prev_c;
|
||||||
|
@ -486,6 +580,10 @@ struct l2cap_pinfo {
|
||||||
|
|
||||||
#define L2CAP_ERTM_RX_STATE_RECV 0x01
|
#define L2CAP_ERTM_RX_STATE_RECV 0x01
|
||||||
#define L2CAP_ERTM_RX_STATE_SREJ_SENT 0x02
|
#define L2CAP_ERTM_RX_STATE_SREJ_SENT 0x02
|
||||||
|
#define L2CAP_ERTM_RX_STATE_AMP_MOVE 0x03
|
||||||
|
#define L2CAP_ERTM_RX_STATE_WAIT_P_FLAG 0x04
|
||||||
|
#define L2CAP_ERTM_RX_STATE_WAIT_P_FLAG_RECONFIGURE 0x05
|
||||||
|
#define L2CAP_ERTM_RX_STATE_WAIT_F_FLAG 0x06
|
||||||
|
|
||||||
#define L2CAP_ERTM_TXSEQ_EXPECTED 0x00
|
#define L2CAP_ERTM_TXSEQ_EXPECTED 0x00
|
||||||
#define L2CAP_ERTM_TXSEQ_EXPECTED_SREJ 0x01
|
#define L2CAP_ERTM_TXSEQ_EXPECTED_SREJ 0x01
|
||||||
|
@ -511,6 +609,24 @@ struct l2cap_pinfo {
|
||||||
#define L2CAP_ERTM_EVENT_RECV_SREJ 0x0d
|
#define L2CAP_ERTM_EVENT_RECV_SREJ 0x0d
|
||||||
#define L2CAP_ERTM_EVENT_RECV_FRAME 0x0e
|
#define L2CAP_ERTM_EVENT_RECV_FRAME 0x0e
|
||||||
|
|
||||||
|
#define L2CAP_AMP_MOVE_NONE 0
|
||||||
|
#define L2CAP_AMP_MOVE_INITIATOR 1
|
||||||
|
#define L2CAP_AMP_MOVE_RESPONDER 2
|
||||||
|
|
||||||
|
#define L2CAP_AMP_STATE_STABLE 0
|
||||||
|
#define L2CAP_AMP_STATE_WAIT_CREATE 1
|
||||||
|
#define L2CAP_AMP_STATE_WAIT_CREATE_RSP 2
|
||||||
|
#define L2CAP_AMP_STATE_WAIT_MOVE 3
|
||||||
|
#define L2CAP_AMP_STATE_WAIT_MOVE_RSP 4
|
||||||
|
#define L2CAP_AMP_STATE_WAIT_MOVE_RSP_SUCCESS 5
|
||||||
|
#define L2CAP_AMP_STATE_WAIT_MOVE_CONFIRM 6
|
||||||
|
#define L2CAP_AMP_STATE_WAIT_MOVE_CONFIRM_RSP 7
|
||||||
|
#define L2CAP_AMP_STATE_WAIT_LOGICAL_COMPLETE 8
|
||||||
|
#define L2CAP_AMP_STATE_WAIT_LOGICAL_CONFIRM 9
|
||||||
|
#define L2CAP_AMP_STATE_WAIT_LOCAL_BUSY 10
|
||||||
|
#define L2CAP_AMP_STATE_WAIT_PREPARE 11
|
||||||
|
#define L2CAP_AMP_STATE_RESEGMENT 12
|
||||||
|
|
||||||
#define __delta_seq(x, y, pi) ((x) >= (y) ? (x) - (y) : \
|
#define __delta_seq(x, y, pi) ((x) >= (y) ? (x) - (y) : \
|
||||||
(pi)->tx_win_max + 1 - (y) + (x))
|
(pi)->tx_win_max + 1 - (y) + (x))
|
||||||
#define __next_seq(x, pi) ((x + 1) & ((pi)->tx_win_max))
|
#define __next_seq(x, pi) ((x + 1) & ((pi)->tx_win_max))
|
||||||
|
|
|
@ -9,4 +9,5 @@ obj-$(CONFIG_BT_CMTP) += cmtp/
|
||||||
obj-$(CONFIG_BT_HIDP) += hidp/
|
obj-$(CONFIG_BT_HIDP) += hidp/
|
||||||
|
|
||||||
bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
|
bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
|
||||||
hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o
|
hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
|
||||||
|
amp.o
|
||||||
|
|
1962
net/bluetooth/amp.c
Normal file
1962
net/bluetooth/amp.c
Normal file
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -538,6 +538,12 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
|
||||||
err = -EFAULT;
|
err = -EFAULT;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case BT_AMP_POLICY:
|
||||||
|
if (put_user(l2cap_pi(sk)->amp_pref, (u32 __user *) optval))
|
||||||
|
err = -EFAULT;
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
err = -ENOPROTOOPT;
|
err = -ENOPROTOOPT;
|
||||||
break;
|
break;
|
||||||
|
@ -737,6 +743,31 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
|
||||||
l2cap_pi(sk)->force_active = pwr.force_active;
|
l2cap_pi(sk)->force_active = pwr.force_active;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case BT_AMP_POLICY:
|
||||||
|
if (get_user(opt, (u32 __user *) optval)) {
|
||||||
|
err = -EFAULT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((opt > BT_AMP_POLICY_PREFER_BR_EDR) ||
|
||||||
|
((l2cap_pi(sk)->mode != L2CAP_MODE_ERTM) &&
|
||||||
|
(l2cap_pi(sk)->mode != L2CAP_MODE_STREAMING))) {
|
||||||
|
err = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
l2cap_pi(sk)->amp_pref = (u8) opt;
|
||||||
|
BT_DBG("BT_AMP_POLICY now %d", opt);
|
||||||
|
|
||||||
|
if ((sk->sk_state == BT_CONNECTED) &&
|
||||||
|
(l2cap_pi(sk)->amp_move_role == L2CAP_AMP_MOVE_NONE) &&
|
||||||
|
(l2cap_pi(sk)->conn->fc_mask & L2CAP_FC_A2MP))
|
||||||
|
l2cap_amp_move_init(sk);
|
||||||
|
else
|
||||||
|
l2cap_pi(sk)->conn_state |= L2CAP_CONN_MOVE_PENDING;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
err = -ENOPROTOOPT;
|
err = -ENOPROTOOPT;
|
||||||
break;
|
break;
|
||||||
|
@ -753,6 +784,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
|
||||||
struct sk_buff *skb;
|
struct sk_buff *skb;
|
||||||
struct sk_buff_head seg_queue;
|
struct sk_buff_head seg_queue;
|
||||||
int err;
|
int err;
|
||||||
|
u8 amp_id;
|
||||||
|
|
||||||
BT_DBG("sock %p, sk %p", sock, sk);
|
BT_DBG("sock %p, sk %p", sock, sk);
|
||||||
|
|
||||||
|
@ -816,6 +848,7 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
|
||||||
* since it's possible to block while waiting for memory
|
* since it's possible to block while waiting for memory
|
||||||
* allocation.
|
* allocation.
|
||||||
*/
|
*/
|
||||||
|
amp_id = pi->amp_id;
|
||||||
err = l2cap_segment_sdu(sk, &seg_queue, msg, len, 0);
|
err = l2cap_segment_sdu(sk, &seg_queue, msg, len, 0);
|
||||||
|
|
||||||
/* The socket lock is released while segmenting, so check
|
/* The socket lock is released while segmenting, so check
|
||||||
|
@ -833,6 +866,14 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pi->amp_id != amp_id) {
|
||||||
|
/* Channel moved while unlocked. Resegment. */
|
||||||
|
err = l2cap_resegment_queue(sk, &seg_queue);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (pi->mode != L2CAP_MODE_STREAMING)
|
if (pi->mode != L2CAP_MODE_STREAMING)
|
||||||
err = l2cap_ertm_tx(sk, 0, &seg_queue,
|
err = l2cap_ertm_tx(sk, 0, &seg_queue,
|
||||||
L2CAP_ERTM_EVENT_DATA_REQUEST);
|
L2CAP_ERTM_EVENT_DATA_REQUEST);
|
||||||
|
@ -1086,6 +1127,7 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
|
||||||
pi->force_reliable = l2cap_pi(parent)->force_reliable;
|
pi->force_reliable = l2cap_pi(parent)->force_reliable;
|
||||||
pi->flushable = l2cap_pi(parent)->flushable;
|
pi->flushable = l2cap_pi(parent)->flushable;
|
||||||
pi->force_active = l2cap_pi(parent)->force_active;
|
pi->force_active = l2cap_pi(parent)->force_active;
|
||||||
|
pi->amp_pref = l2cap_pi(parent)->amp_pref;
|
||||||
} else {
|
} else {
|
||||||
pi->imtu = L2CAP_DEFAULT_MTU;
|
pi->imtu = L2CAP_DEFAULT_MTU;
|
||||||
pi->omtu = 0;
|
pi->omtu = 0;
|
||||||
|
@ -1103,10 +1145,13 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
|
||||||
pi->force_reliable = 0;
|
pi->force_reliable = 0;
|
||||||
pi->flushable = 0;
|
pi->flushable = 0;
|
||||||
pi->force_active = 1;
|
pi->force_active = 1;
|
||||||
|
pi->amp_pref = BT_AMP_POLICY_REQUIRE_BR_EDR;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Default config options */
|
/* Default config options */
|
||||||
sk->sk_backlog_rcv = l2cap_data_channel;
|
sk->sk_backlog_rcv = l2cap_data_channel;
|
||||||
|
pi->ampcon = NULL;
|
||||||
|
pi->ampchan = NULL;
|
||||||
pi->conf_len = 0;
|
pi->conf_len = 0;
|
||||||
pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
|
pi->flush_to = L2CAP_DEFAULT_FLUSH_TO;
|
||||||
pi->scid = 0;
|
pi->scid = 0;
|
||||||
|
|
Loading…
Reference in a new issue