xref: /openbmc/linux/net/bluetooth/eir.h (revision 8bdc2a19)
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