1 /*
2 * SPDX-FileCopyrightText: 2015-2016 Intel Corporation.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #ifndef _BLE_MESH_BYTEORDER_H_
8 #define _BLE_MESH_BYTEORDER_H_
9
10 #include "mesh_types.h"
11 #include "mesh_trace.h"
12
13 #ifdef __cplusplus
14 extern "C" {
15 #endif
16
17 /* Internal helpers only used by the sys_* APIs further below */
18 #ifndef __bswap_16
19 #define __bswap_16(x) ((uint16_t) ((((x) >> 8) & 0xff) | (((x) & 0xff) << 8)))
20 #endif
21
22 #ifndef __bswap_24
23 #define __bswap_24(x) ((uint32_t) ((((x) >> 16) & 0xff) | \
24 (((x)) & 0xff00) | \
25 (((x) & 0xff) << 16)))
26 #endif
27
28 #ifndef __bswap_32
29 #define __bswap_32(x) ((uint32_t) ((((x) >> 24) & 0xff) | \
30 (((x) >> 8) & 0xff00) | \
31 (((x) & 0xff00) << 8) | \
32 (((x) & 0xff) << 24)))
33 #endif
34
35 #ifndef __bswap_48
36 #define __bswap_48(x) ((uint64_t) ((((x) >> 40) & 0xff) | \
37 (((x) >> 24) & 0xff00) | \
38 (((x) >> 8) & 0xff0000) | \
39 (((x) & 0xff0000) << 8) | \
40 (((x) & 0xff00) << 24) | \
41 (((x) & 0xff) << 40)))
42 #endif
43
44 #ifndef __bswap_64
45 #define __bswap_64(x) ((uint64_t) ((((x) >> 56) & 0xff) | \
46 (((x) >> 40) & 0xff00) | \
47 (((x) >> 24) & 0xff0000) | \
48 (((x) >> 8) & 0xff000000) | \
49 (((x) & 0xff000000) << 8) | \
50 (((x) & 0xff0000) << 24) | \
51 (((x) & 0xff00) << 40) | \
52 (((x) & 0xff) << 56)))
53 #endif
54
55 /** @def sys_le16_to_cpu
56 * @brief Convert 16-bit integer from little-endian to host endianness.
57 *
58 * @param val 16-bit integer in little-endian format.
59 *
60 * @return 16-bit integer in host endianness.
61 */
62
63 /** @def sys_cpu_to_le16
64 * @brief Convert 16-bit integer from host endianness to little-endian.
65 *
66 * @param val 16-bit integer in host endianness.
67 *
68 * @return 16-bit integer in little-endian format.
69 */
70
71 /** @def sys_le24_to_cpu
72 * @brief Convert 24-bit integer from little-endian to host endianness.
73 *
74 * @param val 24-bit integer in little-endian format.
75 *
76 * @return 24-bit integer in host endianness.
77 */
78
79 /** @def sys_cpu_to_le24
80 * @brief Convert 24-bit integer from host endianness to little-endian.
81 *
82 * @param val 24-bit integer in host endianness.
83 *
84 * @return 24-bit integer in little-endian format.
85 */
86
87 /** @def sys_le32_to_cpu
88 * @brief Convert 32-bit integer from little-endian to host endianness.
89 *
90 * @param val 32-bit integer in little-endian format.
91 *
92 * @return 32-bit integer in host endianness.
93 */
94
95 /** @def sys_cpu_to_le32
96 * @brief Convert 32-bit integer from host endianness to little-endian.
97 *
98 * @param val 32-bit integer in host endianness.
99 *
100 * @return 32-bit integer in little-endian format.
101 */
102
103 /** @def sys_le48_to_cpu
104 * @brief Convert 48-bit integer from little-endian to host endianness.
105 *
106 * @param val 48-bit integer in little-endian format.
107 *
108 * @return 48-bit integer in host endianness.
109 */
110
111 /** @def sys_cpu_to_le48
112 * @brief Convert 48-bit integer from host endianness to little-endian.
113 *
114 * @param val 48-bit integer in host endianness.
115 *
116 * @return 48-bit integer in little-endian format.
117 */
118
119 /** @def sys_be16_to_cpu
120 * @brief Convert 16-bit integer from big-endian to host endianness.
121 *
122 * @param val 16-bit integer in big-endian format.
123 *
124 * @return 16-bit integer in host endianness.
125 */
126
127 /** @def sys_cpu_to_be16
128 * @brief Convert 16-bit integer from host endianness to big-endian.
129 *
130 * @param val 16-bit integer in host endianness.
131 *
132 * @return 16-bit integer in big-endian format.
133 */
134
135 /** @def sys_be24_to_cpu
136 * @brief Convert 24-bit integer from big-endian to host endianness.
137 *
138 * @param val 24-bit integer in big-endian format.
139 *
140 * @return 24-bit integer in host endianness.
141 */
142
143 /** @def sys_cpu_to_be24
144 * @brief Convert 24-bit integer from host endianness to big-endian.
145 *
146 * @param val 24-bit integer in host endianness.
147 *
148 * @return 24-bit integer in big-endian format.
149 */
150
151 /** @def sys_be32_to_cpu
152 * @brief Convert 32-bit integer from big-endian to host endianness.
153 *
154 * @param val 32-bit integer in big-endian format.
155 *
156 * @return 32-bit integer in host endianness.
157 */
158
159 /** @def sys_cpu_to_be32
160 * @brief Convert 32-bit integer from host endianness to big-endian.
161 *
162 * @param val 32-bit integer in host endianness.
163 *
164 * @return 32-bit integer in big-endian format.
165 */
166
167 /** @def sys_be48_to_cpu
168 * @brief Convert 48-bit integer from big-endian to host endianness.
169 *
170 * @param val 48-bit integer in big-endian format.
171 *
172 * @return 48-bit integer in host endianness.
173 */
174
175 /** @def sys_cpu_to_be48
176 * @brief Convert 48-bit integer from host endianness to big-endian.
177 *
178 * @param val 48-bit integer in host endianness.
179 *
180 * @return 48-bit integer in big-endian format.
181 */
182
183 #ifndef sys_le16_to_cpu
184 #define sys_le16_to_cpu(val) (val)
185 #endif
186 #ifndef sys_cpu_to_le16
187 #define sys_cpu_to_le16(val) (val)
188 #endif
189 #ifndef sys_le24_to_cpu
190 #define sys_le24_to_cpu(val) (val)
191 #endif
192 #ifndef sys_cpu_to_le24
193 #define sys_cpu_to_le24(val) (val)
194 #endif
195 #ifndef sys_le32_to_cpu
196 #define sys_le32_to_cpu(val) (val)
197 #endif
198 #ifndef sys_cpu_to_le32
199 #define sys_cpu_to_le32(val) (val)
200 #endif
201 #ifndef sys_le48_to_cpu
202 #define sys_le48_to_cpu(val) (val)
203 #endif
204 #ifndef sys_cpu_to_le48
205 #define sys_cpu_to_le48(val) (val)
206 #endif
207 #ifndef sys_le64_to_cpu
208 #define sys_le64_to_cpu(val) (val)
209 #endif
210 #ifndef sys_cpu_to_le64
211 #define sys_cpu_to_le64(val) (val)
212 #endif
213 #ifndef sys_be16_to_cpu
214 #define sys_be16_to_cpu(val) __bswap_16(val)
215 #endif
216 #ifndef sys_cpu_to_be16
217 #define sys_cpu_to_be16(val) __bswap_16(val)
218 #endif
219 #ifndef sys_be24_to_cpu
220 #define sys_be24_to_cpu(val) __bswap_24(val)
221 #endif
222 #ifndef sys_cpu_to_be24
223 #define sys_cpu_to_be24(val) __bswap_24(val)
224 #endif
225 #ifndef sys_be32_to_cpu
226 #define sys_be32_to_cpu(val) __bswap_32(val)
227 #endif
228 #ifndef sys_cpu_to_be32
229 #define sys_cpu_to_be32(val) __bswap_32(val)
230 #endif
231 #ifndef sys_be48_to_cpu
232 #define sys_be48_to_cpu(val) __bswap_48(val)
233 #endif
234 #ifndef sys_cpu_to_be48
235 #define sys_cpu_to_be48(val) __bswap_48(val)
236 #endif
237 #ifndef sys_be64_to_cpu
238 #define sys_be64_to_cpu(val) __bswap_64(val)
239 #endif
240 #ifndef sys_cpu_to_be64
241 #define sys_cpu_to_be64(val) __bswap_64(val)
242 #endif
243
244 /**
245 * @brief Put a 16-bit integer as big-endian to arbitrary location.
246 *
247 * Put a 16-bit integer, originally in host endianness, to a
248 * potentially unaligned memory location in big-endian format.
249 *
250 * @param val 16-bit integer in host endianness.
251 * @param dst Destination memory address to store the result.
252 */
sys_put_be16(uint16_t val,uint8_t dst[2])253 static inline void sys_put_be16(uint16_t val, uint8_t dst[2])
254 {
255 dst[0] = val >> 8;
256 dst[1] = val;
257 }
258
259 /**
260 * @brief Put a 24-bit integer as big-endian to arbitrary location.
261 *
262 * Put a 24-bit integer, originally in host endianness, to a
263 * potentially unaligned memory location in big-endian format.
264 *
265 * @param val 24-bit integer in host endianness.
266 * @param dst Destination memory address to store the result.
267 */
sys_put_be24(uint32_t val,uint8_t dst[3])268 static inline void sys_put_be24(uint32_t val, uint8_t dst[3])
269 {
270 dst[0] = val >> 16;
271 sys_put_be16(val, &dst[1]);
272 }
273
274 /**
275 * @brief Put a 32-bit integer as big-endian to arbitrary location.
276 *
277 * Put a 32-bit integer, originally in host endianness, to a
278 * potentially unaligned memory location in big-endian format.
279 *
280 * @param val 32-bit integer in host endianness.
281 * @param dst Destination memory address to store the result.
282 */
sys_put_be32(uint32_t val,uint8_t dst[4])283 static inline void sys_put_be32(uint32_t val, uint8_t dst[4])
284 {
285 sys_put_be16(val >> 16, dst);
286 sys_put_be16(val, &dst[2]);
287 }
288
289 /**
290 * @brief Put a 48-bit integer as big-endian to arbitrary location.
291 *
292 * Put a 48-bit integer, originally in host endianness, to a
293 * potentially unaligned memory location in big-endian format.
294 *
295 * @param val 48-bit integer in host endianness.
296 * @param dst Destination memory address to store the result.
297 */
sys_put_be48(uint64_t val,uint8_t dst[6])298 static inline void sys_put_be48(uint64_t val, uint8_t dst[6])
299 {
300 sys_put_be16(val >> 32, dst);
301 sys_put_be32(val, &dst[2]);
302 }
303
304 /**
305 * @brief Put a 64-bit integer as big-endian to arbitrary location.
306 *
307 * Put a 64-bit integer, originally in host endianness, to a
308 * potentially unaligned memory location in big-endian format.
309 *
310 * @param val 64-bit integer in host endianness.
311 * @param dst Destination memory address to store the result.
312 */
sys_put_be64(uint64_t val,uint8_t dst[8])313 static inline void sys_put_be64(uint64_t val, uint8_t dst[8])
314 {
315 sys_put_be32(val >> 32, dst);
316 sys_put_be32(val, &dst[4]);
317 }
318
319 /**
320 * @brief Put a 16-bit integer as little-endian to arbitrary location.
321 *
322 * Put a 16-bit integer, originally in host endianness, to a
323 * potentially unaligned memory location in little-endian format.
324 *
325 * @param val 16-bit integer in host endianness.
326 * @param dst Destination memory address to store the result.
327 */
sys_put_le16(uint16_t val,uint8_t dst[2])328 static inline void sys_put_le16(uint16_t val, uint8_t dst[2])
329 {
330 dst[0] = val;
331 dst[1] = val >> 8;
332 }
333
334 /**
335 * @brief Put a 24-bit integer as little-endian to arbitrary location.
336 *
337 * Put a 24-bit integer, originally in host endianness, to a
338 * potentially unaligned memory location in littel-endian format.
339 *
340 * @param val 24-bit integer in host endianness.
341 * @param dst Destination memory address to store the result.
342 */
sys_put_le24(uint32_t val,uint8_t dst[3])343 static inline void sys_put_le24(uint32_t val, uint8_t dst[3])
344 {
345 sys_put_le16(val, dst);
346 dst[2] = val >> 16;
347 }
348
349 /**
350 * @brief Put a 32-bit integer as little-endian to arbitrary location.
351 *
352 * Put a 32-bit integer, originally in host endianness, to a
353 * potentially unaligned memory location in little-endian format.
354 *
355 * @param val 32-bit integer in host endianness.
356 * @param dst Destination memory address to store the result.
357 */
sys_put_le32(uint32_t val,uint8_t dst[4])358 static inline void sys_put_le32(uint32_t val, uint8_t dst[4])
359 {
360 sys_put_le16(val, dst);
361 sys_put_le16(val >> 16, &dst[2]);
362 }
363
364 /**
365 * @brief Put a 48-bit integer as little-endian to arbitrary location.
366 *
367 * Put a 48-bit integer, originally in host endianness, to a
368 * potentially unaligned memory location in little-endian format.
369 *
370 * @param val 48-bit integer in host endianness.
371 * @param dst Destination memory address to store the result.
372 */
sys_put_le48(uint64_t val,uint8_t dst[6])373 static inline void sys_put_le48(uint64_t val, uint8_t dst[6])
374 {
375 sys_put_le32(val, dst);
376 sys_put_le16(val >> 32, &dst[4]);
377 }
378
379 /**
380 * @brief Put a 64-bit integer as little-endian to arbitrary location.
381 *
382 * Put a 64-bit integer, originally in host endianness, to a
383 * potentially unaligned memory location in little-endian format.
384 *
385 * @param val 64-bit integer in host endianness.
386 * @param dst Destination memory address to store the result.
387 */
sys_put_le64(uint64_t val,uint8_t dst[8])388 static inline void sys_put_le64(uint64_t val, uint8_t dst[8])
389 {
390 sys_put_le32(val, dst);
391 sys_put_le32(val >> 32, &dst[4]);
392 }
393
394 /**
395 * @brief Get a 16-bit integer stored in big-endian format.
396 *
397 * Get a 16-bit integer, stored in big-endian format in a potentially
398 * unaligned memory location, and convert it to the host endianness.
399 *
400 * @param src Location of the big-endian 16-bit integer to get.
401 *
402 * @return 16-bit integer in host endianness.
403 */
sys_get_be16(const uint8_t src[2])404 static inline uint16_t sys_get_be16(const uint8_t src[2])
405 {
406 return ((uint16_t)src[0] << 8) | src[1];
407 }
408
409 /**
410 * @brief Get a 24-bit integer stored in big-endian format.
411 *
412 * Get a 24-bit integer, stored in big-endian format in a potentially
413 * unaligned memory location, and convert it to the host endianness.
414 *
415 * @param src Location of the big-endian 24-bit integer to get.
416 *
417 * @return 24-bit integer in host endianness.
418 */
sys_get_be24(const uint8_t src[3])419 static inline uint32_t sys_get_be24(const uint8_t src[3])
420 {
421 return ((uint32_t)src[0] << 16) | sys_get_be16(&src[1]);
422 }
423
424 /**
425 * @brief Get a 32-bit integer stored in big-endian format.
426 *
427 * Get a 32-bit integer, stored in big-endian format in a potentially
428 * unaligned memory location, and convert it to the host endianness.
429 *
430 * @param src Location of the big-endian 32-bit integer to get.
431 *
432 * @return 32-bit integer in host endianness.
433 */
sys_get_be32(const uint8_t src[4])434 static inline uint32_t sys_get_be32(const uint8_t src[4])
435 {
436 return ((uint32_t)sys_get_be16(&src[0]) << 16) | sys_get_be16(&src[2]);
437 }
438
439 /**
440 * @brief Get a 48-bit integer stored in big-endian format.
441 *
442 * Get a 48-bit integer, stored in big-endian format in a potentially
443 * unaligned memory location, and convert it to the host endianness.
444 *
445 * @param src Location of the big-endian 48-bit integer to get.
446 *
447 * @return 48-bit integer in host endianness.
448 */
sys_get_be48(const uint8_t src[6])449 static inline uint64_t sys_get_be48(const uint8_t src[6])
450 {
451 return ((uint64_t)sys_get_be32(&src[0]) << 32) | sys_get_be16(&src[4]);
452 }
453
454 /**
455 * @brief Get a 64-bit integer stored in big-endian format.
456 *
457 * Get a 64-bit integer, stored in big-endian format in a potentially
458 * unaligned memory location, and convert it to the host endianness.
459 *
460 * @param src Location of the big-endian 64-bit integer to get.
461 *
462 * @return 64-bit integer in host endianness.
463 */
sys_get_be64(const uint8_t src[8])464 static inline uint64_t sys_get_be64(const uint8_t src[8])
465 {
466 return ((uint64_t)sys_get_be32(&src[0]) << 32) | sys_get_be32(&src[4]);
467 }
468
469 /**
470 * @brief Get a 16-bit integer stored in little-endian format.
471 *
472 * Get a 16-bit integer, stored in little-endian format in a potentially
473 * unaligned memory location, and convert it to the host endianness.
474 *
475 * @param src Location of the little-endian 16-bit integer to get.
476 *
477 * @return 16-bit integer in host endianness.
478 */
sys_get_le16(const uint8_t src[2])479 static inline uint16_t sys_get_le16(const uint8_t src[2])
480 {
481 return ((uint16_t)src[1] << 8) | src[0];
482 }
483
484 /**
485 * @brief Get a 24-bit integer stored in big-endian format.
486 *
487 * Get a 24-bit integer, stored in big-endian format in a potentially
488 * unaligned memory location, and convert it to the host endianness.
489 *
490 * @param src Location of the big-endian 24-bit integer to get.
491 *
492 * @return 24-bit integer in host endianness.
493 */
sys_get_le24(const uint8_t src[3])494 static inline uint32_t sys_get_le24(const uint8_t src[3])
495 {
496 return ((uint32_t)src[2] << 16) | sys_get_le16(&src[0]);
497 }
498
499 /**
500 * @brief Get a 32-bit integer stored in little-endian format.
501 *
502 * Get a 32-bit integer, stored in little-endian format in a potentially
503 * unaligned memory location, and convert it to the host endianness.
504 *
505 * @param src Location of the little-endian 32-bit integer to get.
506 *
507 * @return 32-bit integer in host endianness.
508 */
sys_get_le32(const uint8_t src[4])509 static inline uint32_t sys_get_le32(const uint8_t src[4])
510 {
511 return ((uint32_t)sys_get_le16(&src[2]) << 16) | sys_get_le16(&src[0]);
512 }
513
514 /**
515 * @brief Get a 48-bit integer stored in little-endian format.
516 *
517 * Get a 48-bit integer, stored in little-endian format in a potentially
518 * unaligned memory location, and convert it to the host endianness.
519 *
520 * @param src Location of the little-endian 48-bit integer to get.
521 *
522 * @return 48-bit integer in host endianness.
523 */
sys_get_le48(const uint8_t src[6])524 static inline uint64_t sys_get_le48(const uint8_t src[6])
525 {
526 return ((uint64_t)sys_get_le32(&src[2]) << 32) | sys_get_le16(&src[0]);
527 }
528
529 /**
530 * @brief Get a 64-bit integer stored in little-endian format.
531 *
532 * Get a 64-bit integer, stored in little-endian format in a potentially
533 * unaligned memory location, and convert it to the host endianness.
534 *
535 * @param src Location of the little-endian 64-bit integer to get.
536 *
537 * @return 64-bit integer in host endianness.
538 */
sys_get_le64(const uint8_t src[8])539 static inline uint64_t sys_get_le64(const uint8_t src[8])
540 {
541 return ((uint64_t)sys_get_le32(&src[4]) << 32) | sys_get_le32(&src[0]);
542 }
543
544 /**
545 * @brief Swap one buffer content into another
546 *
547 * Copy the content of src buffer into dst buffer in reversed order,
548 * i.e.: src[n] will be put in dst[end-n]
549 * Where n is an index and 'end' the last index in both arrays.
550 * The 2 memory pointers must be pointing to different areas, and have
551 * a minimum size of given length.
552 *
553 * @param dst A valid pointer on a memory area where to copy the data in
554 * @param src A valid pointer on a memory area where to copy the data from
555 * @param length Size of both dst and src memory areas
556 */
sys_memcpy_swap(void * dst,const void * src,size_t length)557 static inline void sys_memcpy_swap(void *dst, const void *src, size_t length)
558 {
559 uint8_t *pdst = (uint8_t *)dst;
560 const uint8_t *psrc = (const uint8_t *)src;
561
562 __ASSERT(((psrc < pdst && (psrc + length) <= pdst) ||
563 (psrc > pdst && (pdst + length) <= psrc)),
564 "Source and destination buffers must not overlap");
565
566 psrc += length - 1;
567
568 for (; length > 0; length--) {
569 *pdst++ = *psrc--;
570 }
571 }
572
573 /**
574 * @brief Swap buffer content
575 *
576 * In-place memory swap, where final content will be reversed.
577 * I.e.: buf[n] will be put in buf[end-n]
578 * Where n is an index and 'end' the last index of buf.
579 *
580 * @param buf A valid pointer on a memory area to swap
581 * @param length Size of buf memory area
582 */
sys_mem_swap(void * buf,size_t length)583 static inline void sys_mem_swap(void *buf, size_t length)
584 {
585 size_t i;
586
587 for (i = 0; i < (length / 2); i++) {
588 uint8_t tmp = ((uint8_t *)buf)[i];
589
590 ((uint8_t *)buf)[i] = ((uint8_t *)buf)[length - 1 - i];
591 ((uint8_t *)buf)[length - 1 - i] = tmp;
592 }
593 }
594
595 #ifdef __cplusplus
596 }
597 #endif
598
599 #endif /* _BLE_MESH_BYTEORDER_H_ */
600