1 /*
2 * Copyright (c) 2024, 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 #include <stdio.h>
30
31 #include <openthread/platform/dnssd.h>
32
33 #include "test_platform.h"
34 #include "test_util.h"
35 #include "common/code_utils.hpp"
36 #include "lib/spinel/spinel_buffer.hpp"
37 #include "lib/spinel/spinel_encoder.hpp"
38 #include "ncp/ncp_base.hpp"
39
40 #if OPENTHREAD_CONFIG_NCP_DNSSD_ENABLE && OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE
41
42 namespace ot {
43
44 constexpr uint16_t kMaxSpinelBufferSize = 2048;
45 static uint32_t sRequestId;
46 static uint8_t sError;
47
GenerateSpinelDnssdSetStateFrame(otPlatDnssdState aState,uint8_t * aBuf,uint16_t & aLen)48 static otError GenerateSpinelDnssdSetStateFrame(otPlatDnssdState aState, uint8_t *aBuf, uint16_t &aLen)
49 {
50 otError error = OT_ERROR_NONE;
51 uint8_t buf[kMaxSpinelBufferSize];
52 Spinel::Buffer ncpBuffer(buf, kMaxSpinelBufferSize);
53 Spinel::Encoder encoder(ncpBuffer);
54
55 uint8_t header = SPINEL_HEADER_FLAG | 0 /* Iid */ | 1 /* Tid */;
56 SuccessOrExit(error = encoder.BeginFrame(header, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_DNSSD_STATE));
57 SuccessOrExit(error = encoder.WriteUint8(aState));
58 SuccessOrExit(error = encoder.EndFrame());
59
60 SuccessOrExit(ncpBuffer.OutFrameBegin());
61 aLen = ncpBuffer.OutFrameGetLength();
62 VerifyOrExit(ncpBuffer.OutFrameRead(aLen, aBuf) == aLen, error = OT_ERROR_FAILED);
63
64 exit:
65 return error;
66 }
67
TestPlatDnssdRegisterCallback(otInstance * aInstance,otPlatDnssdRequestId aRequestId,otError aError)68 static void TestPlatDnssdRegisterCallback(otInstance *aInstance, otPlatDnssdRequestId aRequestId, otError aError)
69 {
70 sRequestId = aRequestId;
71 sError = aError;
72 }
73
GenerateSpinelDnssdRequestResultFrame(uint32_t aRequestId,otError aError,uint8_t * aBuf,uint16_t & aLen)74 static otError GenerateSpinelDnssdRequestResultFrame(uint32_t aRequestId, otError aError, uint8_t *aBuf, uint16_t &aLen)
75 {
76 otError error = OT_ERROR_NONE;
77 uint8_t buf[kMaxSpinelBufferSize];
78 Spinel::Buffer ncpBuffer(buf, kMaxSpinelBufferSize);
79 Spinel::Encoder encoder(ncpBuffer);
80 otPlatDnssdRegisterCallback callback = &TestPlatDnssdRegisterCallback;
81
82 uint8_t header = SPINEL_HEADER_FLAG | 0 /* Iid */ | 1 /* Tid */;
83 SuccessOrExit(error = encoder.BeginFrame(header, SPINEL_CMD_PROP_VALUE_SET, SPINEL_PROP_DNSSD_REQUEST_RESULT));
84 SuccessOrExit(error = encoder.WriteUint8(aError));
85 SuccessOrExit(error = encoder.WriteUint32(aRequestId));
86 SuccessOrExit(error = encoder.WriteData(reinterpret_cast<const uint8_t *>(&callback), sizeof(callback)));
87 SuccessOrExit(error = encoder.EndFrame());
88
89 SuccessOrExit(ncpBuffer.OutFrameBegin());
90 aLen = ncpBuffer.OutFrameGetLength();
91 VerifyOrExit(ncpBuffer.OutFrameRead(aLen, aBuf) == aLen, error = OT_ERROR_FAILED);
92
93 exit:
94 return error;
95 }
96
TestNcpDnssdGetState(void)97 void TestNcpDnssdGetState(void)
98 {
99 Instance *instance = static_cast<Instance *>(testInitInstance());
100 Ncp::NcpBase ncpBase(instance);
101
102 uint8_t recvBuf[kMaxSpinelBufferSize];
103 uint16_t recvLen;
104 otPlatDnssdState dnssdState;
105
106 dnssdState = otPlatDnssdGetState(instance);
107 VerifyOrQuit(dnssdState == OT_PLAT_DNSSD_STOPPED);
108
109 SuccessOrQuit(GenerateSpinelDnssdSetStateFrame(OT_PLAT_DNSSD_READY, recvBuf, recvLen));
110 ncpBase.HandleReceive(recvBuf, recvLen);
111 dnssdState = otPlatDnssdGetState(instance);
112 VerifyOrQuit(dnssdState == OT_PLAT_DNSSD_READY);
113 }
114
TestNcpDnssdRegistrations(void)115 void TestNcpDnssdRegistrations(void)
116 {
117 Instance *instance = static_cast<Instance *>(testInitInstance());
118 Ncp::NcpBase ncpBase(instance);
119
120 uint8_t recvBuf[kMaxSpinelBufferSize];
121 uint16_t recvLen;
122 otPlatDnssdHost dnssdHost;
123 otPlatDnssdService dnssdService;
124 otPlatDnssdKey dnssdKey;
125
126 sRequestId = 0; // Use 0 to indicate `sRequestId` hasn't been set.
127
128 // Register a dnssd host when the dnssd state is DISABLED
129 dnssdHost.mHostName = "ot-test";
130 dnssdHost.mAddressesLength = 0;
131 otPlatDnssdRegisterHost(instance, &dnssdHost, 1 /* aRequestId */, TestPlatDnssdRegisterCallback);
132 VerifyOrQuit(sRequestId == 1);
133 VerifyOrQuit(sError == OT_ERROR_INVALID_STATE);
134
135 // Set the dnssd state to READY
136 SuccessOrQuit(GenerateSpinelDnssdSetStateFrame(OT_PLAT_DNSSD_READY, recvBuf, recvLen));
137 ncpBase.HandleReceive(recvBuf, recvLen);
138
139 otPlatDnssdUnregisterHost(instance, &dnssdHost, 2 /* aRequestId */, TestPlatDnssdRegisterCallback);
140 SuccessOrQuit(GenerateSpinelDnssdRequestResultFrame(2 /* aRequestId */, OT_ERROR_NOT_FOUND, recvBuf, recvLen));
141 ncpBase.HandleReceive(recvBuf, recvLen);
142 VerifyOrQuit(sRequestId == 2);
143 VerifyOrQuit(sError == OT_ERROR_NOT_FOUND);
144
145 dnssdService.mHostName = "test-service";
146 dnssdService.mServiceInstance = nullptr;
147 dnssdService.mServiceType = nullptr;
148 dnssdService.mSubTypeLabelsLength = 0;
149 dnssdService.mPort = 1234;
150 dnssdService.mTxtDataLength = 0;
151 otPlatDnssdRegisterService(instance, &dnssdService, 3 /* aRequestId */, TestPlatDnssdRegisterCallback);
152 SuccessOrQuit(GenerateSpinelDnssdRequestResultFrame(3 /* aRequestId */, OT_ERROR_NONE, recvBuf, recvLen));
153 ncpBase.HandleReceive(recvBuf, recvLen);
154 VerifyOrQuit(sRequestId == 3);
155 VerifyOrQuit(sError == OT_ERROR_NONE);
156
157 sRequestId = 0;
158 sError = OT_ERROR_FAILED;
159 otPlatDnssdUnregisterService(instance, &dnssdService, 3 /* aRequestId */, TestPlatDnssdRegisterCallback);
160 ncpBase.HandleReceive(recvBuf, recvLen);
161 VerifyOrQuit(sRequestId == 3);
162 VerifyOrQuit(sError == OT_ERROR_NONE);
163
164 dnssdKey.mName = "test-key";
165 dnssdKey.mServiceType = "someType";
166 dnssdKey.mKeyDataLength = 0;
167 otPlatDnssdRegisterKey(instance, &dnssdKey, 4 /* aRequestId */, TestPlatDnssdRegisterCallback);
168 SuccessOrQuit(GenerateSpinelDnssdRequestResultFrame(4 /* aRequestId */, OT_ERROR_NONE, recvBuf, recvLen));
169 ncpBase.HandleReceive(recvBuf, recvLen);
170 VerifyOrQuit(sRequestId == 4);
171 VerifyOrQuit(sError == OT_ERROR_NONE);
172
173 sRequestId = 0;
174 sError = OT_ERROR_FAILED;
175 otPlatDnssdUnregisterKey(instance, &dnssdKey, 4 /* aRequestId */, TestPlatDnssdRegisterCallback);
176 ncpBase.HandleReceive(recvBuf, recvLen);
177 VerifyOrQuit(sRequestId == 4);
178 VerifyOrQuit(sError == OT_ERROR_NONE);
179 }
180
181 } // namespace ot
182
183 #endif // OPENTHREAD_CONFIG_NCP_DNSSD_ENABLE && OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE
184
main(void)185 int main(void)
186 {
187 #if OPENTHREAD_CONFIG_NCP_DNSSD_ENABLE && OPENTHREAD_CONFIG_PLATFORM_DNSSD_ENABLE
188 ot::TestNcpDnssdGetState();
189 ot::TestNcpDnssdRegistrations();
190 #endif
191 printf("All tests passed\n");
192 return 0;
193 }
194