Skip to content

Commit

Permalink
[OTA] Set default configuration values for OTA Provider to prevent crash
Browse files Browse the repository at this point in the history
- Update README on application usage
  • Loading branch information
carol-apple committed Feb 10, 2022
1 parent 31b5331 commit c157447
Show file tree
Hide file tree
Showing 4 changed files with 79 additions and 109 deletions.
8 changes: 8 additions & 0 deletions .github/.wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ ApplicationId
ApplicationIdentifier
ApplicationLauncher
ApplyUpdateRequest
ApplyUpdateResponse
approver
appspot
aps
Expand Down Expand Up @@ -280,6 +281,7 @@ debianutils
DEDEDEDE
deepnote
DelayedActionTime
delayedActionTimeSec
demangle
deployable
depottools
Expand Down Expand Up @@ -855,6 +857,7 @@ QRCodeUrl
QSPI
QueryImage
QueryImageResponse
queryImageStatus
qvCHIP
RADVD
raspberryPi
Expand Down Expand Up @@ -966,6 +969,7 @@ SoftDevice
softmmu
SoftwareDiagnostics
SoftwareVersion
softwareVersionStr
SoftwareVersionString
softwareVersionValid
SPI
Expand Down Expand Up @@ -1085,12 +1089,16 @@ UniFlash
unpair
unprovisioned
untrusted
updateAvailable
updateNotAvailable
UpdateTokens
upstreamed
URI
usbmodem
USBtoUART
uscif
UserConsentNeeded
userConsentState
userguide
USERINTERFACE
UserLabel
Expand Down
80 changes: 36 additions & 44 deletions examples/ota-provider-app/linux/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,52 +10,44 @@ Suggest doing the following:

## Usage

`./ota-provider-app [-f/--filepath \<file\>] [-o/--otaImageList \<file\>]`

If `--filepath` is supplied, `ota-provider-app` will automatically serve that
file to the OTA Requestor (SoftwareVersion will be Requester version + 1).

If `--otaImageList` is supplied, `ota-provider-app` will parse the JSON file and
extract all required data. Then the most recent, valid software version will be
selected and the corresponding ota-file will be sent to the OTA Requestor.

Here's an example of the otaImageList file contents:

{ "foo": 1, // ignored by parser "deviceSoftwareVersionModel": [ { "vendorId":
1, "productId": 1, "softwareVersion": 10, "softwareVersionString": "1.0.0",
"cDVersionNumber": 18, "softwareVersionValid": true,
"minApplicableSoftwareVersion": 0, "maxApplicableSoftwareVersion": 100,
"otaURL": "/tmp/ota.txt" }, { "vendorId": 1, "productId": 1, "softwareVersion":
20, "softwareVersionString": "1.0.1", "cDVersionNumber": 18,
"softwareVersionValid": false, "minApplicableSoftwareVersion": 0,
"maxApplicableSoftwareVersion": 100, "otaURL": "/tmp/ota.txt" }, { "vendorId":
1, "productId": 1, "softwareVersion": 30, "softwareVersionString": "1.0.2",
"cDVersionNumber": 18, "softwareVersionValid": true,
"minApplicableSoftwareVersion": 0, "maxApplicableSoftwareVersion": 100,
"otaURL": "/tmp/ota.txt" }, { "vendorId": 1, "productId": 1, "softwareVersion":
40, "softwareVersionString": "1.1.0", "cDVersionNumber": 18,
"softwareVersionValid": true, "minApplicableSoftwareVersion": 0,
"maxApplicableSoftwareVersion": 100, "otaURL": "/tmp/ota.txt" }, { "vendorId":
1, "productId": 1, "softwareVersion": 50, "softwareVersionString": "1.1.1",
"cDVersionNumber": 18, "softwareVersionValid": false,
"minApplicableSoftwareVersion": 0, "maxApplicableSoftwareVersion": 100,
"otaURL": "/tmp/ota.txt" } ] }

If neither `--filepath` nor `--otaImageList` are supplied, `ota-provider-app`
will respond to `QueryImage` with `NotAvailable` status.

## Current Features/Limitations

### Features

- can provide local filepath to serve as OTA image
- can complete full BDX transfer
- supports variable-length / startoffset for BDX transfer

### Limitations:
| Command Line Options | Description |
| --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| -f/--filepath <file> | Path to a file containing an OTA image |
| -o/--otaImageList <file> | Path to a file containing a list of OTA images |
| -q/--queryImageStatus <updateAvailable \| busy \| updateNotAvailable> | Value for the Status field in the QueryImageResponse |
| -t/--delayedActionTimeSec <time> | Value in seconds for the DelayedActionTime field in the QueryImageResponse and ApplyUpdateResponse |
| -u/--userConsentState <granted \| denied \| deferred> | Current user consent state which results in various values for Status field in QueryImageResponse <br> Note that -q/--queryImageStatus overrides this option <li> granted: Status field in QueryImageResponse is set to updateAvailable <li> denied: Status field in QueryImageResponse is set to updateNotAvailable <li> deferred: Status field in QueryImageResponse is set to busy |
| -s/--softwareVersion <version> | Value for the SoftwareVersion field in the QueryImageResponse <br> Note that -o/--otaImageList overrides this option |
| -S/--softwareVersionStr <version string> | Value for the SoftwareVersionString field in the QueryImageResponse <br> Note that -o/--otaImageList overrides this option |
| -c/--UserConsentNeeded | If provided, value of UserConsentNeeded in the Query Image Response is set to true |

### Using `--filepath` and `--otaImageList`

- The two options cannot be supplied together
- If neither option is supplied, the application will respond with
`NotAvailable` status
- If `--filepath` is supplied, the application will automatically serve that
file to the OTA Requestor (SoftwareVersion will be Requester version + 1).
- If `--otaImageList` is supplied, the application will parse the JSON file
and extract all required data. The most recent/valid software version will
be selected and the corresponding OTA file will be sent to the OTA
Requestor.

An example of the `--otaImageList` file contents:

```
{ "foo": 1, // ignored by parser
"deviceSoftwareVersionModel": [
{ "vendorId": 1, "productId": 1, "softwareVersion": 10, "softwareVersionString": "1.0.0", "cDVersionNumber": 18, "softwareVersionValid": true, "minApplicableSoftwareVersion": 0, "maxApplicableSoftwareVersion": 100, "otaURL": "/tmp/ota.txt" },
{ "vendorId": 1, "productId": 1, "softwareVersion": 20, "softwareVersionString": "1.0.1", "cDVersionNumber": 18, "softwareVersionValid": false, "minApplicableSoftwareVersion": 0, "maxApplicableSoftwareVersion": 100, "otaURL": "/tmp/ota.txt" },
{ "vendorId": 1, "productId": 1, "softwareVersion": 30, "softwareVersionString": "1.0.2", "cDVersionNumber": 18, "softwareVersionValid": true, "minApplicableSoftwareVersion": 0, "maxApplicableSoftwareVersion": 100, "otaURL": "/tmp/ota.txt" },
{ "vendorId": 1, "productId": 1, "softwareVersion": 40, "softwareVersionString": "1.1.0", "cDVersionNumber": 18, "softwareVersionValid": true, "minApplicableSoftwareVersion": 0, "maxApplicableSoftwareVersion": 100, "otaURL": "/tmp/ota.txt" },
{ "vendorId": 1, "productId": 1, "softwareVersion": 50, "softwareVersionString": "1.1.1", "cDVersionNumber": 18, "softwareVersionValid": false, "minApplicableSoftwareVersion": 0, "maxApplicableSoftwareVersion": 100, "otaURL": "/tmp/ota.txt" } ] }
```

## Current Limitations

- Synchronous BDX transfer only
- using hardcoded test values for local and peer Node IDs
- does not check VID/PID
- no configuration for `AwaitNextAction`
- only one transfer at a time (does not check incoming `UpdateTokens`)
85 changes: 30 additions & 55 deletions examples/ota-provider-app/linux/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@

using chip::BitFlags;
using chip::app::Clusters::OTAProviderDelegate;
using chip::ArgParser::HelpOptions;
using chip::ArgParser::OptionDef;
using chip::ArgParser::OptionSet;
using chip::ArgParser::PrintArgError;
Expand All @@ -45,17 +44,15 @@ constexpr chip::EndpointId kOtaProviderEndpoint = 0;

constexpr uint16_t kOptionFilepath = 'f';
constexpr uint16_t kOptionOtaImageList = 'o';
constexpr uint16_t kOptionQueryImageBehavior = 'q';
constexpr uint16_t kOptionQueryImageStatus = 'q';
constexpr uint16_t kOptionUserConsentState = 'u';
constexpr uint16_t kOptionDelayedActionTimeSec = 't';
constexpr uint16_t kOptionDiscriminator = 'd';
constexpr uint16_t kOptionSoftwareVersion = 's';
constexpr uint16_t kOptionSoftwareVersionStr = 'S';
constexpr uint16_t kOptionUserConsentNeeded = 'c';

static constexpr uint16_t kMaximumDiscriminatorValue = 0xFFF;

OTAProviderExample gOtaProvider;
chip::ota::DefaultUserConsentProvider gUserConsentProvider;

// Global variables used for passing the CLI arguments to the OTAProviderExample object
static OTAProviderExample::QueryImageBehaviorType gQueryImageBehavior = OTAProviderExample::kRespondWithUnknown;
Expand All @@ -64,7 +61,6 @@ static const char * gOtaFilepath = nullptr;
static const char * gOtaImageListFilepath = nullptr;
static chip::ota::UserConsentState gUserConsentState = chip::ota::UserConsentState::kUnknown;
static bool gUserConsentNeeded = false;
static chip::Optional<uint16_t> gSetupDiscriminator;
static chip::Optional<uint32_t> gSoftwareVersion;
static const char * gSoftwareVersionString = nullptr;

Expand Down Expand Up @@ -163,27 +159,27 @@ bool HandleOptions(const char * aProgram, OptionSet * aOptions, int aIdentifier,
gOtaImageListFilepath = aValue;
}
break;
case kOptionQueryImageBehavior:
case kOptionQueryImageStatus:
if (aValue == NULL)
{
PrintArgError("%s: ERROR: NULL QueryImageBehavior parameter\n", aProgram);
PrintArgError("%s: ERROR: NULL queryImageStatus parameter\n", aProgram);
retval = false;
}
else if (strcmp(aValue, "UpdateAvailable") == 0)
else if (strcmp(aValue, "updateAvailable") == 0)
{
gQueryImageBehavior = OTAProviderExample::kRespondWithUpdateAvailable;
}
else if (strcmp(aValue, "Busy") == 0)
else if (strcmp(aValue, "busy") == 0)
{
gQueryImageBehavior = OTAProviderExample::kRespondWithBusy;
}
else if (strcmp(aValue, "UpdateNotAvailable") == 0)
else if (strcmp(aValue, "updateNotAvailable") == 0)
{
gQueryImageBehavior = OTAProviderExample::kRespondWithNotAvailable;
}
else
{
PrintArgError("%s: ERROR: Invalid QueryImageBehavior parameter: %s\n", aProgram, aValue);
PrintArgError("%s: ERROR: Invalid queryImageStatus parameter: %s\n", aProgram, aValue);
retval = false;
}
break;
Expand Down Expand Up @@ -214,16 +210,6 @@ bool HandleOptions(const char * aProgram, OptionSet * aOptions, int aIdentifier,
retval = false;
}
break;
case kOptionDiscriminator: {
uint16_t discriminator = static_cast<uint16_t>(strtoul(aValue, NULL, 0));
if (discriminator > kMaximumDiscriminatorValue)
{
PrintArgError("%s: Input ERROR: setupDiscriminator value %s is out of range \n", aProgram, aValue);
retval = false;
}
gSetupDiscriminator.SetValue(discriminator);
break;
}
case kOptionSoftwareVersion:
gSoftwareVersion.SetValue(static_cast<uint32_t>(strtoul(aValue, NULL, 0)));
break;
Expand Down Expand Up @@ -258,10 +244,9 @@ bool HandleOptions(const char * aProgram, OptionSet * aOptions, int aIdentifier,
OptionDef cmdLineOptionsDef[] = {
{ "filepath", chip::ArgParser::kArgumentRequired, kOptionFilepath },
{ "otaImageList", chip::ArgParser::kArgumentRequired, kOptionOtaImageList },
{ "QueryImageBehavior", chip::ArgParser::kArgumentRequired, kOptionQueryImageBehavior },
{ "DelayedActionTimeSec", chip::ArgParser::kArgumentRequired, kOptionDelayedActionTimeSec },
{ "UserConsentState", chip::ArgParser::kArgumentRequired, kOptionUserConsentState },
{ "discriminator", chip::ArgParser::kArgumentRequired, kOptionDiscriminator },
{ "queryImageStatus", chip::ArgParser::kArgumentRequired, kOptionQueryImageStatus },
{ "delayedActionTimeSec", chip::ArgParser::kArgumentRequired, kOptionDelayedActionTimeSec },
{ "userConsentState", chip::ArgParser::kArgumentRequired, kOptionUserConsentState },
{ "softwareVersion", chip::ArgParser::kArgumentRequired, kOptionSoftwareVersion },
{ "softwareVersionStr", chip::ArgParser::kArgumentRequired, kOptionSoftwareVersionStr },
{ "UserConsentNeeded", chip::ArgParser::kNoArgument, kOptionUserConsentNeeded },
Expand All @@ -270,43 +255,33 @@ OptionDef cmdLineOptionsDef[] = {

OptionSet cmdLineOptions = { HandleOptions, cmdLineOptionsDef, "PROGRAM OPTIONS",
" -f/--filepath <file>\n"
" Path to a file containing an OTA image.\n"
" Path to a file containing an OTA image\n"
" -o/--otaImageList <file>\n"
" Path to a file containing a list of OTA images.\n"
" -q/--QueryImageBehavior <UpdateAvailable | Busy | UpdateNotAvailable>\n"
" Status value in the Query Image Response\n"
" -t/--DelayedActionTimeSec <time>\n"
" Value in seconds for the DelayedActionTime in the Query Image Response\n"
" and Apply Update Response\n"
" -u/--UserConsentState <granted | denied | deferred>\n"
" granted: Status value in QueryImageResponse is set to UpdateAvailable\n"
" denied: Status value in QueryImageResponse is set to UpdateNotAvailable\n"
" deferred: Status value in QueryImageResponse is set to Busy\n"
" -q/--QueryImageBehavior overrides this option\n"
" -d/--discriminator <discriminator>\n"
" A 12-bit value used to discern between multiple commissionable CHIP device\n"
" advertisements. If none is specified, default value is 3840.\n"
" Path to a file containing a list of OTA images\n"
" -q/--queryImageStatus <updateAvailable | busy | updateNotAvailable>\n"
" Value for the Status field in the QueryImageResponse\n"
" -t/--delayedActionTimeSec <time>\n"
" Value in seconds for the DelayedActionTime field in the QueryImageResponse\n"
" and ApplyUpdateResponse\n"
" -u/--userConsentState <granted | denied | deferred>\n"
" granted: Status field in QueryImageResponse is set to updateAvailable\n"
" denied: Status field in QueryImageResponse is set to updateNotAvailable\n"
" deferred: Status field in QueryImageResponse is set to busy\n"
" -q/--queryImageStatus overrides this option\n"
" -s/--softwareVersion <version>\n"
" Value of SoftwareVersion in the Query Image Response\n"
" If ota image list is present along with this option\n"
" then value from ota image list is used.\n"
" Otherwise, this value will be used is then value from that will be used\n"
" Value for the SoftwareVersion field in the QueryImageResponse\n"
" -o/--otaImageList overrides this option\n"
" -S/--softwareVersionStr <version string>\n"
" Value of SoftwareVersionString in the Query Image Response\n"
" If ota image list is present along with this option\n"
" then value from ota image list is used.\n"
" Otherwise, this value will be used is then value from that will be used\n"
" Value for the SoftwareVersionString field in the QueryImageResponse\n"
" -o/--otaImageList overrides this option\n"
" -c/--UserConsentNeeded\n"
" If provided, value of UserConsentNeeded in the Query Image Response is set to true\n" };

HelpOptions helpOptions("ota-provider-app", "Usage: ota-provider-app [options]", "1.0");

OptionSet * allOptions[] = { &cmdLineOptions, &helpOptions, nullptr };
OptionSet * allOptions[] = { &cmdLineOptions, nullptr };

void ApplicationInit()
{
CHIP_ERROR err = CHIP_NO_ERROR;
chip::ota::DefaultUserConsentProvider userConsentProvider;

BdxOtaSender * bdxOtaSender = gOtaProvider.GetBdxOtaSender();
VerifyOrReturn(bdxOtaSender != nullptr);
Expand Down Expand Up @@ -338,8 +313,8 @@ void ApplicationInit()

if (gUserConsentState != chip::ota::UserConsentState::kUnknown)
{
userConsentProvider.SetGlobalUserConsentState(gUserConsentState);
gOtaProvider.SetUserConsentDelegate(&userConsentProvider);
gUserConsentProvider.SetGlobalUserConsentState(gUserConsentState);
gOtaProvider.SetUserConsentDelegate(&gUserConsentProvider);
}

if (gUserConsentNeeded)
Expand Down
Loading

0 comments on commit c157447

Please sign in to comment.