Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Matter 1.4 Protocol #1687

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions packages/matter.js/src/CommissioningServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ import {
ManualPairingCodeCodec,
ProductDescription,
QrPairingCodeCodec,
TypeFromBitSchema,
TypeFromPartialBitSchema,
VendorId,
} from "#types";
Expand Down Expand Up @@ -768,7 +767,7 @@ export class CommissioningServer extends MatterNode {
* Return the pairing information for the device
*/
getPairingCode(
discoveryCapabilities?: TypeFromBitSchema<typeof DiscoveryCapabilitiesBitmap>,
discoveryCapabilities?: TypeFromPartialBitSchema<typeof DiscoveryCapabilitiesBitmap>,
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dummy comment to prevent merging

): DevicePairingInformation {
const basicInformation = this.getRootClusterServer(BasicInformationCluster);
if (basicInformation == undefined) {
Expand Down
20 changes: 18 additions & 2 deletions packages/protocol/src/common/Scanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,25 @@
*/

import { BasicSet, ChannelType, Environment, Environmental, Lifespan, ServerAddress, ServerAddressIp } from "#general";
import { DiscoveryCapabilitiesBitmap, NodeId, TypeFromPartialBitSchema, VendorId } from "#types";
import { BitFlag, BitmapSchema, DiscoveryCapabilitiesBitmap, NodeId, TypeFromPartialBitSchema, VendorId } from "#types";
import { Fabric } from "../fabric/Fabric.js";

export const SupportedTransportsBitmap = {
// Bit 0 is reserved
/**
* TCP Client
* The advertising Node implements the TCP Client mode and MAY connect to a peer Node that is a TCP Server.
*/
tcpClient: BitFlag(1),

/**
* TCP Server
* The advertising Node implements the TCP Server mode and SHALL listen for incoming TCP connections.
*/
tcpServer: BitFlag(2),
};
export const SupportedTransportsSchema = BitmapSchema(SupportedTransportsBitmap);

/**
* All information exposed by a commissionable device via announcements.
* The properties are named identical as in the Matter specification.
Expand Down Expand Up @@ -41,7 +57,7 @@ export type DiscoveryData = {
SAT?: number;

/** TCP supported */
T?: number;
T?: number; // SupportedTransportsBitmap but comes in as number, so converted on usage

/** ICD Long Idle Time operating mode supported */
ICD?: number;
Expand Down
6 changes: 3 additions & 3 deletions packages/protocol/src/mdns/MdnsBroadcaster.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ export class MdnsBroadcaster {
`SII=${sessionIdleInterval}` /* Session Idle Interval */,
`SAI=${sessionActiveInterval}` /* Session Active Interval */,
`SAT=${sessionActiveThreshold}` /* Session Active Threshold */,
//`T=${TCP_SUPPORTED}` /* TCP not supported */,
//`T=${TCP_SUPPORTED}` /* TODO TCP not supported */,
`D=${discriminator}` /* Discriminator */,
`CM=${mode}` /* Commission Mode */,
`PH=${PairingHintBitmapSchema.encode(pairingHint)}` /* Pairing Hint */,
Expand Down Expand Up @@ -324,7 +324,7 @@ export class MdnsBroadcaster {
`SII=${sessionIdleInterval}` /* Session Idle Interval */,
`SAI=${sessionActiveInterval}` /* Session Active Interval */,
`SAT=${sessionActiveThreshold}` /* Session Active Threshold */,
//`T=${TCP_SUPPORTED}` /* TCP not supported */,
//`T=${TCP_SUPPORTED}` /* TODO TCP not supported */,
//`ICD=${ICD_SUPPORTED}` /* ICD not supported */,
],
deviceMatterQname,
Expand Down Expand Up @@ -387,7 +387,7 @@ export class MdnsBroadcaster {
`SII=${sessionIdleInterval}` /* Session Idle Interval */,
`SAI=${sessionActiveInterval}` /* Session Active Interval */,
`SAT=${sessionActiveThreshold}` /* Session Active Threshold */,
//`T=${TCP_SUPPORTED}` /* TCP not supported */,
//`T=${TCP_SUPPORTED}` /* TODO TCP not supported */,
//`ICD=${ICD_SUPPORTED}` /* ICD not supported */,
]),
];
Expand Down
3 changes: 3 additions & 0 deletions packages/protocol/src/mdns/MdnsScanner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1319,6 +1319,9 @@ export class MdnsScanner implements Scanner {
} else if (result.T === 1) {
// Value 1 is reserved and should be handled as 0 according to Matter spec
result.T = 0; // TCP not supported
} else if (result.T !== 2 && result.T !== 4 && result.T !== 6) {
// performant way to check if tcpClient (Bit 1) or tcpServer (Bit 2) or both are supported, all other values are invalid
result.T = 0; // TCP not supported
}
if (result.ICD === undefined) {
result.ICD = 0; // Device is not operating as Long Idle Time ICD
Expand Down
107 changes: 55 additions & 52 deletions packages/protocol/src/peer/ControllerCommissioningFlow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,47 +313,50 @@ export class ControllerCommissioningFlow {

// Step 1: is outside of this class and requires to have relevant information needed by next steps
// Step 2: is about discovery which is already done before this starts here
// Step 3: is the PASE session establishment which is done before this starts here
// TODO Step 3-5: Commissioner handles/prepares for T&C Ack, if supported
// Step 6: is the PASE session establishment which is done before this starts here

this.#commissioningSteps.push({
stepNumber: 4,
stepNumber: 7,
subStepNumber: 1,
name: "GeneralCommissioning.ArmFailsafe",
stepLogic: () => this.#armFailsafe(),
});

this.#commissioningSteps.push({
stepNumber: 5,
stepNumber: 8,
subStepNumber: 1,
name: "GeneralCommissioning.ConfigureRegulatoryInformation",
stepLogic: () => this.#configureRegulatoryInformation(),
});

this.#commissioningSteps.push({
stepNumber: 5,
stepNumber: 8,
subStepNumber: 2,
name: "TimeSynchronization.SynchronizeTime",
stepLogic: () => this.#synchronizeTime(),
});

// TODO Step 9: If device and Controller supports T&C Feature then User consent is handled

this.#commissioningSteps.push({
stepNumber: 6,
stepNumber: 10,
subStepNumber: 1,
name: "OperationalCredentials.DeviceAttestation",
stepLogic: () => this.#deviceAttestation(),
});

this.#commissioningSteps.push({
stepNumber: 7, // includes 7-9
stepNumber: 11, // includes 11-13
subStepNumber: 1,
name: "OperationalCredentials.Certificates",
stepLogic: () => this.#certificates(),
});

// TODO Step 10: TimeSynchronization.SetTrustedTimeSource if supported
// TODO Step 14: TimeSynchronization.SetTrustedTimeSource if supported

this.#commissioningSteps.push({
stepNumber: 11,
stepNumber: 15,
subStepNumber: 1,
name: "AccessControl",
stepLogic: () => this.#configureAccessControlLists(),
Expand All @@ -362,14 +365,14 @@ export class ControllerCommissioningFlow {
// Care about Network commissioning only when we are on BLE, because else we are already on IP network
if (this.#interactionClient.channelType === ChannelType.BLE) {
this.#commissioningSteps.push({
stepNumber: 12,
stepNumber: 16,
subStepNumber: 1,
name: "NetworkCommissioning.Validate",
stepLogic: () => this.#validateNetwork(),
});
if (this.#commissioningOptions.wifiNetwork !== undefined) {
this.#commissioningSteps.push({
stepNumber: 12, // includes step 13
stepNumber: 16, // includes step 17
subStepNumber: 2,
name: "NetworkCommissioning.Wifi",
reArmFailsafe: true,
Expand All @@ -378,7 +381,7 @@ export class ControllerCommissioningFlow {
}
if (this.#commissioningOptions.threadNetwork !== undefined) {
this.#commissioningSteps.push({
stepNumber: 12, // includes step 13
stepNumber: 16, // includes step 17
subStepNumber: 3,
name: "NetworkCommissioning.Thread",
reArmFailsafe: true,
Expand All @@ -392,22 +395,22 @@ export class ControllerCommissioningFlow {
}

this.#commissioningSteps.push({
stepNumber: 14, // includes step 15 (CASE connection)
stepNumber: 18, // includes step 19 (CASE connection)
subStepNumber: 1,
name: "Reconnect",
reArmFailsafe: true,
stepLogic: () => this.#reconnectWithDevice(),
});

this.#commissioningSteps.push({
stepNumber: 16,
stepNumber: 20,
subStepNumber: 1,
name: "GeneralCommissioning.Complete",
stepLogic: () => this.#completeCommissioning(),
});

this.#commissioningSteps.push({
stepNumber: 17, // Should be allowed in Step 9, but Tasmota is not supporting this
stepNumber: 99, // Should be allowed in Step 13, but Tasmota is not supporting this
subStepNumber: 1,
name: "OperationalCredentials.UpdateFabricLabel",
stepLogic: () => this.#updateFabricLabel(),
Expand Down Expand Up @@ -531,7 +534,7 @@ export class ControllerCommissioningFlow {
}

/**
* Step 4
* Step 7
* Commissioner SHALL re-arm the Fail-safe timer on the Commissionee to the desired commissioning
* timeout within 60 seconds of the completion of PASE session establishment, using the
* ArmFailSafe command (see Section 11.10.6.2, “ArmFailSafe Command”). A Commissioner MAY
Expand Down Expand Up @@ -579,7 +582,7 @@ export class ControllerCommissioningFlow {
}

/**
* Step 5 - 1
* Step 8 - 1
* Commissioner SHALL configure regulatory information if the Commissionee has at least one instance of
* the Network Commissioning cluster on any endpoint with either the WI (i.e. Wi-Fi) or TH (i.e. Thread)
* feature flags set in its FeatureMap, Commissioner SHALL configure regulatory information in the
Expand Down Expand Up @@ -650,7 +653,7 @@ export class ControllerCommissioningFlow {
}

/**
* Step 5 - 2
* Step 8 - 2
* Commissioner SHOULD configure UTC time, timezone, and DST offset, if the Commissionee supports the
* time synchronization cluster.
* ▪ The Commissioner SHOULD configure UTC time using the SetUTCTime command.
Expand All @@ -675,7 +678,7 @@ export class ControllerCommissioningFlow {
}

/**
* Step 6
* Step 10
* Commissioner SHALL establish the authenticity of the Commissionee as a certified Matter device
* (see Section 6.2.3, “Device Attestation Procedure”).
*/
Expand Down Expand Up @@ -721,20 +724,20 @@ export class ControllerCommissioningFlow {
}

/**
* Step 7-9
* 7: Following the Device Attestation Procedure yielding a decision to proceed with commissioning, the Commissioner
* SHALL request operational CSR from Commissionee using the CSRRequest command (see Section 11.17.6.5,
* “CSRRequest Command”). The CSRRequest command will cause the generation of a new operational key pair at the
* Commissionee.
* 8: Commissioner SHALL generate or otherwise obtain an Operational Certificate containing Operational ID after
* receiving the CSRResponse command from the Commissionee (see Section 11.17.6.5, “CSRRequest Command”), using
* implementation-specific means.
* 9: Commissioner SHALL install operational credentials (see Figure 40, “Node Operational Credentials
* flow”) on the Commissionee using the AddTrustedRootCertificate and AddNOC commands,
* and SHALL use the UpdateFabricLabel command to set a string that the user can recognize and
* relate to this Commissioner/Administrator.
* The AdminVendorId field of the AddNOC command SHALL be set to a value for which the Vendor Schema in
* DCL contains the name and other information of the Commissioner’s manufacturer.
* Step 11-13
* 11: Following the Device Attestation Procedure yielding a decision to proceed with commissioning, the Commissioner
* SHALL request operational CSR from Commissionee using the CSRRequest command (see Section 11.17.6.5,
* “CSRRequest Command”). The CSRRequest command will cause the generation of a new operational key pair at the
* Commissionee.
* 12: Commissioner SHALL generate or otherwise obtain an Operational Certificate containing Operational ID after
* receiving the CSRResponse command from the Commissionee (see Section 11.17.6.5, “CSRRequest Command”), using
* implementation-specific means.
* 13: Commissioner SHALL install operational credentials (see Figure 40, “Node Operational Credentials
* flow”) on the Commissionee using the AddTrustedRootCertificate and AddNOC commands,
* and SHALL use the UpdateFabricLabel command to set a string that the user can recognize and
* relate to this Commissioner/Administrator.
* The AdminVendorId field of the AddNOC command SHALL be set to a value for which the Vendor Schema in
* DCL contains the name and other information of the Commissioner’s manufacturer.
*/
async #certificates() {
const operationalCredentialsClusterClient = this.#getClusterClient(OperationalCredentials.Cluster);
Expand Down Expand Up @@ -786,7 +789,7 @@ export class ControllerCommissioningFlow {
}

/**
* Step 9 - 2
* Step 13-2 (we do as 99 at the end because)
* The Administrator having established a CASE session with the Commissionee over the operational network in the
* previous steps SHALL invoke the CommissioningComplete command (see Section 11.9.6.6,
* “CommissioningComplete Command”). A success response after invocation of the CommissioningComplete command ends
Expand Down Expand Up @@ -825,7 +828,7 @@ export class ControllerCommissioningFlow {
}

/**
* Step 11
* Step 15
* Commissioner MAY configure the Access Control List (see Access Control Cluster) on the Commissionee in any way
* it sees fit, if the singular entry added by the AddNOC command in the previous step granting Administer
* privilege over CASE authentication type for the Node ID provided with the command is not sufficient to express
Expand All @@ -841,16 +844,17 @@ export class ControllerCommissioningFlow {
}

/**
* Step 12-13
* 12: If the Commissionee both supports it and requires it, the Commissioner SHALL configure the operational network
* at the Commissionee using commands such as AddOrUpdateWiFiNetwork (see Section 11.8.7.3, “AddOrUpdateWiFiNetwork
* Command”) and AddOrUpdateThreadNetwork (see Section 11.8.7.4, “AddOrUpdateThreadNetwork Command”).
* A Commissionee requires network commissioning if it is not already on the desired operational network.
* A Commissionee supports network commissioning if it has any NetworkCommissioning cluster instances.
* A Commissioner MAY learn about the networks visible to the Commissionee using ScanNetworks command
* (see Section 11.8.7.1, “ScanNetworks Command”).
* 13: The Commissioner SHALL trigger the Commissionee to connect to the operational network using ConnectNetwork
* command (see Section 11.8.7.9, “ConnectNetwork Command”) unless the Commissionee is already on the desired operational network.
* Step 16-17
* 16: If the Commissionee both supports it and requires it, the Commissioner SHALL configure the operational network
* at the Commissionee using commands such as AddOrUpdateWiFiNetwork (see Section 11.8.7.3, “AddOrUpdateWiFiNetwork
* Command”) and AddOrUpdateThreadNetwork (see Section 11.8.7.4, “AddOrUpdateThreadNetwork Command”).
* A Commissionee requires network commissioning if it is not already on the desired operational network.
* A Commissionee supports network commissioning if it has any NetworkCommissioning cluster instances.
* A Commissioner MAY learn about the networks visible to the Commissionee using ScanNetworks command
* (see Section 11.8.7.1, “ScanNetworks Command”).
* 17: The Commissioner SHALL trigger the Commissionee to connect to the operational network using ConnectNetwork
* command (see Section 11.8.7.9, “ConnectNetwork Command”) unless the Commissionee is already on the desired
* operational network.
*/
async #validateNetwork() {
if (
Expand Down Expand Up @@ -1161,13 +1165,12 @@ export class ControllerCommissioningFlow {
}

/**
* Step 14-15
* 14: Finalization of the Commissioning process begins. An Administrator configured in the ACL of the Commissionee
* by the Commissioner SHALL use Operational Discovery to discover the Commissionee. This Administrator MAY be
* the Commissioner itself, or another Node to which the Commissioner has delegated the task.
* 15: The Administrator SHALL open a CASE (see Section 4.13.2, “Certificate Authenticated Session Establishment
* (CASE)”) session with the Commissionee over the operational network.
*
* Step 18-19
* 18: Finalization of the Commissioning process begins. An Administrator configured in the ACL of the Commissionee
* by the Commissioner SHALL use Operational Discovery to discover the Commissionee. This Administrator MAY be
* the Commissioner itself, or another Node to which the Commissioner has delegated the task.
* 19: The Administrator SHALL open a CASE (see Section 4.13.2, “Certificate Authenticated Session Establishment
* (CASE)”) session with the Commissionee over the operational network.
*/
async #reconnectWithDevice() {
const isConcurrentFlow = this.#collectedCommissioningData.supportsConcurrentConnection !== false;
Expand Down Expand Up @@ -1229,7 +1232,7 @@ export class ControllerCommissioningFlow {
}

/**
* Step 16
* Step 20
* The Administrator having established a CASE session with the Commissionee over the operational network in the
* previous steps SHALL invoke the CommissioningComplete command (see Section 11.9.6.6,
* “CommissioningComplete Command”). A success response after invocation of the CommissioningComplete command ends
Expand Down
Loading