forked from mirrors/linux
		
	Bluetooth: Add BTPROTO_ISO socket type
This introduces a new socket type BTPROTO_ISO which can be enabled with use of ISO Socket experiemental UUID, it can used to initiate/accept connections and transfer packets between userspace and kernel similarly to how BTPROTO_SCO works: Central -> uses connect with address set to destination bdaddr: > tools/isotest -s 00:AA:01:00:00:00 Peripheral -> uses listen: > tools/isotest -d Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This commit is contained in:
		
							parent
							
								
									26afbd826e
								
							
						
					
					
						commit
						ccf74f2390
					
				
					 8 changed files with 1636 additions and 5 deletions
				
			
		|  | @ -590,6 +590,27 @@ static inline void sco_exit(void) | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #if IS_ENABLED(CONFIG_BT_LE) | ||||||
|  | int iso_init(void); | ||||||
|  | int iso_exit(void); | ||||||
|  | bool iso_enabled(void); | ||||||
|  | #else | ||||||
|  | static inline int iso_init(void) | ||||||
|  | { | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline int iso_exit(void) | ||||||
|  | { | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static inline bool iso_enabled(void) | ||||||
|  | { | ||||||
|  | 	return false; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| int mgmt_init(void); | int mgmt_init(void); | ||||||
| void mgmt_exit(void); | void mgmt_exit(void); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -843,6 +843,21 @@ static inline void sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb) | ||||||
| } | } | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #if IS_ENABLED(CONFIG_BT_LE) | ||||||
|  | int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 *flags); | ||||||
|  | void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, u16 flags); | ||||||
|  | #else | ||||||
|  | static inline int iso_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, | ||||||
|  | 				  __u8 *flags) | ||||||
|  | { | ||||||
|  | 	return 0; | ||||||
|  | } | ||||||
|  | static inline void iso_recv(struct hci_conn *hcon, struct sk_buff *skb, | ||||||
|  | 			    u16 flags) | ||||||
|  | { | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| /* ----- Inquiry cache ----- */ | /* ----- Inquiry cache ----- */ | ||||||
| #define INQUIRY_CACHE_AGE_MAX   (HZ*30)   /* 30 seconds */ | #define INQUIRY_CACHE_AGE_MAX   (HZ*30)   /* 30 seconds */ | ||||||
| #define INQUIRY_ENTRY_AGE_MAX   (HZ*60)   /* 60 seconds */ | #define INQUIRY_ENTRY_AGE_MAX   (HZ*60)   /* 60 seconds */ | ||||||
|  | @ -1640,8 +1655,7 @@ static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, | ||||||
| 		return sco_connect_ind(hdev, bdaddr, flags); | 		return sco_connect_ind(hdev, bdaddr, flags); | ||||||
| 
 | 
 | ||||||
| 	case ISO_LINK: | 	case ISO_LINK: | ||||||
| 		/* TODO: Handle connection indication */ | 		return iso_connect_ind(hdev, bdaddr, flags); | ||||||
| 		return -EINVAL; |  | ||||||
| 
 | 
 | ||||||
| 	default: | 	default: | ||||||
| 		BT_ERR("unknown link type %d", type); | 		BT_ERR("unknown link type %d", type); | ||||||
|  |  | ||||||
							
								
								
									
										21
									
								
								include/net/bluetooth/iso.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								include/net/bluetooth/iso.h
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,21 @@ | ||||||
|  | /* SPDX-License-Identifier: GPL-2.0 */ | ||||||
|  | /*
 | ||||||
|  |  * BlueZ - Bluetooth protocol stack for Linux | ||||||
|  |  * | ||||||
|  |  * Copyright (C) 2022 Intel Corporation | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #ifndef __ISO_H | ||||||
|  | #define __ISO_H | ||||||
|  | 
 | ||||||
|  | /* ISO defaults */ | ||||||
|  | #define ISO_DEFAULT_MTU		251 | ||||||
|  | 
 | ||||||
|  | /* ISO socket address */ | ||||||
|  | struct sockaddr_iso { | ||||||
|  | 	sa_family_t	iso_family; | ||||||
|  | 	bdaddr_t	iso_bdaddr; | ||||||
|  | 	__u8		iso_bdaddr_type; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #endif /* __ISO_H */ | ||||||
|  | @ -18,6 +18,7 @@ bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \ | ||||||
| 	eir.o hci_sync.o | 	eir.o hci_sync.o | ||||||
| 
 | 
 | ||||||
| bluetooth-$(CONFIG_BT_BREDR) += sco.o | bluetooth-$(CONFIG_BT_BREDR) += sco.o | ||||||
|  | bluetooth-$(CONFIG_BT_LE) += iso.o | ||||||
| bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.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 | ||||||
|  |  | ||||||
|  | @ -38,7 +38,7 @@ | ||||||
| #include "selftest.h" | #include "selftest.h" | ||||||
| 
 | 
 | ||||||
| /* Bluetooth sockets */ | /* Bluetooth sockets */ | ||||||
| #define BT_MAX_PROTO	8 | #define BT_MAX_PROTO	(BTPROTO_LAST + 1) | ||||||
| static const struct net_proto_family *bt_proto[BT_MAX_PROTO]; | static const struct net_proto_family *bt_proto[BT_MAX_PROTO]; | ||||||
| static DEFINE_RWLOCK(bt_proto_lock); | static DEFINE_RWLOCK(bt_proto_lock); | ||||||
| 
 | 
 | ||||||
|  | @ -52,6 +52,7 @@ static const char *const bt_key_strings[BT_MAX_PROTO] = { | ||||||
| 	"sk_lock-AF_BLUETOOTH-BTPROTO_CMTP", | 	"sk_lock-AF_BLUETOOTH-BTPROTO_CMTP", | ||||||
| 	"sk_lock-AF_BLUETOOTH-BTPROTO_HIDP", | 	"sk_lock-AF_BLUETOOTH-BTPROTO_HIDP", | ||||||
| 	"sk_lock-AF_BLUETOOTH-BTPROTO_AVDTP", | 	"sk_lock-AF_BLUETOOTH-BTPROTO_AVDTP", | ||||||
|  | 	"sk_lock-AF_BLUETOOTH-BTPROTO_ISO", | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| static struct lock_class_key bt_slock_key[BT_MAX_PROTO]; | static struct lock_class_key bt_slock_key[BT_MAX_PROTO]; | ||||||
|  | @ -64,6 +65,7 @@ static const char *const bt_slock_key_strings[BT_MAX_PROTO] = { | ||||||
| 	"slock-AF_BLUETOOTH-BTPROTO_CMTP", | 	"slock-AF_BLUETOOTH-BTPROTO_CMTP", | ||||||
| 	"slock-AF_BLUETOOTH-BTPROTO_HIDP", | 	"slock-AF_BLUETOOTH-BTPROTO_HIDP", | ||||||
| 	"slock-AF_BLUETOOTH-BTPROTO_AVDTP", | 	"slock-AF_BLUETOOTH-BTPROTO_AVDTP", | ||||||
|  | 	"slock-AF_BLUETOOTH-BTPROTO_ISO", | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| void bt_sock_reclassify_lock(struct sock *sk, int proto) | void bt_sock_reclassify_lock(struct sock *sk, int proto) | ||||||
|  |  | ||||||
|  | @ -3822,12 +3822,16 @@ static void hci_isodata_packet(struct hci_dev *hdev, struct sk_buff *skb) | ||||||
| 	conn = hci_conn_hash_lookup_handle(hdev, handle); | 	conn = hci_conn_hash_lookup_handle(hdev, handle); | ||||||
| 	hci_dev_unlock(hdev); | 	hci_dev_unlock(hdev); | ||||||
| 
 | 
 | ||||||
| 	/* TODO: Send to upper protocol */ |  | ||||||
| 	if (!conn) { | 	if (!conn) { | ||||||
| 		bt_dev_err(hdev, "ISO packet for unknown connection handle %d", | 		bt_dev_err(hdev, "ISO packet for unknown connection handle %d", | ||||||
| 			   handle); | 			   handle); | ||||||
|  | 		goto drop; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/* Send to upper protocol */ | ||||||
|  | 	iso_recv(conn, skb, flags); | ||||||
|  | 	return; | ||||||
|  | 
 | ||||||
| drop: | drop: | ||||||
| 	kfree_skb(skb); | 	kfree_skb(skb); | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										1501
									
								
								net/bluetooth/iso.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1501
									
								
								net/bluetooth/iso.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							|  | @ -3985,10 +3985,16 @@ static const u8 rpa_resolution_uuid[16] = { | ||||||
| 	0xea, 0x11, 0x73, 0xc2, 0x48, 0xa1, 0xc0, 0x15, | 	0xea, 0x11, 0x73, 0xc2, 0x48, 0xa1, 0xc0, 0x15, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | /* 6fbaf188-05e0-496a-9885-d6ddfdb4e03e */ | ||||||
|  | static const u8 iso_socket_uuid[16] = { | ||||||
|  | 	0x3e, 0xe0, 0xb4, 0xfd, 0xdd, 0xd6, 0x85, 0x98, | ||||||
|  | 	0x6a, 0x49, 0xe0, 0x05, 0x88, 0xf1, 0xba, 0x6f, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev, | static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev, | ||||||
| 				  void *data, u16 data_len) | 				  void *data, u16 data_len) | ||||||
| { | { | ||||||
| 	char buf[102];   /* Enough space for 5 features: 2 + 20 * 5 */ | 	char buf[122];   /* Enough space for 6 features: 2 + 20 * 6 */ | ||||||
| 	struct mgmt_rp_read_exp_features_info *rp = (void *)buf; | 	struct mgmt_rp_read_exp_features_info *rp = (void *)buf; | ||||||
| 	u16 idx = 0; | 	u16 idx = 0; | ||||||
| 	u32 flags; | 	u32 flags; | ||||||
|  | @ -4052,6 +4058,13 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev, | ||||||
| 		idx++; | 		idx++; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (IS_ENABLED(CONFIG_BT_LE)) { | ||||||
|  | 		flags = iso_enabled() ? BIT(0) : 0; | ||||||
|  | 		memcpy(rp->features[idx].uuid, iso_socket_uuid, 16); | ||||||
|  | 		rp->features[idx].flags = cpu_to_le32(flags); | ||||||
|  | 		idx++; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	rp->feature_count = cpu_to_le16(idx); | 	rp->feature_count = cpu_to_le16(idx); | ||||||
| 
 | 
 | ||||||
| 	/* After reading the experimental features information, enable
 | 	/* After reading the experimental features information, enable
 | ||||||
|  | @ -4444,6 +4457,57 @@ static int set_le_simultaneous_roles_func(struct sock *sk, struct hci_dev *hdev, | ||||||
| 	return err; | 	return err; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #ifdef CONFIG_BT_LE | ||||||
|  | static int set_iso_socket_func(struct sock *sk, struct hci_dev *hdev, | ||||||
|  | 			       struct mgmt_cp_set_exp_feature *cp, u16 data_len) | ||||||
|  | { | ||||||
|  | 	struct mgmt_rp_set_exp_feature rp; | ||||||
|  | 	bool val, changed = false; | ||||||
|  | 	int err; | ||||||
|  | 
 | ||||||
|  | 	/* Command requires to use the non-controller index */ | ||||||
|  | 	if (hdev) | ||||||
|  | 		return mgmt_cmd_status(sk, hdev->id, | ||||||
|  | 				       MGMT_OP_SET_EXP_FEATURE, | ||||||
|  | 				       MGMT_STATUS_INVALID_INDEX); | ||||||
|  | 
 | ||||||
|  | 	/* Parameters are limited to a single octet */ | ||||||
|  | 	if (data_len != MGMT_SET_EXP_FEATURE_SIZE + 1) | ||||||
|  | 		return mgmt_cmd_status(sk, MGMT_INDEX_NONE, | ||||||
|  | 				       MGMT_OP_SET_EXP_FEATURE, | ||||||
|  | 				       MGMT_STATUS_INVALID_PARAMS); | ||||||
|  | 
 | ||||||
|  | 	/* Only boolean on/off is supported */ | ||||||
|  | 	if (cp->param[0] != 0x00 && cp->param[0] != 0x01) | ||||||
|  | 		return mgmt_cmd_status(sk, MGMT_INDEX_NONE, | ||||||
|  | 				       MGMT_OP_SET_EXP_FEATURE, | ||||||
|  | 				       MGMT_STATUS_INVALID_PARAMS); | ||||||
|  | 
 | ||||||
|  | 	val = cp->param[0] ? true : false; | ||||||
|  | 	if (val) | ||||||
|  | 		err = iso_init(); | ||||||
|  | 	else | ||||||
|  | 		err = iso_exit(); | ||||||
|  | 
 | ||||||
|  | 	if (!err) | ||||||
|  | 		changed = true; | ||||||
|  | 
 | ||||||
|  | 	memcpy(rp.uuid, iso_socket_uuid, 16); | ||||||
|  | 	rp.flags = cpu_to_le32(val ? BIT(0) : 0); | ||||||
|  | 
 | ||||||
|  | 	hci_sock_set_flag(sk, HCI_MGMT_EXP_FEATURE_EVENTS); | ||||||
|  | 
 | ||||||
|  | 	err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, | ||||||
|  | 				MGMT_OP_SET_EXP_FEATURE, 0, | ||||||
|  | 				&rp, sizeof(rp)); | ||||||
|  | 
 | ||||||
|  | 	if (changed) | ||||||
|  | 		exp_feature_changed(hdev, iso_socket_uuid, val, sk); | ||||||
|  | 
 | ||||||
|  | 	return err; | ||||||
|  | } | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| static const struct mgmt_exp_feature { | static const struct mgmt_exp_feature { | ||||||
| 	const u8 *uuid; | 	const u8 *uuid; | ||||||
| 	int (*set_func)(struct sock *sk, struct hci_dev *hdev, | 	int (*set_func)(struct sock *sk, struct hci_dev *hdev, | ||||||
|  | @ -4457,6 +4521,9 @@ static const struct mgmt_exp_feature { | ||||||
| 	EXP_FEAT(quality_report_uuid, set_quality_report_func), | 	EXP_FEAT(quality_report_uuid, set_quality_report_func), | ||||||
| 	EXP_FEAT(offload_codecs_uuid, set_offload_codec_func), | 	EXP_FEAT(offload_codecs_uuid, set_offload_codec_func), | ||||||
| 	EXP_FEAT(le_simultaneous_roles_uuid, set_le_simultaneous_roles_func), | 	EXP_FEAT(le_simultaneous_roles_uuid, set_le_simultaneous_roles_func), | ||||||
|  | #ifdef CONFIG_BT_LE | ||||||
|  | 	EXP_FEAT(iso_socket_uuid, set_iso_socket_func), | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| 	/* end with a null feature */ | 	/* end with a null feature */ | ||||||
| 	EXP_FEAT(NULL, NULL) | 	EXP_FEAT(NULL, NULL) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Luiz Augusto von Dentz
						Luiz Augusto von Dentz