GNU Linux-libre 5.19-rc6-gnu
[releases.git] / net / bluetooth / eir.h
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);