Line data Source code
1 : /*
2 : * Copyright (c) 2026 Project CHIP Authors
3 : * All rights reserved.
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 : #pragma once
18 :
19 : #include <cstdint>
20 : #include <cstring>
21 : #include <inet/IPAddress.h>
22 : #include <lib/core/CHIPError.h>
23 : #include <lib/core/DataModelTypes.h>
24 : #include <lib/core/Optional.h>
25 : #include <lib/support/Span.h>
26 :
27 : namespace chip {
28 : namespace Groupcast {
29 :
30 : /**
31 : * @brief Class to store GroupcastTesting event data
32 : *
33 : * This class stores all fields from the GroupcastTesting event,
34 : * including IP addresses as byte arrays for proper storage.
35 : */
36 : class Testing
37 : {
38 : public:
39 : class Delegate
40 : {
41 : public:
42 34 : virtual ~Delegate() = default;
43 : virtual void FlushGroupcastTestingEvent() = 0;
44 : };
45 :
46 : /**
47 : * @brief Test result enum matching GroupcastTestResultEnum from the Groupcast cluster.
48 : * This cannot point to the raw code-generated type due to build deps, so it is copied for convenience.
49 : */
50 : enum Result : uint8_t
51 : {
52 : kSuccess = 0x00,
53 : kGeneralError = 0x01,
54 : kMessageReplay = 0x02,
55 : kFailedAuth = 0x03,
56 : kNoAvailableKey = 0x04,
57 : kSendFailure = 0x05,
58 : };
59 :
60 : static constexpr size_t kIPv6AddressLength = 16; // IPv6 address is 16 bytes
61 :
62 25 : Testing() = default;
63 : ~Testing() = default;
64 :
65 66 : void SetDelegate(Delegate * delegate) { mDelegate = delegate; }
66 :
67 0 : void NotifyDelegate()
68 : {
69 0 : if (mDelegate != nullptr)
70 : {
71 0 : mDelegate->FlushGroupcastTestingEvent();
72 : }
73 0 : }
74 :
75 : // Getters for optional fields
76 : const chip::Optional<chip::GroupId> & GetGroupID() const { return mGroupID; }
77 : const chip::Optional<chip::EndpointId> & GetEndpointID() const { return mEndpointID; }
78 : const chip::Optional<chip::ClusterId> & GetClusterID() const { return mClusterID; }
79 : const chip::Optional<uint32_t> & GetElementID() const { return mElementID; }
80 0 : const chip::Optional<bool> & GetAccessAllowed() const { return mAccessAllowed; }
81 :
82 : // Setters for optional fields
83 : void SetGroupID(const chip::Optional<chip::GroupId> & groupID) { mGroupID = groupID; }
84 0 : void SetGroupID(chip::GroupId groupID) { mGroupID = MakeOptional(groupID); }
85 : void ClearGroupID() { mGroupID = chip::Optional<chip::GroupId>(); }
86 :
87 : void SetEndpointID(const chip::Optional<chip::EndpointId> & endpointID) { mEndpointID = endpointID; }
88 0 : void SetEndpointID(chip::EndpointId endpointID) { mEndpointID = MakeOptional(endpointID); }
89 : void ClearEndpointID() { mEndpointID = chip::Optional<chip::EndpointId>(); }
90 :
91 : void SetClusterID(const chip::Optional<chip::ClusterId> & clusterID) { mClusterID = clusterID; }
92 0 : void SetClusterID(chip::ClusterId clusterID) { mClusterID = MakeOptional(clusterID); }
93 : void ClearClusterID() { mClusterID = chip::Optional<chip::ClusterId>(); }
94 :
95 : void SetElementID(const chip::Optional<uint32_t> & elementID) { mElementID = elementID; }
96 0 : void SetElementID(uint32_t elementID) { mElementID = MakeOptional(elementID); }
97 : void ClearElementID() { mElementID = chip::Optional<uint32_t>(); }
98 :
99 : void SetAccessAllowed(const chip::Optional<bool> & accessAllowed) { mAccessAllowed = accessAllowed; }
100 0 : void SetAccessAllowed(bool accessAllowed) { mAccessAllowed = MakeOptional(accessAllowed); }
101 : void ClearAccessAllowed() { mAccessAllowed = chip::Optional<bool>(); }
102 :
103 : // Getters for required fields
104 68 : bool IsEnabled() const { return mEnabled; }
105 : uint8_t GetTestResult() const { return mTestResult; }
106 0 : Result GetTestResultEnum() const { return static_cast<Result>(mTestResult); }
107 17 : chip::FabricIndex GetFabricIndex() const { return mFabricIndex; }
108 0 : bool IsFabricUnderTest(chip::FabricIndex fabricIndex) { return mFabricIndex == fabricIndex; }
109 :
110 : // Setters for required fields
111 4 : void SetEnabled(bool enabled) { mEnabled = enabled; }
112 : void SetTestResult(uint8_t result) { mTestResult = result; }
113 0 : void SetTestResult(Result result) { mTestResult = static_cast<uint8_t>(result); }
114 4 : void SetFabricIndex(chip::FabricIndex fabricIndex) { mFabricIndex = fabricIndex; }
115 :
116 : // IP address getters
117 : chip::ByteSpan GetSourceIpAddress() const { return chip::ByteSpan(mSourceIpAddress, mSourceIpAddressLength); }
118 : chip::ByteSpan GetDestinationIpAddress() const { return chip::ByteSpan(mDestinationIpAddress, mDestinationIpAddressLength); }
119 : bool HasSourceIpAddress() const { return mSourceIpAddressLength > 0; }
120 : bool HasDestinationIpAddress() const { return mDestinationIpAddressLength > 0; }
121 :
122 : /**
123 : * @brief Set source IP address from Inet::IPAddress.
124 : * @param ipAddress IPAddress containing the IPv6 address
125 : */
126 0 : void SetSourceIpAddress(const Inet::IPAddress & ipAddress)
127 : {
128 0 : if (ipAddress.IsIPv6())
129 : {
130 0 : uint8_t * p = mSourceIpAddress;
131 0 : ipAddress.WriteAddress(p);
132 0 : mSourceIpAddressLength = kIPv6AddressLength;
133 : }
134 0 : }
135 :
136 : /**
137 : * @brief Set destination IP address from Inet::IPAddress.
138 : * @param ipAddress IPAddress containing the IPv6 address
139 : */
140 0 : void SetDestinationIpAddress(const Inet::IPAddress & ipAddress)
141 : {
142 0 : if (ipAddress.IsIPv6())
143 : {
144 0 : uint8_t * p = mDestinationIpAddress;
145 0 : ipAddress.WriteAddress(p);
146 0 : mDestinationIpAddressLength = kIPv6AddressLength;
147 : }
148 0 : }
149 :
150 : /**
151 : * @brief Clear source IP address
152 : */
153 : void ClearSourceIpAddress() { mSourceIpAddressLength = 0; }
154 :
155 : /**
156 : * @brief Clear destination IP address
157 : */
158 : void ClearDestinationIpAddress() { mDestinationIpAddressLength = 0; }
159 :
160 : /**
161 : * @brief Template method to convert stored data to event type
162 : * @tparam EventType The event type structure (e.g., Groupcast::Events::GroupcastTesting::Type)
163 : * @param event Output event structure to populate
164 : */
165 : template <typename EventType>
166 0 : void ToEventType(EventType & event) const
167 : {
168 0 : event.groupcastTestResult = static_cast<decltype(event.groupcastTestResult)>(mTestResult);
169 0 : event.fabricIndex = mFabricIndex;
170 0 : event.groupID = mGroupID;
171 0 : event.endpointID = mEndpointID;
172 0 : event.clusterID = mClusterID;
173 0 : event.elementID = mElementID;
174 0 : event.accessAllowed = mAccessAllowed;
175 :
176 0 : if (mSourceIpAddressLength > 0)
177 : {
178 0 : event.sourceIpAddress = MakeOptional(chip::ByteSpan(mSourceIpAddress, mSourceIpAddressLength));
179 : }
180 : else
181 : {
182 0 : event.sourceIpAddress = chip::Optional<chip::ByteSpan>();
183 : }
184 :
185 0 : if (mDestinationIpAddressLength > 0)
186 : {
187 0 : event.destinationIpAddress = MakeOptional(chip::ByteSpan(mDestinationIpAddress, mDestinationIpAddressLength));
188 : }
189 : else
190 : {
191 0 : event.destinationIpAddress = chip::Optional<chip::ByteSpan>();
192 : }
193 0 : }
194 :
195 : /**
196 : * @brief Clear all stored data
197 : */
198 4 : void Clear()
199 : {
200 4 : mSourceIpAddressLength = 0;
201 4 : mDestinationIpAddressLength = 0;
202 4 : mGroupID = chip::Optional<chip::GroupId>();
203 4 : mEndpointID = chip::Optional<chip::EndpointId>();
204 4 : mClusterID = chip::Optional<chip::ClusterId>();
205 4 : mElementID = chip::Optional<uint32_t>();
206 4 : mAccessAllowed = chip::Optional<bool>();
207 4 : mTestResult = 0;
208 4 : }
209 :
210 : private:
211 : Delegate * mDelegate = nullptr;
212 : bool mEnabled = false;
213 : // IP addresses stored as IPv6 address bytes (16 bytes) in network byte order (RFC 4291)
214 : uint8_t mSourceIpAddress[kIPv6AddressLength];
215 : uint8_t mDestinationIpAddress[kIPv6AddressLength];
216 : size_t mSourceIpAddressLength = 0;
217 : size_t mDestinationIpAddressLength = 0;
218 : // Optional fields
219 : chip::Optional<chip::GroupId> mGroupID;
220 : chip::Optional<chip::EndpointId> mEndpointID;
221 : chip::Optional<chip::ClusterId> mClusterID;
222 : chip::Optional<uint32_t> mElementID;
223 : chip::Optional<bool> mAccessAllowed;
224 : // Required fields
225 : uint8_t mTestResult = 0;
226 : chip::FabricIndex mFabricIndex = kUndefinedFabricIndex;
227 : };
228 :
229 : /**
230 : * @brief Get the singleton Testing instance.
231 : *
232 : * Callers must externally synchronize usage of this function.
233 : *
234 : * @return Reference to the global GroupcastTesting instance
235 : */
236 : Testing & GetTesting();
237 :
238 : } // namespace Groupcast
239 : } // namespace chip
|