1 /*
2  * Copyright (c) 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