1 /** @file
2  *  @brief GATT Device Information Service
3  */
4 
5 /*
6  * Copyright (c) 2019 Demant
7  * Copyright (c) 2018 Nordic Semiconductor ASA
8  * Copyright (c) 2016 Intel Corporation
9  *
10  * SPDX-License-Identifier: Apache-2.0
11  */
12 
13 #include <zephyr/types.h>
14 #include <stddef.h>
15 #include <string.h>
16 #include <errno.h>
17 #include <zephyr/kernel.h>
18 #include <zephyr/init.h>
19 
20 #include <zephyr/settings/settings.h>
21 
22 #include <zephyr/bluetooth/bluetooth.h>
23 #include <zephyr/bluetooth/hci.h>
24 #include <zephyr/bluetooth/conn.h>
25 #include <zephyr/bluetooth/uuid.h>
26 #include <zephyr/bluetooth/gatt.h>
27 
28 #include <zephyr/sys/byteorder.h>
29 #include <zephyr/bluetooth/byteorder.h>
30 
31 #define LOG_LEVEL CONFIG_BT_SERVICE_LOG_LEVEL
32 #include <zephyr/logging/log.h>
33 LOG_MODULE_REGISTER(bt_dis);
34 
35 #if CONFIG_BT_DIS_PNP
36 struct dis_pnp {
37 	uint8_t pnp_vid_src;
38 	uint16_t pnp_vid;
39 	uint16_t pnp_pid;
40 	uint16_t pnp_ver;
41 } __packed;
42 
43 static struct dis_pnp dis_pnp_id = {
44 	.pnp_vid_src = CONFIG_BT_DIS_PNP_VID_SRC,
45 	.pnp_vid = CONFIG_BT_DIS_PNP_VID,
46 	.pnp_pid = CONFIG_BT_DIS_PNP_PID,
47 	.pnp_ver = CONFIG_BT_DIS_PNP_VER,
48 };
49 #endif
50 
51 #if defined(CONFIG_BT_DIS_SYSTEM_ID)
52 /*
53  * Casting to uint64_t since the value is at most 5 bytes, but will appear as a 32-bit literal if it
54  * is less, giving a warning when right-shifting by 32.
55  */
56 static uint8_t dis_system_id[8] = {BT_BYTES_LIST_LE40((uint64_t)CONFIG_BT_DIS_SYSTEM_ID_IDENTIFIER),
57 				   BT_BYTES_LIST_LE24(CONFIG_BT_DIS_SYSTEM_ID_OUI)};
58 #endif
59 
60 #if defined(CONFIG_BT_DIS_SETTINGS)
61 #if defined(CONFIG_BT_DIS_MODEL_NUMBER)
62 BUILD_ASSERT(sizeof(CONFIG_BT_DIS_MODEL_NUMBER_STR) <= CONFIG_BT_DIS_STR_MAX + 1);
63 static uint8_t dis_model[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_MODEL_NUMBER_STR;
64 #elif defined(CONFIG_BT_DIS_MODEL_DEPRECATED_USED)
65 BUILD_ASSERT(sizeof(CONFIG_BT_DIS_MODEL) <= CONFIG_BT_DIS_STR_MAX + 1);
66 static uint8_t dis_model[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_MODEL;
67 #endif
68 #if defined(CONFIG_BT_DIS_MANUF_NAME)
69 BUILD_ASSERT(sizeof(CONFIG_BT_DIS_MANUF_NAME_STR) <= CONFIG_BT_DIS_STR_MAX + 1);
70 static uint8_t dis_manuf[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_MANUF_NAME_STR;
71 #elif defined(CONFIG_BT_DIS_MANUF_DEPRECATED_USED)
72 BUILD_ASSERT(sizeof(CONFIG_BT_DIS_MANUF) <= CONFIG_BT_DIS_STR_MAX + 1);
73 static uint8_t dis_manuf[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_MANUF;
74 #endif
75 #if defined(CONFIG_BT_DIS_SERIAL_NUMBER)
76 BUILD_ASSERT(sizeof(CONFIG_BT_DIS_SERIAL_NUMBER_STR) <= CONFIG_BT_DIS_STR_MAX + 1);
77 static uint8_t dis_serial_number[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_SERIAL_NUMBER_STR;
78 #endif
79 #if defined(CONFIG_BT_DIS_FW_REV)
80 BUILD_ASSERT(sizeof(CONFIG_BT_DIS_FW_REV_STR) <= CONFIG_BT_DIS_STR_MAX + 1);
81 static uint8_t dis_fw_rev[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_FW_REV_STR;
82 #endif
83 #if defined(CONFIG_BT_DIS_HW_REV)
84 BUILD_ASSERT(sizeof(CONFIG_BT_DIS_HW_REV_STR) <= CONFIG_BT_DIS_STR_MAX + 1);
85 static uint8_t dis_hw_rev[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_HW_REV_STR;
86 #endif
87 #if defined(CONFIG_BT_DIS_SW_REV)
88 BUILD_ASSERT(sizeof(CONFIG_BT_DIS_SW_REV_STR) <= CONFIG_BT_DIS_STR_MAX + 1);
89 static uint8_t dis_sw_rev[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_SW_REV_STR;
90 #endif
91 #if defined(CONFIG_BT_DIS_UDI)
92 BUILD_ASSERT(sizeof(CONFIG_BT_DIS_UDI_LABEL_STR) <= CONFIG_BT_DIS_STR_MAX + 1);
93 BUILD_ASSERT(sizeof(CONFIG_BT_DIS_UDI_DI_STR) <= CONFIG_BT_DIS_STR_MAX + 1);
94 BUILD_ASSERT(sizeof(CONFIG_BT_DIS_UDI_ISSUER_STR) <= CONFIG_BT_DIS_STR_MAX + 1);
95 BUILD_ASSERT(sizeof(CONFIG_BT_DIS_UDI_AUTHORITY_STR) <= CONFIG_BT_DIS_STR_MAX + 1);
96 
97 static uint8_t dis_udi_label[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_UDI_LABEL_STR;
98 static uint8_t dis_udi_di[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_UDI_DI_STR;
99 static uint8_t dis_udi_issuer[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_UDI_ISSUER_STR;
100 static uint8_t dis_udi_authority[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_UDI_AUTHORITY_STR;
101 #endif
102 #if defined(CONFIG_BT_DIS_IEEE_RCDL)
103 BUILD_ASSERT(sizeof(CONFIG_BT_DIS_IEEE_RCDL_STR) <= CONFIG_BT_DIS_STR_MAX + 1);
104 static uint8_t dis_ieee_rcdl[CONFIG_BT_DIS_STR_MAX + 1] = CONFIG_BT_DIS_IEEE_RCDL_STR;
105 #endif
106 
107 #define BT_DIS_MODEL_REF             dis_model
108 #define BT_DIS_MANUF_REF             dis_manuf
109 #define BT_DIS_SERIAL_NUMBER_STR_REF dis_serial_number
110 #define BT_DIS_FW_REV_STR_REF        dis_fw_rev
111 #define BT_DIS_HW_REV_STR_REF        dis_hw_rev
112 #define BT_DIS_SW_REV_STR_REF        dis_sw_rev
113 #define BT_DIS_UDI_LABEL_STR_REF     dis_udi_label
114 #define BT_DIS_UDI_DI_STR_REF        dis_udi_di
115 #define BT_DIS_UDI_ISSUER_STR_REF    dis_udi_issuer
116 #define BT_DIS_UDI_AUTHORITY_STR_REF dis_udi_authority
117 #define BT_DIS_IEEE_RCDL_STR_REF     dis_ieee_rcdl
118 
119 /*
120  * When assigning too long string literals to the arrays,
121  * the literals may be truncated, removing the null terminator.
122  * Using strnlen to avoid sending data outside the array.
123  */
124 
125 #else /* CONFIG_BT_DIS_SETTINGS */
126 
127 #if defined(CONFIG_BT_DIS_MODEL_NUMBER)
128 #define BT_DIS_MODEL_REF             CONFIG_BT_DIS_MODEL_NUMBER_STR
129 #elif defined(CONFIG_BT_DIS_MODEL_DEPRECATED_USED)
130 #define BT_DIS_MODEL_REF             CONFIG_BT_DIS_MODEL
131 #endif
132 #if defined(CONFIG_BT_DIS_MANUF_NAME)
133 #define BT_DIS_MANUF_REF             CONFIG_BT_DIS_MANUF_NAME_STR
134 #elif defined(CONFIG_BT_DIS_MANUF_DEPRECATED_USED)
135 #define BT_DIS_MANUF_REF             CONFIG_BT_DIS_MANUF
136 #endif
137 #define BT_DIS_SERIAL_NUMBER_STR_REF CONFIG_BT_DIS_SERIAL_NUMBER_STR
138 #define BT_DIS_FW_REV_STR_REF        CONFIG_BT_DIS_FW_REV_STR
139 #define BT_DIS_HW_REV_STR_REF        CONFIG_BT_DIS_HW_REV_STR
140 #define BT_DIS_SW_REV_STR_REF        CONFIG_BT_DIS_SW_REV_STR
141 #define BT_DIS_UDI_LABEL_STR_REF     CONFIG_BT_DIS_UDI_LABEL_STR
142 #define BT_DIS_UDI_DI_STR_REF        CONFIG_BT_DIS_UDI_DI_STR
143 #define BT_DIS_UDI_ISSUER_STR_REF    CONFIG_BT_DIS_UDI_ISSUER_STR
144 #define BT_DIS_UDI_AUTHORITY_STR_REF CONFIG_BT_DIS_UDI_AUTHORITY_STR
145 #define BT_DIS_IEEE_RCDL_STR_REF     CONFIG_BT_DIS_IEEE_RCDL_STR
146 
147 #endif /* CONFIG_BT_DIS_SETTINGS */
148 
149 #define BT_DIS_READ_STR_USED \
150 	(CONFIG_BT_DIS_MODEL_NUMBER || CONFIG_BT_DIS_MODEL_DEPRECATED_USED || \
151 	 CONFIG_BT_DIS_MANUF_NAME || CONFIG_BT_DIS_MANUF_DEPRECATED_USED || \
152 	 CONFIG_BT_DIS_SERIAL_NUMBER || CONFIG_BT_DIS_FW_REV || CONFIG_BT_DIS_HW_REV || \
153 	 CONFIG_BT_DIS_SW_REV || CONFIG_BT_DIS_IEEE_RCDL)
154 
155 #if BT_DIS_READ_STR_USED
read_str(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)156 static ssize_t read_str(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
157 			uint16_t len, uint16_t offset)
158 {
159 	return bt_gatt_attr_read(conn, attr, buf, len, offset, attr->user_data,
160 				 strlen(attr->user_data));
161 }
162 #endif
163 
164 #if CONFIG_BT_DIS_PNP
read_pnp_id(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)165 static ssize_t read_pnp_id(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
166 			   uint16_t len, uint16_t offset)
167 {
168 	return bt_gatt_attr_read(conn, attr, buf, len, offset, &dis_pnp_id, sizeof(dis_pnp_id));
169 }
170 #endif
171 
172 #if CONFIG_BT_DIS_SYSTEM_ID
read_system_id(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)173 static ssize_t read_system_id(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
174 			      uint16_t len, uint16_t offset)
175 {
176 	return bt_gatt_attr_read(conn, attr, buf, len, offset, dis_system_id,
177 				 sizeof(dis_system_id));
178 }
179 #endif
180 
181 #if CONFIG_BT_DIS_UDI
182 #define DIS_STR_SIZE(x)           ((x[0]) != '\0' ? strlen(x) + sizeof('\0') : 0)
183 #define BT_DIS_UDI_FLAG_LABEL     (!!BT_DIS_UDI_LABEL_STR_REF[0])
184 #define BT_DIS_UDI_FLAG_DI        (!!BT_DIS_UDI_DI_STR_REF[0])
185 #define BT_DIS_UDI_FLAG_ISSUER    (!!BT_DIS_UDI_ISSUER_STR_REF[0])
186 #define BT_DIS_UDI_FLAG_AUTHORITY (!!BT_DIS_UDI_AUTHORITY_STR_REF[0])
187 #define BT_DIS_UDI_FLAGS                                                                           \
188 	(BT_DIS_UDI_FLAG_LABEL | (BT_DIS_UDI_FLAG_DI << 1) | (BT_DIS_UDI_FLAG_ISSUER << 2) |       \
189 	 (BT_DIS_UDI_FLAG_AUTHORITY << 3))
190 
191 /*
192  * UDI for medical devices contains a flag and 4 different null-terminated strings that may have
193  * unknown length. This requires its own encode method.
194  */
read_udi_subval(const char * str,uint16_t val_len,char * buf,uint16_t * bytes_read,uint16_t * index,uint16_t len,uint16_t offset)195 static void read_udi_subval(const char *str, uint16_t val_len, char *buf, uint16_t *bytes_read,
196 			    uint16_t *index, uint16_t len, uint16_t offset)
197 {
198 	/* String should not be with included null-terminator if empty */
199 	if (val_len == sizeof('\0')) {
200 		return;
201 	}
202 
203 	if (*bytes_read == len) {
204 		return;
205 	}
206 
207 	if (*index + val_len < offset) {
208 		*index += val_len;
209 		return;
210 	}
211 
212 	for (uint16_t i = 0; i < val_len; i++) {
213 		if (*index >= offset && *bytes_read < len) {
214 			buf[*bytes_read] = str[i];
215 
216 			(*bytes_read)++;
217 		}
218 
219 		(*index)++;
220 	}
221 }
222 
read_udi(struct bt_conn * conn,const struct bt_gatt_attr * attr,void * buf,uint16_t len,uint16_t offset)223 static ssize_t read_udi(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf,
224 			uint16_t len, uint16_t offset)
225 {
226 	uint16_t bytes_read = 0;
227 
228 	char *buf_i = (char *)buf;
229 
230 	/* Flag */
231 	uint16_t index = sizeof(uint8_t);
232 
233 	if (offset == 0) {
234 		buf_i[0] = BT_DIS_UDI_FLAGS;
235 		bytes_read = 1U;
236 	}
237 
238 	read_udi_subval(BT_DIS_UDI_LABEL_STR_REF, DIS_STR_SIZE(BT_DIS_UDI_LABEL_STR_REF), buf_i,
239 			&bytes_read, &index, len, offset);
240 	read_udi_subval(BT_DIS_UDI_DI_STR_REF, DIS_STR_SIZE(BT_DIS_UDI_DI_STR_REF), buf_i,
241 			&bytes_read, &index, len, offset);
242 	read_udi_subval(BT_DIS_UDI_ISSUER_STR_REF, DIS_STR_SIZE(BT_DIS_UDI_ISSUER_STR_REF), buf_i,
243 			&bytes_read, &index, len, offset);
244 	read_udi_subval(BT_DIS_UDI_AUTHORITY_STR_REF, DIS_STR_SIZE(BT_DIS_UDI_AUTHORITY_STR_REF),
245 			buf_i, &bytes_read, &index, len, offset);
246 
247 	return bytes_read;
248 }
249 #endif
250 
251 /* Device Information Service Declaration */
252 BT_GATT_SERVICE_DEFINE(
253 	dis_svc, BT_GATT_PRIMARY_SERVICE(BT_UUID_DIS),
254 
255 #if defined(CONFIG_BT_DIS_MODEL_NUMBER) || defined(CONFIG_BT_DIS_MODEL_DEPRECATED_USED)
256 	BT_GATT_CHARACTERISTIC(BT_UUID_DIS_MODEL_NUMBER, BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
257 			       read_str, NULL, BT_DIS_MODEL_REF),
258 #endif
259 
260 #if defined(CONFIG_BT_DIS_MANUF_NAME) || defined(CONFIG_BT_DIS_MANUF_DEPRECATED_USED)
261 	BT_GATT_CHARACTERISTIC(BT_UUID_DIS_MANUFACTURER_NAME, BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
262 			       read_str, NULL, BT_DIS_MANUF_REF),
263 #endif
264 
265 #if CONFIG_BT_DIS_PNP
266 	BT_GATT_CHARACTERISTIC(BT_UUID_DIS_PNP_ID, BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
267 			       read_pnp_id, NULL, &dis_pnp_id),
268 #endif
269 
270 #if defined(CONFIG_BT_DIS_SERIAL_NUMBER)
271 	BT_GATT_CHARACTERISTIC(BT_UUID_DIS_SERIAL_NUMBER, BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
272 			       read_str, NULL, BT_DIS_SERIAL_NUMBER_STR_REF),
273 #endif
274 #if defined(CONFIG_BT_DIS_FW_REV)
275 	BT_GATT_CHARACTERISTIC(BT_UUID_DIS_FIRMWARE_REVISION, BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
276 			       read_str, NULL, BT_DIS_FW_REV_STR_REF),
277 #endif
278 #if defined(CONFIG_BT_DIS_HW_REV)
279 	BT_GATT_CHARACTERISTIC(BT_UUID_DIS_HARDWARE_REVISION, BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
280 			       read_str, NULL, BT_DIS_HW_REV_STR_REF),
281 #endif
282 #if defined(CONFIG_BT_DIS_SW_REV)
283 	BT_GATT_CHARACTERISTIC(BT_UUID_DIS_SOFTWARE_REVISION, BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
284 			       read_str, NULL, BT_DIS_SW_REV_STR_REF),
285 #endif
286 #if defined(CONFIG_BT_DIS_UDI)
287 	BT_GATT_CHARACTERISTIC(BT_UUID_UDI_FOR_MEDICAL_DEVICES, BT_GATT_CHRC_READ,
288 			       BT_GATT_PERM_READ, read_udi, NULL, NULL),
289 #endif
290 #if defined(CONFIG_BT_DIS_SYSTEM_ID)
291 	BT_GATT_CHARACTERISTIC(BT_UUID_DIS_SYSTEM_ID, BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
292 			       read_system_id, NULL, NULL),
293 #endif
294 #if defined(CONFIG_BT_DIS_IEEE_RCDL)
295 	BT_GATT_CHARACTERISTIC(BT_UUID_GATT_IEEE_RCDL, BT_GATT_CHRC_READ, BT_GATT_PERM_READ,
296 			       read_str, NULL, BT_DIS_IEEE_RCDL_STR_REF),
297 #endif
298 
299 );
300 
301 #if defined(CONFIG_BT_DIS_SETTINGS)
302 #if defined(CONFIG_BT_DIS_UDI)
dis_update_udi_value(const char * new,char * old,settings_read_cb read_cb,const char * logkey)303 static void dis_update_udi_value(const char *new, char *old, settings_read_cb read_cb,
304 				 const char *logkey)
305 {
306 	/*
307 	 * The characteristic contains 1 one-byte flag and 4-null-terminated.
308 	 * The null-terminators are only present for strings that are in the flags.
309 	 */
310 	const size_t merged_size = sizeof(uint8_t) + DIS_STR_SIZE(BT_DIS_UDI_LABEL_STR_REF) +
311 				   DIS_STR_SIZE(BT_DIS_UDI_DI_STR_REF) +
312 				   DIS_STR_SIZE(BT_DIS_UDI_ISSUER_STR_REF) +
313 				   DIS_STR_SIZE(BT_DIS_UDI_AUTHORITY_STR_REF);
314 
315 	size_t without_old = merged_size - DIS_STR_SIZE(old);
316 
317 	bool valid = BT_ATT_MAX_ATTRIBUTE_LEN >= without_old + DIS_STR_SIZE(new);
318 
319 	if (!valid) {
320 		LOG_ERR("Failed to set UDI %s. Not enough space. The sum of the 4 DIS UDI for "
321 			"Medical Devices strings may not exceed the maximum attribute length.",
322 			logkey);
323 		return;
324 	}
325 
326 	int16_t len = read_cb((void *)new, (void *)old, CONFIG_BT_DIS_STR_MAX);
327 
328 	if (len < 0) {
329 		LOG_ERR("Failed to read UDI %s from storage (err %zd)", logkey, len);
330 	} else {
331 		old[len] = '\0';
332 
333 		LOG_DBG("UDI %s set to %s", logkey, old);
334 	}
335 }
336 #endif
337 
dis_set(const char * name,size_t len_rd,settings_read_cb read_cb,void * store)338 static int dis_set(const char *name, size_t len_rd, settings_read_cb read_cb, void *store)
339 {
340 	ssize_t len;
341 	int nlen;
342 	const char *next;
343 
344 	ARG_UNUSED(len);
345 
346 	nlen = settings_name_next(name, &next);
347 #if defined(CONFIG_BT_DIS_MANUF_NAME) || defined(CONFIG_BT_DIS_MANUF_DEPRECATED_USED)
348 	if (!strncmp(name, "manuf", nlen)) {
349 		len = read_cb(store, &dis_manuf, sizeof(dis_manuf) - 1);
350 		if (len < 0) {
351 			LOG_ERR("Failed to read manufacturer from storage (err %zd)", len);
352 		} else {
353 			dis_manuf[len] = '\0';
354 
355 			LOG_DBG("Manufacturer set to %s", dis_manuf);
356 		}
357 		return 0;
358 	}
359 #endif
360 #if defined(CONFIG_BT_DIS_MODEL_NUMBER) || defined(CONFIG_BT_DIS_MODEL_DEPRECATED_USED)
361 	if (!strncmp(name, "model", nlen)) {
362 		len = read_cb(store, &dis_model, sizeof(dis_model) - 1);
363 		if (len < 0) {
364 			LOG_ERR("Failed to read model from storage (err %zd)", len);
365 		} else {
366 			dis_model[len] = '\0';
367 
368 			LOG_DBG("Model set to %s", dis_model);
369 		}
370 		return 0;
371 	}
372 #endif
373 #if defined(CONFIG_BT_DIS_SERIAL_NUMBER)
374 	if (!strncmp(name, "serial", nlen)) {
375 		len = read_cb(store, &dis_serial_number, sizeof(dis_serial_number) - 1);
376 		if (len < 0) {
377 			LOG_ERR("Failed to read serial number from storage (err %zd)", len);
378 		} else {
379 			dis_serial_number[len] = '\0';
380 
381 			LOG_DBG("Serial number set to %s", dis_serial_number);
382 		}
383 		return 0;
384 	}
385 #endif
386 #if defined(CONFIG_BT_DIS_FW_REV)
387 	if (!strncmp(name, "fw", nlen)) {
388 		len = read_cb(store, &dis_fw_rev, sizeof(dis_fw_rev) - 1);
389 		if (len < 0) {
390 			LOG_ERR("Failed to read firmware revision from storage (err %zd)", len);
391 		} else {
392 			dis_fw_rev[len] = '\0';
393 
394 			LOG_DBG("Firmware revision set to %s", dis_fw_rev);
395 		}
396 		return 0;
397 	}
398 #endif
399 #if defined(CONFIG_BT_DIS_HW_REV)
400 	if (!strncmp(name, "hw", nlen)) {
401 		len = read_cb(store, &dis_hw_rev, sizeof(dis_hw_rev) - 1);
402 		if (len < 0) {
403 			LOG_ERR("Failed to read hardware revision from storage (err %zd)", len);
404 		} else {
405 			dis_hw_rev[len] = '\0';
406 
407 			LOG_DBG("Hardware revision set to %s", dis_hw_rev);
408 		}
409 		return 0;
410 	}
411 #endif
412 #if defined(CONFIG_BT_DIS_SW_REV)
413 	if (!strncmp(name, "sw", nlen)) {
414 		len = read_cb(store, &dis_sw_rev, sizeof(dis_sw_rev) - 1);
415 		if (len < 0) {
416 			LOG_ERR("Failed to read software revision from storage (err %zd)", len);
417 		} else {
418 			dis_sw_rev[len] = '\0';
419 
420 			LOG_DBG("Software revision set to %s", dis_sw_rev);
421 		}
422 		return 0;
423 	}
424 #endif
425 #if defined(CONFIG_BT_DIS_UDI)
426 	if (!strncmp(name, "udi_label", nlen)) {
427 		dis_update_udi_value(store, BT_DIS_UDI_LABEL_STR_REF, read_cb, "label");
428 		return 0;
429 	}
430 
431 	if (!strncmp(name, "udi_di", nlen)) {
432 		dis_update_udi_value(store, BT_DIS_UDI_DI_STR_REF, read_cb, "device information");
433 		return 0;
434 	}
435 
436 	if (!strncmp(name, "udi_issuer", nlen)) {
437 		dis_update_udi_value(store, BT_DIS_UDI_ISSUER_STR_REF, read_cb, "issuer");
438 		return 0;
439 	}
440 
441 	if (!strncmp(name, "udi_authority", nlen)) {
442 		dis_update_udi_value(store, BT_DIS_UDI_AUTHORITY_STR_REF, read_cb, "authority");
443 		return 0;
444 	}
445 #endif
446 #if defined(CONFIG_BT_DIS_SYSTEM_ID)
447 	if (!strncmp(name, "sysid_oui", nlen)) {
448 		uint32_t oui = 0;
449 
450 		len = read_cb(store, &oui, sizeof(oui));
451 		if (len < 0) {
452 			LOG_ERR("Failed to read System ID OUI from storage (err %zd)", len);
453 		} else {
454 			sys_put_le24(oui, &dis_system_id[5]);
455 			LOG_DBG("System ID OUI set to %06X", oui);
456 		}
457 		return 0;
458 	}
459 	if (!strncmp(name, "sysid_identifier", nlen)) {
460 		uint64_t identifier = 0;
461 
462 		len = read_cb(store, &identifier, sizeof(identifier));
463 		if (len < 0) {
464 			LOG_ERR("Failed to read System ID identifier from storage (err %zd)", len);
465 		} else {
466 			sys_put_le40(identifier, &dis_system_id[0]);
467 			LOG_DBG("System ID identifier set to %10llX", identifier);
468 		}
469 		return 0;
470 	}
471 #endif
472 #if defined(CONFIG_BT_DIS_IEEE_RCDL)
473 	if (!strncmp(name, "ieeercdl", nlen)) {
474 		len = read_cb(store, &dis_ieee_rcdl, sizeof(dis_ieee_rcdl) - 1);
475 		if (len < 0) {
476 			LOG_ERR("Failed to read IEEE 11073-20601 Regulatory Certification Data "
477 				"List from storage (err %zd)",
478 				len);
479 		} else {
480 			dis_ieee_rcdl[len] = '\0';
481 
482 			LOG_DBG("IEEE 11073-20601 Regulatory Certification Data List set to %s",
483 				dis_ieee_rcdl);
484 		}
485 		return 0;
486 	}
487 #endif
488 	return 0;
489 }
490 
491 SETTINGS_STATIC_HANDLER_DEFINE(bt_dis, "bt/dis", NULL, dis_set, NULL, NULL);
492 
493 #endif /* CONFIG_BT_DIS_SETTINGS*/
494