forked from mirrors/linux
		
	Bluetooth: Remove BT_HS
High Speed, Alternate MAC and PHY (AMP) extension, has been removed from
Bluetooth Core specification on 5.3:
https://www.bluetooth.com/blog/new-core-specification-v5-3-feature-enhancements/
Fixes: 244bc37759 ("Bluetooth: Add BT_HS config option")
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
			
			
This commit is contained in:
		
							parent
							
								
									b79e040910
								
							
						
					
					
						commit
						e7b02296fb
					
				
					 13 changed files with 20 additions and 3056 deletions
				
			
		|  | @ -394,7 +394,6 @@ enum { | ||||||
| 	HCI_LIMITED_PRIVACY, | 	HCI_LIMITED_PRIVACY, | ||||||
| 	HCI_RPA_EXPIRED, | 	HCI_RPA_EXPIRED, | ||||||
| 	HCI_RPA_RESOLVING, | 	HCI_RPA_RESOLVING, | ||||||
| 	HCI_HS_ENABLED, |  | ||||||
| 	HCI_LE_ENABLED, | 	HCI_LE_ENABLED, | ||||||
| 	HCI_ADVERTISING, | 	HCI_ADVERTISING, | ||||||
| 	HCI_ADVERTISING_CONNECTABLE, | 	HCI_ADVERTISING_CONNECTABLE, | ||||||
|  |  | ||||||
|  | @ -59,8 +59,6 @@ | ||||||
| #define L2CAP_WAIT_ACK_POLL_PERIOD	msecs_to_jiffies(200) | #define L2CAP_WAIT_ACK_POLL_PERIOD	msecs_to_jiffies(200) | ||||||
| #define L2CAP_WAIT_ACK_TIMEOUT		msecs_to_jiffies(10000) | #define L2CAP_WAIT_ACK_TIMEOUT		msecs_to_jiffies(10000) | ||||||
| 
 | 
 | ||||||
| #define L2CAP_A2MP_DEFAULT_MTU		670 |  | ||||||
| 
 |  | ||||||
| /* L2CAP socket address */ | /* L2CAP socket address */ | ||||||
| struct sockaddr_l2 { | struct sockaddr_l2 { | ||||||
| 	sa_family_t	l2_family; | 	sa_family_t	l2_family; | ||||||
|  | @ -109,12 +107,6 @@ struct l2cap_conninfo { | ||||||
| #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 | ||||||
| #define L2CAP_LE_CONN_REQ	0x14 | #define L2CAP_LE_CONN_REQ	0x14 | ||||||
|  | @ -144,7 +136,6 @@ struct l2cap_conninfo { | ||||||
| /* L2CAP fixed channels */ | /* L2CAP fixed channels */ | ||||||
| #define L2CAP_FC_SIG_BREDR	0x02 | #define L2CAP_FC_SIG_BREDR	0x02 | ||||||
| #define L2CAP_FC_CONNLESS	0x04 | #define L2CAP_FC_CONNLESS	0x04 | ||||||
| #define L2CAP_FC_A2MP		0x08 |  | ||||||
| #define L2CAP_FC_ATT		0x10 | #define L2CAP_FC_ATT		0x10 | ||||||
| #define L2CAP_FC_SIG_LE		0x20 | #define L2CAP_FC_SIG_LE		0x20 | ||||||
| #define L2CAP_FC_SMP_LE		0x40 | #define L2CAP_FC_SMP_LE		0x40 | ||||||
|  | @ -267,7 +258,6 @@ struct l2cap_conn_rsp { | ||||||
| /* channel identifier */ | /* channel identifier */ | ||||||
| #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_ATT		0x0004 | #define L2CAP_CID_ATT		0x0004 | ||||||
| #define L2CAP_CID_LE_SIGNALING	0x0005 | #define L2CAP_CID_LE_SIGNALING	0x0005 | ||||||
| #define L2CAP_CID_SMP		0x0006 | #define L2CAP_CID_SMP		0x0006 | ||||||
|  | @ -282,7 +272,6 @@ struct l2cap_conn_rsp { | ||||||
| #define L2CAP_CR_BAD_PSM	0x0002 | #define L2CAP_CR_BAD_PSM	0x0002 | ||||||
| #define L2CAP_CR_SEC_BLOCK	0x0003 | #define L2CAP_CR_SEC_BLOCK	0x0003 | ||||||
| #define L2CAP_CR_NO_MEM		0x0004 | #define L2CAP_CR_NO_MEM		0x0004 | ||||||
| #define L2CAP_CR_BAD_AMP	0x0005 |  | ||||||
| #define L2CAP_CR_INVALID_SCID	0x0006 | #define L2CAP_CR_INVALID_SCID	0x0006 | ||||||
| #define L2CAP_CR_SCID_IN_USE	0x0007 | #define L2CAP_CR_SCID_IN_USE	0x0007 | ||||||
| 
 | 
 | ||||||
|  | @ -404,29 +393,6 @@ struct l2cap_info_rsp { | ||||||
| 	__u8        data[]; | 	__u8        data[]; | ||||||
| } __packed; | } __packed; | ||||||
| 
 | 
 | ||||||
| struct l2cap_create_chan_req { |  | ||||||
| 	__le16      psm; |  | ||||||
| 	__le16      scid; |  | ||||||
| 	__u8        amp_id; |  | ||||||
| } __packed; |  | ||||||
| 
 |  | ||||||
| struct l2cap_create_chan_rsp { |  | ||||||
| 	__le16      dcid; |  | ||||||
| 	__le16      scid; |  | ||||||
| 	__le16      result; |  | ||||||
| 	__le16      status; |  | ||||||
| } __packed; |  | ||||||
| 
 |  | ||||||
| struct l2cap_move_chan_req { |  | ||||||
| 	__le16      icid; |  | ||||||
| 	__u8        dest_amp_id; |  | ||||||
| } __packed; |  | ||||||
| 
 |  | ||||||
| struct l2cap_move_chan_rsp { |  | ||||||
| 	__le16      icid; |  | ||||||
| 	__le16      result; |  | ||||||
| } __packed; |  | ||||||
| 
 |  | ||||||
| #define L2CAP_MR_SUCCESS	0x0000 | #define L2CAP_MR_SUCCESS	0x0000 | ||||||
| #define L2CAP_MR_PEND		0x0001 | #define L2CAP_MR_PEND		0x0001 | ||||||
| #define L2CAP_MR_BAD_ID		0x0002 | #define L2CAP_MR_BAD_ID		0x0002 | ||||||
|  | @ -539,8 +505,6 @@ struct l2cap_seq_list { | ||||||
| 
 | 
 | ||||||
| struct l2cap_chan { | struct l2cap_chan { | ||||||
| 	struct l2cap_conn	*conn; | 	struct l2cap_conn	*conn; | ||||||
| 	struct hci_conn		*hs_hcon; |  | ||||||
| 	struct hci_chan		*hs_hchan; |  | ||||||
| 	struct kref	kref; | 	struct kref	kref; | ||||||
| 	atomic_t	nesting; | 	atomic_t	nesting; | ||||||
| 
 | 
 | ||||||
|  | @ -591,12 +555,6 @@ struct l2cap_chan { | ||||||
| 	unsigned long	conn_state; | 	unsigned long	conn_state; | ||||||
| 	unsigned long	flags; | 	unsigned long	flags; | ||||||
| 
 | 
 | ||||||
| 	__u8		remote_amp_id; |  | ||||||
| 	__u8		local_amp_id; |  | ||||||
| 	__u8		move_id; |  | ||||||
| 	__u8		move_state; |  | ||||||
| 	__u8		move_role; |  | ||||||
| 
 |  | ||||||
| 	__u16		next_tx_seq; | 	__u16		next_tx_seq; | ||||||
| 	__u16		expected_ack_seq; | 	__u16		expected_ack_seq; | ||||||
| 	__u16		expected_tx_seq; | 	__u16		expected_tx_seq; | ||||||
|  |  | ||||||
|  | @ -62,14 +62,6 @@ source "net/bluetooth/cmtp/Kconfig" | ||||||
| 
 | 
 | ||||||
| source "net/bluetooth/hidp/Kconfig" | source "net/bluetooth/hidp/Kconfig" | ||||||
| 
 | 
 | ||||||
| config BT_HS |  | ||||||
| 	bool "Bluetooth High Speed (HS) features" |  | ||||||
| 	depends on BT_BREDR |  | ||||||
| 	help |  | ||||||
| 	  Bluetooth High Speed includes support for off-loading |  | ||||||
| 	  Bluetooth connections via 802.11 (wifi) physical layer |  | ||||||
| 	  available with Bluetooth version 3.0 or later. |  | ||||||
| 
 |  | ||||||
| config BT_LE | config BT_LE | ||||||
| 	bool "Bluetooth Low Energy (LE) features" | 	bool "Bluetooth Low Energy (LE) features" | ||||||
| 	depends on BT | 	depends on BT | ||||||
|  |  | ||||||
|  | @ -21,7 +21,6 @@ bluetooth-$(CONFIG_DEV_COREDUMP) += coredump.o | ||||||
| 
 | 
 | ||||||
| bluetooth-$(CONFIG_BT_BREDR) += sco.o | bluetooth-$(CONFIG_BT_BREDR) += sco.o | ||||||
| bluetooth-$(CONFIG_BT_LE) += iso.o | bluetooth-$(CONFIG_BT_LE) += iso.o | ||||||
| bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o |  | ||||||
| bluetooth-$(CONFIG_BT_LEDS) += leds.o | bluetooth-$(CONFIG_BT_LEDS) += leds.o | ||||||
| bluetooth-$(CONFIG_BT_MSFTEXT) += msft.o | bluetooth-$(CONFIG_BT_MSFTEXT) += msft.o | ||||||
| bluetooth-$(CONFIG_BT_AOSPEXT) += aosp.o | bluetooth-$(CONFIG_BT_AOSPEXT) += aosp.o | ||||||
|  |  | ||||||
							
								
								
									
										1054
									
								
								net/bluetooth/a2mp.c
									
									
									
									
									
								
							
							
						
						
									
										1054
									
								
								net/bluetooth/a2mp.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -1,154 +0,0 @@ | ||||||
| /* SPDX-License-Identifier: GPL-2.0-only */ |  | ||||||
| /*
 |  | ||||||
|    Copyright (c) 2010,2011 Code Aurora Forum.  All rights reserved. |  | ||||||
|    Copyright (c) 2011,2012 Intel Corp. |  | ||||||
| 
 |  | ||||||
| */ |  | ||||||
| 
 |  | ||||||
| #ifndef __A2MP_H |  | ||||||
| #define __A2MP_H |  | ||||||
| 
 |  | ||||||
| #include <net/bluetooth/l2cap.h> |  | ||||||
| 
 |  | ||||||
| enum amp_mgr_state { |  | ||||||
| 	READ_LOC_AMP_INFO, |  | ||||||
| 	READ_LOC_AMP_ASSOC, |  | ||||||
| 	READ_LOC_AMP_ASSOC_FINAL, |  | ||||||
| 	WRITE_REMOTE_AMP_ASSOC, |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| 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; |  | ||||||
| 	unsigned long		state; |  | ||||||
| 	unsigned long		flags; |  | ||||||
| 
 |  | ||||||
| 	struct list_head	amp_ctrls; |  | ||||||
| 	struct mutex		amp_ctrls_lock; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| struct a2mp_cmd { |  | ||||||
| 	__u8	code; |  | ||||||
| 	__u8	ident; |  | ||||||
| 	__le16	len; |  | ||||||
| 	__u8	data[]; |  | ||||||
| } __packed; |  | ||||||
| 
 |  | ||||||
| /* A2MP command codes */ |  | ||||||
| #define A2MP_COMMAND_REJ         0x01 |  | ||||||
| struct a2mp_cmd_rej { |  | ||||||
| 	__le16	reason; |  | ||||||
| 	__u8	data[]; |  | ||||||
| } __packed; |  | ||||||
| 
 |  | ||||||
| #define A2MP_DISCOVER_REQ        0x02 |  | ||||||
| struct a2mp_discov_req { |  | ||||||
| 	__le16	mtu; |  | ||||||
| 	__le16	ext_feat; |  | ||||||
| } __packed; |  | ||||||
| 
 |  | ||||||
| struct a2mp_cl { |  | ||||||
| 	__u8	id; |  | ||||||
| 	__u8	type; |  | ||||||
| 	__u8	status; |  | ||||||
| } __packed; |  | ||||||
| 
 |  | ||||||
| #define A2MP_DISCOVER_RSP        0x03 |  | ||||||
| struct a2mp_discov_rsp { |  | ||||||
| 	__le16     mtu; |  | ||||||
| 	__le16     ext_feat; |  | ||||||
| 	struct a2mp_cl cl[]; |  | ||||||
| } __packed; |  | ||||||
| 
 |  | ||||||
| #define A2MP_CHANGE_NOTIFY       0x04 |  | ||||||
| #define A2MP_CHANGE_RSP          0x05 |  | ||||||
| 
 |  | ||||||
| #define A2MP_GETINFO_REQ         0x06 |  | ||||||
| struct a2mp_info_req { |  | ||||||
| 	__u8       id; |  | ||||||
| } __packed; |  | ||||||
| 
 |  | ||||||
| #define A2MP_GETINFO_RSP         0x07 |  | ||||||
| struct a2mp_info_rsp { |  | ||||||
| 	__u8	id; |  | ||||||
| 	__u8	status; |  | ||||||
| 	__le32	total_bw; |  | ||||||
| 	__le32	max_bw; |  | ||||||
| 	__le32	min_latency; |  | ||||||
| 	__le16	pal_cap; |  | ||||||
| 	__le16	assoc_size; |  | ||||||
| } __packed; |  | ||||||
| 
 |  | ||||||
| #define A2MP_GETAMPASSOC_REQ     0x08 |  | ||||||
| struct a2mp_amp_assoc_req { |  | ||||||
| 	__u8	id; |  | ||||||
| } __packed; |  | ||||||
| 
 |  | ||||||
| #define A2MP_GETAMPASSOC_RSP     0x09 |  | ||||||
| struct a2mp_amp_assoc_rsp { |  | ||||||
| 	__u8	id; |  | ||||||
| 	__u8	status; |  | ||||||
| 	__u8	amp_assoc[]; |  | ||||||
| } __packed; |  | ||||||
| 
 |  | ||||||
| #define A2MP_CREATEPHYSLINK_REQ  0x0A |  | ||||||
| #define A2MP_DISCONNPHYSLINK_REQ 0x0C |  | ||||||
| struct a2mp_physlink_req { |  | ||||||
| 	__u8	local_id; |  | ||||||
| 	__u8	remote_id; |  | ||||||
| 	__u8	amp_assoc[]; |  | ||||||
| } __packed; |  | ||||||
| 
 |  | ||||||
| #define A2MP_CREATEPHYSLINK_RSP  0x0B |  | ||||||
| #define A2MP_DISCONNPHYSLINK_RSP 0x0D |  | ||||||
| struct a2mp_physlink_rsp { |  | ||||||
| 	__u8	local_id; |  | ||||||
| 	__u8	remote_id; |  | ||||||
| 	__u8	status; |  | ||||||
| } __packed; |  | ||||||
| 
 |  | ||||||
| /* A2MP response status */ |  | ||||||
| #define A2MP_STATUS_SUCCESS			0x00 |  | ||||||
| #define A2MP_STATUS_INVALID_CTRL_ID		0x01 |  | ||||||
| #define A2MP_STATUS_UNABLE_START_LINK_CREATION	0x02 |  | ||||||
| #define A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS	0x02 |  | ||||||
| #define A2MP_STATUS_COLLISION_OCCURED		0x03 |  | ||||||
| #define A2MP_STATUS_DISCONN_REQ_RECVD		0x04 |  | ||||||
| #define A2MP_STATUS_PHYS_LINK_EXISTS		0x05 |  | ||||||
| #define A2MP_STATUS_SECURITY_VIOLATION		0x06 |  | ||||||
| 
 |  | ||||||
| struct amp_mgr *amp_mgr_get(struct amp_mgr *mgr); |  | ||||||
| 
 |  | ||||||
| #if IS_ENABLED(CONFIG_BT_HS) |  | ||||||
| int amp_mgr_put(struct amp_mgr *mgr); |  | ||||||
| struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn, |  | ||||||
| 				       struct sk_buff *skb); |  | ||||||
| void a2mp_discover_amp(struct l2cap_chan *chan); |  | ||||||
| #else |  | ||||||
| static inline int amp_mgr_put(struct amp_mgr *mgr) |  | ||||||
| { |  | ||||||
| 	return 0; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn, |  | ||||||
| 						     struct sk_buff *skb) |  | ||||||
| { |  | ||||||
| 	return NULL; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline void a2mp_discover_amp(struct l2cap_chan *chan) |  | ||||||
| { |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| 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); |  | ||||||
| void a2mp_send_create_phy_link_rsp(struct hci_dev *hdev, u8 status); |  | ||||||
| 
 |  | ||||||
| #endif /* __A2MP_H */ |  | ||||||
|  | @ -1,590 +0,0 @@ | ||||||
| // SPDX-License-Identifier: GPL-2.0-only
 |  | ||||||
| /*
 |  | ||||||
|    Copyright (c) 2011,2012 Intel Corp. |  | ||||||
| 
 |  | ||||||
| */ |  | ||||||
| 
 |  | ||||||
| #include <net/bluetooth/bluetooth.h> |  | ||||||
| #include <net/bluetooth/hci.h> |  | ||||||
| #include <net/bluetooth/hci_core.h> |  | ||||||
| #include <crypto/hash.h> |  | ||||||
| 
 |  | ||||||
| #include "hci_request.h" |  | ||||||
| #include "a2mp.h" |  | ||||||
| #include "amp.h" |  | ||||||
| 
 |  | ||||||
| /* Remote AMP Controllers interface */ |  | ||||||
| void amp_ctrl_get(struct amp_ctrl *ctrl) |  | ||||||
| { |  | ||||||
| 	BT_DBG("ctrl %p orig refcnt %d", ctrl, |  | ||||||
| 	       kref_read(&ctrl->kref)); |  | ||||||
| 
 |  | ||||||
| 	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, |  | ||||||
| 	       kref_read(&ctrl->kref)); |  | ||||||
| 
 |  | ||||||
| 	return kref_put(&ctrl->kref, &_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 %u", 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->hcon->dst; |  | ||||||
| 	struct hci_conn *hcon; |  | ||||||
| 	u8 role = out ? HCI_ROLE_MASTER : HCI_ROLE_SLAVE; |  | ||||||
| 
 |  | ||||||
| 	hcon = hci_conn_add(hdev, AMP_LINK, dst, role, __next_handle(mgr)); |  | ||||||
| 	if (!hcon) |  | ||||||
| 		return NULL; |  | ||||||
| 
 |  | ||||||
| 	BT_DBG("hcon %p dst %pMR", hcon, dst); |  | ||||||
| 
 |  | ||||||
| 	hcon->state = BT_CONNECT; |  | ||||||
| 	hcon->attempt++; |  | ||||||
| 	hcon->remote_id = remote_id; |  | ||||||
| 	hcon->amp_mgr = amp_mgr_get(mgr); |  | ||||||
| 
 |  | ||||||
| 	return hcon; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /* AMP crypto key generation interface */ |  | ||||||
| static int hmac_sha256(u8 *key, u8 ksize, char *plaintext, u8 psize, u8 *output) |  | ||||||
| { |  | ||||||
| 	struct crypto_shash *tfm; |  | ||||||
| 	struct shash_desc *shash; |  | ||||||
| 	int ret; |  | ||||||
| 
 |  | ||||||
| 	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); |  | ||||||
| 		goto failed; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	shash = kzalloc(sizeof(*shash) + crypto_shash_descsize(tfm), |  | ||||||
| 			GFP_KERNEL); |  | ||||||
| 	if (!shash) { |  | ||||||
| 		ret = -ENOMEM; |  | ||||||
| 		goto failed; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	shash->tfm = tfm; |  | ||||||
| 
 |  | ||||||
| 	ret = crypto_shash_digest(shash, plaintext, psize, output); |  | ||||||
| 
 |  | ||||||
| 	kfree(shash); |  | ||||||
| 
 |  | ||||||
| failed: |  | ||||||
| 	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_dev_err(hdev, "legacy key type %u", 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_dev_err(hdev, "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); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void read_local_amp_assoc_complete(struct hci_dev *hdev, u8 status, |  | ||||||
| 					  u16 opcode, 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 send_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; |  | ||||||
| 
 |  | ||||||
| send_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); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 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; |  | ||||||
| 	struct hci_request req; |  | ||||||
| 	int err; |  | ||||||
| 
 |  | ||||||
| 	BT_DBG("%s handle %u", 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_req_init(&req, hdev); |  | ||||||
| 	hci_req_add(&req, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); |  | ||||||
| 	err = hci_req_run_skb(&req, read_local_amp_assoc_complete); |  | ||||||
| 	if (err < 0) |  | ||||||
| 		a2mp_send_getampassoc_rsp(hdev, A2MP_STATUS_INVALID_CTRL_ID); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr) |  | ||||||
| { |  | ||||||
| 	struct hci_cp_read_local_amp_assoc cp; |  | ||||||
| 	struct hci_request req; |  | ||||||
| 	int err; |  | ||||||
| 
 |  | ||||||
| 	memset(&hdev->loc_assoc, 0, sizeof(struct amp_assoc)); |  | ||||||
| 	memset(&cp, 0, sizeof(cp)); |  | ||||||
| 
 |  | ||||||
| 	cp.max_len = cpu_to_le16(hdev->amp_assoc_size); |  | ||||||
| 
 |  | ||||||
| 	set_bit(READ_LOC_AMP_ASSOC, &mgr->state); |  | ||||||
| 	hci_req_init(&req, hdev); |  | ||||||
| 	hci_req_add(&req, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); |  | ||||||
| 	err = hci_req_run_skb(&req, read_local_amp_assoc_complete); |  | ||||||
| 	if (err < 0) |  | ||||||
| 		a2mp_send_getampassoc_rsp(hdev, A2MP_STATUS_INVALID_CTRL_ID); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 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; |  | ||||||
| 	struct hci_request req; |  | ||||||
| 	int err; |  | ||||||
| 
 |  | ||||||
| 	if (!mgr) |  | ||||||
| 		return; |  | ||||||
| 
 |  | ||||||
| 	cp.phy_handle = hcon->handle; |  | ||||||
| 	cp.len_so_far = cpu_to_le16(0); |  | ||||||
| 	cp.max_len = cpu_to_le16(hdev->amp_assoc_size); |  | ||||||
| 
 |  | ||||||
| 	set_bit(READ_LOC_AMP_ASSOC_FINAL, &mgr->state); |  | ||||||
| 
 |  | ||||||
| 	/* Read Local AMP Assoc final link information data */ |  | ||||||
| 	hci_req_init(&req, hdev); |  | ||||||
| 	hci_req_add(&req, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp); |  | ||||||
| 	err = hci_req_run_skb(&req, read_local_amp_assoc_complete); |  | ||||||
| 	if (err < 0) |  | ||||||
| 		a2mp_send_getampassoc_rsp(hdev, A2MP_STATUS_INVALID_CTRL_ID); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void write_remote_amp_assoc_complete(struct hci_dev *hdev, u8 status, |  | ||||||
| 					    u16 opcode, 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); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /* 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; |  | ||||||
| 	struct hci_request req; |  | ||||||
| 	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_req_init(&req, hdev); |  | ||||||
| 	hci_req_add(&req, HCI_OP_WRITE_REMOTE_AMP_ASSOC, len, cp); |  | ||||||
| 	hci_req_run_skb(&req, write_remote_amp_assoc_complete); |  | ||||||
| 
 |  | ||||||
| 	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; |  | ||||||
| 
 |  | ||||||
| 	/* Send A2MP create phylink rsp when all fragments are written */ |  | ||||||
| 	if (amp_write_rem_assoc_frag(hdev, hcon)) |  | ||||||
| 		a2mp_send_create_phy_link_rsp(hdev, 0); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 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); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void create_phylink_complete(struct hci_dev *hdev, u8 status, |  | ||||||
| 				    u16 opcode) |  | ||||||
| { |  | ||||||
| 	struct hci_cp_create_phy_link *cp; |  | ||||||
| 
 |  | ||||||
| 	BT_DBG("%s status 0x%2.2x", hdev->name, status); |  | ||||||
| 
 |  | ||||||
| 	cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_PHY_LINK); |  | ||||||
| 	if (!cp) |  | ||||||
| 		return; |  | ||||||
| 
 |  | ||||||
| 	hci_dev_lock(hdev); |  | ||||||
| 
 |  | ||||||
| 	if (status) { |  | ||||||
| 		struct hci_conn *hcon; |  | ||||||
| 
 |  | ||||||
| 		hcon = hci_conn_hash_lookup_handle(hdev, cp->phy_handle); |  | ||||||
| 		if (hcon) |  | ||||||
| 			hci_conn_del(hcon); |  | ||||||
| 	} else { |  | ||||||
| 		amp_write_remote_assoc(hdev, cp->phy_handle); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	hci_dev_unlock(hdev); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void amp_create_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, |  | ||||||
| 			struct hci_conn *hcon) |  | ||||||
| { |  | ||||||
| 	struct hci_cp_create_phy_link cp; |  | ||||||
| 	struct hci_request req; |  | ||||||
| 
 |  | ||||||
| 	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_req_init(&req, hdev); |  | ||||||
| 	hci_req_add(&req, HCI_OP_CREATE_PHY_LINK, sizeof(cp), &cp); |  | ||||||
| 	hci_req_run(&req, create_phylink_complete); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void accept_phylink_complete(struct hci_dev *hdev, u8 status, |  | ||||||
| 				    u16 opcode) |  | ||||||
| { |  | ||||||
| 	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); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr, |  | ||||||
| 			struct hci_conn *hcon) |  | ||||||
| { |  | ||||||
| 	struct hci_cp_accept_phy_link cp; |  | ||||||
| 	struct hci_request req; |  | ||||||
| 
 |  | ||||||
| 	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_req_init(&req, hdev); |  | ||||||
| 	hci_req_add(&req, HCI_OP_ACCEPT_PHY_LINK, sizeof(cp), &cp); |  | ||||||
| 	hci_req_run(&req, accept_phylink_complete); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon) |  | ||||||
| { |  | ||||||
| 	struct hci_dev *bredr_hdev = hci_dev_hold(bredr_hcon->hdev); |  | ||||||
| 	struct amp_mgr *mgr = hs_hcon->amp_mgr; |  | ||||||
| 	struct l2cap_chan *bredr_chan; |  | ||||||
| 
 |  | ||||||
| 	BT_DBG("bredr_hcon %p hs_hcon %p mgr %p", bredr_hcon, hs_hcon, mgr); |  | ||||||
| 
 |  | ||||||
| 	if (!bredr_hdev || !mgr || !mgr->bredr_chan) |  | ||||||
| 		return; |  | ||||||
| 
 |  | ||||||
| 	bredr_chan = mgr->bredr_chan; |  | ||||||
| 
 |  | ||||||
| 	l2cap_chan_lock(bredr_chan); |  | ||||||
| 
 |  | ||||||
| 	set_bit(FLAG_EFS_ENABLE, &bredr_chan->flags); |  | ||||||
| 	bredr_chan->remote_amp_id = hs_hcon->remote_id; |  | ||||||
| 	bredr_chan->local_amp_id = hs_hcon->hdev->id; |  | ||||||
| 	bredr_chan->hs_hcon = hs_hcon; |  | ||||||
| 	bredr_chan->conn->mtu = hs_hcon->hdev->block_mtu; |  | ||||||
| 
 |  | ||||||
| 	__l2cap_physical_cfm(bredr_chan, 0); |  | ||||||
| 
 |  | ||||||
| 	l2cap_chan_unlock(bredr_chan); |  | ||||||
| 
 |  | ||||||
| 	hci_dev_put(bredr_hdev); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void amp_create_logical_link(struct l2cap_chan *chan) |  | ||||||
| { |  | ||||||
| 	struct hci_conn *hs_hcon = chan->hs_hcon; |  | ||||||
| 	struct hci_cp_create_accept_logical_link cp; |  | ||||||
| 	struct hci_dev *hdev; |  | ||||||
| 
 |  | ||||||
| 	BT_DBG("chan %p hs_hcon %p dst %pMR", chan, hs_hcon, |  | ||||||
| 	       &chan->conn->hcon->dst); |  | ||||||
| 
 |  | ||||||
| 	if (!hs_hcon) |  | ||||||
| 		return; |  | ||||||
| 
 |  | ||||||
| 	hdev = hci_dev_hold(chan->hs_hcon->hdev); |  | ||||||
| 	if (!hdev) |  | ||||||
| 		return; |  | ||||||
| 
 |  | ||||||
| 	cp.phy_handle = hs_hcon->handle; |  | ||||||
| 
 |  | ||||||
| 	cp.tx_flow_spec.id = chan->local_id; |  | ||||||
| 	cp.tx_flow_spec.stype = chan->local_stype; |  | ||||||
| 	cp.tx_flow_spec.msdu = cpu_to_le16(chan->local_msdu); |  | ||||||
| 	cp.tx_flow_spec.sdu_itime = cpu_to_le32(chan->local_sdu_itime); |  | ||||||
| 	cp.tx_flow_spec.acc_lat = cpu_to_le32(chan->local_acc_lat); |  | ||||||
| 	cp.tx_flow_spec.flush_to = cpu_to_le32(chan->local_flush_to); |  | ||||||
| 
 |  | ||||||
| 	cp.rx_flow_spec.id = chan->remote_id; |  | ||||||
| 	cp.rx_flow_spec.stype = chan->remote_stype; |  | ||||||
| 	cp.rx_flow_spec.msdu = cpu_to_le16(chan->remote_msdu); |  | ||||||
| 	cp.rx_flow_spec.sdu_itime = cpu_to_le32(chan->remote_sdu_itime); |  | ||||||
| 	cp.rx_flow_spec.acc_lat = cpu_to_le32(chan->remote_acc_lat); |  | ||||||
| 	cp.rx_flow_spec.flush_to = cpu_to_le32(chan->remote_flush_to); |  | ||||||
| 
 |  | ||||||
| 	if (hs_hcon->out) |  | ||||||
| 		hci_send_cmd(hdev, HCI_OP_CREATE_LOGICAL_LINK, sizeof(cp), |  | ||||||
| 			     &cp); |  | ||||||
| 	else |  | ||||||
| 		hci_send_cmd(hdev, HCI_OP_ACCEPT_LOGICAL_LINK, sizeof(cp), |  | ||||||
| 			     &cp); |  | ||||||
| 
 |  | ||||||
| 	hci_dev_put(hdev); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void amp_disconnect_logical_link(struct hci_chan *hchan) |  | ||||||
| { |  | ||||||
| 	struct hci_conn *hcon = hchan->conn; |  | ||||||
| 	struct hci_cp_disconn_logical_link cp; |  | ||||||
| 
 |  | ||||||
| 	if (hcon->state != BT_CONNECTED) { |  | ||||||
| 		BT_DBG("hchan %p not connected", hchan); |  | ||||||
| 		return; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	cp.log_handle = cpu_to_le16(hchan->handle); |  | ||||||
| 	hci_send_cmd(hcon->hdev, HCI_OP_DISCONN_LOGICAL_LINK, sizeof(cp), &cp); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void amp_destroy_logical_link(struct hci_chan *hchan, u8 reason) |  | ||||||
| { |  | ||||||
| 	BT_DBG("hchan %p", hchan); |  | ||||||
| 
 |  | ||||||
| 	hci_chan_del(hchan); |  | ||||||
| } |  | ||||||
|  | @ -1,60 +0,0 @@ | ||||||
| /* SPDX-License-Identifier: GPL-2.0-only */ |  | ||||||
| /*
 |  | ||||||
|    Copyright (c) 2011,2012 Intel Corp. |  | ||||||
| 
 |  | ||||||
| */ |  | ||||||
| 
 |  | ||||||
| #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_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); |  | ||||||
| 
 |  | ||||||
| #if IS_ENABLED(CONFIG_BT_HS) |  | ||||||
| void amp_create_logical_link(struct l2cap_chan *chan); |  | ||||||
| void amp_disconnect_logical_link(struct hci_chan *hchan); |  | ||||||
| #else |  | ||||||
| static inline void amp_create_logical_link(struct l2cap_chan *chan) |  | ||||||
| { |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static inline void amp_disconnect_logical_link(struct hci_chan *hchan) |  | ||||||
| { |  | ||||||
| } |  | ||||||
| #endif |  | ||||||
| 
 |  | ||||||
| void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle); |  | ||||||
| void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle); |  | ||||||
| void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon); |  | ||||||
| void amp_create_logical_link(struct l2cap_chan *chan); |  | ||||||
| void amp_disconnect_logical_link(struct hci_chan *hchan); |  | ||||||
| void amp_destroy_logical_link(struct hci_chan *hchan, u8 reason); |  | ||||||
| 
 |  | ||||||
| #endif /* __AMP_H */ |  | ||||||
|  | @ -36,7 +36,6 @@ | ||||||
| 
 | 
 | ||||||
| #include "hci_request.h" | #include "hci_request.h" | ||||||
| #include "smp.h" | #include "smp.h" | ||||||
| #include "a2mp.h" |  | ||||||
| #include "eir.h" | #include "eir.h" | ||||||
| 
 | 
 | ||||||
| struct sco_param { | struct sco_param { | ||||||
|  | @ -1175,9 +1174,6 @@ void hci_conn_del(struct hci_conn *conn) | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (conn->amp_mgr) |  | ||||||
| 		amp_mgr_put(conn->amp_mgr); |  | ||||||
| 
 |  | ||||||
| 	skb_queue_purge(&conn->data_q); | 	skb_queue_purge(&conn->data_q); | ||||||
| 
 | 
 | ||||||
| 	/* Remove the connection from the list and cleanup its remaining
 | 	/* Remove the connection from the list and cleanup its remaining
 | ||||||
|  |  | ||||||
|  | @ -36,8 +36,6 @@ | ||||||
| #include "hci_request.h" | #include "hci_request.h" | ||||||
| #include "hci_debugfs.h" | #include "hci_debugfs.h" | ||||||
| #include "hci_codec.h" | #include "hci_codec.h" | ||||||
| #include "a2mp.h" |  | ||||||
| #include "amp.h" |  | ||||||
| #include "smp.h" | #include "smp.h" | ||||||
| #include "msft.h" | #include "msft.h" | ||||||
| #include "eir.h" | #include "eir.h" | ||||||
|  |  | ||||||
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -1027,23 +1027,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, | ||||||
| 			break; | 			break; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (opt > BT_CHANNEL_POLICY_AMP_PREFERRED) { | 		err = -EOPNOTSUPP; | ||||||
| 			err = -EINVAL; |  | ||||||
| 			break; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		if (chan->mode != L2CAP_MODE_ERTM && |  | ||||||
| 		    chan->mode != L2CAP_MODE_STREAMING) { |  | ||||||
| 			err = -EOPNOTSUPP; |  | ||||||
| 			break; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		chan->chan_policy = (u8) opt; |  | ||||||
| 
 |  | ||||||
| 		if (sk->sk_state == BT_CONNECTED && |  | ||||||
| 		    chan->move_role == L2CAP_MOVE_ROLE_NONE) |  | ||||||
| 			l2cap_move_start(chan); |  | ||||||
| 
 |  | ||||||
| 		break; | 		break; | ||||||
| 
 | 
 | ||||||
| 	case BT_SNDMTU: | 	case BT_SNDMTU: | ||||||
|  |  | ||||||
|  | @ -835,8 +835,6 @@ static u32 get_supported_settings(struct hci_dev *hdev) | ||||||
| 
 | 
 | ||||||
| 		if (lmp_ssp_capable(hdev)) { | 		if (lmp_ssp_capable(hdev)) { | ||||||
| 			settings |= MGMT_SETTING_SSP; | 			settings |= MGMT_SETTING_SSP; | ||||||
| 			if (IS_ENABLED(CONFIG_BT_HS)) |  | ||||||
| 				settings |= MGMT_SETTING_HS; |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if (lmp_sc_capable(hdev)) | 		if (lmp_sc_capable(hdev)) | ||||||
|  | @ -901,9 +899,6 @@ static u32 get_current_settings(struct hci_dev *hdev) | ||||||
| 	if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) | 	if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) | ||||||
| 		settings |= MGMT_SETTING_SSP; | 		settings |= MGMT_SETTING_SSP; | ||||||
| 
 | 
 | ||||||
| 	if (hci_dev_test_flag(hdev, HCI_HS_ENABLED)) |  | ||||||
| 		settings |= MGMT_SETTING_HS; |  | ||||||
| 
 |  | ||||||
| 	if (hci_dev_test_flag(hdev, HCI_ADVERTISING)) | 	if (hci_dev_test_flag(hdev, HCI_ADVERTISING)) | ||||||
| 		settings |= MGMT_SETTING_ADVERTISING; | 		settings |= MGMT_SETTING_ADVERTISING; | ||||||
| 
 | 
 | ||||||
|  | @ -1938,7 +1933,6 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err) | ||||||
| 
 | 
 | ||||||
| 		if (enable && hci_dev_test_and_clear_flag(hdev, | 		if (enable && hci_dev_test_and_clear_flag(hdev, | ||||||
| 							  HCI_SSP_ENABLED)) { | 							  HCI_SSP_ENABLED)) { | ||||||
| 			hci_dev_clear_flag(hdev, HCI_HS_ENABLED); |  | ||||||
| 			new_settings(hdev, NULL); | 			new_settings(hdev, NULL); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | @ -1951,12 +1945,6 @@ static void set_ssp_complete(struct hci_dev *hdev, void *data, int err) | ||||||
| 		changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED); | 		changed = !hci_dev_test_and_set_flag(hdev, HCI_SSP_ENABLED); | ||||||
| 	} else { | 	} else { | ||||||
| 		changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED); | 		changed = hci_dev_test_and_clear_flag(hdev, HCI_SSP_ENABLED); | ||||||
| 
 |  | ||||||
| 		if (!changed) |  | ||||||
| 			changed = hci_dev_test_and_clear_flag(hdev, |  | ||||||
| 							      HCI_HS_ENABLED); |  | ||||||
| 		else |  | ||||||
| 			hci_dev_clear_flag(hdev, HCI_HS_ENABLED); |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match); | 	mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match); | ||||||
|  | @ -2020,11 +2008,6 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) | ||||||
| 		} else { | 		} else { | ||||||
| 			changed = hci_dev_test_and_clear_flag(hdev, | 			changed = hci_dev_test_and_clear_flag(hdev, | ||||||
| 							      HCI_SSP_ENABLED); | 							      HCI_SSP_ENABLED); | ||||||
| 			if (!changed) |  | ||||||
| 				changed = hci_dev_test_and_clear_flag(hdev, |  | ||||||
| 								      HCI_HS_ENABLED); |  | ||||||
| 			else |  | ||||||
| 				hci_dev_clear_flag(hdev, HCI_HS_ENABLED); |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev); | 		err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev); | ||||||
|  | @ -2070,63 +2053,10 @@ static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) | ||||||
| 
 | 
 | ||||||
| static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) | static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) | ||||||
| { | { | ||||||
| 	struct mgmt_mode *cp = data; |  | ||||||
| 	bool changed; |  | ||||||
| 	u8 status; |  | ||||||
| 	int err; |  | ||||||
| 
 |  | ||||||
| 	bt_dev_dbg(hdev, "sock %p", sk); | 	bt_dev_dbg(hdev, "sock %p", sk); | ||||||
| 
 | 
 | ||||||
| 	if (!IS_ENABLED(CONFIG_BT_HS)) | 	return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, | ||||||
| 		return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, |  | ||||||
| 				       MGMT_STATUS_NOT_SUPPORTED); | 				       MGMT_STATUS_NOT_SUPPORTED); | ||||||
| 
 |  | ||||||
| 	status = mgmt_bredr_support(hdev); |  | ||||||
| 	if (status) |  | ||||||
| 		return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status); |  | ||||||
| 
 |  | ||||||
| 	if (!lmp_ssp_capable(hdev)) |  | ||||||
| 		return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, |  | ||||||
| 				       MGMT_STATUS_NOT_SUPPORTED); |  | ||||||
| 
 |  | ||||||
| 	if (!hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) |  | ||||||
| 		return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, |  | ||||||
| 				       MGMT_STATUS_REJECTED); |  | ||||||
| 
 |  | ||||||
| 	if (cp->val != 0x00 && cp->val != 0x01) |  | ||||||
| 		return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, |  | ||||||
| 				       MGMT_STATUS_INVALID_PARAMS); |  | ||||||
| 
 |  | ||||||
| 	hci_dev_lock(hdev); |  | ||||||
| 
 |  | ||||||
| 	if (pending_find(MGMT_OP_SET_SSP, hdev)) { |  | ||||||
| 		err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, |  | ||||||
| 				      MGMT_STATUS_BUSY); |  | ||||||
| 		goto unlock; |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if (cp->val) { |  | ||||||
| 		changed = !hci_dev_test_and_set_flag(hdev, HCI_HS_ENABLED); |  | ||||||
| 	} else { |  | ||||||
| 		if (hdev_is_powered(hdev)) { |  | ||||||
| 			err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_HS, |  | ||||||
| 					      MGMT_STATUS_REJECTED); |  | ||||||
| 			goto unlock; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		changed = hci_dev_test_and_clear_flag(hdev, HCI_HS_ENABLED); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev); |  | ||||||
| 	if (err < 0) |  | ||||||
| 		goto unlock; |  | ||||||
| 
 |  | ||||||
| 	if (changed) |  | ||||||
| 		err = new_settings(hdev, sk); |  | ||||||
| 
 |  | ||||||
| unlock: |  | ||||||
| 	hci_dev_unlock(hdev); |  | ||||||
| 	return err; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void set_le_complete(struct hci_dev *hdev, void *data, int err) | static void set_le_complete(struct hci_dev *hdev, void *data, int err) | ||||||
|  | @ -6774,7 +6704,6 @@ static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) | ||||||
| 			hci_dev_clear_flag(hdev, HCI_SSP_ENABLED); | 			hci_dev_clear_flag(hdev, HCI_SSP_ENABLED); | ||||||
| 			hci_dev_clear_flag(hdev, HCI_LINK_SECURITY); | 			hci_dev_clear_flag(hdev, HCI_LINK_SECURITY); | ||||||
| 			hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE); | 			hci_dev_clear_flag(hdev, HCI_FAST_CONNECTABLE); | ||||||
| 			hci_dev_clear_flag(hdev, HCI_HS_ENABLED); |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		hci_dev_change_flag(hdev, HCI_BREDR_ENABLED); | 		hci_dev_change_flag(hdev, HCI_BREDR_ENABLED); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Luiz Augusto von Dentz
						Luiz Augusto von Dentz