3 * Copyright (c) 2019 Apple Computer, Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * srp host API implementation for Thread accessories using OpenThread.
27 #include <openthread/ip6.h>
28 #include <openthread/instance.h>
29 #include <openthread/thread.h>
30 #include <openthread/joiner.h>
31 #include <openthread/message.h>
32 #include <openthread/udp.h>
33 #include <openthread/platform/time.h>
34 #include <openthread/platform/settings.h>
37 #include "app_scheduler.h"
38 #include "app_timer.h"
40 #include "srp-thread.h"
43 #include "HAPPlatformRandomNumber.h"
46 #define SRP_CRYPTO_MBEDTLS_INTERNAL 1
47 #include "srp-crypto.h"
49 APP_TIMER_DEF(m_srp_timer
);
50 #define HAPTIME_FREQUENCY 1000ULL
52 const char *key_filename
= "srp.key";
54 #define SRP_IO_CONTEXT_MAGIC 0xFEEDFACEFADEBEEFULL // BEES! Everybody gets BEES!
55 typedef struct io_context io_context_t
;
58 uint64_t magic_cookie1
;
61 void *NONNULL srp_context
;
64 srp_wakeup_callback_t wakeup_callback
;
65 srp_datagram_callback_t datagram_callback
;
67 uint64_t magic_cookie2
;
70 static otInstance
*otThreadInstance
;
73 validate_io_context(io_context_t
**dest
, void *src
)
75 io_context_t
*context
= src
;
76 if (context
->magic_cookie1
== SRP_IO_CONTEXT_MAGIC
&&
77 context
->magic_cookie2
== SRP_IO_CONTEXT_MAGIC
)
80 return kDNSServiceErr_NoError
;
82 return kDNSServiceErr_BadState
;
86 datagram_callback(void *context
, otMessage
*message
, const otMessageInfo
*messageInfo
)
89 const int buf_len
= 1500;
91 io_context_t
*io_context
;
92 if (validate_io_context(&io_context
, context
) == kDNSServiceErr_NoError
) {
94 buf
= malloc(buf_len
);
96 INFO("No memory for read buffer");
101 DEBUG("%d bytes received", otMessageGetLength(message
) - otMessageGetOffset(message
));
102 length
= otMessageRead(message
, otMessageGetOffset(message
), buf
, buf_len
- 1);
103 io_context
->datagram_callback(io_context
->srp_context
, buf
, length
);
107 static void wakeup_callback(void *context
);
110 note_wakeup(const char *what
, void *at
, uint64_t when
)
112 #ifdef VERBOSE_DEBUG_MESSAGES
113 int microseconds
= (int)(when
% HAPTIME_FREQUENCY
);
114 HAPTime seconds
= when
/ HAPTIME_FREQUENCY
;
115 int minute
= (int)((seconds
/ 60) % 60);
116 int hour
= (int)((seconds
/ 3600) % (7 * 24));
117 int second
= (int)(seconds
% 60);
119 DEBUG(PUB_S_SRP
" %p at %llu %d:%d:%d.%d", what
, at
, when
, hour
, minute
, second
, microseconds
);
124 compute_wakeup_time(HAPTime now
)
126 io_context_t
*io_context
;
130 for (io_context
= io_contexts
; io_context
; io_context
= io_context
->next
) {
131 if (next
== 0 || (io_context
->wakeup_time
!= 0 && io_context
->wakeup_time
< next
)) {
132 next
= io_context
->wakeup_time
;
136 // If we don't have a wakeup to schedule, wake up anyway in ten seconds.
138 next
= now
+ 10 * HAPTIME_FREQUENCY
;
140 note_wakeup("next wakeup", NULL
, next
);
146 milliseconds
= (int)((next
- now
) / (HAPTIME_FREQUENCY
/ 1000));
148 err
= app_timer_start(m_srp_timer
, APP_TIMER_TICKS(milliseconds
), NULL
);
150 ERROR("app_timer_start returned %lu", err
);
156 wakeup_callback(void *context
)
158 io_context_t
*io_context
;
159 HAPTime now
= HAPPlatformClockGetCurrent(), next
= 0;
162 note_wakeup(" wakeup", NULL
, now
);
165 for (io_context
= io_contexts
; io_context
; io_context
= io_context
->next
) {
166 if (io_context
->wakeup_time
!= 0 && io_context
->wakeup_time
< now
) {
168 note_wakeup("io wakeup", io_context
, io_context
->wakeup_time
);
169 io_context
->wakeup_time
= 0;
170 io_context
->wakeup_callback(io_context
->srp_context
);
173 note_wakeup("no wakeup", io_context
, io_context
->wakeup_time
);
174 if (next
== 0 || (io_context
->wakeup_time
!= 0 && io_context
->wakeup_time
< next
))
176 next
= io_context
->wakeup_time
;
180 compute_wakeup_time(now
);
184 srp_deactivate_udp_context(void *host_context
, void *in_context
)
186 io_context_t
*io_context
, **p_io_contexts
;
189 err
= validate_io_context(&io_context
, in_context
);
190 if (err
== kDNSServiceErr_NoError
) {
191 for (p_io_contexts
= &io_contexts
; *p_io_contexts
; p_io_contexts
= &(*p_io_contexts
)->next
) {
192 if (*p_io_contexts
== io_context
) {
196 // If we don't find it on the list, something is wrong.
197 if (*p_io_contexts
== NULL
) {
198 return kDNSServiceErr_Invalid
;
200 *p_io_contexts
= io_context
->next
;
201 io_context
->wakeup_time
= 0;
202 if (io_context
->sock_active
) {
203 otUdpClose(&io_context
->sock
);
211 srp_connect_udp(void *context
, const uint8_t *port
, uint16_t address_type
, const uint8_t *address
, uint16_t addrlen
)
213 io_context_t
*io_context
;
216 err
= validate_io_context(&io_context
, context
);
218 if (err
== kDNSServiceErr_NoError
) {
219 if (address_type
!= dns_rrtype_aaaa
|| addrlen
!= 16) {
220 ERROR("srp_make_udp_context: invalid address");
221 return kDNSServiceErr_Invalid
;
223 memcpy(&io_context
->sockaddr
.mAddress
, address
, 16);
224 memcpy(&io_context
->sockaddr
.mPort
, port
, 2);
225 #ifdef OT_NETIF_INTERFACE_ID_THREAD
226 io_context
->sockaddr
.mScopeId
= OT_NETIF_INTERFACE_ID_THREAD
;
229 oterr
= otUdpOpen(otThreadInstance
, &io_context
->sock
, datagram_callback
, io_context
);
230 if (oterr
!= OT_ERROR_NONE
) {
231 ERROR("srp_make_udp_context: otUdpOpen returned %d", oterr
);
232 return kDNSServiceErr_Unknown
;
235 oterr
= otUdpConnect(&io_context
->sock
, &io_context
->sockaddr
);
236 if (oterr
!= OT_ERROR_NONE
) {
237 otUdpClose(&io_context
->sock
);
238 ERROR("srp_make_udp_context: otUdpConnect returned %d", oterr
);
239 return kDNSServiceErr_Unknown
;
241 io_context
->sock_active
= true;
242 err
= kDNSServiceErr_NoError
;
248 srp_disconnect_udp(void *context
)
250 io_context_t
*io_context
;
253 err
= validate_io_context(&io_context
, context
);
254 if (err
== kDNSServiceErr_NoError
&& io_context
->sock_active
) {
255 otUdpClose(&io_context
->sock
);
256 io_context
->sock_active
= false;
262 srp_make_udp_context(void *host_context
, void **p_context
, srp_datagram_callback_t callback
, void *context
)
264 io_context_t
*io_context
= calloc(1, sizeof *io_context
);
265 if (io_context
== NULL
) {
266 ERROR("srp_make_udp_context: no memory");
267 return kDNSServiceErr_NoMemory
;
269 io_context
->magic_cookie1
= io_context
->magic_cookie2
= SRP_IO_CONTEXT_MAGIC
;
270 io_context
->datagram_callback
= callback
;
271 io_context
->srp_context
= context
;
273 *p_context
= io_context
;
274 io_context
->next
= io_contexts
;
275 io_contexts
= io_context
;
276 return kDNSServiceErr_NoError
;
280 srp_set_wakeup(void *host_context
, void *context
, int milliseconds
, srp_wakeup_callback_t callback
)
283 io_context_t
*io_context
;
286 err
= validate_io_context(&io_context
, context
);
287 if (err
== kDNSServiceErr_NoError
) {
288 now
= HAPPlatformClockGetCurrent();
289 io_context
->wakeup_time
= now
+ milliseconds
* (HAPTIME_FREQUENCY
/ 1000);
290 io_context
->wakeup_callback
= callback
;
291 INFO("srp_set_wakeup: %llu (%llu + %dms)", io_context
->wakeup_time
, now
, milliseconds
);
292 compute_wakeup_time(now
);
298 srp_cancel_wakeup(void *host_context
, void *context
)
301 io_context_t
*io_context
;
303 err
= validate_io_context(&io_context
, context
);
304 if (err
== kDNSServiceErr_NoError
) {
305 io_context
->wakeup_time
= 0;
311 srp_send_datagram(void *host_context
, void *context
, void *payload
, size_t message_length
)
314 io_context_t
*io_context
;
316 otMessageInfo messageInfo
;
317 otMessage
* message
= NULL
;
320 #ifdef VERBOSE_DEBUG_MESSAGES
323 char *hexdigits
= "01234567689abcdef";
324 uint8_t *msg
= payload
;
325 #endif // VERBOSE_DEBUG_MESSAGES
327 err
= validate_io_context(&io_context
, context
);
328 if (err
== kDNSServiceErr_NoError
) {
329 memset(&messageInfo
, 0, sizeof(messageInfo
));
330 #ifdef OT_NETIF_INTERFACE_ID_THREAD
331 messageInfo
.mInterfaceId
= OT_NETIF_INTERFACE_ID_THREAD
;
333 messageInfo
.mPeerPort
= io_context
->sockaddr
.mPort
;
334 messageInfo
.mPeerAddr
= io_context
->sockaddr
.mAddress
;
335 ap
= (uint8_t *)&io_context
->sockaddr
.mAddress
;
336 SEGMENTED_IPv6_ADDR_GEN_SRP(ap
, ap_buf
);
337 INFO("Sending to " PRI_SEGMENTED_IPv6_ADDR_SRP
" port %d", SEGMENTED_IPv6_ADDR_PARAM_SRP(ap
, ap_buf
),
338 io_context
->sockaddr
.mPort
);
339 #ifdef VERBOSE_DEBUG_MESSAGES
340 for (i
= 0; i
< message_length
; i
+= 32) {
342 for (j
= 0; bufp
< buf
+ sizeof buf
&& i
+ j
< message_length
; j
++) {
343 *bufp
++ = hexdigits
[msg
[i
+ j
] >> 4];
344 if (bufp
< buf
+ sizeof buf
) {
345 *bufp
++ = hexdigits
[msg
[i
+ j
] % 15];
347 if (bufp
< buf
+ sizeof buf
&& (j
& 1) == 1) {
352 DEBUG(PUB_S_SRP
, buf
);
356 message
= otUdpNewMessage(otThreadInstance
, NULL
);
357 if (message
== NULL
) {
358 ERROR("srp_send_datagram: otUdpNewMessage returned NULL");
359 return kDNSServiceErr_NoMemory
;
362 error
= otMessageAppend(message
, payload
, message_length
);
363 if (error
!= OT_ERROR_NONE
) {
364 ERROR("srp_send_datagram: otMessageAppend returned %d", error
);
365 return kDNSServiceErr_NoMemory
;
368 error
= otUdpSend(&io_context
->sock
, message
, &messageInfo
);
369 if (error
!= OT_ERROR_NONE
) {
370 ERROR("srp_send_datagram: otUdpSend returned %d", error
);
371 return kDNSServiceErr_Unknown
;
379 srp_load_key_data(void *host_context
, const char *key_name
,
380 uint8_t *buffer
, uint16_t *length
, uint16_t buffer_size
)
382 #ifndef DEBUG_CONFLICTS
384 uint16_t rlength
= buffer_size
;
385 // Note that at present we ignore the key name: we are only going to have one host key on an
387 err
= otPlatSettingsGet(otThreadInstance
, KEY_ID
, 0, buffer
, &rlength
);
388 if (err
!= OT_ERROR_NONE
) {
390 return kDNSServiceErr_NoSuchKey
;
393 return kDNSServiceErr_NoError
;
395 return kDNSServiceErr_NoSuchKey
;
400 srp_store_key_data(void *host_context
, const char *name
, uint8_t *buffer
, uint16_t length
)
403 err
= otPlatSettingsAdd(otThreadInstance
, KEY_ID
, buffer
, length
);
404 if (err
!= OT_ERROR_NONE
) {
405 ERROR("Unable to store key (length %d): %d", length
, err
);
406 return kDNSServiceErr_Unknown
;
408 return kDNSServiceErr_NoError
;
412 srp_reset_key(const char *name
, void *host_context
)
414 otPlatSettingsDelete(otThreadInstance
, KEY_ID
);
418 register_callback(DNSServiceRef sdRef
, DNSServiceFlags flags
, DNSServiceErrorType errorCode
,
419 const char *name
, const char *regtype
, const char *domain
, void *context
)
421 INFO("Register Reply: %ld " PRI_S_SRP
" " PRI_S_SRP
" " PRI_S_SRP
"\n", errorCode
, name
== NULL
? "<NULL>" : name
,
422 regtype
== NULL
? "<NULL>" : regtype
, domain
== NULL
? "<NULL>" : domain
);
426 conflict_callback(const char *hostname
)
428 ERROR("Host name conflict: %s", hostname
);
432 srp_thread_init(otInstance
*instance
)
435 DEBUG("In srp_thread_init().");
436 otThreadInstance
= instance
;
437 srp_host_init(otThreadInstance
);
439 app_err
= app_timer_create(&m_srp_timer
, APP_TIMER_MODE_SINGLE_SHOT
, wakeup_callback
);
441 ERROR("app_timer_create returned %lu", app_err
);
442 return kDNSServiceErr_Unknown
;
444 return kDNSServiceErr_NoError
;
448 srp_thread_shutdown(otInstance
*instance
)
450 INFO("In srp_thread_shutdown().");
452 app_err
= app_timer_stop(m_srp_timer
);
454 ERROR("app_timer_stop returned %lu", app_err
);
455 return kDNSServiceErr_Unknown
;
457 return kDNSServiceErr_NoError
;
463 // c-file-style: "bsd"
466 // indent-tabs-mode: nil