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