1 /*
2  *  Copyright (c) 2023, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 /**
30  * @file
31  * @brief
32  *   This file includes the platform abstraction for DNS-SD (e.g., mDNS) on the infrastructure network.
33  *
34  */
35 
36 #ifndef OPENTHREAD_PLATFORM_DNSSD_H_
37 #define OPENTHREAD_PLATFORM_DNSSD_H_
38 
39 #include <stdint.h>
40 
41 #include <openthread/dns.h>
42 #include <openthread/error.h>
43 #include <openthread/instance.h>
44 #include <openthread/ip6.h>
45 
46 #ifdef __cplusplus
47 extern "C" {
48 #endif
49 
50 /**
51  * @addtogroup plat-dns-sd
52  *
53  * @brief
54  *   This module includes the platform abstraction for DNS-SD (e.g., mDNS) on the infrastructure network.
55  *
56  * @{
57  *
58  * The DNS-SD platform APIs are used only when `OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE` is enabled.
59  *
60  */
61 
62 /**
63  * Represents the state of the DNS-SD platform.
64  *
65  */
66 typedef enum otPlatDnssdState
67 {
68     OT_PLAT_DNSSD_STOPPED, ///< Stopped and unable to register any service or host.
69     OT_PLAT_DNSSD_READY,   ///< Running and ready to register service or host.
70 } otPlatDnssdState;
71 
72 /**
73  * Represents a request ID for registering/unregistering a service or host.
74  *
75  */
76 typedef uint32_t otPlatDnssdRequestId;
77 
78 /**
79  * Represents the callback function used when registering/unregistering a host or service.
80  *
81  * See `otPlatDnssdRegisterService()`, `otPlatDnssdUnregisterService()`, `otPlatDnssdRegisterHost()`, and
82  * `otPlatDnssdUnregisterHost()` for more details about when to invoke the callback and the `aError` values that can
83  * be returned in each case.
84  *
85  * @param[in] aInstance     The OpenThread instance.
86  * @param[in] aRequestId    The request ID.
87  * @param[in] aError        Error indicating the outcome of request.
88  *
89  */
90 typedef void (*otPlatDnssdRegisterCallback)(otInstance *aInstance, otPlatDnssdRequestId aRequestId, otError aError);
91 
92 /**
93  * Represents a DNS-SD service.
94  *
95  * See `otPlatDnssdRegisterService()`, `otPlatDnssdUnregisterService()` for more details about fields in each case.
96  *
97  */
98 typedef struct otPlatDnssdService
99 {
100     const char        *mHostName;            ///< The host name (does not include domain name).
101     const char        *mServiceInstance;     ///< The service instance name label (not the full name).
102     const char        *mServiceType;         ///< The service type (e.g., "_mt._udp", does not include domain name).
103     const char *const *mSubTypeLabels;       ///< Array of sub-type labels (can be NULL if no label).
104     uint16_t           mSubTypeLabelsLength; ///< Length of array of sub-type labels.
105     const uint8_t     *mTxtData;             ///< Encoded TXT data bytes.
106     uint16_t           mTxtDataLength;       ///< Length of TXT data.
107     uint16_t           mPort;                ///< The service port number.
108     uint16_t           mPriority;            ///< The service priority.
109     uint16_t           mWeight;              ///< The service weight.
110     uint32_t           mTtl;                 ///< The service TTL in seconds.
111     uint32_t           mInfraIfIndex;        ///< The infrastructure network interface index.
112 } otPlatDnssdService;
113 
114 /**
115  * Represents a DNS-SD host.
116  *
117  * See `otPlatDnssdRegisterHost()`, `otPlatDnssdUnregisterHost()` for more details about fields in each case.
118  *
119  */
120 typedef struct otPlatDnssdHost
121 {
122     const char         *mHostName;        ///< The host name (does not include domain name).
123     const otIp6Address *mAddresses;       ///< Array of IPv6 host addresses.
124     uint16_t            mAddressesLength; ///< Number of entries in @p mAddresses array.
125     uint32_t            mTtl;             ///< The host TTL in seconds.
126     uint32_t            mInfraIfIndex;    ///< The infrastructure network interface index.
127 } otPlatDnssdHost;
128 
129 /**
130  * Represents a DNS-SD key record.
131  *
132  * See `otPlatDnssdRegisterKey()`, `otPlatDnssdUnregisterKey()` for more details about fields in each case.
133  *
134  */
135 typedef struct otPlatDnssdKey
136 {
137     const char    *mName;          ///< A host or a service instance name (does not include domain name).
138     const char    *mServiceType;   ///< The service type if key is for a service (does not include domain name).
139     const uint8_t *mKeyData;       ///< Byte array containing the key record data.
140     uint16_t       mKeyDataLength; ///< Length of @p mKeyData in bytes.
141     uint16_t       mClass;         ///< The resource record class.
142     uint32_t       mTtl;           ///< The TTL in seconds.
143     uint32_t       mInfraIfIndex;  ///< The infrastructure network interface index.
144 } otPlatDnssdKey;
145 
146 /**
147  * Callback to notify state changes of the DNS-SD platform.
148  *
149  * The OpenThread stack will call `otPlatDnssdGetState()` (from this callback or later) to get the new state. The
150  * platform MUST therefore ensure that the returned state from `otPlatDnssdGetState()` is updated before calling this.
151  *
152  * @param[in] aInstance The OpenThread instance structure.
153  *
154  */
155 extern void otPlatDnssdStateHandleStateChange(otInstance *aInstance);
156 
157 /**
158  * Gets the current state of the DNS-SD module.
159  *
160  * The platform MUST notify the OpenThread stack whenever its state gets changed by invoking
161  * `otPlatDnssdStateHandleStateChange()`.
162  *
163  * @param[in] aInstance     The OpenThread instance.
164  *
165  * @returns The current state of the DNS-SD module.
166  *
167  */
168 otPlatDnssdState otPlatDnssdGetState(otInstance *aInstance);
169 
170 /**
171  * Registers or updates a service on the infrastructure network's DNS-SD module.
172  *
173  * The @p aService and all its contained information (strings and buffers) are only valid during this call. The
174  * platform MUST save a copy of the information if it wants to retain the information after returning from this
175  * function.
176  *
177  * The fields in @p aService follow these rules:
178  *
179  * - The `mServiceInstance` and `mServiceType` fields specify the service instance label and service type name,
180  *   respectively. They are never NULL.
181  * - The `mHostName` field specifies the host name of the service if it is not NULL. Otherwise, if it is NULL, it
182  *   indicates that this service is for the device itself and leaves the host name selection to DNS-SD platform.
183  * - The `mSubTypeLabels` is an array of strings representing sub-types associated with the service. It can be NULL
184  *   if there are no sub-types. Otherwise, the array length is specified by `mSubTypeLabelsLength`.
185  * - The `mTxtData` and `mTxtDataLength` fields specify the encoded TXT data.
186  * - The `mPort`, `mWeight`, and `mPriority` fields specify the service's parameters (as specified in DNS SRV record).
187  * - The `mTtl` field specifies the TTL if non-zero. If zero, the platform can choose the TTL to use.
188  * - The `mInfraIfIndex` field, if non-zero, specifies the infrastructure network interface index to use for this
189  *   request. If zero, the platform implementation can decided the interface.
190  *
191  * When the `mHostName` field in @p aService is not NULL (indicating that this registration is on behalf of another
192  * host), the OpenThread stack will ensure that `otPlatDnssdRegisterHost()` is also called for the same host before any
193  * service registration requests for the same host.
194  *
195  * Once the registration request is finished, either successfully or failed, the platform reports the outcome by
196  * invoking the @p aCallback and passing the same @p aRequestId in the callback. The @p aCallback function pointer can
197  * be NULL, which indicates that the OpenThread stack does not need to be notified of the outcome of the request.
198  * If the outcome is determined, the platform implementation may invoke the @p aCallback before returning from this
199  * function. The OpenThread stack will ensure to handle such a situation.
200  *
201  * On success, the @p aCallback MUST be called (if non-NULL) with `OT_ERROR_NONE` as the `aError` input parameter. If
202  * the registration causes a name conflict on DNS-SD domain (the service instance name is already claimed by another
203  * host), the `OT_ERROR_DUPLICATED` error MUST be used. The platform implementation can use other `OT_ERROR` types for
204  * other types of errors.
205  *
206  * The platform implementation MUST not assume that the @p aRequestId used in subsequent requests will be different.
207  * OpenThread may reuse the same request ID again for a different request.
208  *
209  * The OpenThread stack will not register the same service (with no changes) that was registered successfully earlier.
210  * Therefore, the platform implementation does not need to check for duplicate/same service and can assume that calls
211  * to this function are either registering a new entry or changing some parameter in a previously registered item. As
212  * a result, these changes always need to be synced on the infrastructure DNS-SD module.
213  *
214  * The OpenThread stack does not require the platform implementation to always invoke the @p aCallback function.
215  * The OpenThread stack has its own mechanism to time out an aged request with no response. This relaxes the
216  * requirement for platform implementations.
217  *
218  * @param[in] aInstance     The OpenThread instance.
219  * @param[in] aService      Information about the service to register.
220  * @param[in] aRequestId    The ID associated with this request.
221  * @param[in] aCallback     The callback function pointer to report the outcome (may be NULL if no callback needed).
222  *
223  */
224 void otPlatDnssdRegisterService(otInstance                 *aInstance,
225                                 const otPlatDnssdService   *aService,
226                                 otPlatDnssdRequestId        aRequestId,
227                                 otPlatDnssdRegisterCallback aCallback);
228 
229 /**
230  * Unregisters a service on the infrastructure network's DNS-SD module.
231  *
232  * The @p aService and all its contained information (strings and buffers) are only valid during this call. The
233  * platform MUST save a copy of the information if it wants to retain the information after returning from this
234  * function.
235  *
236  * The fields in @p aService follow these rules:
237  *
238  * - The `mServiceInstance` and `mServiceType` fields specify the service instance label and service type name,
239  *   respectively. They are never NULL.
240  * - The `mHostName` field specifies the host name of the service if it is not NULL. Otherwise, if it is NULL, it
241  *   indicates that this service is for the device itself and leaves the host name selection to DNS-SD platform.
242  * - The `mInfraIfIndex` field, if non-zero, specifies the infrastructure network interface index to use for this
243  *   request. If zero, the platform implementation can decided the interface.
244  * - The rest of the fields in @p aService structure MUST be ignored in `otPlatDnssdUnregisterService()` call and may
245  *   be set to zero by the OpenThread stack.
246  *
247  * Regarding the invocation of the @p aCallback and the reuse of the @p aRequestId, this function follows the same
248  * rules as described in `otPlatDnssdRegisterService()`.
249  *
250  * The OpenThread stack may request the unregistration of a service that was not previously registered, and the
251  * platform implementation MUST handle this case. In such a case, the platform can use either `OT_ERROR_NOT_FOUND` to
252  * indicate that there was no such registration, or `OT_ERROR_NONE` when invoking the @p aCallback function. The
253  * OpenThread stack will handle either case correctly.
254  *
255  * @param[in] aInstance     The OpenThread instance.
256  * @param[in] aService      Information about the service to unregister.
257  * @param[in] aRequestId    The ID associated with this request.
258  * @param[in] aCallback     The callback function pointer to report the outcome (may be NULL if no callback needed).
259  *
260  */
261 void otPlatDnssdUnregisterService(otInstance                 *aInstance,
262                                   const otPlatDnssdService   *aService,
263                                   otPlatDnssdRequestId        aRequestId,
264                                   otPlatDnssdRegisterCallback aCallback);
265 
266 /**
267  * Registers or updates a host on the infrastructure network's DNS-SD module.
268  *
269  * The @p aHost and all its contained information (strings and arrays) are only valid during this call. The
270  * platform MUST save a copy of the information if it wants to retain the information after returning from this
271  * function.
272  *
273  * The fields in @p aHost follow these rules:
274  *
275  * - The `mHostName` field specifies the host name to register. It is never NULL.
276  * - The `mAddresses` field is an array of IPv6 addresses to register with the host. `mAddressesLength` field provides
277  *   the number of entries in `mAddresses` array. The platform implementation MUST not filter or remove any of
278  *   addresses in the list.
279  *   The OpenThread stack will already ensure that the given addresses are externally reachable. For example, when
280  *   registering host from an SRP registration, link-local or mesh-local addresses associated with the host which are
281  *   intended for use within Thread mesh are not included in `mAddresses` array passed to this API. The `mAddresses`
282  *   array can be empty with zero `mAddressesLength`. In such a case, the platform MUST stop advertising any addresses
283  *   for this host name on the infrastructure DNS-SD.
284  * - The `mTtl` field specifies the TTL if non-zero. If zero, the platform can choose the TTL to use.
285  * - The `mInfraIfIndex` field, if non-zero, specifies the infrastructure network interface index to use for this
286  *   request. If zero, the platform implementation can decided the interface.
287  *
288  * Regarding the invocation of the @p aCallback and the reuse of the @p aRequestId, this function follows the same
289  * rules as described in `otPlatDnssdRegisterService()`.
290  *
291  * The OpenThread stack will not register the same host (with no changes) that was registered successfully earlier.
292  * Therefore, the platform implementation does not need to check for duplicate/same host and can assume that calls
293  * to this function are either registering a new entry or changing some parameter in a previously registered item. As
294  * a result, these changes always need to be synced on the infrastructure DNS-SD module.
295  *
296  * @param[in] aInstance     The OpenThread instance.
297  * @param[in] aHost         Information about the host to register.
298  * @param[in] aRequestId    The ID associated with this request.
299  * @param[in] aCallback     The callback function pointer to report the outcome (may be NULL if no callback needed).
300  *
301  */
302 void otPlatDnssdRegisterHost(otInstance                 *aInstance,
303                              const otPlatDnssdHost      *aHost,
304                              otPlatDnssdRequestId        aRequestId,
305                              otPlatDnssdRegisterCallback aCallback);
306 
307 /**
308  * Unregisters a host on the infrastructure network's DNS-SD module.
309  *
310  * The @p aHost and all its contained information (strings and arrays) are only valid during this call. The
311  * platform MUST save a copy of the information if it wants to retain the information after returning from this
312  * function.
313  *
314  * The fields in @p aHost follow these rules:
315  *
316  * - The `mHostName` field specifies the host name to unregister. It is never NULL.
317  * - The `mInfraIfIndex` field, if non-zero, specifies the infrastructure network interface index to use for this
318  *   request. If zero, the platform implementation can decided the interface.
319  * - The rest of the fields in @p aHost structure MUST be ignored in `otPlatDnssdUnregisterHost()` call and may
320  *   be set to zero by the OpenThread stack.
321  *
322  * Regarding the invocation of the @p aCallback and the reuse of the @p aRequestId, this function follows the same
323  * rules as described in `otPlatDnssdRegisterService()`.
324  *
325  * The OpenThread stack may request the unregistration of a host that was not previously registered, and the platform
326  * implementation MUST handle this case. In such a case, the platform can use either `OT_ERROR_NOT_FOUND` to indicate
327  * that there was no such registration, or `OT_ERROR_NONE` when invoking the @p aCallback function. OpenThread stack
328  * will handle either case correctly.
329  *
330  * When unregistering a host, the OpenThread stack will also unregister any previously registered services
331  * associated with the same host (by calling `otPlatDnssdUnregisterService()`). However, the platform implementation
332  * MAY assume that unregistering a host also unregisters all its associated services.
333  *
334  * @param[in] aInstance     The OpenThread instance.
335  * @param[in] aHost         Information about the host to unregister.
336  * @param[in] aRequestId    The ID associated with this request.
337  * @param[in] aCallback     The callback function pointer to report the outcome (may be NULL if no callback needed).
338  *
339  */
340 void otPlatDnssdUnregisterHost(otInstance                 *aInstance,
341                                const otPlatDnssdHost      *aHost,
342                                otPlatDnssdRequestId        aRequestId,
343                                otPlatDnssdRegisterCallback aCallback);
344 
345 /**
346  * Registers or updates a key record on the infrastructure network's DNS-SD module.
347  *
348  * The @p aKey and all its contained information (strings and arrays) are only valid during this call. The
349  * platform MUST save a copy of the information if it wants to retain the information after returning from this
350  * function.
351  *
352  * The fields in @p aKey follow these rules:
353  *
354  * - If the key is associated with a host, `mName` field specifies the host name and `mServiceType` will be NULL.
355  * - If the key is associated with a service, `mName` field specifies the service instance label and `mServiceType`
356  *   field specifies the service type. In this case the DNS name for key record is `{mName}.{mServiceTye}`.
357  * - The `mKeyData` field contains the key record's data with `mKeyDataLength` as its length in byes. It is never NULL.
358  * - The `mClass` fields specifies the resource record class to use when registering key record.
359  * - The `mTtl` field specifies the TTL if non-zero. If zero, the platform can choose the TTL to use.
360  * - The `mInfraIfIndex` field, if non-zero, specifies the infrastructure network interface index to use for this
361  *   request. If zero, the platform implementation can decided the interface.
362  *
363  * Regarding the invocation of the @p aCallback and the reuse of the @p aRequestId, this function follows the same
364  * rules as described in `otPlatDnssdRegisterService()`.
365  *
366  * The OpenThread stack will not register the same key (with no changes) that was registered successfully earlier.
367  * Therefore, the platform implementation does not need to check for duplicate/same name and can assume that calls
368  * to this function are either registering a new key or changing the key data in a previously registered one. As
369  * a result, these changes always need to be synced on the infrastructure DNS-SD module.
370  *
371  * @param[in] aInstance     The OpenThread instance.
372  * @param[in] aHost         Information about the key record to register.
373  * @param[in] aRequestId    The ID associated with this request.
374  * @param[in] aCallback     The callback function pointer to report the outcome (may be NULL if no callback needed).
375  *
376  */
377 void otPlatDnssdRegisterKey(otInstance                 *aInstance,
378                             const otPlatDnssdKey       *aKey,
379                             otPlatDnssdRequestId        aRequestId,
380                             otPlatDnssdRegisterCallback aCallback);
381 
382 /**
383  * Unregisters a key record on the infrastructure network's DNS-SD module.
384  *
385  * The @p aKey and all its contained information (strings and arrays) are only valid during this call. The
386  * platform MUST save a copy of the information if it wants to retain the information after returning from this
387  * function.
388  *
389  * The fields in @p aKey follow these rules:
390  *
391  * - If the key is associated with a host, `mName` field specifies the host name and `mServiceType` will be NULL.
392  * - If the key is associated with a service, `mName` field specifies the service instance label and `mServiceType`
393  *   field specifies the service type. In this case the DNS name for key record is `{mName}.{mServiceTye}`.
394  * - The `mInfraIfIndex` field, if non-zero, specifies the infrastructure network interface index to use for this
395  *   request. If zero, the platform implementation can decided the interface.
396  * - The rest of the fields in @p aKey structure MUST be ignored in `otPlatDnssdUnregisterKey()` call and may
397  *   be set to zero by the OpenThread stack.
398  *
399  * Regarding the invocation of the @p aCallback and the reuse of the @p aRequestId, this function follows the same
400  * rules as described in `otPlatDnssdRegisterService()`.
401  *
402  * The OpenThread stack may request the unregistration of a key that was not previously registered, and the platform
403  * implementation MUST handle this case. In such a case, the platform can use either `OT_ERROR_NOT_FOUND` to indicate
404  * that there was no such registration, or `OT_ERROR_NONE` when invoking the @p aCallback function. the OpenThread
405  * stack will handle either case correctly.
406  *
407  * @param[in] aInstance     The OpenThread instance.
408  * @param[in] aKey          Information about the key to unregister.
409  * @param[in] aRequestId    The ID associated with this request.
410  * @param[in] aCallback     The callback function pointer to report the outcome (may be NULL if no callback needed).
411  *
412  */
413 void otPlatDnssdUnregisterKey(otInstance                 *aInstance,
414                               const otPlatDnssdKey       *aKey,
415                               otPlatDnssdRequestId        aRequestId,
416                               otPlatDnssdRegisterCallback aCallback);
417 
418 /**
419  * @}
420  *
421  */
422 
423 #ifdef __cplusplus
424 } // extern "C"
425 #endif
426 
427 #endif // OPENTHREAD_PLATFORM_DNSSD_H_
428