1 /* srp.h
2  *
3  * Copyright (c) 2018 Apple Computer, Inc. All rights reserved.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * Service Registration Protocol common definitions
18  */
19 
20 #ifndef __SRP_H
21 #define __SRP_H
22 
23 #include <stdint.h>
24 #include <stdbool.h>
25 
26 #ifdef __clang__
27     #define NULLABLE _Nullable
28     #define NONNULL _Nonnull
29 #else
30     #define NULLABLE
31     #define NONNULL
32 #endif
33 
34 #ifdef DEBUG
35     #undef DEBUG
36     // #define DEBUG_VERBOSE
37 #endif
38 
39 // We always want this until we start shipping
40 #define DEBUG_VERBOSE
41 
42 #pragma clang diagnostic push
43 #pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
44 #ifdef THREAD_DEVKIT_ADK
45 
46     #include "nrf_delay.h"
47 
48     #define NULLABLE
49     #define NONNULL
50 
51     #if !(DARWIN)
52         struct in_addr {
53             uint8_t s_addr;
54         };
55         typedef struct in6_addr {
56             union {
57                 __uint8_t __u6_addr8[16];
58                 __uint16_t __u6_addr16[8];
59                 __uint32_t __u6_addr32[4];
60             } __u6_addr; /* 128-bit IP6 address */
61         } in6_addr_t;
62 
63         #define s6_addr __u6_addr.__u6_addr8
64 
65         #define ntohs(x) ((((uint16_t)(x) & 0xff00) >> 8) | (((uint16_t)(x) & 0xff) << 8))
66         #define htons(x) ntohs(x)
67 
68         struct iovec {
69             void *base;
70             size_t len;
71         };
72     #endif // !(DARWIN)
73 
74     #define OPENLOG(consolep)
75     #define DELAY 250
76     #define ERROR(fmt, ...) do {                               \
77             nrf_delay_ms(DELAY);                               \
78             HAPLogError(&kHAPLog_Default, fmt, ##__VA_ARGS__); \
79             nrf_delay_ms(DELAY);                               \
80         } while (0)
81     #define INFO(fmt, ...) do {                                \
82             nrf_delay_ms(DELAY);                               \
83             HAPLogInfo(&kHAPLog_Default, fmt, ##__VA_ARGS__);  \
84             nrf_delay_ms(DELAY);                               \
85         } while (0)
86 
87     #ifdef DEBUG_VERBOSE
88         #define DEBUG(fmt, ...) do {                               \
89                 nrf_delay_ms(DELAY);                               \
90                 HAPLogDebug(&kHAPLog_Default, fmt, ##__VA_ARGS__); \
91                 nrf_delay_ms(DELAY);                               \
92             } while (0)
93     #else // ifdef DEBUG_VERBOSE
94         #define DEBUG(fmt, ...)
95     #endif // ifdef DEBUG_VERBOSE
96 
97     #define NO_CLOCK
98 #else // ifdef THREAD_DEVKIT_ADK
99 
100     #ifdef LOG_FPRINTF_STDERR
101         #define OPENLOG(consolep)
102         #define ERROR(fmt, ...) fprintf(stderr, fmt "\n", ##__VA_ARGS__)
103         #define INFO(fmt, ...)  fprintf(stderr, fmt "\n", ##__VA_ARGS__)
104         #ifdef DEBUG_VERBOSE
105             #ifdef IOLOOP_MACOS
106                 int get_num_fds(void);
107             #endif // ifdef IOLOOP_MACOS
108             #define DEBUG(fmt, ...) fprintf(stderr, fmt "\n", ##__VA_ARGS__)
109         #else // ifdef DEBUG_VERBOSE
110             #define DEBUG(fmt, ...)
111         #endif
112     #else // ifdef LOG_FPRINTF_STDERR
113         #include <syslog.h>
114 
115         // Apple device always has OS_LOG support.
116         #ifdef __APPLE__
117             #define OS_LOG_ENABLED 1
118             #include <os/log.h>
119 
120             // Define log level
121             #define LOG_TYPE_FAULT      OS_LOG_TYPE_FAULT
122             #define LOG_TYPE_ERROR      OS_LOG_TYPE_ERROR
123             #define LOG_TYPE_DEFAULT    OS_LOG_TYPE_DEFAULT
124             #define LOG_TYPE_DEBUG      OS_LOG_TYPE_DEBUG
125             // Define log macro
126             #define log_with_component_and_type(CATEGORY, LEVEL, FORMAT, ...) os_log_with_type((CATEGORY), (LEVEL), \
127                                                                                 (FORMAT), ##__VA_ARGS__)
128 
129             #define OPENLOG(consolep) do {} while(0)
130             #define FAULT(FORMAT, ...)  log_with_component_and_type(OS_LOG_DEFAULT, LOG_TYPE_FAULT, FORMAT, \
131                                             ##__VA_ARGS__)
132             #define ERROR(FORMAT, ...)  log_with_component_and_type(OS_LOG_DEFAULT, LOG_TYPE_ERROR, FORMAT, \
133                                             ##__VA_ARGS__)
134 
135             #ifdef DEBUG_VERBOSE
136                 #ifdef DEBUG_FD_LEAKS
137                     int get_num_fds(void);
138                     #define INFO(FORMAT, ...) \
139                         do { \
140                             int foo = get_num_fds(); \
141                             log_with_component_and_type(OS_LOG_DEFAULT, LOG_TYPE_DEFAULT, "%d " FORMAT, foo, \
142                                 ##__VA_ARGS__); \
143                         } while(0)
144                 #else // ifdef IOLOOP_MACOS
145                     #define INFO(FORMAT, ...)   log_with_component_and_type(OS_LOG_DEFAULT, LOG_TYPE_DEFAULT, FORMAT, \
146                                                     ##__VA_ARGS__)
147                 #endif // ifdef IOLOOP_MACOS
148 
149                 #define DEBUG(FORMAT, ...)  log_with_component_and_type(OS_LOG_DEFAULT, LOG_TYPE_DEBUG, FORMAT, \
150                                                 ##__VA_ARGS__)
151             #else // ifdef DEBUG_VERBOSE
152                 #define INFO(FORMAT, ...)   log_with_component_and_type(OS_LOG_DEFAULT, LOG_TYPE_DEFAULT, FORMAT, \
153                                                 ##__VA_ARGS__)
154                 #define DEBUG(FORMAT, ...)  do {} while(0)
155             #endif // ifdef DEBUG_VERBOSE
156         #else // ifdef __APPLE__
157             #define OS_LOG_ENABLED 0
158 
159             #define OPENLOG(consolep) openlog("srp-mdns-proxy", (consolep ? LOG_PERROR : 0) | LOG_PID, LOG_DAEMON)
160             #define FAULT(fmt, ...) syslog(LOG_CRIT, fmt, ##__VA_ARGS__)
161             #define ERROR(fmt, ...) syslog(LOG_ERR, fmt, ##__VA_ARGS__)
162 
163             #ifdef DEBUG_VERBOSE
164                 #ifdef DEBUG_FD_LEAKS
165                     int get_num_fds(void);
166                     #define INFO(fmt, ...) \
167                         do { \
168                             int foo = get_num_fds(); \
169                             syslog(LOG_INFO, "%d " fmt, foo, ##__VA_ARGS__); \
170                         } while (0)
171                 #else // ifdef IOLOOP_MACOS
172                     #define INFO(fmt, ...)  syslog(LOG_INFO, fmt, ##__VA_ARGS__)
173                 #endif // ifdef IOLOOP_MACOS
174                 #define DEBUG(fmt, ...) syslog(LOG_DEBUG, fmt, ##__VA_ARGS__)
175             #else // ifdef DEBUG_VERBOSE
176                 #define INFO(fmt, ...)  syslog(LOG_INFO, fmt, ##__VA_ARGS__)
177                 #define DEBUG(fmt, ...) do {} while(0)
178             #endif // ifdef DEBUG_VERBOSE
179         #endif // ifdef __APPLE__
180     #endif // ifdef LOG_FPRINTF_STDERR
181 #endif // ifdef THREAD_DEVKIT_ADK
182 
183 //======================================================================================================================
184 // MARK: - Logging Macros
185 /**
186  * With the logging routines defined above, the logging macros are defined to facilitate the log redaction enforced by
187  * os_log on Apple platforms. By using the specifier "%{mask.hash}", the "<private>" text in the logs of customer device
188  * would be shown as a hashing value, which could be used as a way to associate other SRP logs even if it's redacted.
189  *
190  * On Apple platforms, the current existing log routines will be defined as:
191  * #define log_with_component_and_type(CATEGORY, LEVEL, FORMAT, ...) os_log_with_type((CATEGORY), (LEVEL), (FORMAT), \
192  *                                                                      ##__VA_ARGS__)
193  * #define ERROR(FORMAT, ...)  log_with_component_and_type(OS_LOG_DEFAULT, LOG_TYPE_ERROR, FORMAT, ##__VA_ARGS__)
194  * #define INFO(FORMAT, ...)   log_with_component_and_type(OS_LOG_DEFAULT, LOG_TYPE_DEFAULT, FORMAT, ##__VA_ARGS__)
195  * #define DEBUG(FORMAT, ...)  log_with_component_and_type(OS_LOG_DEFAULT, LOG_TYPE_DEBUG, FORMAT, ##__VA_ARGS__)
196  * And to follow the same log level with os_log, FAULT() is defined.
197  * #define FAULT(FORMAT, ...)  log_with_component_and_type(OS_LOG_DEFAULT, LOG_TYPE_FAULT, FORMAT, ##__VA_ARGS__)
198  * Therefore, all the previous logs would be put under OS_LOG_DEFAULT category.
199  * FAULT level lof will be mapped to  LOG_TYPE_FAULT in os_log.
200  * ERROR level log will be mapped to LOG_TYPE_ERROR in os_log.
201  * INFO level log will be mapped to LOG_TYPE_DEFAULT in os_log.
202  * DEBUG level log woll be mapped to LOG_TYPE_DEBUG in os_log.
203  *
204  * On platforms other than Apple, syslog will be used to write logs.
205  * FAULT level lof will be mapped to  LOG_CRIT in syslog.
206  * ERROR level log will be mapped to LOG_ERR in syslog.
207  * INFO level log will be mapped to LOG_INFO in syslog.
208  * DEBUG level log woll be mapped to LOG_DEBUG in syslog.
209  *
210  * The defined specifiers are:
211  * String specifier:
212  *      PUB_S_SRP: Use this in the format string when trying to log string and do not want it to be redacted.
213  *      PRI_S_SRP: Use this when trying to log string and redact it to a hash string.
214  *      Usage:
215  *          INFO("Public string: " PUB_S_SRP, ", private string: " PRI_S_SRP, string_ptr, string_ptr);
216  *
217  * DNS name (with dns_label_t type) specifier:
218  *      DNS_NAME_GEN_SRP: Always call this before logging DNS name.
219  *      PUB_DNS_NAME_SRP: Use this in the format string when trying to log DNS name and do not want it to be redacted.
220  *      PRI_DNS_NAME_SRP: Use this in the format string when trying to log DNS name and redact it to a hash string.
221  *      DNS_NAME_PARAM_SRP: Always use DNS_NAME_PARAM_SRP in the paramter list.
222  *      Usage:
223  *          DNS_NAME_GEN_SRP(dns_name_ptr, dns_name_buf);
224  *          INFO("Public DNS name: " PUB_DNS_NAME_SRP, ", private DNS name: " PRI_DNS_NAME_SRP,
225  *              DNS_NAME_PARAM_SRP(dns_name_ptr, dns_name_buf), DNS_NAME_PARAM_SRP(dns_name_ptr, dns_name_buf));
226  *
227  * IPv4 address specifier (with in_addr * type or a pointer to uint8_t[4]):
228  *      IPv4_ADDR_GEN_SRP: Always call this before logging IPv4 address.
229  *      PUB_IPv4_ADDR_SRP: Use this in the format string when trying to log IPv4 address and do not want it to be
230  *                         redacted.
231  *      PRI_IPv4_ADDR_SRP: Use this in the format string when trying to log IPv4 address and redact it to a hash string.
232  *      IPv4_ADDR_PARAM_SRP: Always use IPv4_ADDR_PARAM_SRP in the paramter list.
233  *      Usage:
234  *          IPv4_ADDR_GEN_SRP(in_addr_ptr_1, in_addr_buf_1);
235  *          IPv4_ADDR_GEN_SRP(in_addr_ptr_2, in_addr_buf_2);
236  *          INFO("Public IPv4 address: " PUB_IPv4_ADDR_SRP, ", private IPv4 address: " PRI_IPv4_ADDR_SRP,
237  *              IPv4_ADDR_PARAM_SRP(in_addr_ptr_1, in_addr_buf_1), IPv4_ADDR_PARAM_SRP(in_addr_ptr_2, in_addr_buf_2));
238  *
239  * IPv6 address specifier (with in6_addr * type or a pointer to uint8_t[16]):
240  *      IPv6_ADDR_GEN_SRP: Always call this before logging IPv6 address.
241  *      PUB_IPv6_ADDR_SRP: Use this in the format string when trying to log IPv6 address and do not want it to be
242  *                         redacted.
243  *      PRI_IPv6_ADDR_SRP: Use this in the format string when trying to log IPv6 address and redact it to a hash string.
244  *      IPv6_ADDR_PARAM_SRP: Always use IPv6_ADDR_PARAM_SRP in the paramter list.
245  *      Usage:
246  *          IPv6_ADDR_GEN_SRP(in6_addr_ptr_1, in6_addr_buf_1);
247  *          IPv6_ADDR_GEN_SRP(in6_addr_ptr_2, in6_addr_buf_2);
248  *          INFO("Public IPv6 address: " PUB_IPv6_ADDR_SRP, ", private IPv6 address: " PRI_IPv6_ADDR_SRP,
249  *              IPv6_ADDR_PARAM_SRP(in6_addr_ptr_1, in6_addr_buf_1),
250  *              IPv6_ADDR_PARAM_SRP(in6_addr_ptr_2, in6_addr_buf_2));
251  *
252  * Segmented IPv6  address specifier (with in6_addr * type or a pointer to uint8_t[16]):
253  *      SEGMENTED_IPv6_ADDR_GEN_SRP: Always call this before logging segmented IPv6 address.
254  *      PUB_SEGMENTED_IPv6_ADDR_SRP: Use this in the format string when trying to log segmented IPv6 address and do not
255  *                                   want it to be redacted.
256  *      PRI_SEGMENTED_IPv6_ADDR_SRP: Use this in the format string when trying to log segmented IPv6 address and redact
257  *                                   it to a hash string.
258  *      SEGMENTED_IPv6_ADDR_PARAM_SRP: Always use SEGMENTED_IPv6_ADDR_PARAM_SRP in the paramter list.
259  *      Usage:
260  *          SEGMENTED_IPv6_ADDR_GEN_SRP(in6_addr_ptr_1, in6_addr_buf_1);
261  *          SEGMENTED_IPv6_ADDR_GEN_SRP(in6_addr_ptr_2, in6_addr_buf_2);
262  *          INFO("Public IPv6 address: " PUB_SEGMENTED_IPv6_ADDR_SRP, ", private IPv6 address: "
263  *               PRI_SEGMENTED_IPv6_ADDR_SRP, SEGMENTED_IPv6_ADDR_PARAM_SRP(in6_addr_ptr_1, in6_addr_buf_1),
264  *               SEGMENTED_IPv6_ADDR_PARAM_SRP(in6_addr_ptr_2, in6_addr_buf_2));
265  *      Note:
266  *          Segmented IPv6 is prefered when logging IPv6 address in SRP, because the address is divided to: 48 bit
267  *          prefix, 16 bit subnet, 64 bit host, which makes it easier to match the prefix even when log redaction is
268  *          turned on and the address is hashed to a string.
269  *
270  * IPv6 prefix specifier (with a pointer to uint8_t[] array):
271  *      IPv6_PREFIX_GEN_SRP: Always call this before logging IPv6 prefix (which is also segmented).
272  *      PUB_IPv6_PREFIX_SRP: Use this in the format string when trying to log IPv6 prefix and do not want it to be
273  *                           redacted.
274  *      PRI_IPv6_PREFIX_SRP: Use this in the format string when trying to log IPv6 prefix and redact it to a hash
275  *                           string.
276  *      IPv6_PREFIX_PARAM_SRP: Always use IPv6_PREFIX_PARAM_SRP in the paramter list.
277  *      Usage:
278  *          IPv6_PREFIX_GEN_SRP(in6_prefix_ptr_1, sizeof(in6_prefix_1), in6_prefix_buf_1);
279  *          IPv6_PREFIX_GEN_SRP(in6_prefix_ptr_2, sizeof(in6_prefix_2), in6_prefix_buf_2);
280  *          INFO("Public IPv6 prefix: " PUB_IPv6_PREFIX_SRP, ", private IPv6 prefix: " PRI_IPv6_PREFIX_SRP,
281  *              IPv6_PREFIX_PARAM_SRP(in6_prefix_buf_1), IPv6_PREFIX_PARAM_SRP(in6_prefix_buf_2));
282  *
283  * Mac address specifier (with a pointer to uint8_t[6] array):
284  *      PUB_MAC_ADDR_SRP: Use this in the format string when trying to log Mac address and do not want it to be
285  *                        redacted.
286  *      PRI_MAC_ADDR_SRP: Use this in the format string when trying to log Mac address and redact it to a hash string.
287  *      MAC_ADDR_PARAM_SRP: Always use MAC_ADDR_PARAM_SRP in the paramter list.
288  *      Usage:
289  *          INFO("Public MAC address: " PUB_MAC_ADDR_SRP, ", private MAC address: " PRI_MAC_ADDR_SRP,
290  *              MAC_ADDR_PARAM_SRP(mac_addr), MAC_ADDR_PARAM_SRP(mac_addr));
291  */
292 
293 // Helper macro to display if the correspoding IPv6 is ULA (Unique Local Address), LUA (Link Local Address)
294 // or GUA (Global Unicast Address).
295 // ULA starts with FC00::/7.
296 // LUA starts with fe80::/10.
297 // GUA starts with 2000::/3.
298 #define ADDRESS_RANGE_STR(ADDR) ( \
299                                     ((ADDR)[0] & 0xFE) == 0xFC ? \
300                                         " (ULA)" : \
301                                         ( \
302                                             ( ((ADDR)[0] == 0xFE) && ((uint8_t)(ADDR)[1] & 0xC0) == 0x80 ) ? \
303                                                 " (LUA)" : \
304                                                 ( ((ADDR)[0] & 0xE0) == 0x20 ? " (GUA)" : "" ) \
305                                         ) \
306                                 )
307 
308 // Logging macros
309 #if OS_LOG_ENABLED
310     // Define log specifier
311     // String
312     #define PUB_S_SRP "%{public}s"
313     #define PRI_S_SRP "%{private, mask.hash}s"
314     // DNS name, when the pointer to DNS name is NULL, <NULL> will be logged.
315     #define DNS_NAME_GEN_SRP(NAME, BUF_NAME) \
316         char BUF_NAME[DNS_MAX_NAME_SIZE_ESCAPED + 1]; \
317         if (NAME != NULL) { \
318             dns_name_print(NAME, BUF_NAME, sizeof(BUF_NAME)); \
319         } else { \
320             strncpy(BUF_NAME, "<null>", sizeof("<null>") < sizeof(BUF_NAME) ? sizeof("<null>") : sizeof(BUF_NAME)); \
321         }
322     #define PUB_DNS_NAME_SRP PUB_S_SRP
323     #define PRI_DNS_NAME_SRP PRI_S_SRP
324     #define DNS_NAME_PARAM_SRP(NAME, BUF) (BUF)
325     // IP address
326     // IPv4
327     #define IPv4_ADDR_GEN_SRP(ADDR, BUF_NAME) do {} while(0)
328     #define PUB_IPv4_ADDR_SRP "%{public, network:in_addr}.4P"
329     #define PRI_IPv4_ADDR_SRP "%{private, mask.hash, network:in_addr}.4P"
330     #define IPv4_ADDR_PARAM_SRP(ADDR, BUF) ((uint8_t *)ADDR)
331     // IPv6
332     #define IPv6_ADDR_GEN_SRP(ADDR, BUF_NAME) do {} while(0)
333     #define PUB_IPv6_ADDR_SRP "%{public, network:in6_addr}.16P%{public}s"
334     #define PRI_IPv6_ADDR_SRP "%{private, mask.hash, network:in6_addr}.16P%{public}s"
335     #define IPv6_ADDR_PARAM_SRP(ADDR, BUF) ((uint8_t *)ADDR), ADDRESS_RANGE_STR((uint8_t *)ADDR)
336     // Segmented IPv6
337     // Subnet part can always be public.
338     #define SEGMENTED_IPv6_ADDR_GEN_SRP(ADDR, BUF_NAME) do {} while(0)
339     #define PUB_SEGMENTED_IPv6_ADDR_SRP "{%{public, srp:in6_addr_segment}.6P%{public}s, " \
340                                             "%{public, srp:in6_addr_segment}.2P, " \
341                                             "%{public, srp:in6_addr_segment}.8P}"
342     #define PRI_SEGMENTED_IPv6_ADDR_SRP "{%{private, mask.hash, srp:in6_addr_segment}.6P%{public}s, " \
343                                             "%{public, mask.hash, srp:in6_addr_segment}.2P, " \
344                                             "%{private, mask.hash, srp:in6_addr_segment}.8P}"
345     #define SEGMENTED_IPv6_ADDR_PARAM_SRP(ADDR, BUF) ((uint8_t *)(ADDR)), ADDRESS_RANGE_STR((uint8_t *)ADDR), \
346                                                         ((uint8_t *)(ADDR) + 6), ((uint8_t *)(ADDR) + 8)
347     // MAC address
348     #define PUB_MAC_ADDR_SRP "%{public, srp:mac_addr}.6P"
349     #define PRI_MAC_ADDR_SRP "%{private, mask.hash, srp:mac_addr}.6P"
350     #define MAC_ADDR_PARAM_SRP(ADDR) ((uint8_t *)ADDR)
351 
352 #else // ifdef OS_LOG_ENABLED
353     // When os_log is not available, all logs would be public.
354     // Define log specifier
355     // String
356     #define PUB_S_SRP "%s"
357     #define PRI_S_SRP PUB_S_SRP
358     // DNS name, when the pointer to DNS name is NULL, <NULL> will be logged.
359     #define DNS_NAME_GEN_SRP(NAME, BUF_NAME) \
360         char BUF_NAME[DNS_MAX_NAME_SIZE_ESCAPED + 1]; \
361         if (NAME != NULL) { \
362             dns_name_print(NAME, BUF_NAME, sizeof(BUF_NAME)); \
363         } else { \
364             strncpy(BUF_NAME, "<null>", sizeof("<null>") < sizeof(BUF_NAME) ? sizeof("<null>") : sizeof(BUF_NAME)); \
365         }
366     #define PUB_DNS_NAME_SRP "%s"
367     #define PRI_DNS_NAME_SRP PUB_DNS_NAME_SRP
368     #define DNS_NAME_PARAM_SRP(NAME, BUF) (BUF)
369     // IP address
370     // IPv4
371     #define IPv4_ADDR_GEN_SRP(ADDR, BUF_NAME) char BUF_NAME[INET_ADDRSTRLEN]; \
372                                                     inet_ntop(AF_INET, ((uint8_t *)ADDR), BUF_NAME, sizeof(BUF_NAME))
373     #define PUB_IPv4_ADDR_SRP "%s"
374     #define PRI_IPv4_ADDR_SRP PUB_IPv4_ADDR_SRP
375     #define IPv4_ADDR_PARAM_SRP(ADDR, BUF) (BUF)
376     // IPv6
377     #define IPv6_ADDR_GEN_SRP(ADDR, BUF_NAME) char BUF_NAME[INET6_ADDRSTRLEN]; \
378                                                     inet_ntop(AF_INET6, ((uint8_t *)ADDR), BUF_NAME, sizeof(BUF_NAME))
379     #define PUB_IPv6_ADDR_SRP "%s%s"
380     #define PRI_IPv6_ADDR_SRP PUB_IPv6_ADDR_SRP
381     #define IPv6_ADDR_PARAM_SRP(ADDR, BUF) (BUF), ADDRESS_RANGE_STR((uint8_t *)ADDR)
382     // Segmented IPv6
383     #define SEGMENTED_IPv6_ADDR_GEN_SRP(ADDR, BUF_NAME) IPv6_ADDR_GEN_SRP(ADDR, BUF_NAME)
384 
385     #define PUB_SEGMENTED_IPv6_ADDR_SRP PUB_IPv6_ADDR_SRP
386     #define PRI_SEGMENTED_IPv6_ADDR_SRP PRI_IPv6_ADDR_SRP
387     #define SEGMENTED_IPv6_ADDR_PARAM_SRP(ADDR, BUF) IPv6_ADDR_PARAM_SRP(ADDR, BUF)
388     // MAC address
389     #define PUB_MAC_ADDR_SRP "%02x:%02x:%02x:%02x:%02x:%02x"
390     #define PRI_MAC_ADDR_SRP PUB_MAC_ADDR_SRP
391     #define MAC_ADDR_PARAM_SRP(ADDR) ((uint8_t *)ADDR)[0], ((uint8_t *)ADDR)[1], ((uint8_t *)ADDR)[2], \
392                                         ((uint8_t *)ADDR)[3], ((uint8_t *)ADDR)[4], ((uint8_t *)ADDR)[5]
393 
394 #endif // ifdef OS_LOG_ENABLED
395 
396 // IPv6 ULA 48-bit prefix
397 #define IPv6_PREFIX_GEN_SRP(PREFIX, PREFIX_LEN, BUF_NAME) \
398     struct in6_addr _in6_addr_##BUF_NAME##_full_addr = {0}; \
399     memcpy(_in6_addr_##BUF_NAME##_full_addr.s6_addr, (PREFIX), \
400         MIN(sizeof(_in6_addr_##BUF_NAME##_full_addr.s6_addr), (PREFIX_LEN))); \
401     SEGMENTED_IPv6_ADDR_GEN_SRP(_in6_addr_##BUF_NAME##_full_addr.s6_addr, BUF_NAME);
402 #define PUB_IPv6_PREFIX_SRP PUB_SEGMENTED_IPv6_ADDR_SRP
403 #define PRI_IPv6_PREFIX_SRP PRI_SEGMENTED_IPv6_ADDR_SRP
404 #define IPv6_PREFIX_PARAM_SRP(BUF_NAME) SEGMENTED_IPv6_ADDR_PARAM_SRP(_in6_addr_##BUF_NAME##_full_addr.s6_addr, \
405                                             BUF_NAME)
406 
407 //======================================================================================================================
408 
409 #pragma clang diagnostic pop
410 
411 #ifdef DEBUG_VERBOSE
412 #ifdef __clang_analyzer__
413 #define RELEASE_BASE(x, finalize, file, line) \
414     finalize(x)
415 #else
416 #define RELEASE_BASE(x, finalize, file, line)                                 \
417     do {                                                                      \
418         INFO("ALLOC: release at %2.2d: %p (%10s): %s:%d",                     \
419              (x)->ref_count, (void *)(x), # x, strrchr(file, '/') + 1, line); \
420         --(x)->ref_count;                                                     \
421         if ((x)->ref_count == 0) {                                            \
422             INFO("ALLOC:      finalize: %p (%10s): %s:%d",                    \
423                  (void *)(x), # x, strrchr(file, '/') + 1, line);             \
424             finalize(x);                                                      \
425         }                                                                     \
426     } while (0)
427 #endif // __clang_analyzer__
428 #define RETAIN_BASE(x, file, line)                                            \
429     do {                                                                      \
430         INFO("ALLOC:  retain at %2.2d: %p (%10s): %s:%d",                     \
431              (x)->ref_count, (void *)(x), # x, strrchr(file, '/') + 1, line); \
432         ++(x)->ref_count;                                                     \
433     } while (0)
434 #define RELEASE(x, finalize) RELEASE_BASE(x, finalize, file, line)
435 #define RETAIN(x) RETAIN_BASE(x, file, line)
436 #define RELEASE_HERE(x, finalize) RELEASE_BASE(x, finalize, __FILE__, __LINE__)
437 #define RETAIN_HERE(x) RETAIN_BASE(x, __FILE__, __LINE__)
438 #else
439 #ifdef __clang_analyzer__
440 #define RELEASE(x, finalize) finalize(x)
441 #define RELEASE_HERE(x, finalize) finalize(x)
442 #define RETAIN(x)
443 #define RETAIN_HERE(x)
444 #else
445 #define RELEASE(x, finalize) do {    \
446         if (--(x)->ref_count == 0) { \
447             finalize(x);             \
448             (void)file; (void)line;  \
449         }                            \
450     } while (0)
451 #define RETAIN(x) do {          \
452         (x)->ref_count++;       \
453         (void)file; (void)line; \
454     } while (0)
455 #define RELEASE_HERE(x, finalize) do {    \
456         if (--(x)->ref_count == 0) {      \
457             finalize(x);                  \
458         }                                 \
459     } while (0)
460 #define RETAIN_HERE(x) ((x)->ref_count++)
461 #endif
462 #endif // DEBUG_VERBOSE
463 
464 #define THREAD_ENTERPRISE_NUMBER ((uint64_t)44970)
465 #define THREAD_SRP_SERVER_OPTION 0x5d
466 #define THREAD_PREF_ID_OPTION    0x9d
467 
468 #define IS_SRP_SERVICE(service) \
469     ((cti_service)->enterprise_number == THREAD_ENTERPRISE_NUMBER &&    \
470      (cti_service)->service_type == THREAD_SRP_SERVER_OPTION &&         \
471      (cti_service)->service_version == 1 &&                             \
472      (cti_service)->server_length == 18)
473 #define IS_PREF_ID_SERVICE(service) \
474     ((cti_service)->enterprise_number == THREAD_ENTERPRISE_NUMBER &&    \
475      (cti_service)->service_type == THREAD_PREF_ID_OPTION &&            \
476      (cti_service)->service_version == 1 &&                             \
477      (cti_service)->server_length == 9)
478 
479 #ifdef MALLOC_DEBUG_LOGGING
480 void *debug_malloc(size_t len, const char *file, int line);
481 void *debug_calloc(size_t count, size_t len, const char *file, int line);
482 char *debug_strdup(const char *s, const char *file, int line);
483 void debug_free(void *p, const char *file, int line);
484 
485 #define malloc(x) debug_malloc(x, __FILE__, __LINE__)
486 #define calloc(c, y) debug_calloc(c, y, __FILE__, __LINE__)
487 #define strdup(s) debug_strdup(s, __FILE__, __LINE__)
488 #define free(p) debug_free(p, __FILE__, __LINE__)
489 #endif
490 
491 typedef struct srp_key srp_key_t;
492 #endif // __SRP_H
493 
494 // Local Variables:
495 // mode: C
496 // tab-width: 4
497 // c-file-style: "bsd"
498 // c-basic-offset: 4
499 // fill-column: 108
500 // indent-tabs-mode: nil
501 // End:
502