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

Bluetooth: Add support for appearance in scan rsp

This patch enables prepending appearance value to scan response data.
It also adds support for setting appearance value through mgmt command.
If currently advertised instance has apperance flag set it is expired
immediately.

Signed-off-by: Michał Narajowski <michal.narajowski@codecoup.pl>
Signed-off-by: Szymon Janc <szymon.janc@codecoup.pl>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>

authored by

Michał Narajowski and committed by
Marcel Holtmann
c4960ecf 7c295c48

+52
+1
include/net/bluetooth/hci_core.h
··· 211 211 __u8 dev_name[HCI_MAX_NAME_LENGTH]; 212 212 __u8 short_name[HCI_MAX_SHORT_NAME_LENGTH]; 213 213 __u8 eir[HCI_MAX_EIR_LENGTH]; 214 + __u16 appearance; 214 215 __u8 dev_class[3]; 215 216 __u8 major_class; 216 217 __u8 minor_class;
+6
include/net/bluetooth/mgmt.h
··· 598 598 __u8 eir[0]; 599 599 } __packed; 600 600 601 + #define MGMT_OP_SET_APPEARANCE 0x0043 602 + struct mgmt_cp_set_appearance { 603 + __u16 appearance; 604 + } __packed; 605 + #define MGMT_SET_APPEARANCE_SIZE 2 606 + 601 607 #define MGMT_EV_CMD_COMPLETE 0x0001 602 608 struct mgmt_ev_cmd_complete { 603 609 __le16 opcode;
+8
net/bluetooth/hci_request.c
··· 1015 1015 1016 1016 instance_flags = adv_instance->flags; 1017 1017 1018 + if ((instance_flags & MGMT_ADV_FLAG_APPEARANCE) && hdev->appearance) { 1019 + ptr[0] = 3; 1020 + ptr[1] = EIR_APPEARANCE; 1021 + put_unaligned_le16(hdev->appearance, ptr + 2); 1022 + scan_rsp_len += 4; 1023 + ptr += 4; 1024 + } 1025 + 1018 1026 memcpy(ptr, adv_instance->scan_rsp_data, 1019 1027 adv_instance->scan_rsp_len); 1020 1028
+37
net/bluetooth/mgmt.c
··· 105 105 MGMT_OP_GET_ADV_SIZE_INFO, 106 106 MGMT_OP_START_LIMITED_DISCOVERY, 107 107 MGMT_OP_READ_EXT_INFO, 108 + MGMT_OP_SET_APPEARANCE, 108 109 }; 109 110 110 111 static const u16 mgmt_events[] = { ··· 3144 3143 return err; 3145 3144 } 3146 3145 3146 + static int set_appearance(struct sock *sk, struct hci_dev *hdev, void *data, 3147 + u16 len) 3148 + { 3149 + struct mgmt_cp_set_appearance *cp = data; 3150 + u16 apperance; 3151 + int err; 3152 + 3153 + BT_DBG(""); 3154 + 3155 + apperance = le16_to_cpu(cp->appearance); 3156 + 3157 + hci_dev_lock(hdev); 3158 + 3159 + if (hdev->appearance != apperance) { 3160 + hdev->appearance = apperance; 3161 + 3162 + if (hci_dev_test_flag(hdev, HCI_LE_ADV)) 3163 + adv_expire(hdev, MGMT_ADV_FLAG_APPEARANCE); 3164 + } 3165 + 3166 + err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_SET_APPEARANCE, 0, NULL, 3167 + 0); 3168 + 3169 + hci_dev_unlock(hdev); 3170 + 3171 + return err; 3172 + } 3173 + 3147 3174 static void read_local_oob_data_complete(struct hci_dev *hdev, u8 status, 3148 3175 u16 opcode, struct sk_buff *skb) 3149 3176 { ··· 5947 5918 flags |= MGMT_ADV_FLAG_DISCOV; 5948 5919 flags |= MGMT_ADV_FLAG_LIMITED_DISCOV; 5949 5920 flags |= MGMT_ADV_FLAG_MANAGED_FLAGS; 5921 + flags |= MGMT_ADV_FLAG_APPEARANCE; 5950 5922 flags |= MGMT_ADV_FLAG_LOCAL_NAME; 5951 5923 5952 5924 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) ··· 6029 5999 /* at least 1 byte of name should fit in */ 6030 6000 if (adv_flags & MGMT_ADV_FLAG_LOCAL_NAME) 6031 6001 max_len -= 3; 6002 + 6003 + if (adv_flags & MGMT_ADV_FLAG_APPEARANCE) 6004 + max_len -= 4; 6032 6005 } 6033 6006 6034 6007 if (len > max_len) ··· 6368 6335 /* at least 1 byte of name should fit in */ 6369 6336 if (adv_flags & MGMT_ADV_FLAG_LOCAL_NAME) 6370 6337 max_len -= 3; 6338 + 6339 + if (adv_flags & (MGMT_ADV_FLAG_APPEARANCE)) 6340 + max_len -= 4; 6371 6341 } 6372 6342 6373 6343 return max_len; ··· 6506 6470 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE }, 6507 6471 { read_ext_controller_info,MGMT_READ_EXT_INFO_SIZE, 6508 6472 HCI_MGMT_UNTRUSTED }, 6473 + { set_appearance, MGMT_SET_APPEARANCE_SIZE }, 6509 6474 }; 6510 6475 6511 6476 void mgmt_index_added(struct hci_dev *hdev)