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