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
 | 
			
		||||
 | 
			
		||||
#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