Skip to content

Commit 2d1c9a6

Browse files
committed
Initial implementation of WebRTC Provider cluster
1 parent 44f3cce commit 2d1c9a6

File tree

2 files changed

+444
-0
lines changed

2 files changed

+444
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
/*
2+
*
3+
* Copyright (c) 2025 Project CHIP Authors
4+
* All rights reserved.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
#include "commissioner-control-server.h"
19+
20+
#include <protocols/interaction_model/StatusCode.h>
21+
22+
#include <app-common/zap-generated/attributes/Accessors.h>
23+
#include <app-common/zap-generated/cluster-enums.h>
24+
#include <app-common/zap-generated/cluster-objects.h>
25+
#include <app/CommandHandler.h>
26+
#include <app/CommandHandlerInterfaceRegistry.h>
27+
#include <app/EventLogging.h>
28+
#include <app/reporting/reporting.h>
29+
#include <platform/CHIPDeviceLayer.h>
30+
#include <platform/PlatformManager.h>
31+
32+
#include <memory>
33+
34+
using namespace chip;
35+
using namespace chip::app;
36+
37+
using chip::Protocols::InteractionModel::Status;
38+
39+
namespace {
40+
41+
NodeId GetNodeId(const CommandHandler & commandHandler)
42+
{
43+
auto descriptor = commandHandler.GetSubjectDescriptor();
44+
45+
if (descriptor.authMode != Access::AuthMode::kCase)
46+
{
47+
return kUndefinedNodeId;
48+
}
49+
return descriptor.subject;
50+
}
51+
52+
void AddReverseOpenCommissioningWindowResponse(CommandHandler & commandHandler, const ConcreteCommandPath & path,
53+
const Clusters::WebRTCTransportProvider::CommissioningWindowParams & params)
54+
{
55+
Clusters::WebRTCTransportProvider::Commands::ReverseOpenCommissioningWindow::Type response;
56+
response.commissioningTimeout = params.commissioningTimeout;
57+
response.discriminator = params.discriminator;
58+
response.iterations = params.iterations;
59+
response.PAKEPasscodeVerifier = params.PAKEPasscodeVerifier;
60+
response.salt = params.salt;
61+
62+
commandHandler.AddResponse(path, response);
63+
}
64+
65+
} // namespace
66+
67+
namespace chip {
68+
namespace app {
69+
namespace Clusters {
70+
namespace WebRTCTransportProvider {
71+
72+
WebRTCProviderServer::WebRTCProviderServer(Delegate * delegate, EndpointId endpointId) :
73+
CommandHandlerInterface(MakeOptional(endpointId), Id)
74+
{
75+
mDelegate = delegate;
76+
}
77+
78+
WebRTCProviderServer::~WebRTCProviderServer()
79+
{
80+
CommandHandlerInterfaceRegistry::Instance().UnregisterCommandHandler(this);
81+
}
82+
83+
CHIP_ERROR WebRTCProviderServer::Init()
84+
{
85+
ReturnErrorOnFailure(CommandHandlerInterfaceRegistry::Instance().RegisterCommandHandler(this));
86+
return CHIP_NO_ERROR;
87+
}
88+
89+
Status WebRTCProviderServer::GetSupportedDeviceCategoriesValue(
90+
EndpointId endpoint, BitMask<SupportedDeviceCategoryBitmap> * supportedDeviceCategories) const
91+
{
92+
Status status = Attributes::SupportedDeviceCategories::Get(endpoint, supportedDeviceCategories);
93+
if (status != Status::Success)
94+
{
95+
ChipLogProgress(Zcl, "WebRTCTransportProvider: reading supportedDeviceCategories, err:0x%x", to_underlying(status));
96+
}
97+
return status;
98+
}
99+
100+
Status
101+
WebRTCProviderServer::SetSupportedDeviceCategoriesValue(EndpointId endpoint,
102+
const BitMask<SupportedDeviceCategoryBitmap> supportedDeviceCategories)
103+
{
104+
Status status = Status::Success;
105+
106+
if ((status = Attributes::SupportedDeviceCategories::Set(endpoint, supportedDeviceCategories)) != Status::Success)
107+
{
108+
ChipLogProgress(Zcl, "WebRTCTransportProvider: writing supportedDeviceCategories, err:0x%x", to_underlying(status));
109+
return status;
110+
}
111+
112+
return status;
113+
}
114+
115+
CHIP_ERROR
116+
WebRTCProviderServer::GenerateCommissioningRequestResultEvent(EndpointId endpoint,
117+
const Events::CommissioningRequestResult::Type & result)
118+
{
119+
EventNumber eventNumber;
120+
CHIP_ERROR error = LogEvent(result, endpoint, eventNumber);
121+
if (CHIP_NO_ERROR != error)
122+
{
123+
ChipLogError(Zcl, "WebRTCTransportProvider: Unable to emit CommissioningRequestResult event: %" CHIP_ERROR_FORMAT,
124+
error.Format());
125+
}
126+
127+
return error;
128+
}
129+
130+
void WebRTCProviderServer::InvokeCommand(HandlerContext & handlerContext)
131+
{
132+
ChipLogDetail(Zcl, "WebRTCTransportProvider: InvokeCommand");
133+
switch (handlerContext.mRequestPath.mCommandId)
134+
{
135+
case Commands::RequestCommissioningApproval::Id:
136+
ChipLogDetail(Zcl, "WebRTCTransportProvider: Entering RequestCommissioningApproval");
137+
138+
CommandHandlerInterface::HandleCommand<Commands::RequestCommissioningApproval::DecodableType>(
139+
handlerContext, [this](HandlerContext & ctx, const auto & req) { HandleRequestCommissioningApproval(ctx, req); });
140+
break;
141+
142+
case Commands::CommissionNode::Id:
143+
ChipLogDetail(Zcl, "WebRTCTransportProvider: Entering CommissionNode");
144+
145+
CommandHandlerInterface::HandleCommand<Commands::CommissionNode::DecodableType>(
146+
handlerContext, [this](HandlerContext & ctx, const auto & req) { HandleCommissionNode(ctx, req); });
147+
break;
148+
}
149+
}
150+
151+
void WebRTCProviderServer::HandleRequestCommissioningApproval(
152+
HandlerContext & ctx, const Commands::RequestCommissioningApproval::DecodableType & req)
153+
{
154+
CHIP_ERROR err = CHIP_NO_ERROR;
155+
Status status = Status::Success;
156+
157+
ChipLogProgress(Zcl, "Received command to request commissioning approval");
158+
159+
auto sourceNodeId = GetNodeId(ctx.mCommandHandler);
160+
161+
// Check if the command is executed via a CASE session
162+
if (sourceNodeId == kUndefinedNodeId)
163+
{
164+
ChipLogError(Zcl, "Commissioning approval request not executed via CASE session, failing with UNSUPPORTED_ACCESS");
165+
ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::UnsupportedAccess);
166+
return;
167+
}
168+
169+
auto fabricIndex = ctx.mCommandHandler.GetAccessingFabricIndex();
170+
auto requestId = req.requestID;
171+
auto vendorId = req.vendorID;
172+
auto productId = req.productID;
173+
174+
// The label assigned from req need to be stored in WebRTCTransportProvider::Delegate which ensure that the backing buffer
175+
// of it has a valid lifespan during fabric sync setup process.
176+
auto & label = req.label;
177+
178+
// Create a CommissioningApprovalRequest struct and populate it with the command data
179+
Clusters::WebRTCTransportProvider::CommissioningApprovalRequest request = { .requestId = requestId,
180+
.vendorId = vendorId,
181+
.productId = productId,
182+
.clientNodeId = sourceNodeId,
183+
.fabricIndex = fabricIndex,
184+
.label = label };
185+
186+
VerifyOrExit(mDelegate != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
187+
188+
// Handle commissioning approval request
189+
err = mDelegate->HandleCommissioningApprovalRequest(request);
190+
191+
exit:
192+
if (err != CHIP_NO_ERROR)
193+
{
194+
ChipLogError(Zcl, "HandleRequestCommissioningApproval error: %" CHIP_ERROR_FORMAT, err.Format());
195+
status = StatusIB(err).mStatus;
196+
}
197+
198+
ctx.mCommandHandler.AddStatus(ctx.mRequestPath, status);
199+
}
200+
201+
void WebRTCProviderServer::HandleCommissionNode(HandlerContext & ctx, const Commands::CommissionNode::DecodableType & req)
202+
{
203+
CHIP_ERROR err = CHIP_NO_ERROR;
204+
205+
ChipLogProgress(Zcl, "Received command to commission node");
206+
207+
auto sourceNodeId = GetNodeId(ctx.mCommandHandler);
208+
209+
// Constraint on responseTimeoutSeconds is [30; 120] seconds
210+
if ((req.responseTimeoutSeconds < 30) || (req.responseTimeoutSeconds > 120))
211+
{
212+
ChipLogError(Zcl, "Invalid responseTimeoutSeconds for CommissionNode.");
213+
ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::ConstraintError);
214+
return;
215+
}
216+
217+
// Check if the command is executed via a CASE session
218+
if (sourceNodeId == kUndefinedNodeId)
219+
{
220+
ChipLogError(Zcl, "Commission node request not executed via CASE session, failing with UNSUPPORTED_ACCESS");
221+
ctx.mCommandHandler.AddStatus(ctx.mRequestPath, Status::UnsupportedAccess);
222+
return;
223+
}
224+
225+
auto requestId = req.requestID;
226+
auto delegate = mDelegate;
227+
auto commissioningWindowParams = std::make_unique<Clusters::WebRTCTransportProvider::CommissioningWindowParams>();
228+
229+
VerifyOrExit(mDelegate != nullptr, err = CHIP_ERROR_INCORRECT_STATE);
230+
231+
// Validate the commission node command.
232+
err = mDelegate->ValidateCommissionNodeCommand(sourceNodeId, requestId);
233+
SuccessOrExit(err);
234+
235+
// Populate the parameters for the commissioning window
236+
err = mDelegate->GetCommissioningWindowParams(*commissioningWindowParams);
237+
SuccessOrExit(err);
238+
239+
// Add the response for the commissioning window.
240+
AddReverseOpenCommissioningWindowResponse(ctx.mCommandHandler, ctx.mRequestPath, *commissioningWindowParams);
241+
242+
// Schedule the deferred reverse commission node task
243+
DeviceLayer::SystemLayer().ScheduleLambda([delegate, params = commissioningWindowParams.release()]() {
244+
if (delegate != nullptr)
245+
{
246+
CHIP_ERROR error = delegate->HandleCommissionNode(*params);
247+
if (error != CHIP_NO_ERROR)
248+
{
249+
ChipLogError(Zcl, "HandleCommissionNode error: %" CHIP_ERROR_FORMAT, error.Format());
250+
}
251+
}
252+
else
253+
{
254+
ChipLogError(Zcl, "No delegate available for HandleCommissionNode");
255+
}
256+
257+
delete params;
258+
});
259+
260+
exit:
261+
if (err != CHIP_NO_ERROR)
262+
{
263+
ChipLogError(Zcl, "HandleCommissionNode error: %" CHIP_ERROR_FORMAT, err.Format());
264+
ctx.mCommandHandler.AddStatus(ctx.mRequestPath, StatusIB(err).mStatus);
265+
}
266+
}
267+
268+
} // namespace WebRTCTransportProvider
269+
} // namespace Clusters
270+
} // namespace app
271+
} // namespace chip
272+
273+
void MatterWebRTCTransportProviderPluginServerInitCallback()
274+
{
275+
ChipLogProgress(Zcl, "Initializing WebRTC Transport Provider cluster.");
276+
}

0 commit comments

Comments
 (0)