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 | ||||
| 
 | ||||
| #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); | ||||
| void mgmt_exit(void); | ||||
| 
 | ||||
|  |  | |||
|  | @ -843,6 +843,21 @@ static inline void sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb) | |||
| } | ||||
| #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 ----- */ | ||||
| #define INQUIRY_CACHE_AGE_MAX   (HZ*30)   /* 30 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); | ||||
| 
 | ||||
| 	case ISO_LINK: | ||||
| 		/* TODO: Handle connection indication */ | ||||
| 		return -EINVAL; | ||||
| 		return iso_connect_ind(hdev, bdaddr, flags); | ||||
| 
 | ||||
| 	default: | ||||
| 		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 | ||||
| 
 | ||||
| bluetooth-$(CONFIG_BT_BREDR) += sco.o | ||||
| bluetooth-$(CONFIG_BT_LE) += iso.o | ||||
| bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o | ||||
| bluetooth-$(CONFIG_BT_LEDS) += leds.o | ||||
| bluetooth-$(CONFIG_BT_MSFTEXT) += msft.o | ||||
|  |  | |||
|  | @ -38,7 +38,7 @@ | |||
| #include "selftest.h" | ||||
| 
 | ||||
| /* 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 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_HIDP", | ||||
| 	"sk_lock-AF_BLUETOOTH-BTPROTO_AVDTP", | ||||
| 	"sk_lock-AF_BLUETOOTH-BTPROTO_ISO", | ||||
| }; | ||||
| 
 | ||||
| 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_HIDP", | ||||
| 	"slock-AF_BLUETOOTH-BTPROTO_AVDTP", | ||||
| 	"slock-AF_BLUETOOTH-BTPROTO_ISO", | ||||
| }; | ||||
| 
 | ||||
| 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); | ||||
| 	hci_dev_unlock(hdev); | ||||
| 
 | ||||
| 	/* TODO: Send to upper protocol */ | ||||
| 	if (!conn) { | ||||
| 		bt_dev_err(hdev, "ISO packet for unknown connection handle %d", | ||||
| 			   handle); | ||||
| 		goto drop; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Send to upper protocol */ | ||||
| 	iso_recv(conn, skb, flags); | ||||
| 	return; | ||||
| 
 | ||||
| drop: | ||||
| 	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, | ||||
| }; | ||||
| 
 | ||||
| /* 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, | ||||
| 				  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; | ||||
| 	u16 idx = 0; | ||||
| 	u32 flags; | ||||
|  | @ -4052,6 +4058,13 @@ static int read_exp_features_info(struct sock *sk, struct hci_dev *hdev, | |||
| 		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); | ||||
| 
 | ||||
| 	/* 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; | ||||
| } | ||||
| 
 | ||||
| #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 { | ||||
| 	const u8 *uuid; | ||||
| 	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(offload_codecs_uuid, set_offload_codec_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 */ | ||||
| 	EXP_FEAT(NULL, NULL) | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Luiz Augusto von Dentz
						Luiz Augusto von Dentz