diff --git a/PROTOCOL.md b/PROTOCOL.md index c84eb1fc..a3af296d 100644 --- a/PROTOCOL.md +++ b/PROTOCOL.md @@ -306,8 +306,40 @@ The device should answer: }, "id" : } +``` + +#### Controller wants the device to apply a given fixed configuration + +Controller sends this command when it requires the device to apply fixed configuration, eg. country code. The device +should respond with message indicating failure or success. +```json +{ "jsonrpc" : "2.0", + "method" : "fixedconfig", + "params" : { + "serial" : , + "when" : Optional - + "country" : "" + }, +} ``` + +The device should answer: +```json +{ "jsonrpc" : "2.0", + "result" : { + "serial": , + "status": { + "error": 0 or an error number, + "text": + }, + "uuid": + } +} + +``` + + ##### The Answer The device can answer and tell the controller it has rejected certain parts of the config and potentially replaced them with appropriate values. This could be used to allow a device to replace frequencies for the regions it is located in. The device diff --git a/openapi/owgw.yaml b/openapi/owgw.yaml index a03a1d27..2ff02dae 100644 --- a/openapi/owgw.yaml +++ b/openapi/owgw.yaml @@ -12,7 +12,7 @@ info: url: https://www.ucentral.info/support servers: - - url: 'https://localhost:16001/api/v1' + - url: 'https://localhost:16002/api/v1' security: - bearerAuth: [] diff --git a/src/RESTAPI/RESTAPI_device_commandHandler.cpp b/src/RESTAPI/RESTAPI_device_commandHandler.cpp index e0a6f0d4..6d0ef9d3 100644 --- a/src/RESTAPI/RESTAPI_device_commandHandler.cpp +++ b/src/RESTAPI/RESTAPI_device_commandHandler.cpp @@ -167,7 +167,10 @@ namespace OpenWifi { {APCommands::Commands::certupdate, false, true, &RESTAPI_device_commandHandler::CertUpdate, 60000ms}, {APCommands::Commands::transfer, false, true, &RESTAPI_device_commandHandler::Transfer, 60000ms}, {APCommands::Commands::script, false, true, &RESTAPI_device_commandHandler::Script, 60000ms}, - {APCommands::Commands::powercycle, false, true, &RESTAPI_device_commandHandler::PowerCycle, 60000ms} + {APCommands::Commands::powercycle, false, true, &RESTAPI_device_commandHandler::PowerCycle, 60000ms}, + {APCommands::Commands::fixedconfig, false, true, &RESTAPI_device_commandHandler::FixedConfig, 120000ms}, + {APCommands::Commands::cablediagnostics, false, true, &RESTAPI_device_commandHandler::CableDiagnostics, 120000ms}, + }; void RESTAPI_device_commandHandler::DoPost() { @@ -1548,4 +1551,82 @@ namespace OpenWifi { Logger_); } + // `fixedconfig` command is used set country propery on AP + // This handler uses `fixedconfig` command definitions + void RESTAPI_device_commandHandler::FixedConfig( + const std::string &CMD_UUID, uint64_t CMD_RPC, std::chrono::milliseconds timeout, + [[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) { + poco_debug(Logger_, fmt::format("FIXEDCONFIG({},{}): TID={} user={} serial={}", CMD_UUID, CMD_RPC, + TransactionId_, Requester(), SerialNumber_)); + // do not allow `fixedconfig` command for simulated devices + if(IsDeviceSimulated(SerialNumber_)) { + CallCanceled("FIXEDCONFIG", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported); + return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported); + } + + // setup and validate fixedconfig object + GWObjects::FixedConfig fixed_config; + if(!fixed_config.from_json(ParsedBody_)) { + return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); + } + + // setup command message + GWObjects::CommandDetails Cmd; + Cmd.SerialNumber = SerialNumber_; + Cmd.SubmittedBy = Requester(); + Cmd.UUID = CMD_UUID; + Cmd.Command = uCentralProtocol::FIXEDCONFIG; + std::ostringstream os; + ParsedBody_->stringify(os); + Cmd.Details = os.str(); + Cmd.RunAt = 0; + Cmd.ErrorCode = 0; + Cmd.WaitingForFile = 0; + + // send fixedconfig command to device and return status + return RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::fixedconfig, false, Cmd, + *ParsedBody_, *Request, *Response, timeout, nullptr, this, + Logger_); + } + + void RESTAPI_device_commandHandler::CableDiagnostics( + const std::string &CMD_UUID, uint64_t CMD_RPC, + [[maybe_unused]] std::chrono::milliseconds timeout, + [[maybe_unused]] const GWObjects::DeviceRestrictions &Restrictions) { + + if(UserInfo_.userinfo.userRole != SecurityObjects::ROOT && + UserInfo_.userinfo.userRole != SecurityObjects::ADMIN) { + CallCanceled("CABLEDIAGNOSTICS", CMD_UUID, CMD_RPC, RESTAPI::Errors::ACCESS_DENIED); + return UnAuthorized(RESTAPI::Errors::ACCESS_DENIED); + } + + poco_debug(Logger_, fmt::format("CABLEDIAGNOSTICS({},{}): TID={} user={} serial={}", CMD_UUID, + CMD_RPC, TransactionId_, Requester(), SerialNumber_)); + + if(IsDeviceSimulated(SerialNumber_)) { + CallCanceled("CABLEDIAGNOSTICS", CMD_UUID, CMD_RPC, RESTAPI::Errors::SimulatedDeviceNotSupported); + return BadRequest(RESTAPI::Errors::SimulatedDeviceNotSupported); + } + + GWObjects::CableDiagnostics PR; + if(!PR.from_json(ParsedBody_)) { + return BadRequest(RESTAPI::Errors::MissingOrInvalidParameters); + } + + GWObjects::CommandDetails Cmd; + Cmd.SerialNumber = SerialNumber_; + Cmd.SubmittedBy = Requester(); + Cmd.UUID = CMD_UUID; + Cmd.Command = uCentralProtocol::CABLEDIAGNOSTICS; + std::ostringstream os; + ParsedBody_->stringify(os); + Cmd.Details = os.str(); + Cmd.RunAt = PR.when; + Cmd.ErrorCode = 0; + Cmd.WaitingForFile = 0; + + return RESTAPI_RPC::WaitForCommand(CMD_RPC, APCommands::Commands::cablediagnostics, false, Cmd, + *ParsedBody_, *Request, *Response, timeout, nullptr, this, + Logger_); + } } // namespace OpenWifi diff --git a/src/RESTAPI/RESTAPI_device_commandHandler.h b/src/RESTAPI/RESTAPI_device_commandHandler.h index e20800f3..25f22d9f 100644 --- a/src/RESTAPI/RESTAPI_device_commandHandler.h +++ b/src/RESTAPI/RESTAPI_device_commandHandler.h @@ -70,6 +70,10 @@ namespace OpenWifi { const GWObjects::DeviceRestrictions &R); void PowerCycle(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout, const GWObjects::DeviceRestrictions &R); + void FixedConfig(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout, + const GWObjects::DeviceRestrictions &R); + void CableDiagnostics(const std::string &UUID, uint64_t RPC, std::chrono::milliseconds timeout, + const GWObjects::DeviceRestrictions &R); static auto PathName() { return std::list{"/api/v1/device/{serialNumber}/{command}"}; diff --git a/src/RESTObjects/RESTAPI_GWobjects.cpp b/src/RESTObjects/RESTAPI_GWobjects.cpp index 09da2c36..ead5968d 100644 --- a/src/RESTObjects/RESTAPI_GWobjects.cpp +++ b/src/RESTObjects/RESTAPI_GWobjects.cpp @@ -799,4 +799,24 @@ namespace OpenWifi::GWObjects { return false; } + bool FixedConfig::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "serial", serialNumber); + field_from_json(Obj, "country", country); + return true; + } catch (const Poco::Exception &E) { + } + return false; + } + + bool CableDiagnostics::from_json(const Poco::JSON::Object::Ptr &Obj) { + try { + field_from_json(Obj, "serial", serialNumber); + field_from_json(Obj, "when", when); + field_from_json(Obj, "ports", ports); + return true; + } catch (const Poco::Exception &E) { + } + return false; + } } // namespace OpenWifi::GWObjects diff --git a/src/RESTObjects/RESTAPI_GWobjects.h b/src/RESTObjects/RESTAPI_GWobjects.h index ed17aba7..c2136c45 100644 --- a/src/RESTObjects/RESTAPI_GWobjects.h +++ b/src/RESTObjects/RESTAPI_GWobjects.h @@ -532,6 +532,19 @@ namespace OpenWifi::GWObjects { std::uint64_t when; std::vector ports; + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + struct FixedConfig { + std::string serialNumber; + std::string country; + + bool from_json(const Poco::JSON::Object::Ptr &Obj); + }; + struct CableDiagnostics { + std::string serialNumber; + std::uint64_t when; + std::vector ports; + bool from_json(const Poco::JSON::Object::Ptr &Obj); }; } // namespace OpenWifi::GWObjects diff --git a/src/framework/ConfigurationValidator.cpp b/src/framework/ConfigurationValidator.cpp index e170dd9a..807d416c 100644 --- a/src/framework/ConfigurationValidator.cpp +++ b/src/framework/ConfigurationValidator.cpp @@ -2411,11 +2411,18 @@ static std::string DefaultAPSchema = R"foo( "$ref": "#/$defs/interface.ssid.encryption" }, "multi-psk": { - "type": "array", - "items": { - "$ref": "#/$defs/interface.ssid.multi-psk" - } - }, + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/interface.ssid.multi-psk" + } + }, + { + "type": "boolean" + } + ] + }, "rrm": { "$ref": "#/$defs/interface.ssid.rrm" }, @@ -6603,10 +6610,17 @@ static std::string DefaultSWITCHSchema = R"foo( "$ref": "#/$defs/interface.ssid.encryption" }, "multi-psk": { - "type": "array", - "items": { - "$ref": "#/$defs/interface.ssid.multi-psk" - } + "anyOf": [ + { + "type": "array", + "items": { + "$ref": "#/$defs/interface.ssid.multi-psk" + } + }, + { + "type": "boolean" + } + ] }, "rrm": { "$ref": "#/$defs/interface.ssid.rrm" diff --git a/src/framework/ow_constants.h b/src/framework/ow_constants.h index 2e838ff2..adac0cc6 100644 --- a/src/framework/ow_constants.h +++ b/src/framework/ow_constants.h @@ -580,6 +580,9 @@ namespace OpenWifi::RESTAPI::Protocol { static const char *INTERVAL = "interval"; static const char *UI = "UI"; static const char *BANDWIDTH = "bandwidth"; + + static const char *FIXEDCONFIG = "fixedconfig"; + static const char *CABLEDIAGNOSTICS = "cable-diagnostics"; } // namespace OpenWifi::RESTAPI::Protocol namespace OpenWifi::uCentralProtocol { @@ -692,6 +695,9 @@ namespace OpenWifi::uCentralProtocol { static const char *RRM = "rrm"; static const char *ACTIONS = "actions"; + static const char *FIXEDCONFIG = "fixedconfig"; + static const char *CABLEDIAGNOSTICS = "cable-diagnostics"; + } // namespace OpenWifi::uCentralProtocol namespace OpenWifi::uCentralProtocol::Events { @@ -788,6 +794,8 @@ namespace OpenWifi::APCommands { certupdate, transfer, powercycle, + fixedconfig, + cablediagnostics, unknown }; @@ -802,7 +810,8 @@ namespace OpenWifi::APCommands { RESTAPI::Protocol::EVENTQUEUE, RESTAPI::Protocol::TELEMETRY, RESTAPI::Protocol::PING, RESTAPI::Protocol::SCRIPT, RESTAPI::Protocol::RRM, RESTAPI::Protocol::CERTUPDATE, - RESTAPI::Protocol::TRANSFER, RESTAPI::Protocol::POWERCYCLE + RESTAPI::Protocol::TRANSFER, RESTAPI::Protocol::POWERCYCLE, + RESTAPI::Protocol::FIXEDCONFIG, RESTAPI::Protocol::CABLEDIAGNOSTICS }; inline const char *to_string(Commands Cmd) { return uCentralAPCommands[(uint8_t)Cmd]; }