Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Bluetooth: ISO: Add support to bind to trigger PAST

This makes it possible to bind to a different destination address
after being connected (BT_CONNECTED, BT_CONNECT2) which then triggers
PAST Sender proceedure to transfer the PA Sync to the destination
address.

Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

+187 -17
+1
include/net/bluetooth/hci_core.h
··· 1602 1602 struct hci_conn *hci_bind_bis(struct hci_dev *hdev, bdaddr_t *dst, __u8 sid, 1603 1603 struct bt_iso_qos *qos, 1604 1604 __u8 base_len, __u8 *base, u16 timeout); 1605 + int hci_past_bis(struct hci_conn *conn, bdaddr_t *dst, __u8 dst_type); 1605 1606 struct hci_conn *hci_connect_cis(struct hci_dev *hdev, bdaddr_t *dst, 1606 1607 __u8 dst_type, struct bt_iso_qos *qos, 1607 1608 u16 timeout);
+1
include/net/bluetooth/hci_sync.h
··· 188 188 189 189 int hci_connect_pa_sync(struct hci_dev *hdev, struct hci_conn *conn); 190 190 int hci_connect_big_sync(struct hci_dev *hdev, struct hci_conn *conn); 191 + int hci_past_sync(struct hci_conn *conn, struct hci_conn *le);
+12
net/bluetooth/hci_conn.c
··· 2245 2245 return conn; 2246 2246 } 2247 2247 2248 + int hci_past_bis(struct hci_conn *conn, bdaddr_t *dst, __u8 dst_type) 2249 + { 2250 + struct hci_conn *le; 2251 + 2252 + /* Lookup existing LE connection to rebind to */ 2253 + le = hci_conn_hash_lookup_le(conn->hdev, dst, dst_type); 2254 + if (!le) 2255 + return -EINVAL; 2256 + 2257 + return hci_past_sync(conn, le); 2258 + } 2259 + 2248 2260 static void bis_mark_per_adv(struct hci_conn *conn, void *data) 2249 2261 { 2250 2262 struct iso_list_data *d = data;
+92
net/bluetooth/hci_sync.c
··· 7228 7228 return hci_cmd_sync_queue_once(hdev, hci_le_big_create_sync, conn, 7229 7229 create_big_complete); 7230 7230 } 7231 + 7232 + struct past_data { 7233 + struct hci_conn *conn; 7234 + struct hci_conn *le; 7235 + }; 7236 + 7237 + static void past_complete(struct hci_dev *hdev, void *data, int err) 7238 + { 7239 + struct past_data *past = data; 7240 + 7241 + bt_dev_dbg(hdev, "err %d", err); 7242 + 7243 + kfree(past); 7244 + } 7245 + 7246 + static int hci_le_past_set_info_sync(struct hci_dev *hdev, void *data) 7247 + { 7248 + struct past_data *past = data; 7249 + struct hci_cp_le_past_set_info cp; 7250 + 7251 + hci_dev_lock(hdev); 7252 + 7253 + if (!hci_conn_valid(hdev, past->conn) || 7254 + !hci_conn_valid(hdev, past->le)) { 7255 + hci_dev_unlock(hdev); 7256 + return -ECANCELED; 7257 + } 7258 + 7259 + memset(&cp, 0, sizeof(cp)); 7260 + cp.handle = cpu_to_le16(past->le->handle); 7261 + cp.adv_handle = past->conn->iso_qos.bcast.bis; 7262 + 7263 + hci_dev_unlock(hdev); 7264 + 7265 + return __hci_cmd_sync_status(hdev, HCI_OP_LE_PAST_SET_INFO, 7266 + sizeof(cp), &cp, HCI_CMD_TIMEOUT); 7267 + } 7268 + 7269 + static int hci_le_past_sync(struct hci_dev *hdev, void *data) 7270 + { 7271 + struct past_data *past = data; 7272 + struct hci_cp_le_past cp; 7273 + 7274 + hci_dev_lock(hdev); 7275 + 7276 + if (!hci_conn_valid(hdev, past->conn) || 7277 + !hci_conn_valid(hdev, past->le)) { 7278 + hci_dev_unlock(hdev); 7279 + return -ECANCELED; 7280 + } 7281 + 7282 + memset(&cp, 0, sizeof(cp)); 7283 + cp.handle = cpu_to_le16(past->le->handle); 7284 + cp.sync_handle = cpu_to_le16(past->conn->sync_handle); 7285 + 7286 + hci_dev_unlock(hdev); 7287 + 7288 + return __hci_cmd_sync_status(hdev, HCI_OP_LE_PAST, 7289 + sizeof(cp), &cp, HCI_CMD_TIMEOUT); 7290 + } 7291 + 7292 + int hci_past_sync(struct hci_conn *conn, struct hci_conn *le) 7293 + { 7294 + struct past_data *data; 7295 + int err; 7296 + 7297 + if (conn->type != BIS_LINK && conn->type != PA_LINK) 7298 + return -EINVAL; 7299 + 7300 + if (!past_sender_capable(conn->hdev)) 7301 + return -EOPNOTSUPP; 7302 + 7303 + data = kmalloc(sizeof(*data), GFP_KERNEL); 7304 + if (!data) 7305 + return -ENOMEM; 7306 + 7307 + data->conn = conn; 7308 + data->le = le; 7309 + 7310 + if (conn->role == HCI_ROLE_MASTER) 7311 + err = hci_cmd_sync_queue_once(conn->hdev, 7312 + hci_le_past_set_info_sync, data, 7313 + past_complete); 7314 + else 7315 + err = hci_cmd_sync_queue_once(conn->hdev, hci_le_past_sync, 7316 + data, past_complete); 7317 + 7318 + if (err) 7319 + kfree(data); 7320 + 7321 + return err; 7322 + }
+81 -17
net/bluetooth/iso.c
··· 987 987 return 0; 988 988 } 989 989 990 - static int iso_sock_bind_pa_sk(struct sock *sk, struct sockaddr_iso *sa, 990 + /* Must be called on the locked socket. */ 991 + static int iso_sock_rebind_bis(struct sock *sk, struct sockaddr_iso *sa, 991 992 int addr_len) 992 993 { 993 994 int err = 0; 994 995 995 - if (sk->sk_type != SOCK_SEQPACKET) { 996 - err = -EINVAL; 997 - goto done; 998 - } 999 - 1000 - if (addr_len != sizeof(*sa) + sizeof(*sa->iso_bc)) { 1001 - err = -EINVAL; 1002 - goto done; 1003 - } 996 + if (!test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags)) 997 + return -EBADFD; 1004 998 1005 999 if (sa->iso_bc->bc_num_bis > ISO_MAX_NUM_BIS) { 1006 1000 err = -EINVAL; ··· 1017 1023 return err; 1018 1024 } 1019 1025 1026 + static struct hci_dev *iso_conn_get_hdev(struct iso_conn *conn) 1027 + { 1028 + struct hci_dev *hdev = NULL; 1029 + 1030 + iso_conn_lock(conn); 1031 + if (conn->hcon) 1032 + hdev = hci_dev_hold(conn->hcon->hdev); 1033 + iso_conn_unlock(conn); 1034 + 1035 + return hdev; 1036 + } 1037 + 1038 + /* Must be called on the locked socket. */ 1039 + static int iso_sock_rebind_bc(struct sock *sk, struct sockaddr_iso *sa, 1040 + int addr_len) 1041 + { 1042 + struct hci_dev *hdev; 1043 + struct hci_conn *bis; 1044 + int err; 1045 + 1046 + if (sk->sk_type != SOCK_SEQPACKET || !iso_pi(sk)->conn) 1047 + return -EINVAL; 1048 + 1049 + /* Check if it is really a Broadcast address being requested */ 1050 + if (addr_len != sizeof(*sa) + sizeof(*sa->iso_bc)) 1051 + return -EINVAL; 1052 + 1053 + /* Check if the address hasn't changed then perhaps only the number of 1054 + * bis has changed. 1055 + */ 1056 + if (!bacmp(&iso_pi(sk)->dst, &sa->iso_bc->bc_bdaddr) || 1057 + !bacmp(&sa->iso_bc->bc_bdaddr, BDADDR_ANY)) 1058 + return iso_sock_rebind_bis(sk, sa, addr_len); 1059 + 1060 + /* Check if the address type is of LE type */ 1061 + if (!bdaddr_type_is_le(sa->iso_bc->bc_bdaddr_type)) 1062 + return -EINVAL; 1063 + 1064 + hdev = iso_conn_get_hdev(iso_pi(sk)->conn); 1065 + if (!hdev) 1066 + return -EINVAL; 1067 + 1068 + bis = iso_pi(sk)->conn->hcon; 1069 + 1070 + /* Release the socket before lookups since that requires hci_dev_lock 1071 + * which shall not be acquired while holding sock_lock for proper 1072 + * ordering. 1073 + */ 1074 + release_sock(sk); 1075 + hci_dev_lock(bis->hdev); 1076 + lock_sock(sk); 1077 + 1078 + if (!iso_pi(sk)->conn || iso_pi(sk)->conn->hcon != bis) { 1079 + /* raced with iso_conn_del() or iso_disconn_sock() */ 1080 + err = -ENOTCONN; 1081 + goto unlock; 1082 + } 1083 + 1084 + BT_DBG("sk %p %pMR type %u", sk, &sa->iso_bc->bc_bdaddr, 1085 + sa->iso_bc->bc_bdaddr_type); 1086 + 1087 + err = hci_past_bis(bis, &sa->iso_bc->bc_bdaddr, 1088 + le_addr_type(sa->iso_bc->bc_bdaddr_type)); 1089 + 1090 + unlock: 1091 + hci_dev_unlock(hdev); 1092 + hci_dev_put(hdev); 1093 + 1094 + return err; 1095 + } 1096 + 1020 1097 static int iso_sock_bind(struct socket *sock, struct sockaddr_unsized *addr, 1021 1098 int addr_len) 1022 1099 { ··· 1103 1038 1104 1039 lock_sock(sk); 1105 1040 1106 - /* Allow the user to bind a PA sync socket to a number 1107 - * of BISes to sync to. 1108 - */ 1109 - if ((sk->sk_state == BT_CONNECT2 || 1110 - sk->sk_state == BT_CONNECTED) && 1111 - test_bit(BT_SK_PA_SYNC, &iso_pi(sk)->flags)) { 1112 - err = iso_sock_bind_pa_sk(sk, sa, addr_len); 1041 + if ((sk->sk_state == BT_CONNECT2 || sk->sk_state == BT_CONNECTED) && 1042 + addr_len > sizeof(*sa)) { 1043 + /* Allow the user to rebind to a different address using 1044 + * PAST procedures. 1045 + */ 1046 + err = iso_sock_rebind_bc(sk, sa, addr_len); 1113 1047 goto done; 1114 1048 } 1115 1049