Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2026 Project CHIP Authors
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 :
18 : #include <app/server/ThreadRendezvousAnnouncement.h>
19 :
20 : #include <inttypes.h>
21 : #include <stdarg.h>
22 : #include <stdio.h>
23 :
24 : #include <lib/support/CodeUtils.h>
25 :
26 : #if CHIP_DEVICE_CONFIG_ENABLE_THREAD_MESHCOP
27 : #include <lib/dnssd/minimal_mdns/ResponseBuilder.h> // nogncheck
28 : #include <lib/dnssd/minimal_mdns/records/Srv.h> // nogncheck
29 : #include <lib/dnssd/minimal_mdns/records/Txt.h> // nogncheck
30 : #endif
31 :
32 : namespace chip {
33 : namespace app {
34 :
35 2 : CHIP_ERROR TxtStringsBuilder::Fill(const Dnssd::CommissionAdvertisingParameters & params)
36 : {
37 : // VP
38 2 : auto vendorId = params.GetVendorId();
39 2 : auto productId = params.GetProductId();
40 2 : if (vendorId.has_value() && productId.has_value())
41 : {
42 2 : ReturnErrorOnFailure(FormatAndAdd("VP=%d+%d", *vendorId, *productId));
43 : }
44 0 : else if (vendorId.has_value())
45 : {
46 0 : ReturnErrorOnFailure(FormatAndAdd("VP=%d", *vendorId));
47 : }
48 :
49 : // D
50 2 : ReturnErrorOnFailure(FormatAndAdd("D=%d", params.GetLongDiscriminator()));
51 :
52 : // CM
53 2 : ReturnErrorOnFailure(FormatAndAdd("CM=%d", static_cast<int>(params.GetCommissioningMode())));
54 :
55 : // DT
56 2 : auto deviceType = params.GetDeviceType();
57 2 : if (deviceType.has_value())
58 : {
59 2 : ReturnErrorOnFailure(FormatAndAdd("DT=%" PRIu32, *deviceType));
60 : }
61 :
62 : // DN
63 2 : auto deviceName = params.GetDeviceName();
64 2 : if (deviceName.has_value())
65 : {
66 2 : ReturnErrorOnFailure(FormatAndAdd("DN=%s", *deviceName));
67 : }
68 :
69 : // RI
70 2 : auto rotatingId = params.GetRotatingDeviceId();
71 2 : if (rotatingId.has_value())
72 : {
73 2 : ReturnErrorOnFailure(FormatAndAdd("RI=%s", *rotatingId));
74 : }
75 :
76 : // PH
77 2 : auto pairingHint = params.GetPairingHint();
78 2 : if (pairingHint.has_value())
79 : {
80 2 : ReturnErrorOnFailure(FormatAndAdd("PH=%d", *pairingHint));
81 : }
82 :
83 : // PI
84 2 : auto pairingInstr = params.GetPairingInstruction();
85 2 : if (pairingInstr.has_value())
86 : {
87 2 : ReturnErrorOnFailure(FormatAndAdd("PI=%s", *pairingInstr));
88 : }
89 :
90 1 : return CHIP_NO_ERROR;
91 : }
92 :
93 16 : CHIP_ERROR TxtStringsBuilder::FormatAndAdd(const char * format, ...)
94 : {
95 16 : VerifyOrReturnError(mCount < MATTER_ARRAY_SIZE(mTxtStrings), CHIP_ERROR_BUFFER_TOO_SMALL);
96 :
97 16 : size_t offset = static_cast<size_t>(mNextStart - &mTxtBuffer[0]);
98 16 : VerifyOrReturnError(sizeof(mTxtBuffer) > offset, CHIP_ERROR_BUFFER_TOO_SMALL);
99 :
100 : va_list args;
101 16 : va_start(args, format);
102 16 : int len = vsnprintf(mNextStart, sizeof(mTxtBuffer) - offset, format, args);
103 16 : va_end(args);
104 :
105 : // Make sure not overflowed.
106 16 : VerifyOrReturnError(len > 0 && offset + static_cast<size_t>(len) < sizeof(mTxtBuffer), CHIP_ERROR_BUFFER_TOO_SMALL);
107 :
108 15 : mTxtStrings[mCount++] = mNextStart;
109 :
110 : // skip the null terminator.
111 15 : mNextStart += len + 1;
112 :
113 15 : return CHIP_NO_ERROR;
114 : }
115 :
116 : #if CHIP_DEVICE_CONFIG_ENABLE_THREAD_MESHCOP
117 : CHIP_ERROR BuildThreadRendezvousAnnouncement(const Dnssd::CommissionAdvertisingParameters & params,
118 : System::PacketBufferHandle & outBuffer)
119 : {
120 : System::PacketBufferHandle buffer = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize);
121 : VerifyOrReturnError(!buffer.IsNull(), CHIP_ERROR_NO_MEMORY);
122 :
123 : {
124 : mdns::Minimal::ResponseBuilder builder(std::move(buffer));
125 : builder.Header().SetMessageId(0);
126 : builder.Header().SetFlags(builder.Header().GetFlags().SetResponse().SetAuthoritative());
127 :
128 : static const char * matterc_udp_local[] = { "_matterc", "_udp", "local" };
129 : mdns::Minimal::FullQName serviceName(matterc_udp_local);
130 :
131 : static const char * root[] = { "" };
132 : mdns::Minimal::FullQName targetName(root);
133 : mdns::Minimal::SrvResourceRecord srvRecord(serviceName, targetName, params.GetPort());
134 : builder.AddRecord(mdns::Minimal::ResourceType::kAnswer, srvRecord);
135 :
136 : TxtStringsBuilder txtStringsBuilder;
137 : ReturnErrorOnFailure(txtStringsBuilder.Fill(params));
138 : mdns::Minimal::TxtResourceRecord txtRecord(serviceName, txtStringsBuilder.GetEntries(), txtStringsBuilder.GetCount());
139 : builder.AddRecord(mdns::Minimal::ResourceType::kAnswer, txtRecord);
140 :
141 : outBuffer = builder.ReleasePacket();
142 : }
143 :
144 : return CHIP_NO_ERROR;
145 : }
146 : #endif // CHIP_DEVICE_CONFIG_ENABLE_THREAD_MESHCOP
147 :
148 : } // namespace app
149 : } // namespace chip
|