mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	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