From e55ad303338b15260503cef933b94416279ce178 Mon Sep 17 00:00:00 2001 From: Sagar Dhawan Date: Thu, 8 Jul 2021 13:51:57 -0700 Subject: [PATCH] Add ObjC Thread Operational Dataset (#8172) * Add an ObjC wrapper for the CHIP Thread Operational Dataset * Restyled by clang-format * Address review comments * Restyled by clang-format * address comments * Restyled by clang-format Co-authored-by: Restyled.io --- .../Framework/CHIP.xcodeproj/project.pbxproj | 13 +- src/darwin/Framework/CHIP/CHIP.h | 1 + .../CHIP/CHIPThreadOperationalDataset.h | 81 ++++++++++++ .../CHIP/CHIPThreadOperationalDataset.mm | 119 ++++++++++++++++++ .../CHIPThreadOperationalDatasetTests.mm | 68 ++++++++++ 5 files changed, 281 insertions(+), 1 deletion(-) create mode 100644 src/darwin/Framework/CHIP/CHIPThreadOperationalDataset.h create mode 100644 src/darwin/Framework/CHIP/CHIPThreadOperationalDataset.mm create mode 100644 src/darwin/Framework/CHIPTests/CHIPThreadOperationalDatasetTests.mm diff --git a/src/darwin/Framework/CHIP.xcodeproj/project.pbxproj b/src/darwin/Framework/CHIP.xcodeproj/project.pbxproj index 1c5b57f67a9369..46c561108c8a30 100644 --- a/src/darwin/Framework/CHIP.xcodeproj/project.pbxproj +++ b/src/darwin/Framework/CHIP.xcodeproj/project.pbxproj @@ -53,6 +53,9 @@ 991DC0892475F47D00C13860 /* CHIPDeviceController.mm in Sources */ = {isa = PBXBuildFile; fileRef = 991DC0872475F47D00C13860 /* CHIPDeviceController.mm */; }; 991DC08B247704DC00C13860 /* CHIPLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = 991DC08A247704DC00C13860 /* CHIPLogging.h */; }; 9956064426420367000C28DE /* CHIPSetupPayload_Internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 9956064326420367000C28DE /* CHIPSetupPayload_Internal.h */; }; + 997DED162695343400975E97 /* CHIPThreadOperationalDataset.mm in Sources */ = {isa = PBXBuildFile; fileRef = 997DED152695343400975E97 /* CHIPThreadOperationalDataset.mm */; }; + 997DED182695344800975E97 /* CHIPThreadOperationalDataset.h in Headers */ = {isa = PBXBuildFile; fileRef = 997DED172695344800975E97 /* CHIPThreadOperationalDataset.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 997DED1A26955D0200975E97 /* CHIPThreadOperationalDatasetTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 997DED1926955D0200975E97 /* CHIPThreadOperationalDatasetTests.mm */; }; 99C65E10267282F1003402F6 /* CHIPControllerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 99C65E0F267282F1003402F6 /* CHIPControllerTests.m */; }; B20252972459E34F00F97062 /* CHIP.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B202528D2459E34F00F97062 /* CHIP.framework */; }; B289D4212639C0D300D4E314 /* CHIPOnboardingPayloadParser.h in Headers */ = {isa = PBXBuildFile; fileRef = B289D41F2639C0D300D4E314 /* CHIPOnboardingPayloadParser.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -127,6 +130,9 @@ 991DC0872475F47D00C13860 /* CHIPDeviceController.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CHIPDeviceController.mm; sourceTree = ""; }; 991DC08A247704DC00C13860 /* CHIPLogging.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CHIPLogging.h; sourceTree = ""; }; 9956064326420367000C28DE /* CHIPSetupPayload_Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CHIPSetupPayload_Internal.h; sourceTree = ""; }; + 997DED152695343400975E97 /* CHIPThreadOperationalDataset.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CHIPThreadOperationalDataset.mm; sourceTree = ""; }; + 997DED172695344800975E97 /* CHIPThreadOperationalDataset.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CHIPThreadOperationalDataset.h; sourceTree = ""; }; + 997DED1926955D0200975E97 /* CHIPThreadOperationalDatasetTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CHIPThreadOperationalDatasetTests.mm; sourceTree = ""; }; 99C65E0F267282F1003402F6 /* CHIPControllerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CHIPControllerTests.m; sourceTree = ""; }; B202528D2459E34F00F97062 /* CHIP.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CHIP.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B20252912459E34F00F97062 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -243,6 +249,8 @@ 2C222ACE255C620600E446B9 /* CHIPDevice.h */, 2C222ACF255C620600E446B9 /* CHIPDevice.mm */, 2C8C8FBE253E0C2100797F05 /* CHIPPersistentStorageDelegate.h */, + 997DED152695343400975E97 /* CHIPThreadOperationalDataset.mm */, + 997DED172695344800975E97 /* CHIPThreadOperationalDataset.h */, 2C8C8FBD253E0C2100797F05 /* CHIPPersistentStorageDelegateBridge.h */, 2C8C8FBF253E0C2100797F05 /* CHIPPersistentStorageDelegateBridge.mm */, 2CB7163E252F731E0026E2BB /* CHIPDevicePairingDelegate.h */, @@ -274,6 +282,7 @@ 1EB41B7A263C4CC60048E4C1 /* CHIPClustersTests.m */, 99C65E0F267282F1003402F6 /* CHIPControllerTests.m */, B2F53AF1245B0DCF0010745E /* CHIPSetupPayloadParserTests.m */, + 997DED1926955D0200975E97 /* CHIPThreadOperationalDatasetTests.mm */, B202529D2459E34F00F97062 /* Info.plist */, ); path = CHIPTests; @@ -304,6 +313,7 @@ B2E0D7B2245B0B5C003C5B48 /* CHIPManualSetupPayloadParser.h in Headers */, B2E0D7B1245B0B5C003C5B48 /* CHIP.h in Headers */, B2E0D7B8245B0B5C003C5B48 /* CHIPSetupPayload.h in Headers */, + 997DED182695344800975E97 /* CHIPThreadOperationalDataset.h in Headers */, 9956064426420367000C28DE /* CHIPSetupPayload_Internal.h in Headers */, 2C8C8FC1253E0C2100797F05 /* CHIPPersistentStorageDelegate.h in Headers */, B2E0D7B5245B0B5C003C5B48 /* CHIPQRCodeSetupPayloadParser.h in Headers */, @@ -438,6 +448,7 @@ files = ( 2C8C8FC2253E0C2100797F05 /* CHIPPersistentStorageDelegateBridge.mm in Sources */, 2CB7163C252E8A7C0026E2BB /* CHIPDevicePairingDelegateBridge.mm in Sources */, + 997DED162695343400975E97 /* CHIPThreadOperationalDataset.mm in Sources */, 1E85732426551A490050A4D9 /* attribute-list-byte-span.cpp in Sources */, 1E85730E265519AE0050A4D9 /* CHIPClusters.cpp in Sources */, 1E85732326551A490050A4D9 /* process-global-message.cpp in Sources */, @@ -481,6 +492,7 @@ buildActionMask = 2147483647; files = ( 1EB41B7B263C4CC60048E4C1 /* CHIPClustersTests.m in Sources */, + 997DED1A26955D0200975E97 /* CHIPThreadOperationalDatasetTests.mm in Sources */, 99C65E10267282F1003402F6 /* CHIPControllerTests.m in Sources */, B2F53AF2245B0DCF0010745E /* CHIPSetupPayloadParserTests.m in Sources */, ); @@ -630,7 +642,6 @@ isa = XCBuildConfiguration; buildSettings = { CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = CHIPTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", diff --git a/src/darwin/Framework/CHIP/CHIP.h b/src/darwin/Framework/CHIP/CHIP.h index 25b9e374dcffa3..d8bee0039a25e5 100644 --- a/src/darwin/Framework/CHIP/CHIP.h +++ b/src/darwin/Framework/CHIP/CHIP.h @@ -25,6 +25,7 @@ #import #import #import +#import #import //! Project version number for CHIP. diff --git a/src/darwin/Framework/CHIP/CHIPThreadOperationalDataset.h b/src/darwin/Framework/CHIP/CHIPThreadOperationalDataset.h new file mode 100644 index 00000000000000..6543d9b9ede86f --- /dev/null +++ b/src/darwin/Framework/CHIP/CHIPThreadOperationalDataset.h @@ -0,0 +1,81 @@ +/** + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +NS_ASSUME_NONNULL_BEGIN + +@interface CHIPThreadOperationalDataset : NSObject + +/** + * The expected lengths of each of the NSData fields in the CHIPThreadOperationalDataset + * + * initWithNetworkName must be provided NSData fields with at least these lengths otherwise + * the object will fail to init. + */ +extern size_t const CHIPSizeThreadNetworkName; +extern size_t const CHIPSizeThreadExtendedPanId; +extern size_t const CHIPSizeThreadMasterKey; +extern size_t const CHIPSizeThreadPSKc; + +/** + * The Thread Network name + */ +@property (nonatomic, nullable, readwrite) NSString * networkName; +/** + * The Thread Network extendended PAN ID + */ +@property (nonatomic, nullable, readwrite) NSData * extendedPANID; +/** + * The 16 byte Master Key + */ +@property (nonatomic, nullable, readwrite) NSData * masterKey; +/** + * The Thread PSKc + */ +@property (nonatomic, nullable, readwrite) NSData * PSKc; +/** + * The Thread network channel + */ +@property (nonatomic, readwrite) uint16_t channel; +/** + * The Thread PAN ID + */ +@property (nonatomic, nullable, readwrite) NSData * panID; + +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + +/** + * Create a Thread Operational Dataset object with the individual network fields. + * This initializer will return nil if any of the NSData fields are smaller than expected. + */ +- (nullable instancetype)initWithNetworkName:(NSString *)networkName + extendedPANID:(NSData *)extendedPANID + masterKey:(NSData *)masterKey + PSKc:(NSData *)PSKc + channel:(uint16_t)channel + panID:(NSData *)panID; + +/** + * Get the underlying data that represents the Thread Active Operational Dataset + */ +- (NSData *)asData; + +@end + +NS_ASSUME_NONNULL_END diff --git a/src/darwin/Framework/CHIP/CHIPThreadOperationalDataset.mm b/src/darwin/Framework/CHIP/CHIPThreadOperationalDataset.mm new file mode 100644 index 00000000000000..461af9ea113af4 --- /dev/null +++ b/src/darwin/Framework/CHIP/CHIPThreadOperationalDataset.mm @@ -0,0 +1,119 @@ +/** + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import "CHIPThreadOperationalDataset.h" + +#include "CHIPLogging.h" +#include +#include + +size_t const CHIPSizeThreadNetworkName = chip::Thread::kSizeNetworkName; +size_t const CHIPSizeThreadExtendedPanId = chip::Thread::kSizeExtendedPanId; +size_t const CHIPSizeThreadMasterKey = chip::Thread::kSizeMasterKey; +size_t const CHIPSizeThreadPSKc = chip::Thread::kSizePSKc; + +@interface CHIPThreadOperationalDataset () + +@property (readonly) chip::Thread::OperationalDataset cppThreadOperationalDataset; + +@end + +@implementation CHIPThreadOperationalDataset + +- (nullable instancetype)initWithNetworkName:(NSString *)networkName + extendedPANID:(NSData *)extendedPANID + masterKey:(NSData *)masterKey + PSKc:(NSData *)PSKc + channel:(uint16_t)channel + panID:(NSData *)panID +{ + if (self = [super init]) { + _networkName = networkName; + _extendedPANID = extendedPANID; + _masterKey = masterKey; + _PSKc = PSKc; + _channel = channel; + _panID = panID; + _cppThreadOperationalDataset = chip::Thread::OperationalDataset(); + if ([self _populateCppOperationalDataset]) { + return self; + } + } + return nil; +} + +- (BOOL)_populateCppOperationalDataset +{ + _cppThreadOperationalDataset.Clear(); + _cppThreadOperationalDataset.SetNetworkName([self.networkName cStringUsingEncoding:NSUTF8StringEncoding]); + + if (![self _checkDataLength:self.extendedPANID expectedLength:chip::Thread::kSizeExtendedPanId]) { + CHIP_LOG_ERROR("Invalid ExtendedPANID"); + return NO; + } + uint8_t extendedPanId[chip::Thread::kSizeExtendedPanId]; + [self.extendedPANID getBytes:&extendedPanId length:chip::Thread::kSizeExtendedPanId]; + _cppThreadOperationalDataset.SetExtendedPanId(extendedPanId); + + if (![self _checkDataLength:self.masterKey expectedLength:chip::Thread::kSizeMasterKey]) { + CHIP_LOG_ERROR("Invalid MasterKey"); + return NO; + } + uint8_t masterKey[chip::Thread::kSizeMasterKey]; + [self.masterKey getBytes:&masterKey length:chip::Thread::kSizeMasterKey]; + _cppThreadOperationalDataset.SetMasterKey(masterKey); + + if (![self _checkDataLength:self.PSKc expectedLength:chip::Thread::kSizePSKc]) { + CHIP_LOG_ERROR("Invalid PKSc"); + return NO; + } + uint8_t PSKc[chip::Thread::kSizePSKc]; + [self.PSKc getBytes:&PSKc length:chip::Thread::kSizePSKc]; + _cppThreadOperationalDataset.SetPSKc(PSKc); + + _cppThreadOperationalDataset.SetChannel(self.channel); + + // Thread's PAN ID is 2 bytes + if (![self _checkDataLength:self.panID expectedLength:2]) { + CHIP_LOG_ERROR("Invalid PAN ID"); + return NO; + } + uint16_t * valuePtr = (uint16_t *) [self.panID bytes]; + if (valuePtr == nullptr) { + return NO; + } + _cppThreadOperationalDataset.SetPanId(*valuePtr); + + return YES; +} + +- (BOOL)_checkDataLength:(NSData *)data expectedLength:(size_t)expectedLength +{ + if (data.length != expectedLength) { + CHIP_LOG_ERROR("Length Check Failed. Length:%tu is too short, must be at least %tu", data.length, expectedLength); + return NO; + } + return YES; +} + +- (NSData *)asData +{ + chip::ByteSpan span = _cppThreadOperationalDataset.AsByteSpan(); + return [NSData dataWithBytes:span.data() length:span.size()]; +} + +@end diff --git a/src/darwin/Framework/CHIPTests/CHIPThreadOperationalDatasetTests.mm b/src/darwin/Framework/CHIPTests/CHIPThreadOperationalDatasetTests.mm new file mode 100644 index 00000000000000..1f1b2390308a64 --- /dev/null +++ b/src/darwin/Framework/CHIPTests/CHIPThreadOperationalDatasetTests.mm @@ -0,0 +1,68 @@ +// +// CHIPControllerTests.m +// CHIPControllerTests +/** + * + * Copyright (c) 2021 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#import + +// system dependencies +#import + +@interface CHIPThreadOperationalDatasetTests : XCTestCase + +@end + +@implementation CHIPThreadOperationalDatasetTests + +- (void)testThreadOperationalDataset +{ + const unsigned char extendedPANID[] = { 0x68, 0x09, 0x45, 0x04, 0xae, 0xef, 0x42, 0x67 }; + const unsigned char masterKey[] + = { 0x7c, 0x77, 0x08, 0x70, 0xeb, 0x05, 0xcc, 0x6d, 0xbe, 0xcc, 0x6d, 0x62, 0x32, 0xea, 0xb8, 0xb9 }; + const unsigned char PKSc[] = { 0xc4, 0xa3, 0x81, 0x25, 0x94, 0x77, 0x81, 0x99, 0x6e, 0xf5, 0x61, 0xdf, 0x8f, 0xb7, 0x8d, 0x23 }; + const uint16_t panID = 0x28f4; + CHIPThreadOperationalDataset * dataset = [[CHIPThreadOperationalDataset alloc] + initWithNetworkName:@"TestNetwork" + extendedPANID:[NSData dataWithBytes:&extendedPANID length:CHIPSizeThreadExtendedPanId] + masterKey:[NSData dataWithBytes:&masterKey length:CHIPSizeThreadMasterKey] + PSKc:[NSData dataWithBytes:&PKSc length:CHIPSizeThreadPSKc] + channel:25 + panID:[NSData dataWithBytes:&panID length:sizeof(panID)]]; + XCTAssertNotNil(dataset); + NSData * data = [dataset asData]; + XCTAssertNotNil(data); +} + +- (void)testThreadOperationalDatasetInvalid +{ + const unsigned char extendedPANID[] = { 0x67 }; + const unsigned char masterKey[] = {}; + const unsigned char PKSc[] = { 0xb7, 0x8d, 0x23 }; + const uint16_t panID = 0x0; + CHIPThreadOperationalDataset * dataset = + [[CHIPThreadOperationalDataset alloc] initWithNetworkName:@"TestNetwork" + extendedPANID:[NSData dataWithBytes:&extendedPANID length:sizeof(extendedPANID)] + masterKey:[NSData dataWithBytes:&masterKey length:sizeof(masterKey)] + PSKc:[NSData dataWithBytes:&PKSc length:sizeof(PKSc)] + channel:25 + panID:[NSData dataWithBytes:&panID length:sizeof(panID)]]; + + XCTAssertNil(dataset); +} + +@end