1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * BlueZ - Bluetooth protocol stack for Linux 4 * 5 * Copyright (C) 2021 Intel Corporation 6 */ 7 8 #include <asm/unaligned.h> 9 10 void eir_create(struct hci_dev *hdev, u8 *data); 11 12 u8 eir_create_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr); 13 u8 eir_create_scan_rsp(struct hci_dev *hdev, u8 instance, u8 *ptr); 14 15 u8 eir_append_local_name(struct hci_dev *hdev, u8 *eir, u8 ad_len); 16 u8 eir_append_appearance(struct hci_dev *hdev, u8 *ptr, u8 ad_len); 17 u8 eir_append_service_data(u8 *eir, u16 eir_len, u16 uuid, u8 *data, 18 u8 data_len); 19 20 static inline u16 eir_precalc_len(u8 data_len) 21 { 22 return sizeof(u8) * 2 + data_len; 23 } 24 25 static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, 26 u8 *data, u8 data_len) 27 { 28 eir[eir_len++] = sizeof(type) + data_len; 29 eir[eir_len++] = type; 30 memcpy(&eir[eir_len], data, data_len); 31 eir_len += data_len; 32 33 return eir_len; 34 } 35 36 static inline u16 eir_append_le16(u8 *eir, u16 eir_len, u8 type, u16 data) 37 { 38 eir[eir_len++] = sizeof(type) + sizeof(data); 39 eir[eir_len++] = type; 40 put_unaligned_le16(data, &eir[eir_len]); 41 eir_len += sizeof(data); 42 43 return eir_len; 44 } 45 46 static inline u16 eir_skb_put_data(struct sk_buff *skb, u8 type, u8 *data, u8 data_len) 47 { 48 u8 *eir; 49 u16 eir_len; 50 51 eir_len = eir_precalc_len(data_len); 52 eir = skb_put(skb, eir_len); 53 WARN_ON(sizeof(type) + data_len > U8_MAX); 54 eir[0] = sizeof(type) + data_len; 55 eir[1] = type; 56 memcpy(&eir[2], data, data_len); 57 58 return eir_len; 59 } 60 61 static inline void *eir_get_data(u8 *eir, size_t eir_len, u8 type, 62 size_t *data_len) 63 { 64 size_t parsed = 0; 65 66 if (eir_len < 2) 67 return NULL; 68 69 while (parsed < eir_len - 1) { 70 u8 field_len = eir[0]; 71 72 if (field_len == 0) 73 break; 74 75 parsed += field_len + 1; 76 77 if (parsed > eir_len) 78 break; 79 80 if (eir[1] != type) { 81 eir += field_len + 1; 82 continue; 83 } 84 85 /* Zero length data */ 86 if (field_len == 1) 87 return NULL; 88 89 if (data_len) 90 *data_len = field_len - 1; 91 92 return &eir[2]; 93 } 94 95 return NULL; 96 } 97 98 void *eir_get_service_data(u8 *eir, size_t eir_len, u16 uuid, size_t *len); 99