Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2021 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 "ServiceNaming.h"
19 :
20 : #include <lib/core/CHIPEncoding.h>
21 : #include <lib/support/BytesToHex.h>
22 : #include <lib/support/CodeUtils.h>
23 :
24 : #include <cstdio>
25 : #include <inttypes.h>
26 : #include <string.h>
27 :
28 : namespace chip {
29 : namespace Dnssd {
30 :
31 45 : CHIP_ERROR MakeInstanceName(char * buffer, size_t bufferLen, const PeerId & peerId)
32 : {
33 45 : ReturnErrorCodeIf(bufferLen <= Operational::kInstanceNameMaxLength, CHIP_ERROR_BUFFER_TOO_SMALL);
34 :
35 11 : NodeId nodeId = peerId.GetNodeId();
36 11 : CompressedFabricId fabricId = peerId.GetCompressedFabricId();
37 :
38 11 : snprintf(buffer, bufferLen, "%08" PRIX32 "%08" PRIX32 "-%08" PRIX32 "%08" PRIX32, static_cast<uint32_t>(fabricId >> 32),
39 11 : static_cast<uint32_t>(fabricId), static_cast<uint32_t>(nodeId >> 32), static_cast<uint32_t>(nodeId));
40 :
41 11 : return CHIP_NO_ERROR;
42 : }
43 :
44 19 : CHIP_ERROR ExtractIdFromInstanceName(const char * name, PeerId * peerId)
45 : {
46 19 : ReturnErrorCodeIf(name == nullptr, CHIP_ERROR_INVALID_ARGUMENT);
47 17 : ReturnErrorCodeIf(peerId == nullptr, CHIP_ERROR_INVALID_ARGUMENT);
48 :
49 : // Make sure the string is long enough.
50 : static constexpr size_t fabricIdByteLength = 8;
51 : static constexpr size_t fabricIdStringLength = fabricIdByteLength * 2;
52 : static constexpr size_t nodeIdByteLength = 8;
53 : static constexpr size_t nodeIdStringLength = nodeIdByteLength * 2;
54 : static constexpr size_t totalLength = fabricIdStringLength + nodeIdStringLength + 1; // +1 for '-'
55 :
56 : // Ensure we have at least totalLength chars.
57 16 : size_t len = strnlen(name, totalLength);
58 16 : ReturnErrorCodeIf(len < totalLength, CHIP_ERROR_INVALID_ARGUMENT);
59 :
60 : // Check that we have a proper terminator.
61 12 : ReturnErrorCodeIf(name[totalLength] != '\0' && name[totalLength] != '.', CHIP_ERROR_WRONG_NODE_ID);
62 :
63 : // Check what we have a separator where we expect.
64 10 : ReturnErrorCodeIf(name[fabricIdStringLength] != '-', CHIP_ERROR_WRONG_NODE_ID);
65 :
66 : static constexpr size_t bufferSize = max(fabricIdByteLength, nodeIdByteLength);
67 : uint8_t buf[bufferSize];
68 :
69 5 : ReturnErrorCodeIf(Encoding::HexToBytes(name, fabricIdStringLength, buf, bufferSize) == 0, CHIP_ERROR_WRONG_NODE_ID);
70 : // Buf now stores the fabric id, as big-endian bytes.
71 : static_assert(fabricIdByteLength == sizeof(uint64_t), "Wrong number of bytes");
72 4 : peerId->SetCompressedFabricId(Encoding::BigEndian::Get64(buf));
73 :
74 4 : ReturnErrorCodeIf(Encoding::HexToBytes(name + fabricIdStringLength + 1, nodeIdStringLength, buf, bufferSize) == 0,
75 : CHIP_ERROR_WRONG_NODE_ID);
76 : // Buf now stores the node id id, as big-endian bytes.
77 : static_assert(nodeIdByteLength == sizeof(uint64_t), "Wrong number of bytes");
78 4 : peerId->SetNodeId(Encoding::BigEndian::Get64(buf));
79 :
80 4 : return CHIP_NO_ERROR;
81 : }
82 :
83 20 : CHIP_ERROR MakeHostName(char * buffer, size_t bufferLen, const chip::ByteSpan & macOrEui64)
84 : {
85 20 : ReturnErrorCodeIf(bufferLen < macOrEui64.size() * 2 + 1, CHIP_ERROR_BUFFER_TOO_SMALL);
86 :
87 20 : int idx = 0;
88 180 : for (size_t i = 0; i < macOrEui64.size(); ++i)
89 : {
90 160 : idx += snprintf(buffer + idx, 3, "%02X", macOrEui64.data()[i]);
91 : }
92 20 : return CHIP_NO_ERROR;
93 : }
94 :
95 84 : CHIP_ERROR MakeServiceSubtype(char * buffer, size_t bufferLen, DiscoveryFilter subtype)
96 : {
97 : int requiredSize;
98 84 : switch (subtype.type)
99 : {
100 18 : case DiscoveryFilterType::kShortDiscriminator:
101 : // 4-bit number
102 18 : if (subtype.code >= 1 << 4)
103 : {
104 2 : return CHIP_ERROR_INVALID_ARGUMENT;
105 : }
106 16 : requiredSize = snprintf(buffer, bufferLen, "_S%u", static_cast<uint16_t>(subtype.code));
107 16 : break;
108 18 : case DiscoveryFilterType::kLongDiscriminator:
109 : // 12-bit number
110 18 : if (subtype.code >= 1 << 12)
111 : {
112 2 : return CHIP_ERROR_INVALID_ARGUMENT;
113 : }
114 16 : requiredSize = snprintf(buffer, bufferLen, "_L%u", static_cast<uint16_t>(subtype.code));
115 16 : break;
116 17 : case DiscoveryFilterType::kVendorId:
117 17 : if (subtype.code >= 1 << 16)
118 : {
119 2 : return CHIP_ERROR_INVALID_ARGUMENT;
120 : }
121 15 : requiredSize = snprintf(buffer, bufferLen, "_V%u", static_cast<uint16_t>(subtype.code));
122 15 : break;
123 5 : case DiscoveryFilterType::kDeviceType:
124 5 : requiredSize = snprintf(buffer, bufferLen, "_T%" PRIu32, static_cast<uint32_t>(subtype.code));
125 5 : break;
126 14 : case DiscoveryFilterType::kCommissioningMode:
127 14 : requiredSize = snprintf(buffer, bufferLen, "_CM");
128 14 : break;
129 0 : case DiscoveryFilterType::kCommissioner:
130 0 : if (subtype.code > 1)
131 : {
132 0 : return CHIP_ERROR_INVALID_ARGUMENT;
133 : }
134 0 : requiredSize = snprintf(buffer, bufferLen, "_D%u", static_cast<uint16_t>(subtype.code));
135 0 : break;
136 10 : case DiscoveryFilterType::kCompressedFabricId:
137 10 : requiredSize = snprintf(buffer, bufferLen, "_I");
138 20 : return Encoding::Uint64ToHex(subtype.code, &buffer[requiredSize], bufferLen - static_cast<size_t>(requiredSize),
139 10 : Encoding::HexFlags::kUppercaseAndNullTerminate);
140 : break;
141 1 : case DiscoveryFilterType::kInstanceName:
142 1 : requiredSize = snprintf(buffer, bufferLen, "%s", subtype.instanceName);
143 1 : break;
144 1 : case DiscoveryFilterType::kNone:
145 1 : requiredSize = 0;
146 1 : buffer[0] = '\0';
147 1 : break;
148 : }
149 68 : return (static_cast<size_t>(requiredSize) <= (bufferLen - 1)) ? CHIP_NO_ERROR : CHIP_ERROR_NO_MEMORY;
150 : }
151 :
152 17 : CHIP_ERROR MakeServiceTypeName(char * buffer, size_t bufferLen, DiscoveryFilter nameDesc, DiscoveryType type)
153 : {
154 : int requiredSize;
155 17 : if (nameDesc.type == DiscoveryFilterType::kNone)
156 : {
157 4 : if (type == DiscoveryType::kCommissionableNode)
158 : {
159 3 : requiredSize = snprintf(buffer, bufferLen, kCommissionableServiceName);
160 : }
161 1 : else if (type == DiscoveryType::kCommissionerNode)
162 : {
163 1 : requiredSize = snprintf(buffer, bufferLen, kCommissionerServiceName);
164 : }
165 : else
166 : {
167 0 : return CHIP_ERROR_NOT_IMPLEMENTED;
168 : }
169 : }
170 : else
171 : {
172 13 : ReturnErrorOnFailure(MakeServiceSubtype(buffer, bufferLen, nameDesc));
173 10 : size_t subtypeLen = strlen(buffer);
174 10 : if (type == DiscoveryType::kCommissionableNode)
175 : {
176 9 : requiredSize = snprintf(buffer + subtypeLen, bufferLen - subtypeLen, ".%s.%s", kSubtypeServiceNamePart,
177 : kCommissionableServiceName);
178 : }
179 1 : else if (type == DiscoveryType::kCommissionerNode)
180 : {
181 : requiredSize =
182 0 : snprintf(buffer + subtypeLen, bufferLen - subtypeLen, ".%s.%s", kSubtypeServiceNamePart, kCommissionerServiceName);
183 : }
184 1 : else if (type == DiscoveryType::kOperational)
185 : {
186 : requiredSize =
187 1 : snprintf(buffer + subtypeLen, bufferLen - subtypeLen, ".%s.%s", kSubtypeServiceNamePart, kOperationalServiceName);
188 : }
189 : else
190 : {
191 0 : return CHIP_ERROR_NOT_IMPLEMENTED;
192 : }
193 : }
194 :
195 14 : return (static_cast<size_t>(requiredSize) <= (bufferLen - 1)) ? CHIP_NO_ERROR : CHIP_ERROR_NO_MEMORY;
196 : }
197 :
198 : } // namespace Dnssd
199 : } // namespace chip
|