diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index d44975fd..2f2c89fe 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1 +1,84 @@
-If you would like to contribute code to this project you can do so through GitHub by forking the repository and sending a pull request. Before RDK accepts your code into the project you must sign the RDK Contributor License Agreement (CLA).
+# Contributing to RFC
+
+Thank you for your interest in contributing to the Remote Feature Control (RFC) project!
+
+---
+
+## Getting Started
+
+1. **Fork** the repository on GitHub
+2. **Clone** your fork locally
+3. **Create** a feature branch from `develop`:
+ ```bash
+ git checkout -b feature/JIRA-XXXX-description develop
+ ```
+4. **Build** and verify your changes:
+ ```bash
+ autoreconf -i
+ ./configure --enable-gtestapp
+ make && make check
+ ```
+5. **Commit** with a clear message referencing the JIRA ticket
+6. **Push** your branch and open a Pull Request against `develop`
+
+---
+
+## Branch Naming
+
+| Type | Pattern | Example |
+|------|---------|---------|
+| Feature | `feature/JIRA-XXXX-short-desc` | `feature/RDKC-15902-camera-support` |
+| Bugfix | `bugfix/JIRA-XXXX-short-desc` | `bugfix/DELIA-69554-cert-retry` |
+| Release | `release/X.Y.Z` | `release/1.2.3` |
+
+---
+
+## Coding Standards
+
+- **C++ Standard:** C++11 minimum
+- **Platform guards:** Use `#ifdef RDKC`, `#ifdef RDKB_SUPPORT`, or `#ifndef` blocks for platform-specific code
+- **Comments:** Use Doxygen-style documentation (`/** @brief ... */`, `@param`, `@return`)
+- **Logging:** Use `RDK_LOG_*` macros with appropriate log levels
+- **Security:** Use `v_secure_system()` / `v_secure_popen()` instead of raw `system()` / `popen()`
+
+---
+
+## Pull Request Checklist
+
+- [ ] Code compiles for all target platforms (STB, RDKB, RDKC)
+- [ ] Unit tests pass (`make check`)
+- [ ] New functionality includes corresponding tests
+- [ ] No Coverity or static analysis warnings introduced
+- [ ] Platform-specific code is properly guarded with `#ifdef`
+- [ ] Documentation updated if architecture changes were made
+
+---
+
+## Testing
+
+```bash
+# Unit tests (L1)
+./run_ut.sh
+
+# Integration tests (L2)
+./run_l2.sh
+
+# Reboot trigger tests
+./run_l2_reboot_trigger.sh
+```
+
+---
+
+## Contributor License Agreement
+
+Before RDK accepts your code into the project you must sign the [RDK Contributor License Agreement (CLA)](https://wiki.rdkcentral.com/display/DOC/Contributor+License+Agreement).
+
+---
+
+## Repository Documentation
+
+For architecture details, diagrams, and data flow documentation, see the [documentation/](documentation/) folder:
+
+- [Architecture](documentation/architecture.md) — Component architecture, class hierarchy, build system
+- [Sequence Diagrams](documentation/sequence-diagrams.md) — End-to-end execution flows
+- [Data Processing Flow](documentation/data-processing-flow.md) — Parameter lifecycle and storage strategies
diff --git a/Makefile.am b/Makefile.am
index ccd9619c..ee691f19 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -17,7 +17,7 @@
# limitations under the License.
##########################################################################
if ENABLE_RDKC
-SUBDIRS = rfcapi
+SUBDIRS = rfcapi rfcMgr
else
if ENABLE_RDKB
SUBDIRS = rfcMgr
diff --git a/README.md b/README.md
index b1e0ea93..b27efa31 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,28 @@
-# RFC — Remote Feature Control Module
+# RFC — Remote Feature Control
+
+[](#building)
+[](LICENSE)
+[](#platform-support)
+
+> C++ daemon and API library for fetching, applying, and managing Remote Feature Control (RFC) settings from an Xconf configuration server across RDK device platforms.
+
+---
+
+## Table of Contents
+
+- [Overview](#overview)
+- [Platform Support](#platform-support)
+- [Repository Structure](#repository-structure)
+- [Architecture Overview](#architecture-overview)
+- [Building](#building)
+- [Configuration](#configuration)
+- [Usage](#usage)
+- [Testing](#testing)
+- [Documentation](#documentation)
+- [Contributing](#contributing)
+- [License](#license)
+
+---
## Overview
@@ -6,6 +30,29 @@ The RFC (Remote Feature Control) module enables dynamic configuration of RDK dev
Licensed under the Apache License 2.0. Copyright 2016–2024 RDK Management.
+**rfcMgr** is a C++ daemon that replaces the legacy shell-based `RFCbase.sh` for Remote Feature Control. It:
+
+1. **Detects** when the device is online
+2. **Collects** device identity (MAC, firmware, model, partner ID, account ID)
+3. **Queries** the Xconf server for feature-control configuration
+4. **Applies** RFC parameters to the local device
+5. **Evaluates** whether a reboot is needed for `effectiveImmediate` features
+6. **Schedules** periodic re-checks via cron
+
+The **rfcapi** library provides a public C API (`getRFCParameter`, `setRFCParameter`, `isRFCEnabled`) for other RDK components to read/write RFC parameters.
+
+---
+
+## Platform Support
+
+| Platform | Define Flag | Description |
+|----------|-------------|-------------|
+| **STB** | *(default)* | Set-Top Box — uses hostif/WDMP APIs, TR-181 data model |
+| **RDKB** | `-DRDKB_SUPPORT` | RDK Broadband — uses rbus for TR-181 access |
+| **RDKC** | `-DRDKC` | RDK Camera (XHC1/XCAM2) — flat-file parameter storage, mfrApi for device identity |
+
+All platform-specific code is behind `#ifdef` guards, ensuring a single codebase builds cleanly for all targets.
+
---
## Quick Start
@@ -29,153 +76,164 @@ sh run_l2_reboot_trigger.sh
## Repository Structure
```
-rfc/
-├── configure.ac # Autoconf build configuration
-├── Makefile.am # Top-level automake
-├── rfc.properties # Default RFC server properties
-├── rfcMgr/ # RFC manager daemon
-│ ├── rfc_main.cpp # Entry point, fork, signal handling
-│ ├── rfc_manager.cpp/.h # RFCManager class — orchestrates fetch/apply
-│ ├── rfc_common.cpp/.h # Shared utilities, macros, error codes
-│ ├── rfc_xconf_handler.cpp/.h # RuntimeFeatureControlProcessor
-│ ├── xconf_handler.cpp/.h # XconfHandler — HTTP device metadata
-│ ├── mtlsUtils.cpp/.h # mTLS certificate selection
-│ ├── rfc_mgr_key.h # TR181 key string constants
-│ ├── rfc_mgr_json.h # JSON payload processing
-│ ├── rfc_mgr_iarm.h # IARM bus definitions
-│ └── gtest/ # Unit tests + mocks
-├── rfcapi/ # Public RFC get/set API library
-│ ├── rfcapi.cpp/.h # getRFCParameter / setRFCParameter
-│ └── docs/ # rfcapi documentation
-├── tr181api/ # TR181 parameter store API library
-│ ├── tr181api.cpp/.h # getParam / setParam / clearParam
-│ └── docs/ # tr181api documentation
-├── utils/ # Shared JSON and TR181 utilities
-│ ├── jsonhandler.cpp/.h
-│ ├── tr181utils.cpp
-│ └── trsetutils.cpp/.h
-└── test/ # L2 functional tests
- └── functional-tests/
+rfc-fork/
+├── rfcMgr/ # RFC Manager daemon (core component)
+│ ├── rfc_main.cpp # Entry point — daemonize, init directories
+│ ├── rfc_manager.h/cpp # Lifecycle orchestrator
+│ ├── xconf_handler.h/cpp # Base device-identity collector
+│ ├── rfc_xconf_handler.h/cpp # Core RFC state machine & Xconf logic
+│ ├── rdkc_rfc_xconf_handler.h/cpp # RDKC camera-specific overrides
+│ ├── mtlsUtils.h/cpp # mTLS certificate handling
+│ ├── rfc_common.h/cpp # Shared utilities
+│ ├── rfc_mgr_iarm.h # IARM bus integration
+│ ├── rfc_mgr_json.h # JSON field constants
+│ ├── rfc_mgr_key.h # Configuration key constants
+│ └── gtest/ # Unit & L2 integration tests
+│ └── mocks/ # Test doubles
+├── rfcapi/ # Public RFC parameter API library
+│ ├── rfcapi.h # C API header
+│ └── rfcapi.cpp # Implementation
+├── tr181api/ # TR-181 data model API
+│ ├── tr181api.h
+│ └── tr181api.cpp
+├── utils/ # Utility libraries
+│ ├── jsonhandler.h/cpp # JSON parsing helpers
+│ ├── trsetutils.h/cpp # TR-181 set utilities
+│ └── tr181utils.cpp # TR-181 access utilities
+├── test/ # Functional test suite
+│ └── functional-tests/
+├── documentation/ # Architecture & design docs
+│ ├── architecture.md # Component architecture & class diagrams
+│ ├── sequence-diagrams.md # End-to-end sequence flows
+│ └── data-processing-flow.md # Data processing & parameter flow
+├── .github/ # CI/CD workflows
+│ ├── workflows/
+│ └── CODEOWNERS
+├── configure.ac # Autotools build configuration
+├── Makefile.am # Top-level Automake
+├── rfc.properties # Runtime configuration
+├── getRFC.sh # Legacy shell wrapper
+├── isFeatureEnabled.sh # Feature check script
+├── CHANGELOG.md # Release history
+├── CONTRIBUTING.md # Contribution guidelines
+├── LICENSE / COPYING / NOTICE # Legal
+└── run_ut.sh / run_l2.sh # Test runners
```
---
-## System Architecture
+## Architecture Overview
```mermaid
graph TB
- subgraph Device
- main["rfc_main.cpp\n(fork + signals)"]
- mgr["RFCManager\n(rfc_manager.cpp)"]
- rfcp["RuntimeFeatureControlProcessor\n(rfc_xconf_handler.cpp)"]
- xconf["XconfHandler\n(xconf_handler.cpp)"]
- mtls["mtlsUtils\n(cert selection)"]
- rfcapi["librfcapi\n(rfcapi.cpp)"]
- tr181api["libtr181api\n(tr181api.cpp)"]
- store["/opt/secure/RFC/\ntr181store.ini\nrfcVariable.ini\nbootstrap.ini"]
- iarm["IARM Bus\n(optional)"]
+ subgraph "rfcMgr Daemon"
+ MAIN["rfc_main.cpp
Daemonize & Init"]
+ MGR["RFCManager
Orchestrator"]
+ XCONF["XconfHandler
Device Identity"]
+ RFC["RuntimeFeatureControl
Processor"]
+ CAM["RdkcRuntimeFeatureControl
Processor"]
+ MTLS["mtlsUtils
Certificate Handling"]
end
- XConfServer["XConf Server\n(HTTPS + mTLS)"]
- RDKComponent["RDK Component\n(consumer)"]
-
- main --> mgr
- mgr --> rfcp
- rfcp --> xconf
- xconf --> mtls
- xconf -->|"HTTP GET (mTLS)"| XConfServer
- XConfServer -->|"JSON response"| rfcp
- rfcp --> rfcapi
- rfcapi --> store
- rfcp --> tr181api
- tr181api --> store
- mgr --> iarm
- RDKComponent --> rfcapi
- RDKComponent --> tr181api
+ subgraph "Libraries"
+ API["rfcapi
Public C API"]
+ TR181["tr181api
TR-181 Access"]
+ UTILS["utils
JSON & Set Helpers"]
+ end
+
+ subgraph "External"
+ SERVER["Xconf Server"]
+ FS["File System
tr181store.ini"]
+ end
+
+ MAIN --> MGR
+ MGR --> RFC
+ RFC --> XCONF
+ RFC -.->|RDKC| CAM
+ RFC --> MTLS
+ RFC --> SERVER
+ RFC --> API
+ API --> FS
+ API --> TR181
+ TR181 --> UTILS
+```
+
+**Class Hierarchy:**
+
+```
+XconfHandler (device identity collection)
+ └── RuntimeFeatureControlProcessor (Xconf query, parse, apply)
+ └── RdkcRuntimeFeatureControlProcessor (camera-specific overrides)
```
+For detailed architecture diagrams, see [documentation/architecture.md](documentation/architecture.md).
+
---
-## Key Workflows
+## Building
-### RFC Fetch and Apply Workflow
+### Prerequisites
-```mermaid
-sequenceDiagram
- participant main as rfc_main.cpp
- participant mgr as RFCManager
- participant rfcp as RuntimeFeatureControlProcessor
- participant xconf as XconfHandler
- participant mtls as mtlsUtils
- participant server as XConf Server
- participant store as /opt/secure/RFC/
-
- main->>mgr: new RFCManager()
- main->>mgr: CheckDeviceIsOnline()
- mgr-->>main: RFCMGR_DEVICE_ONLINE
- main->>mgr: RFCManagerProcessXconfRequest()
- mgr->>rfcp: InitializeRuntimeFeatureControlProcessor()
- rfcp->>rfcp: GetAccountID(), GetRFCPartnerID()
- rfcp->>xconf: initializeXconfHandler()
- xconf->>xconf: Populate device metadata\n(MAC, firmware, model, partner)
- rfcp->>mtls: getMtlscert()
- mtls-->>rfcp: MtlsAuth_t (cert + key paths)
- rfcp->>xconf: ExecuteRequest(FileDwnl_t, MtlsAuth_t)
- xconf->>server: HTTPS GET /featureControl/settings?...
- server-->>xconf: HTTP 200 + JSON payload
- rfcp->>rfcp: ProcessRuntimeFeatureControlReq()
- rfcp->>store: Write rfcVariable.ini / tr181store.ini
- rfcp-->>mgr: SUCCESS / rebootRequired
-```
+- GNU Autotools (`autoconf`, `automake`, `libtool`)
+- C++11 compiler
+- `libcurl`, `libcjson`
+- Platform-specific: `librbus` (RDKB), `libhostif` (STB), `libmfrapi` (RDKC)
-### RFC State Machine
+### Build Commands
-```mermaid
-stateDiagram-v2
- [*] --> Init : daemon start
- Init --> Local : check ConfigSetHash\n(no change needed)
- Init --> Redo : new firmware detected
- Init --> Redo_With_Valid_Data : accountId valid
- Local --> Finish : settings already current
- Redo --> Redo_With_Valid_Data : XConf fetch OK
- Redo --> Finish : fetch failed (offline)
- Redo_With_Valid_Data --> Finish : parameters applied
- Finish --> [*] : cleanup + optional reboot
-```
+```bash
+# Generate build system
+autoreconf -i
----
+# Configure for target platform
+./configure # STB (default)
+./configure --enable-rdkc # RDK Camera
+./configure --enable-rdkb # RDK Broadband
-## Component Descriptions
+# Build
+make
-| Component | Location | Role |
-|-----------|----------|------|
-| `rfc_main.cpp` | `rfcMgr/` | Entry point — forks daemon, manages PID lock, handles SIGTERM |
-| `RFCManager` | `rfcMgr/rfc_manager.cpp` | Orchestrates online-check, IARM init, XConf request cycle |
-| `RuntimeFeatureControlProcessor` | `rfcMgr/rfc_xconf_handler.cpp` | Extends XconfHandler; owns RFC state machine and parameter apply |
-| `XconfHandler` | `rfcMgr/xconf_handler.cpp` | Populates device metadata; executes HTTPS request via libcurl |
-| `mtlsUtils` | `rfcMgr/mtlsUtils.cpp` | Selects dynamic or static mTLS certificate; optionally uses librdkcertselector |
-| `librfcapi` | `rfcapi/rfcapi.cpp` | Public C API for RFC parameter get/set used by all RDK components |
-| `libtr181api` | `tr181api/tr181api.cpp` | Higher-level TR181 API with typed parameters, local store, and defaults |
-| `jsonhandler` | `utils/jsonhandler.cpp` | Parses XConf JSON response payloads |
-| `tr181utils` | `utils/tr181utils.cpp` | TR181 store manipulation utilities |
+# Install
+make install # Installs /usr/bin/rfcMgr and librfcapi
----
+# Unit tests
+./configure --enable-gtestapp
+make check
+```
-## Build Options
+### Build Flags
-| `configure` flag | Effect |
-|-----------------|--------|
+| Option | Description |
+|--------|-------------|
+| `--enable-rdkc` | Enable RDKC camera platform support |
+| `--enable-rdkb` | Enable RDKB broadband platform support |
+| `--enable-gtestapp` | Enable Google Test unit tests |
+| `--enable-rdkcertselector` | Use `librdkcertselector` for mTLS |
+| `--enable-mountutils` | Use `librdkconfig` for configuration |
| `--enable-rfctool=yes` | Build `librfcapi` (default: yes) |
| `--enable-tr181set=yes` | Build `libtr181api` |
-| `--enable-gtestapp=yes` | Build gtest binaries in `rfcMgr/gtest/` |
| `--enable-rdkcertselector=yes` | Enable `librdkcertselector` for dynamic mTLS cert selection |
-| `--enable-mountutils=yes` | Enable `librdkconfig` for config mount utilities |
-| `--enable-rdkb=yes` | Enable RDK-B (broadband) platform adaptations |
-| `--enable-rdkc=yes` | Enable RDK-C (camera) platform adaptations |
| `--enable-iarmbus=yes` | Enable IARM bus integration |
---
+## Configuration
+
+### rfc.properties
+
+Runtime configuration is read from `rfc.properties`:
+
+| Property | Description |
+|----------|-------------|
+| `RFC_CONFIG_SERVER_URL` | Primary Xconf server endpoint |
+| `RFC_CONFIG_SERVER_URL_EU` | EU region Xconf server endpoint |
+| `RFC_RAM_PATH` | Temporary storage path (`/tmp/RFC`) |
+| `TR181_STORE_FILENAME` | Persistent parameter storage file |
+| `RFC_POSTPROCESS` | Post-processing script path |
+| `RFC_SERVICE_LOCK` | Lock file to prevent concurrent runs |
+
+---
+
## Platform Notes
### RDK-V (Video — default)
@@ -214,6 +272,56 @@ stateDiagram-v2
---
+### RDKC Device Files
+
+| File | Purpose |
+|------|---------|
+| `/opt/usr_config/partnerid.txt` | Syndication partner ID |
+| `/opt/usr_config/service_number.txt` | Account ID |
+| `/opt/usr_config/accounthash.txt` | MD5 account hash |
+| `/opt/secure/RFC/tr181store.ini` | Persisted RFC parameters |
+| `/tmp/RFC/.hashValue` | Configuration hash (RAM) |
+| `/tmp/RFC/.timeValue` | Last update timestamp (RAM) |
+
+---
+
+## Usage
+
+```bash
+# Run the RFC manager daemon
+/usr/bin/rfcMgr
+
+# Check if a feature is enabled
+./isFeatureEnabled.sh
+
+# Query RFC settings (legacy shell)
+./getRFC.sh
+```
+
+### rfcapi Library
+
+```c
+#include "rfcapi.h"
+
+// Read a parameter
+RFC_ParamData_t param;
+int ret = getRFCParameter("module", "Device.X_RDK.Feature.Enable", ¶m);
+if (ret == 0) {
+ printf("Value: %s, Type: %d\n", param.value, param.type);
+}
+
+// Check feature status
+if (isRFCEnabled("AccountInfo")) {
+ // Feature is active
+}
+```
+| `librfcapi` | `rfcapi/rfcapi.cpp` | Public C API for RFC parameter get/set used by all RDK components |
+| `libtr181api` | `tr181api/tr181api.cpp` | Higher-level TR181 API with typed parameters, local store, and defaults |
+| `jsonhandler` | `utils/jsonhandler.cpp` | Parses XConf JSON response payloads |
+| `tr181utils` | `utils/tr181utils.cpp` | TR181 store manipulation utilities |
+
+---
+
## Error Codes
| Code | Value | Meaning |
@@ -230,28 +338,59 @@ stateDiagram-v2
## Testing
-### Unit Tests (`rfcMgr/gtest/`)
-
```bash
-# Build and run all unit tests
-sh run_ut.sh
+# Unit tests (L1)
+./run_ut.sh
+
+# L2 integration tests
+./run_l2.sh
+
+# L2 reboot trigger tests
+./run_l2_reboot_trigger.sh
+```
+
+Test coverage is tracked via GitHub Actions workflows:
+- `L1-Test.yaml` — Unit test execution
+- `L2-tests.yml` — Integration test execution
+- `code-coverage.yml` — Coverage reporting
# Individual binaries
./rfcMgr/gtest/rfcMgr_gtest # RFCManager / XConf handler tests
./rfcMgr/gtest/rfcapi_gtest # RFC API get/set tests
./rfcMgr/gtest/tr181api_gtest # TR181 API tests
./rfcMgr/gtest/utils_gtest # JSON handler / TR181 utils tests
-```
-### L2 Functional Tests (`test/functional-tests/`)
+---
-```bash
-sh run_l2.sh # Main L2 test suite (XConf, TR181, feature flags)
-sh run_l2_reboot_trigger.sh # Reboot trigger / unknown-accountId flow
-```
+## Documentation
+
+| Document | Description |
+|----------|-------------|
+| [Architecture](documentation/architecture.md) | Component architecture, class hierarchy, build system |
+| [Sequence Diagrams](documentation/sequence-diagrams.md) | End-to-end execution flows with Mermaid diagrams |
+| [Data Processing Flow](documentation/data-processing-flow.md) | Parameter lifecycle, storage strategies, data transformations |
+| [Changelog](CHANGELOG.md) | Release history and version changes |
+| [Contributing](CONTRIBUTING.md) | How to contribute to this project |
-Results land in `/tmp/rfc_test_report/` as JSON files.
+---
+
+## Contributing
+
+Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on the contribution process, coding standards, and how to submit pull requests.
+
+Before RDK accepts your code, you must sign the [RDK Contributor License Agreement (CLA)](https://wiki.rdkcentral.com/display/DOC/Contributor+License+Agreement).
+
+---
+## License
+
+This project is licensed under the Apache License, Version 2.0 — see the [LICENSE](LICENSE) file for details.
+
+```
+Copyright 2018-2026 RDK Management
+
+Licensed under the Apache License, Version 2.0
+```
---
## See Also
diff --git a/configure.ac b/configure.ac
index 5db15087..2531f383 100644
--- a/configure.ac
+++ b/configure.ac
@@ -158,6 +158,19 @@ AC_ARG_ENABLE([rdkc],
AM_CONDITIONAL([ENABLE_RDKC], [test x$ENABLE_RDKC = xtrue])
+AC_ARG_ENABLE([xcam2],
+ AS_HELP_STRING([--enable-xcam2],[enable xcam2 (default is no)]),
+ [
+ case "${enableval}" in
+ yes) ENABLE_XCAM2=true;;
+ no) AC_MSG_ERROR([XCAM2 is disabled]) ;;
+ *) AC_MSG_ERROR([bad value ${enableval} for --enable-xcam2]) ;;
+ esac
+ ],
+ [echo "xcam2 is disabled"])
+
+AM_CONDITIONAL([ENABLE_XCAM2], [test x$ENABLE_XCAM2 = xtrue])
+
AC_ARG_ENABLE([rdkb],
AS_HELP_STRING([--enable-rdkb],[enable rdkb (default is no)]),
[
diff --git a/docs/architecture.md b/docs/architecture.md
new file mode 100644
index 00000000..cef42023
--- /dev/null
+++ b/docs/architecture.md
@@ -0,0 +1,386 @@
+# Architecture
+
+> Component architecture, class hierarchy, and build system design for the RFC (Remote Feature Control) daemon.
+
+---
+
+## Table of Contents
+
+- [1. High-Level Architecture](#1-high-level-architecture)
+- [2. Component Diagram](#2-component-diagram)
+- [3. Class Hierarchy](#3-class-hierarchy)
+- [4. Build System Architecture](#4-build-system-architecture)
+- [5. Platform Abstraction Strategy](#5-platform-abstraction-strategy)
+- [6. File Responsibilities](#6-file-responsibilities)
+- [7. Dependency Graph](#7-dependency-graph)
+- [8. External Integrations](#8-external-integrations)
+
+---
+
+## 1. High-Level Architecture
+
+The `rfcMgr` daemon is a multi-platform C++ application that replaces the legacy `RFCbase.sh` shell script. It uses a polymorphic class hierarchy with `#ifdef` conditional compilation to support STB, RDKB, and RDKC platforms from a single codebase.
+
+```mermaid
+graph TD
+ subgraph "Entry & Lifecycle"
+ A["rfc_main.cpp
fork() • signal handlers • directory setup"]
+ end
+
+ subgraph "Orchestration"
+ B["RFCManager
Device online check • processor lifecycle
post-processing • cron scheduling"]
+ end
+
+ subgraph "RFC Processing Engine"
+ C["XconfHandler
Device identity collection
MAC • FW • model • partner ID"]
+ D["RuntimeFeatureControlProcessor
Xconf query • JSON parse • param apply
hash/time management • reboot eval"]
+ E["RdkcRuntimeFeatureControl
Processor
Camera URL • RAM hash/time • no-op metadata"]
+ end
+
+ subgraph "Security"
+ F["mtlsUtils
Dynamic XPKI • Static XPKI • cert selector"]
+ end
+
+ subgraph "Public API"
+ G["rfcapi (librfcapi)
getRFCParameter() • setRFCParameter()
isRFCEnabled()"]
+ end
+
+ subgraph "Data Model Layer"
+ H["tr181api / utils
TR-181 access • JSON handler • set utilities"]
+ end
+
+ subgraph "External Systems"
+ I["Xconf Server
HTTP REST API"]
+ J["File System
tr181store.ini • hash/time files"]
+ K["Platform APIs
hostif • rbus • mfrApi"]
+ end
+
+ A --> B
+ B --> D
+ D --> C
+ D -.->|"#ifdef RDKC"| E
+ D --> F
+ D --> I
+ D --> G
+ G --> J
+ G --> H
+ H --> K
+
+ style E fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px
+ style F fill:#fff9c4,stroke:#f9a825,stroke-width:2px
+ style G fill:#bbdefb,stroke:#1565c0,stroke-width:2px
+```
+
+---
+
+## 2. Component Diagram
+
+```mermaid
+graph LR
+ subgraph "rfcMgr Binary"
+ direction TB
+ MAIN[rfc_main]
+ MGR[rfc_manager]
+ XCONF[xconf_handler]
+ RFCX[rfc_xconf_handler]
+ RDKC_X[rdkc_rfc_xconf_handler]
+ COMMON[rfc_common]
+ MTLS[mtlsUtils]
+ IARM[rfc_mgr_iarm]
+ JSON_H[rfc_mgr_json]
+ KEY_H[rfc_mgr_key]
+
+ MAIN --> MGR
+ MGR --> RFCX
+ RFCX --> XCONF
+ RFCX -.-> RDKC_X
+ RFCX --> COMMON
+ RFCX --> MTLS
+ MGR --> IARM
+ RFCX --> JSON_H
+ RFCX --> KEY_H
+ end
+
+ subgraph "librfcapi.so"
+ RFCAPI[rfcapi]
+ end
+
+ subgraph "libtr181api.so"
+ TR181[tr181api]
+ end
+
+ subgraph "libutils"
+ JSONUTIL[jsonhandler]
+ TRSET[trsetutils]
+ TR181U[tr181utils]
+ end
+
+ RFCX --> RFCAPI
+ RFCAPI --> TR181
+ TR181 --> JSONUTIL
+ TR181 --> TRSET
+
+ style RDKC_X fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px
+```
+
+---
+
+## 3. Class Hierarchy
+
+```mermaid
+classDiagram
+ class XconfHandler {
+ #string _estb_mac_address
+ #string _firmware_version
+ #EBuildType _ebuild_type
+ #string _build_type_str
+ #string _model_number
+ #string _ecm_mac_address
+ #string _manufacturer
+ #string _partner_id
+ +initializeXconfHandler() int
+ +ExecuteRequest(FileDownload*, MtlsAuth_t*, int*) int
+ }
+
+ class RuntimeFeatureControlProcessor {
+ #string _accountId
+ #string _experience
+ #string _xconf_server_url
+ #bool _rfcRebootCronNeeded
+ #set~string~ _effectiveImmediateParams
+ +InitializeRuntimeFeatureControlProcessor() int
+ +ProcessRuntimeFeatureControlReq() int
+ +GetAccountID() void
+ +getRfcRebootCronNeeded() bool
+ #CreateXconfHTTPUrl()* stringstream
+ #RetrieveHashAndTimeFromPreviousDataSet()* void
+ #StoreXconfEndpointMetadata()* void
+ #set_RFCProperty(char*, char*, char*) WDMP_STATUS
+ #clearDB() void
+ #updateHashInDB(string) void
+ #updateTimeInDB(string) void
+ }
+
+ class RdkcRuntimeFeatureControlProcessor {
+ -string _accountHash
+ -GetAccountHash() void
+ #CreateXconfHTTPUrl() stringstream
+ #RetrieveHashAndTimeFromPreviousDataSet() void
+ #StoreXconfEndpointMetadata() void
+ }
+
+ class RFCManager {
+ -RuntimeFeatureControlProcessor* _rfcProcessor
+ +CheckDeviceIsOnline() DeviceStatus
+ +RFCManagerProcess() int
+ +RFCManagerProcessXconfRequest() int
+ +RFCManagerPostProcess() void
+ }
+
+ XconfHandler <|-- RuntimeFeatureControlProcessor : inherits
+ RuntimeFeatureControlProcessor <|-- RdkcRuntimeFeatureControlProcessor : inherits
+ RFCManager --> RuntimeFeatureControlProcessor : creates & uses
+
+ note for RdkcRuntimeFeatureControlProcessor "Compiled only with -DRDKC flag.\nOverrides 3 virtual methods for\ncamera-specific behavior."
+```
+
+### Inheritance Design Rationale
+
+The class hierarchy follows the **Template Method Pattern**:
+
+- **`XconfHandler`** — Collects device identity. Platform differences are behind `#ifdef` blocks within methods.
+- **`RuntimeFeatureControlProcessor`** — Implements the full RFC workflow. Declares `virtual` methods for steps that vary by platform.
+- **`RdkcRuntimeFeatureControlProcessor`** — Overrides only 3 methods, keeping the camera delta minimal:
+ - `CreateXconfHTTPUrl()` — Camera-specific URL parameters
+ - `RetrieveHashAndTimeFromPreviousDataSet()` — RAM-file storage
+ - `StoreXconfEndpointMetadata()` — No-op (camera must not persist Xconf metadata)
+
+---
+
+## 4. Build System Architecture
+
+### Configure Options Flow
+
+```mermaid
+flowchart TD
+ A["./configure"] --> B{"--enable-rdkc?"}
+ B -- Yes --> C["AM_CONDITIONAL ENABLE_RDKC = true
-DRDKC added to CPPFLAGS"]
+ B -- No --> D{"--enable-rdkb?"}
+ D -- Yes --> E["AM_CONDITIONAL ENABLE_RDKB = true
-DRDKB_SUPPORT added"]
+ D -- No --> F["Default STB build"]
+
+ C --> G["SUBDIRS = rfcapi rfcMgr"]
+ E --> H["SUBDIRS = rfcMgr"]
+ F --> I["SUBDIRS = rfcapi tr181api utils rfcMgr"]
+
+ G --> J["rfcMgr sources += rdkc_rfc_xconf_handler.cpp
Links: -lrfcapi -ldwnlutil -lfwutils -lcurl"]
+ H --> K["Links: -lrbus"]
+ I --> L["Links: ../rfcapi/.libs/librfcapi.la"]
+
+ style C fill:#c8e6c9,stroke:#2e7d32
+ style G fill:#c8e6c9,stroke:#2e7d32
+ style J fill:#c8e6c9,stroke:#2e7d32
+```
+
+### Build Outputs
+
+| Platform | Subdirectories Built | Binary | Libraries |
+|----------|---------------------|--------|-----------|
+| **STB** | rfcapi, tr181api, utils, rfcMgr | `/usr/bin/rfcMgr` | librfcapi.so, libtr181api.so |
+| **RDKB** | rfcMgr | `/usr/bin/rfcMgr` | *(links external rbus)* |
+| **RDKC** | rfcapi, rfcMgr | `/usr/bin/rfcMgr` | librfcapi.so |
+
+---
+
+## 5. Platform Abstraction Strategy
+
+The codebase uses two complementary strategies:
+
+### Strategy 1: Preprocessor Guards (`#ifdef`)
+
+Used within shared source files for small, inline platform differences:
+
+```
+┌──────────────────────────────────────────────┐
+│ #ifdef RDKC │
+│ // Camera-specific implementation │
+│ #elif defined(RDKB_SUPPORT) │
+│ // Broadband-specific implementation │
+│ #else │
+│ // STB default implementation │
+│ #endif │
+└──────────────────────────────────────────────┘
+```
+
+**Used in:** `rfc_manager.cpp`, `xconf_handler.cpp`, `rfc_xconf_handler.cpp`, `mtlsUtils.cpp`, `rfcapi.cpp`
+
+### Strategy 2: Polymorphic Override
+
+Used for larger behavioral differences via virtual method dispatch:
+
+```mermaid
+flowchart LR
+ A["RFCManager"] --> B{"Platform?"}
+ B -- RDKC --> C["new RdkcRuntimeFeature
ControlProcessor()"]
+ B -- Other --> D["new RuntimeFeature
ControlProcessor()"]
+ C --> E["Virtual dispatch for
CreateXconfHTTPUrl()
RetrieveHashAndTime...
StoreXconfEndpoint..."]
+ D --> E
+```
+
+---
+
+## 6. File Responsibilities
+
+### Core Daemon (`rfcMgr/`)
+
+| File | Responsibility | Key Functions |
+|------|---------------|---------------|
+| `rfc_main.cpp` | Process entry point | `main()`, `cleanup_lock_file()`, `signal_handler()`, `createDirectoryIfNotExists()` |
+| `rfc_manager.h/cpp` | Lifecycle orchestrator | `CheckDeviceIsOnline()`, `RFCManagerProcess()`, `RFCManagerPostProcess()`, `SendEventToMaintenanceManager()` |
+| `xconf_handler.h/cpp` | Device identity | `initializeXconfHandler()`, `ExecuteRequest()` |
+| `rfc_xconf_handler.h/cpp` | Core RFC logic | `InitializeRuntimeFeatureControlProcessor()`, `ProcessRuntimeFeatureControlReq()`, `set_RFCProperty()`, `clearDB()` |
+| `rdkc_rfc_xconf_handler.h/cpp` | Camera overrides | `CreateXconfHTTPUrl()`, `RetrieveHashAndTimeFromPreviousDataSet()`, `StoreXconfEndpointMetadata()` |
+| `mtlsUtils.h/cpp` | Certificate management | `getMtlscert()`, `isStateRedSupported()`, `isInStateRed()` |
+| `rfc_common.h/cpp` | Shared utilities | `read_RFCProperty()`, `getSyseventValue()`, `waitForRfcCompletion()` |
+| `rfc_mgr_iarm.h` | IARM bus integration | Event handler registration constants |
+| `rfc_mgr_json.h` | JSON field names | Feature/parameter key string constants |
+| `rfc_mgr_key.h` | Config keys | TR-181 parameter name constants |
+
+### Public API (`rfcapi/`)
+
+| File | Responsibility | Key Functions |
+|------|---------------|---------------|
+| `rfcapi.h/cpp` | RFC parameter access | `getRFCParameter()`, `setRFCParameter()`, `isRFCEnabled()`, `getRFCErrorString()` |
+
+### Data Model (`tr181api/`, `utils/`)
+
+| File | Responsibility |
+|------|---------------|
+| `tr181api.h/cpp` | TR-181 data model read/write |
+| `jsonhandler.h/cpp` | JSON parse/build helpers |
+| `trsetutils.h/cpp` | TR-181 set operation utilities |
+| `tr181utils.cpp` | TR-181 access layer |
+
+---
+
+## 7. Dependency Graph
+
+```mermaid
+graph TD
+ subgraph "System Libraries"
+ CURL[libcurl]
+ CJSON[libcjson]
+ PTHREAD[libpthread]
+ end
+
+ subgraph "RDK Platform Libraries"
+ HOSTIF[libhostif
STB only]
+ RBUS[librbus
RDKB only]
+ MFRAPI[mfrApi_test
RDKC only]
+ CERTSELECTOR[librdkcertselector
optional]
+ DWNLUTIL[libdwnlutil
RDKC only]
+ FWUTILS[libfwutils
RDKC only]
+ SECWRAP[libsecure_wrapper]
+ end
+
+ subgraph "RFC Components"
+ RFCMGR[rfcMgr]
+ RFCAPI[librfcapi]
+ TR181API[libtr181api]
+ UTILS_LIB[utils]
+ end
+
+ RFCMGR --> CURL
+ RFCMGR --> CJSON
+ RFCMGR --> PTHREAD
+ RFCMGR --> SECWRAP
+ RFCMGR --> RFCAPI
+ RFCMGR -.->|STB| HOSTIF
+ RFCMGR -.->|RDKB| RBUS
+ RFCMGR -.->|RDKC| DWNLUTIL
+ RFCMGR -.->|RDKC| FWUTILS
+ RFCMGR -.->|optional| CERTSELECTOR
+ RFCAPI --> TR181API
+ TR181API --> UTILS_LIB
+ UTILS_LIB --> CJSON
+
+ style RFCMGR fill:#bbdefb,stroke:#1565c0,stroke-width:2px
+ style RFCAPI fill:#bbdefb,stroke:#1565c0,stroke-width:2px
+```
+
+---
+
+## 8. External Integrations
+
+```mermaid
+graph LR
+ subgraph "rfcMgr"
+ RFC[RFC Daemon]
+ end
+
+ RFC -->|"HTTP GET + mTLS"| XCONF["Xconf Server
featureControl/getSettings"]
+ RFC -->|"read/write"| INI["tr181store.ini
RFC parameters"]
+ RFC -->|"read"| PROPS["rfc.properties
Server URLs & paths"]
+ RFC -->|"read"| DEVICE["Device Identity Files
partnerid.txt
service_number.txt
accounthash.txt"]
+ RFC -->|"execute"| MFRAPI["mfrApi_test
MAC address (RDKC)"]
+ RFC -->|"register events"| IARM["IARM Bus
Maintenance events"]
+ RFC -->|"trigger"| CRON["RfcRebootCronschedule.sh
Reboot scheduling"]
+ RFC -->|"notify"| TELEMETRY["telemetry2_0_client
Feature status (non-RDKC)"]
+ RFC -->|"read/write"| RAMFILES["/tmp/RFC/
.hashValue • .timeValue"]
+
+ style RFC fill:#bbdefb,stroke:#1565c0,stroke-width:2px
+ style XCONF fill:#fff9c4,stroke:#f9a825,stroke-width:2px
+```
+
+### Integration Points Summary
+
+| Integration | Protocol/Method | Platform |
+|------------|-----------------|----------|
+| Xconf Server | HTTP GET + mTLS (libcurl) | All |
+| tr181store.ini | File I/O (flat key=value) | RDKC |
+| TR-181 Data Model | hostif / rbus | STB / RDKB |
+| IARM Bus | Event registration | STB |
+| mfrApi_test | popen() command | RDKC |
+| Maintenance Manager | IARM event | STB |
+| Reboot Cron | v_secure_system() shell exec | RDKC |
+| Telemetry | v_secure_system() call | STB / RDKB |
diff --git a/docs/data-processing-flow.md b/docs/data-processing-flow.md
new file mode 100644
index 00000000..ba880d81
--- /dev/null
+++ b/docs/data-processing-flow.md
@@ -0,0 +1,584 @@
+# Data Processing Flow
+
+> Parameter lifecycle, storage strategies, data transformations, and platform-specific data paths for the RFC system.
+
+---
+
+## Table of Contents
+
+- [1. End-to-End Data Flow Overview](#1-end-to-end-data-flow-overview)
+- [2. Xconf Request Data Pipeline](#2-xconf-request-data-pipeline)
+- [3. Xconf Response Processing Pipeline](#3-xconf-response-processing-pipeline)
+- [4. Parameter Storage Architecture](#4-parameter-storage-architecture)
+- [5. Hash & Timestamp Management](#5-hash--timestamp-management)
+- [6. RFC State Machine](#6-rfc-state-machine)
+- [7. ClearDB Data Flow](#7-cleardb-data-flow)
+- [8. Platform Data Source Matrix](#8-platform-data-source-matrix)
+- [9. Configuration File Formats](#9-configuration-file-formats)
+- [10. Error Handling Flow](#10-error-handling-flow)
+
+---
+
+## 1. End-to-End Data Flow Overview
+
+This diagram shows how data flows through the RFC system from external sources to persistent storage.
+
+```mermaid
+flowchart TD
+ subgraph "Input Sources"
+ DEV["Device Identity
MAC • FW • Model
Partner • Account"]
+ CFG["rfc.properties
Server URLs • Paths"]
+ HASH_IN["Previous Hash/Time
.hashValue • .timeValue"]
+ end
+
+ subgraph "Processing Engine"
+ URL["URL Construction
Query string assembly"]
+ MTLS["mTLS Certificate
Resolution"]
+ HTTP["HTTP GET Request
libcurl + mTLS"]
+ PARSE["JSON Response
Parser"]
+ EVAL["Change Detection
Hash comparison"]
+ APPLY["Parameter
Application"]
+ REBOOT["Reboot
Evaluation"]
+ end
+
+ subgraph "Output Storage"
+ PARAMS["RFC Parameters
tr181store.ini (RDKC)
TR-181 DB (others)"]
+ HASH_OUT["Updated Hash/Time
/tmp/RFC/.hashValue
/tmp/RFC/.timeValue"]
+ CRON["Cron Schedule
Periodic re-run"]
+ REBOOT_OUT["Reboot Trigger
RfcRebootCronschedule.sh"]
+ end
+
+ subgraph "External"
+ XCONF["Xconf Server"]
+ end
+
+ DEV --> URL
+ CFG --> URL
+ HASH_IN --> EVAL
+ URL --> HTTP
+ MTLS --> HTTP
+ HTTP --> XCONF
+ XCONF --> HTTP
+ HTTP --> PARSE
+ PARSE --> EVAL
+ EVAL -->|"Config changed"| APPLY
+ EVAL -->|"No change"| HASH_OUT
+ APPLY --> PARAMS
+ APPLY --> REBOOT
+ REBOOT -->|"Reboot needed"| REBOOT_OUT
+ PARSE --> HASH_OUT
+ APPLY --> CRON
+
+ style XCONF fill:#fff9c4,stroke:#f9a825,stroke-width:2px
+ style PARAMS fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px
+ style REBOOT_OUT fill:#ffcdd2,stroke:#c62828,stroke-width:2px
+```
+
+---
+
+## 2. Xconf Request Data Pipeline
+
+How device data is collected, transformed, and assembled into the Xconf query URL.
+
+```mermaid
+flowchart LR
+ subgraph "Raw Data Sources (RDKC)"
+ A1["mfrApi_test 3 9
→ raw MAC output"]
+ A2["GetFirmwareVersion()
→ version string"]
+ A3["GetBuildType()
→ enum"]
+ A4["GetModelNum()
→ model string"]
+ A5["/opt/usr_config/
partnerid.txt"]
+ A6["/opt/usr_config/
service_number.txt"]
+ A7["/opt/usr_config/
accounthash.txt"]
+ A8["rfc.properties
RFC_CONFIG_SERVER_URL"]
+ end
+
+ subgraph "Transform"
+ T1["Parse popen() output
Extract MAC string"]
+ T2["Map enum to string
dev/vbn/prod"]
+ T3["Read file, trim
whitespace/newline"]
+ T4["URL-encode values"]
+ end
+
+ subgraph "URL Assembly"
+ URL["https://xconf.server/
featureControl/getSettings?
estbMacAddress=MAC
&firmwareVersion=FW
&env=BUILD_TYPE
&model=MODEL
&accountHash=HASH
&partnerId=PID
&accountId=AID
&experience=EXP
&version=2"]
+ end
+
+ A1 --> T1 --> URL
+ A2 --> URL
+ A3 --> T2 --> URL
+ A4 --> URL
+ A5 --> T3 --> URL
+ A6 --> T3
+ A7 --> T3
+ A8 --> URL
+ T4 --> URL
+
+ style URL fill:#bbdefb,stroke:#1565c0,stroke-width:2px
+```
+
+### URL Parameter Comparison
+
+```mermaid
+flowchart TB
+ subgraph "RDKC Camera URL"
+ C1[estbMacAddress]
+ C2[firmwareVersion]
+ C3[env]
+ C4[model]
+ C5[accountHash]
+ C6[partnerId]
+ C7[accountId]
+ C8[experience]
+ C9["version=2"]
+ end
+
+ subgraph "STB/RDKB URL"
+ S1[estbMacAddress]
+ S2[firmwareVersion]
+ S3[env]
+ S4[model]
+ S5[ecmMacAddress]
+ S6[controllerId]
+ S7[channelMapId]
+ S8[vodId]
+ S9[partnerId]
+ S10[accountId]
+ S11[experience]
+ S12[osclass]
+ S13[manufacturer]
+ S14["version=2"]
+ end
+
+ style C5 fill:#c8e6c9,stroke:#2e7d32,stroke-width:2px
+ style S5 fill:#ffcdd2,stroke:#c62828
+ style S6 fill:#ffcdd2,stroke:#c62828
+ style S7 fill:#ffcdd2,stroke:#c62828
+ style S8 fill:#ffcdd2,stroke:#c62828
+ style S12 fill:#ffcdd2,stroke:#c62828
+ style S13 fill:#ffcdd2,stroke:#c62828
+```
+
+> **Green** = RDKC-only field. **Red** = Fields NOT present in RDKC URL.
+
+---
+
+## 3. Xconf Response Processing Pipeline
+
+```mermaid
+flowchart TD
+ A["HTTP Response Body
(JSON)"] --> B["cJSON_Parse()"]
+ B --> C{"Parse successful?"}
+ C -- No --> ERR["Log error, return failure"]
+ C -- Yes --> D["Extract featureControl object"]
+
+ D --> E["Iterate features[] array"]
+
+ E --> F["For each feature:"]
+ F --> G["Read feature name"]
+ F --> H["Read effectiveImmediate flag"]
+ F --> I["Read configData[] array"]
+
+ I --> J["For each config param:"]
+ J --> K["Extract key (TR-181 name)"]
+ J --> L["Extract value"]
+ J --> M["Extract dataType"]
+
+ subgraph "effectiveImmediate Tracking (RDKC)"
+ H -->|true| N["Add all param keys
to _effectiveImmediateParams set"]
+ end
+
+ subgraph "Parameter Application"
+ K --> O["set_RFCProperty(name, key, value)"]
+ L --> O
+ M --> O
+ end
+
+ subgraph "Hash Computation"
+ O --> P["Compute hash of
all applied parameters"]
+ P --> Q{"Hash different
from stored?"}
+ Q -- Yes --> R["Configuration changed
Update hash & time"]
+ Q -- No --> S["No changes detected
Skip update"]
+ end
+
+ style A fill:#fff9c4,stroke:#f9a825
+ style O fill:#c8e6c9,stroke:#2e7d32
+ style R fill:#bbdefb,stroke:#1565c0
+```
+
+### JSON Response Structure
+
+```
+{
+ "featureControl": {
+ "features": [
+ {
+ "name": "AccountInfo",
+ "effectiveImmediate": true,
+ "enable": true,
+ "configData": [
+ {
+ "key": "Device.X_RDK.AccountID",
+ "value": "5789171196032993066",
+ "dataType": 0
+ },
+ {
+ "key": "Device.X_RDK.MD5AccountHash",
+ "value": "1EMvt8zMMd8muKCBJRnp1z6nZTgsBJ1VhL",
+ "dataType": 0
+ }
+ ]
+ }
+ ]
+ }
+}
+```
+
+---
+
+## 4. Parameter Storage Architecture
+
+### Write Path
+
+```mermaid
+flowchart TD
+ A["set_RFCProperty(featureName, key, value)"]
+
+ A --> B{"Platform?"}
+
+ B -- "RDKC" --> C["Read /opt/secure/RFC/tr181store.ini"]
+ C --> D["Parse into lines[]"]
+ D --> E{"Key exists?"}
+ E -- Yes --> F["Replace: line = key=value"]
+ E -- No --> G["Append: lines.push_back(key=value)"]
+ F --> H["Write all lines to tr181store.ini"]
+ G --> H
+ H --> I["Return WDMP_SUCCESS"]
+
+ B -- "RDKB" --> J["rbus_open(handle)"]
+ J --> K["rbus_set(handle, key, value)"]
+ K --> L["rbus_close(handle)"]
+ L --> I
+
+ B -- "STB" --> M["setRFCParameter(key, value, type)
via hostif/WDMP"]
+ M --> I
+
+ style C fill:#c8e6c9,stroke:#2e7d32
+ style H fill:#c8e6c9,stroke:#2e7d32
+```
+
+### Read Path (rfcapi)
+
+```mermaid
+flowchart TD
+ A["getRFCParameter(name, key, ¶m)"]
+
+ A --> B{"Platform / Backend?"}
+
+ B -- "Flat-file (RDKC)" --> C["Open tr181store.ini"]
+ C --> D["Scan for key= prefix"]
+ D --> E{"Found?"}
+ E -- Yes --> F["Extract value after '='"]
+ F --> G["param.value = value
param.type = STRING"]
+ E -- No --> H["Return WDMP_ERR_VALUE_IS_EMPTY"]
+
+ B -- "WDMP (STB)" --> I["Build WDMP request"]
+ I --> J["Send to hostif backend"]
+ J --> K["Parse WDMP response"]
+ K --> G
+
+ B -- "TR-181 int (RDKB)" --> L["rbus_get(key)"]
+ L --> M["Parse rbus response"]
+ M --> G
+
+ G --> N["Return 0 (success)"]
+
+ style C fill:#c8e6c9,stroke:#2e7d32
+```
+
+### File Format: tr181store.ini
+
+```
+Device.X_RDK.Feature.AccountInfo.Enable=true
+Device.X_RDK.AccountID=5789171196032993066
+Device.X_RDK.MD5AccountHash=1EMvt8zMMd8muKCBJRnp1z6nZTgsBJ1VhL
+Device.X_RDK.Feature.VideoAnalytics.Enable=true
+Device.X_RDK.Feature.AmbientListening.Enable=false
+```
+
+---
+
+## 5. Hash & Timestamp Management
+
+```mermaid
+flowchart TD
+ subgraph "Read Phase"
+ R1["GetStoredHashAndTime()"]
+ R1 --> R2{"RDKC?"}
+ R2 -- Yes --> R3["Always call
RetrieveHashAndTime
FromPreviousDataSet()"]
+ R2 -- No --> R4["Check XconfSelector
slot first"]
+ R4 --> R5{"Slot matches?"}
+ R5 -- Yes --> R6["Read from that slot"]
+ R5 -- No --> R3
+
+ R3 --> R7{"RDKC override"}
+ R7 --> R8["Read /tmp/RFC/.hashValue
Default: UPGRADE_HASH"]
+ R7 --> R9["Read /tmp/RFC/.timeValue
Default: 0"]
+ end
+
+ subgraph "Compare Phase"
+ CP1["New hash from
current config"] --> CP2{"Hash matches
stored hash?"}
+ CP2 -- Yes --> CP3["Config unchanged
Skip parameter apply"]
+ CP2 -- No --> CP4["Config changed
Proceed with apply"]
+
+ CP5["First request?
(FW changed or
no prior hash)"] --> CP6{"Is first?"}
+ CP6 -- Yes --> CP4
+ CP6 -- No --> CP2
+ end
+
+ subgraph "Write Phase"
+ W1["updateHashInDB(hash)"]
+ W1 --> W2{"RDKB or RDKC?"}
+ W2 -- Yes --> W3["Write /tmp/RFC/.hashValue"]
+ W2 -- No --> W4["set_RFCProperty(ConfigSetHash)"]
+
+ W5["updateTimeInDB(time)"]
+ W5 --> W6{"RDKB or RDKC?"}
+ W6 -- Yes --> W7["Write /tmp/RFC/.timeValue"]
+ W6 -- No --> W8["set_RFCProperty(ConfigSetTime)"]
+ end
+
+ style R8 fill:#c8e6c9,stroke:#2e7d32
+ style R9 fill:#c8e6c9,stroke:#2e7d32
+ style W3 fill:#c8e6c9,stroke:#2e7d32
+ style W7 fill:#c8e6c9,stroke:#2e7d32
+```
+
+### Storage Location Matrix
+
+| Data | STB | RDKB | RDKC |
+|------|-----|------|------|
+| **Config Hash** | TR-181 DB (`ConfigSetHash`) | `/tmp/RFC/.hashValue` (RAM) | `/tmp/RFC/.hashValue` (RAM) |
+| **Config Time** | TR-181 DB (`ConfigSetTime`) | `/tmp/RFC/.timeValue` (RAM) | `/tmp/RFC/.timeValue` (RAM) |
+| **Xconf URL** | TR-181 DB (`XconfUrl`) | TR-181 DB | **Not stored** (no-op) |
+| **Xconf Selector** | TR-181 DB (`XconfSelector`) | TR-181 DB | **Not stored** (no-op) |
+
+> **Note:** RDKC uses RAM files that do NOT survive reboot. This means every boot is treated as a fresh request, which is intentional for camera devices.
+
+---
+
+## 6. RFC State Machine
+
+```mermaid
+stateDiagram-v2
+ [*] --> Init : ProcessRuntimeFeatureControlReq()
+
+ Init --> CheckLocal : Load rfc.properties
+
+ CheckLocal --> LocalOverride : Local RFC file exists
+ CheckLocal --> Redo : No local override
+
+ LocalOverride --> Finish : Apply local config
+
+ Redo --> BuildURL : CreateXconfHTTPUrl()
+ BuildURL --> AcquireCert : getMtlscert()
+ AcquireCert --> HttpRequest : ExecuteRequest()
+
+ HttpRequest --> ParseResponse : HTTP 200
+ HttpRequest --> Retry : HTTP error
+
+ Retry --> Redo : Retry with backoff
+ Retry --> Finish : Max retries exceeded
+
+ ParseResponse --> CompareHash : ProcessJsonResponse()
+
+ CompareHash --> ApplyParams : Hash changed / first request
+ CompareHash --> Finish : Hash unchanged
+
+ ApplyParams --> ClearDB : clearDB()
+ ClearDB --> SetParams : set_RFCProperty() loop
+ SetParams --> EvalReboot : Check effectiveImmediate [RDKC]
+ EvalReboot --> UpdateHash : updateHashInDB()
+ UpdateHash --> UpdateTime : updateTimeInDB()
+ UpdateTime --> StoreMetadata : StoreXconfEndpointMetadata()
+ StoreMetadata --> NotifyTelemetry
+
+ NotifyTelemetry --> Finish : [RDKC: skip telemetry]
+
+ Finish --> [*]
+
+ note right of Init
+ RfcState enum:
+ Init, Local, Redo,
+ Redo_With_Valid_Data,
+ Finish
+ end note
+
+ note right of ClearDB
+ RDKC: std::remove(tr181store.ini)
+ Others: TR-181 ClearDB parameter
+ end note
+```
+
+---
+
+## 7. ClearDB Data Flow
+
+```mermaid
+flowchart TD
+ A["clearDB() called"] --> B{"Platform?"}
+
+ B -- "RDKC" --> C["std::remove(
/opt/secure/RFC/tr181store.ini)"]
+ C --> D["rfcStashRetrieveParams()"]
+ D --> E["Restore stashed AccountID
and other identity params"]
+
+ B -- "STB / RDKB" --> F["Create empty tr181store.ini"]
+ F --> G["set_RFCProperty(ClearDB, true)"]
+ G --> H["set_RFCProperty(BootstrapClearDB, true)"]
+ H --> I["set_RFCProperty(ConfigChangeTime, timestamp)"]
+
+ I --> J["clearDBEnd()"]
+ J --> K{"RDKC or RDKB?"}
+ K -- Yes --> L["SKIP clearDBEnd()"]
+ K -- No --> M["set_RFCProperty(ClearDBEnd, true)"]
+ M --> N["set_RFCProperty(BootstrapClearDBEnd, true)"]
+ N --> O["set_RFCProperty(ReloadCache, true)"]
+
+ style C fill:#c8e6c9,stroke:#2e7d32
+ style L fill:#c8e6c9,stroke:#2e7d32
+```
+
+---
+
+## 8. Platform Data Source Matrix
+
+### Device Identity
+
+| Data Field | STB Source | RDKB Source | RDKC Source |
+|------------|-----------|-------------|-------------|
+| MAC Address | `GetEstbMac()` → `/tmp/.estb_mac` | `getErouterMac()` | `popen("mfrApi_test 3 9")` |
+| Firmware Version | `GetFirmwareVersion()` | `GetFirmwareVersion()` | `GetFirmwareVersion()` |
+| Build Type | `GetBuildType()` | `GetBuildType()` | `GetBuildType()` |
+| Model Number | `GetModelNum()` | `GetModelNum()` | `GetModelNum()` |
+| Manufacturer | `GetMFRName()` | `GetMFRName()` | **Skipped** |
+| Partner ID | `GetPartnerId()` → `/opt/partnerid` | `GetPartnerId()` | `fopen("/opt/usr_config/partnerid.txt")` |
+| Account ID | `read_RFCProperty()` (TR-181) | `read_RFCProperty()` (rbus) | `ifstream("/opt/usr_config/service_number.txt")` |
+| Account Hash | N/A | N/A | `ifstream("/opt/usr_config/accounthash.txt")` |
+| ECM MAC | N/A | `geteCMMac()` | N/A |
+
+### Parameter Storage
+
+| Operation | STB | RDKB | RDKC |
+|-----------|-----|------|------|
+| **Write** | `setRFCParameter()` via hostif | `rbus_set()` | Write to `tr181store.ini` |
+| **Read** | `getRFCParameter()` via WDMP | `rbus_get()` | Scan `tr181store.ini` |
+| **Clear** | TR-181 ClearDB params | TR-181 ClearDB params | `std::remove(tr181store.ini)` |
+
+### mTLS Certificate
+
+| Strategy | STB | RDKB | RDKC |
+|----------|-----|------|------|
+| **Primary** | `librdkcertselector` | `librdkcertselector` | Dynamic XPKI (`/opt/certs/devicecert_1.pk12`) |
+| **Fallback** | Cert selector retry | Cert selector retry | Static XPKI (`/etc/ssl/certs/staticXpkiCrt.pk12`) |
+| **Last resort** | Fail | Fail | Proceed without mTLS |
+
+### Reboot Mechanism
+
+| Aspect | STB | RDKB | RDKC |
+|--------|-----|------|------|
+| **Trigger** | MaintenanceManager | MaintenanceManager | `RfcRebootCronschedule.sh` |
+| **Conditions** | `effectiveImmediate` flag | `effectiveImmediate` flag | `effectiveImmediate` + provisioned + not identity param |
+| **Notification** | IARM event | IARM event | Shell script (background) |
+
+---
+
+## 9. Configuration File Formats
+
+### rfc.properties
+
+```properties
+# Server endpoints
+RFC_CONFIG_SERVER_URL=https://xconf.example.com/featureControl/getSettings
+RFC_CONFIG_SERVER_URL_EU=https://xconf-eu.example.com/featureControl/getSettings
+
+# Path configuration
+export RFC_RAM_PATH="/tmp/RFC"
+TR181_STORE_FILENAME="/opt/secure/RFC/tr181store.ini"
+RFC_VAR_FILENAME="/opt/secure/RFC/rfcVariable.ini"
+BS_STORE_FILENAME="/opt/secure/RFC/bootstrap.ini"
+
+# Process management
+RFC_SERVICE_LOCK="/tmp/.rfcServiceLock"
+RFC_WRITE_LOCK="/tmp/.rfcWriteLock"
+
+# Tools & scripts
+RFC_WHITELIST_TOOL="rfctool"
+RFC_POSTPROCESS="/lib/rdk/RFCpostprocess.sh"
+```
+
+### tr181store.ini (RFC Parameters)
+
+```ini
+# Format: TR-181_parameter_name=value
+Device.X_RDK.Feature.AccountInfo.Enable=true
+Device.X_RDK.AccountID=5789171196032993066
+Device.X_RDK.MD5AccountHash=1EMvt8zMMd8muKCBJRnp1z6nZTgsBJ1VhL
+Device.X_RDK.Feature.VideoAnalytics.Enable=true
+```
+
+### .hashValue / .timeValue (RAM files)
+
+```
+# /tmp/RFC/.hashValue
+a3f2b8c1d4e5f6a7b8c9d0e1f2a3b4c5
+
+# /tmp/RFC/.timeValue
+1712937600
+```
+
+---
+
+## 10. Error Handling Flow
+
+```mermaid
+flowchart TD
+ A["rfcMgr starts"] --> B{"Lock file exists?"}
+ B -- Yes --> C["Log: Already running
Exit immediately"]
+ B -- No --> D["Create lock file"]
+
+ D --> E{"Network available?"}
+ E -- No --> F["Poll every 10s
(RDKC: getifaddrs loop)"]
+ F --> E
+ E -- Yes --> G["Proceed with RFC"]
+
+ G --> H{"Xconf URL valid?"}
+ H -- No --> I["Log error
Return failure"]
+ H -- Yes --> J["HTTP Request"]
+
+ J --> K{"HTTP success?"}
+ K -- No --> L{"Retry count < max?"}
+ L -- Yes --> M["Backoff & retry"]
+ M --> J
+ L -- No --> N["Log: Max retries
Record error state"]
+ K -- Yes --> O["Parse JSON"]
+
+ O --> P{"JSON valid?"}
+ P -- No --> Q["Log parse error
Return failure"]
+ P -- Yes --> R["Apply parameters"]
+
+ R --> S{"Write error?"}
+ S -- Yes --> T["Log write error
Continue with next param"]
+ S -- No --> U["Parameter applied"]
+
+ U --> V["Cleanup & exit"]
+ N --> V
+ I --> V
+
+ V --> W["Remove lock file"]
+
+ style C fill:#ffcdd2,stroke:#c62828
+ style N fill:#ffcdd2,stroke:#c62828
+ style Q fill:#ffcdd2,stroke:#c62828
+ style T fill:#fff9c4,stroke:#f9a825
+ style U fill:#c8e6c9,stroke:#2e7d32
+```
diff --git a/docs/sequence-diagrams.md b/docs/sequence-diagrams.md
new file mode 100644
index 00000000..397fe084
--- /dev/null
+++ b/docs/sequence-diagrams.md
@@ -0,0 +1,482 @@
+# Sequence Diagrams
+
+> End-to-end execution flows for the RFC daemon across all operational phases.
+
+---
+
+## Table of Contents
+
+- [1. Complete Startup to Shutdown](#1-complete-startup-to-shutdown)
+- [2. Device Online Detection](#2-device-online-detection)
+- [3. Device Identity Collection](#3-device-identity-collection)
+- [4. Xconf Query & Response Processing](#4-xconf-query--response-processing)
+- [5. mTLS Certificate Acquisition](#5-mtls-certificate-acquisition)
+- [6. Parameter Application](#6-parameter-application)
+- [7. Reboot Evaluation & Scheduling](#7-reboot-evaluation--scheduling)
+- [8. Post-Processing & Cleanup](#8-post-processing--cleanup)
+
+---
+
+## 1. Complete Startup to Shutdown
+
+The full lifecycle of a single `rfcMgr` invocation from process start to exit.
+
+```mermaid
+sequenceDiagram
+ participant OS as Operating System
+ participant Main as rfc_main.cpp
+ participant RFCMgr as RFCManager
+ participant Proc as RuntimeFeatureControl
Processor
+ participant Xconf as Xconf Server
+ participant FS as File System
+
+ Note over OS,FS: Phase 1 — Process Initialization
+ OS->>Main: exec /usr/bin/rfcMgr
+ Main->>Main: fork() — daemonize
+ Main->>Main: atexit(cleanup_lock_file)
+ Main->>Main: signal(SIGINT, signal_handler)
+ Main->>Main: signal(SIGTERM, signal_handler)
+ Main->>RFCMgr: new RFCManager()
+ Main->>FS: createDirectoryIfNotExists("/opt/secure/RFC")
+ Main->>FS: createDirectoryIfNotExists("/tmp/RFC")
+ Main->>FS: Create lock file /tmp/.rfcServiceLock
+
+ Note over OS,FS: Phase 2 — Network Readiness
+ Main->>RFCMgr: CheckDeviceIsOnline()
+ loop Until network available
+ RFCMgr->>RFCMgr: Poll network interfaces
+ RFCMgr->>RFCMgr: sleep(10)
+ end
+ RFCMgr-->>Main: RFCMGR_DEVICE_ONLINE
+
+ Note over OS,FS: Phase 3 — RFC Processing
+ Main->>RFCMgr: RFCManagerProcess()
+ RFCMgr->>RFCMgr: sleep(120) [RDKC only]
+ RFCMgr->>Proc: new Processor() [platform-specific]
+ RFCMgr->>Proc: InitializeRuntimeFeatureControlProcessor()
+ RFCMgr->>Proc: ProcessRuntimeFeatureControlReq()
+ Proc->>Xconf: HTTP GET + mTLS
+ Xconf-->>Proc: HTTP 200 + JSON
+ Proc->>FS: Apply parameters (set_RFCProperty)
+ Proc->>FS: Update hash & timestamp
+ Proc-->>RFCMgr: SUCCESS
+
+ Note over OS,FS: Phase 4 — Post-Processing & Exit
+ RFCMgr->>RFCMgr: Evaluate reboot need
+ RFCMgr->>RFCMgr: RFCManagerPostProcess()
+ RFCMgr-->>Main: Return
+ Main->>FS: Remove lock file
+ Main->>OS: exit(0)
+```
+
+---
+
+## 2. Device Online Detection
+
+### RDKC Camera Path
+
+```mermaid
+sequenceDiagram
+ participant MGR as RFCManager
+ participant NET as Network Stack
+ participant SYS as System (getifaddrs)
+
+ MGR->>MGR: CheckDeviceIsOnline()
+
+ loop Poll until IP acquired
+ MGR->>SYS: getifaddrs(&ifaddr)
+ SYS-->>MGR: Linked list of interfaces
+
+ loop For each interface
+ MGR->>MGR: Skip loopback (lo)
+ MGR->>MGR: Check AF_INET or AF_INET6
+
+ alt AF_INET (IPv4)
+ MGR->>MGR: inet_ntop() → IP string
+ alt Is valid non-link-local IP
+ MGR->>MGR: Log "IPv4: "
+ MGR-->>MGR: break — IP found
+ end
+ else AF_INET6
+ MGR->>MGR: inet_ntop() → IP string
+ alt Is valid non-link-local IP
+ MGR->>MGR: Log "IPv6: "
+ MGR-->>MGR: break — IP found
+ end
+ end
+ end
+
+ alt No valid IP found
+ MGR->>SYS: freeifaddrs(ifaddr)
+ MGR->>MGR: sleep(10)
+ else Valid IP found
+ MGR->>SYS: freeifaddrs(ifaddr)
+ MGR-->>MGR: Return RFCMGR_DEVICE_ONLINE
+ end
+ end
+```
+
+### Platform Comparison
+
+```mermaid
+sequenceDiagram
+ participant MGR as RFCManager
+
+ alt RDKC Camera
+ MGR->>MGR: getifaddrs() loop
Every 10s until non-loopback IP found
+ else RDKB Broadband
+ MGR->>MGR: CheckIPConnectivity()
via dmcli eRouter query
+ MGR->>MGR: CheckIProuteConnectivity()
via ip route get
+ MGR->>MGR: isDnsResolve()
via nslookup
+ else STB Set-Top Box
+ MGR->>MGR: Check /tmp/route_available exists
+ MGR->>MGR: Check /etc/resolv.dnsmasq exists
+ end
+```
+
+---
+
+## 3. Device Identity Collection
+
+```mermaid
+sequenceDiagram
+ participant Init as InitializeRuntime
FeatureControlProcessor
+ participant XH as XconfHandler::
initializeXconfHandler()
+ participant Platform as Platform APIs
+ participant Files as Device Files
+
+ Init->>Init: Skip GetBootstrapXconfUrl() [RDKC]
+
+ Init->>XH: initializeXconfHandler()
+
+ rect rgb(200, 230, 255)
+ Note over XH,Platform: MAC Address
+ alt STB
+ XH->>Platform: GetEstbMac() → /tmp/.estb_mac
+ else RDKB
+ XH->>Platform: getErouterMac()
+ else RDKC
+ XH->>Platform: popen("mfrApi_test 3 9")
+ Platform-->>XH: "AA:BB:CC:DD:EE:FF"
+ end
+ Note over XH: _estb_mac_address = result
+ end
+
+ rect rgb(255, 243, 200)
+ Note over XH,Platform: Common Fields (all platforms)
+ XH->>Platform: GetFirmwareVersion()
+ Platform-->>XH: e.g. "XHC1_2.0.1"
+ XH->>Platform: GetBuildType()
+ Platform-->>XH: eDEV / eVBN / ePROD
+ XH->>Platform: GetModelNum()
+ Platform-->>XH: e.g. "XHC1"
+ end
+
+ rect rgb(200, 230, 255)
+ Note over XH,Files: Manufacturer (not RDKC)
+ alt STB / RDKB
+ XH->>Platform: GetMFRName()
+ else RDKC
+ Note over XH: SKIP — not used in camera URL
+ end
+ end
+
+ rect rgb(200, 230, 255)
+ Note over XH,Files: Partner ID
+ alt STB / RDKB
+ XH->>Platform: GetPartnerId() → /opt/partnerid
+ else RDKC
+ XH->>Files: fopen("/opt/usr_config/partnerid.txt")
+ Files-->>XH: "Comcast"
+ end
+ Note over XH: _partner_id = result
+ end
+
+ XH-->>Init: return 0
+
+ rect rgb(220, 255, 220)
+ Note over Init,Files: Account ID
+ alt STB / RDKB
+ Init->>Init: read_RFCProperty() from TR-181 DB
+ else RDKC
+ Init->>Files: ifstream("/opt/usr_config/service_number.txt")
+ Files-->>Init: "5789171196032993066"
+ end
+ Note over Init: _accountId = result
+ end
+
+ rect rgb(220, 255, 220)
+ Note over Init,Files: Account Hash (RDKC only)
+ Init->>Files: ifstream("/opt/usr_config/accounthash.txt")
+ Files-->>Init: "1EMvt8zMMd8muKCBJRnp1z6nZTgsBJ1VhL"
+ Note over Init: _accountHash = result
+ end
+```
+
+---
+
+## 4. Xconf Query & Response Processing
+
+```mermaid
+sequenceDiagram
+ participant Proc as RuntimeFeatureControl
Processor
+ participant Hash as Hash/Time Store
+ participant URL as URL Builder
+ participant mTLS as mtlsUtils
+ participant HTTP as libcurl
+ participant Xconf as Xconf Server
+ participant JSON as JSON Parser
+ participant Store as Parameter Store
+
+ Note over Proc,Store: Step 1 — Load Stored State
+ Proc->>Hash: GetStoredHashAndTime()
+ alt RDKC
+ Hash->>Hash: Read /tmp/RFC/.hashValue
+ Hash->>Hash: Read /tmp/RFC/.timeValue
+ Note over Hash: Default: hash="UPGRADE_HASH", time="0"
+ else Other
+ Hash->>Hash: Check XconfSelector slot
+ Hash->>Hash: read_RFCProperty(ConfigSetHash)
+ end
+ Hash-->>Proc: {hash, timestamp}
+
+ Note over Proc,Store: Step 2 — Build Request URL
+ Proc->>URL: CreateXconfHTTPUrl() [virtual]
+ alt RDKC Override
+ URL->>URL: GetAccountHash()
+ URL->>URL: Build: server?estbMacAddress=MAC
&firmwareVersion=FW&env=BUILD
&model=MODEL&accountHash=HASH
&partnerId=PID&accountId=AID
&experience=EXP&version=2
+ else Default
+ URL->>URL: Build: server?estbMacAddress=MAC
&firmwareVersion=FW&env=BUILD
&model=MODEL&ecmMacAddress=ECM
&partnerId=PID&accountId=AID
&experience=EXP&manufacturer=MFR
&osclass=OS&version=2
+ end
+ URL-->>Proc: URL string
+
+ Note over Proc,Store: Step 3 — Secure HTTP Request
+ Proc->>mTLS: getMtlscert(&sec) [RDKC]
+ mTLS-->>Proc: {cert_path, password, status}
+ Proc->>HTTP: ExecuteRequest(url, &mTLS_creds, &httpCode)
+ HTTP->>Xconf: GET url (with mTLS cert)
+ Xconf-->>HTTP: HTTP 200 + JSON body
+ HTTP-->>Proc: response file path
+
+ Note over Proc,Store: Step 4 — Parse & Apply
+ Proc->>JSON: ProcessJsonResponse(response)
+ JSON->>JSON: Parse features array
+ JSON->>JSON: Extract parameters per feature
+ JSON->>JSON: Build effectiveImmediate set [RDKC]
+
+ loop For each feature parameter
+ Proc->>Store: clearDB() → remove old params
+ Proc->>Store: set_RFCProperty(name, key, value)
+ alt RDKC
+ Store->>Store: Read tr181store.ini
+ Store->>Store: Update/append key=value line
+ Store->>Store: Write tr181store.ini
+ else RDKB
+ Store->>Store: rbus_open → rbus_set → rbus_close
+ else STB
+ Store->>Store: setRFCParameter() via hostif
+ end
+ end
+
+ Note over Proc,Store: Step 5 — Persist Metadata
+ Proc->>Hash: updateHashInDB(new_hash)
+ Proc->>Hash: updateTimeInDB(new_time)
+ Proc->>Proc: StoreXconfEndpointMetadata() [no-op on RDKC]
+```
+
+---
+
+## 5. mTLS Certificate Acquisition
+
+```mermaid
+sequenceDiagram
+ participant Proc as Processor
+ participant mTLS as getMtlscert()
+ participant FS as File System
+ participant Shell as Shell (utils.sh)
+
+ Proc->>mTLS: getMtlscert(&sec)
+
+ alt LIBRDKCERTSELECTOR path
+ mTLS->>mTLS: rdkcertselector_new()
+ mTLS->>mTLS: Iterate cert selector choices
+ mTLS-->>Proc: MTLS_SUCCESS + cert details
+ else RDKC path
+ mTLS->>FS: access("/opt/certs/devicecert_1.pk12")
+ alt Dynamic XPKI exists
+ mTLS->>Shell: popen(". /lib/rdk/utils.sh && getxpkiPass")
+ Shell-->>mTLS: password string
+ alt Password OK
+ Note over mTLS: sec.cert = "/opt/certs/devicecert_1.pk12"
sec.password = password
+ mTLS-->>Proc: MTLS_SUCCESS
+ else Password failed
+ Note over mTLS: Fall through to static
+ end
+ end
+
+ mTLS->>FS: access("/etc/ssl/certs/staticXpkiCrt.pk12")
+ alt Static XPKI exists
+ mTLS->>Shell: popen(". /lib/rdk/utils.sh && getstaticxpkiPass")
+ Shell-->>mTLS: password string
+ alt Password OK
+ Note over mTLS: sec.cert = "/etc/ssl/certs/staticXpkiCrt.pk12"
sec.password = password
+ mTLS-->>Proc: MTLS_SUCCESS
+ else Password failed
+ mTLS-->>Proc: MTLS_FAILURE
+ end
+ else No static cert
+ mTLS-->>Proc: MTLS_FAILURE
+ end
+ end
+
+ alt MTLS_SUCCESS
+ Proc->>Proc: ExecuteRequest(&file_dwnl, &sec, &httpCode)
+ else MTLS_FAILURE
+ Proc->>Proc: ExecuteRequest(&file_dwnl, NULL, &httpCode)
+ Note over Proc: Proceed without mTLS
+ end
+```
+
+---
+
+## 6. Parameter Application
+
+```mermaid
+sequenceDiagram
+ participant Proc as Processor
+ participant JSON as JSON Parser
+ participant INI as tr181store.ini
+ participant API as rfcapi / rbus / hostif
+
+ Proc->>JSON: Read features[] from response
+
+ loop For each feature in features[]
+ JSON->>JSON: Extract feature name, configData[], effectiveImmediate
+
+ loop For each param in configData[]
+ JSON->>JSON: Get {key, value, dataType}
+
+ Proc->>Proc: set_RFCProperty(featureName, key, value)
+
+ alt RDKC Platform
+ Proc->>INI: Read entire file into lines[]
+
+ alt Key exists in file
+ Proc->>INI: Replace line: key=value
+ else Key not found
+ Proc->>INI: Append: key=value
+ end
+
+ Proc->>INI: Write all lines back
+ else RDKB Platform
+ Proc->>API: rbus_open()
+ Proc->>API: rbus_set(key, value)
+ Proc->>API: rbus_close()
+ else STB Platform
+ Proc->>API: setRFCParameter(key, value, type)
+ end
+ end
+ end
+```
+
+---
+
+## 7. Reboot Evaluation & Scheduling
+
+```mermaid
+sequenceDiagram
+ participant Proc as Processor
+ participant JSON as Feature JSON
+ participant Device as Device Properties
+ participant Cron as RfcRebootCronschedule.sh
+ participant MGR as RFCManager
+
+ Note over Proc,MGR: Step 1 — Build effectiveImmediate set (RDKC)
+ Proc->>JSON: Parse features[]
+ loop For each feature
+ alt feature.effectiveImmediate == true
+ loop For each param in feature.configData
+ Proc->>Proc: _effectiveImmediateParams.insert(param.key)
+ end
+ end
+ end
+
+ Note over Proc,MGR: Step 2 — Evaluate per-param reboot need
+ loop For each applied parameter
+ alt param.key in _effectiveImmediateParams
+ Proc->>Device: getDevicePropertyData("RDKC_DEVICE_PROVISION_STATUS")
+ Device-->>Proc: "1" (provisioned) / "0" (not provisioned)
+
+ alt Device is provisioned
+ alt param is NOT AccountID or MD5AccountHash
+ Proc->>Proc: _rfcRebootCronNeeded = true
+ Note over Proc: Reboot required for this parameter
+ else Identity param — skip
+ Note over Proc: No reboot for identity changes
+ end
+ else Not provisioned
+ Note over Proc: No reboot — device not provisioned
+ end
+ else Not in effectiveImmediate set
+ Note over Proc: No reboot needed
+ end
+ end
+
+ Note over Proc,MGR: Step 3 — Trigger reboot (if needed)
+ Proc-->>MGR: Return from ProcessRuntimeFeatureControlReq()
+ MGR->>Proc: getRfcRebootCronNeeded()
+
+ alt _rfcRebootCronNeeded == true
+ MGR->>Cron: v_secure_system("sh /lib/rdk/RfcRebootCronschedule.sh &")
+ Note over Cron: Schedule device reboot via cron
+ else No reboot needed
+ Note over MGR: Continue to post-processing
+ end
+```
+
+---
+
+## 8. Post-Processing & Cleanup
+
+```mermaid
+sequenceDiagram
+ participant MGR as RFCManager
+ participant Proc as Processor
+ participant MM as MaintenanceManager
+ participant Cron as Cron System
+ participant FS as File System
+
+ Note over MGR,FS: After ProcessRuntimeFeatureControlReq() returns
+
+ alt RDKC Platform
+ MGR->>MGR: Skip MaintenanceManager notification
+ MGR->>Proc: getRfcRebootCronNeeded()
+ alt Reboot needed
+ MGR->>FS: v_secure_system("sh /lib/rdk/RfcRebootCronschedule.sh &")
+ end
+ else STB Platform
+ MGR->>MM: SendEventToMaintenanceManager(MAINT_RFC_COMPLETE)
+ alt RFC error occurred
+ MGR->>MM: SendEventToMaintenanceManager(MAINT_RFC_ERROR)
+ end
+ alt Reboot required
+ MGR->>MM: SendEventToMaintenanceManager(MAINT_CRITICAL_UPDATE)
+ MGR->>MM: SendEventToMaintenanceManager(MAINT_REBOOT_REQUIRED)
+ end
+ end
+
+ Note over MGR,FS: Post-Processing
+ MGR->>MGR: RFCManagerPostProcess()
+ MGR->>Cron: Configure periodic cron schedule
+
+ alt RDKC
+ Note over Cron: Entry: schedule /usr/bin/rfcMgr
+ else Other
+ Note over Cron: Entry: schedule /usr/bin/rfcMgr >> /rdklogs/logs/dcmrfc.log.0 2>&1
+ end
+
+ Note over MGR,FS: Cleanup
+ MGR-->>FS: Return → main()
+ FS->>FS: atexit() → cleanup_lock_file()
+ FS->>FS: Remove /tmp/.rfcServiceLock
+```
diff --git a/rfcMgr/Makefile.am b/rfcMgr/Makefile.am
index 2d6186bb..b5cedb3a 100644
--- a/rfcMgr/Makefile.am
+++ b/rfcMgr/Makefile.am
@@ -25,6 +25,19 @@ AM_LDFLAGS = -L$(PKG_CONFIG_SYSROOT_DIR)/$(libdir)
AM_LDFLAGS += $(cjson_LIBS) $(curl_LIBS)
AM_LDFLAGS += -lrdkloggers -ldwnlutil -lfwutils -lparsejson -lsecure_wrapper -lcurl
+if ENABLE_RDKC
+rfcMgr_SOURCES += rdkc_rfc_xconf_handler.cpp
+if ENABLE_XCAM2
+rfcMgr_CPPFLAGS += -DRDKC -I${RDK_FSROOT_PATH}/usr/include/
+AM_LDFLAGS += -L${RDK_FSROOT_PATH}/usr/lib/ -lrdkloggers -ldwnlutil -lfwutils -lparsejson -lsecure_wrapper -lcurl -lrfcapi
+AM_LDFLAGS += -L${RDK_SOURCE_PATH}/rfcapi/.libs/ -lrfcapi
+else
+rfcMgr_CPPFLAGS += -DRDKC -I${STAGING_DIR_TARGET}/usr/include/
+AM_LDFLAGS += -L${STAGING_DIR_TARGET}/usr/lib/ -lrdkloggers -ldwnlutil -lfwutils -lparsejson -lsecure_wrapper -lcurl -lrfcapi
+AM_LDFLAGS += -L../../build/rfcapi/.libs/ -lrfcapi
+endif
+endif
+
if IS_IARMBUS_ENABLED
rfcMgr_CPPFLAGS += $(IARMBUS_EVENT_FLAG) -I$(PKG_CONFIG_SYSROOT_DIR)${includedir}/rdk/iarmbus
AM_LDFLAGS += -lIARMBus
@@ -34,8 +47,10 @@ if ENABLE_RDKB
rfcMgr_CPPFLAGS += $(RDKB_FLAG) $(rbus_CFLAGS) $(RDKBEXTENDER_FLAG)
AM_LDFLAGS += -lrbus
else
+if !ENABLE_RDKC
AM_LDFLAGS += ../rfcapi/.libs/librfcapi.la
endif
+endif
if ENABLE_RDKBEXTENDER
rfcMgr_CPPFLAGS += $(RDKBEXTENDER_FLAG)
diff --git a/rfcMgr/mtlsUtils.cpp b/rfcMgr/mtlsUtils.cpp
index 2963c066..bbee9a37 100644
--- a/rfcMgr/mtlsUtils.cpp
+++ b/rfcMgr/mtlsUtils.cpp
@@ -1,21 +1,23 @@
-/*##############################################################################
- # If not stated otherwise in this file or this component's LICENSE file the
- # following copyright and licenses apply:
- #
- # Copyright 2020 RDK Management
- #
- # 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.
- ##############################################################################
+/**
+ * @file mtlsUtils.cpp
+ * @brief mTLS certificate retrieval and state-red recovery implementation.
+ *
+ * If not stated otherwise in this file or this component's LICENSE file the
+ * following copyright and licenses apply:
+ *
+ * Copyright 2020 RDK Management
+ *
+ * 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.
*/
#include "mtlsUtils.h"
@@ -23,15 +25,20 @@
#ifdef LIBRDKCONFIG_BUILD
#include "rdkconfig.h"
#endif
+#ifdef RDKC
+#include
+#endif
#ifdef __cplusplus
extern "C" {
#endif
-/* Description: Checking state red support is present or not
- * return :1 = if state red support is present
- * return :0 = if state red support is not present */
+/**
+ * @brief Check if state-red recovery is supported on this device.
+ * @retval 1 Supported (support file exists).
+ * @retval 0 Not supported.
+ */
int isStateRedSupported(void) {
int ret = -1;
ret = filePresentCheck(STATE_RED_SPRT_FILE);
@@ -43,10 +50,11 @@ int isStateRedSupported(void) {
return 0;
}
-/* Description: Checking either device is in state red or not.
- * return 1: In state red
- * 0: Not in state red
- * */
+/**
+ * @brief Check if the device is currently in state-red.
+ * @retval 1 Device is in state-red.
+ * @retval 0 Device is not in state-red.
+ */
int isInStateRed(void) {
int ret = -1;
int stateRed = 0;
@@ -66,10 +74,12 @@ int isInStateRed(void) {
}
#ifdef LIBRDKCERTSELECTOR
-/* Description: Use for get all mtls related certificate and key.
- * @param sec: This is a pointer hold the certificate, key and type of certificate.
- * @return : MTLS_CERT_FETCH_SUCCESS on success, MTLS_CERT_FETCH_FAILURE on mtls cert failure , STATE_RED_CERT_FETCH_FAILURE on state red cert failure
- * */
+/**
+ * @brief Fetch mTLS certificate and key via librdkcertselector.
+ * @param[out] sec Populated mTLS auth structure.
+ * @param[out] pthisCertSel Certificate-selector handle (caller frees).
+ * @return MtlsAuthStatus result code.
+ */
MtlsAuthStatus getMtlscert(MtlsAuth_t *sec, rdkcertselector_h* pthisCertSel) {
/*
strncpy(sec->cert_name, STATE_RED_CERT, sizeof(sec->cert_name) - 1);
@@ -83,11 +93,80 @@ MtlsAuthStatus getMtlscert(MtlsAuth_t *sec, rdkcertselector_h* pthisCertSel) {
(void)pthisCertSel;
return MTLS_CERT_FETCH_SUCCESS;
}
+#elif defined(RDKC)
+/**
+ * @brief RDKC camera mTLS certificate retrieval.
+ *
+ * Mirrors mtlsUtils.sh / checkxpki flow from RFCbase.sh:
+ * 1. Try dynamic XPKI cert (CERT_DYNAMIC).
+ * 2. Fall back to static XPKI cert (CERT_STATIC).
+ * 3. If neither available, return MTLS_FAILURE.
+ */
+static int runShellCmd(const char *cmd, char *outBuf, size_t bufLen)
+{
+ FILE *fp = popen(cmd, "r");
+ if (fp == NULL) {
+ return -1;
+ }
+ if (fgets(outBuf, bufLen, fp) != NULL) {
+ size_t len = strlen(outBuf);
+ while (len > 0 && (outBuf[len - 1] == '\n' || outBuf[len - 1] == '\r')) {
+ outBuf[--len] = '\0';
+ }
+ pclose(fp);
+ return (len > 0) ? 0 : -1;
+ }
+ pclose(fp);
+ return -1;
+}
+
+int getMtlscert(MtlsAuth_t *sec) {
+ struct stat st;
+
+ if (sec == NULL) {
+ RDK_LOG(RDK_LOG_ERROR, LOG_RFCMGR, "getMtlscert(): NULL pointer\n");
+ return MTLS_FAILURE;
+ }
+ memset(sec, '\0', sizeof(MtlsAuth_t));
+
+ /* Try dynamic XPKI cert first — matches checkxpki() in utils.sh */
+ if (stat(CERT_DYNAMIC, &st) == 0 && st.st_size > 0) {
+ strncpy(sec->cert_name, CERT_DYNAMIC, sizeof(sec->cert_name) - 1);
+ sec->cert_name[sizeof(sec->cert_name) - 1] = '\0';
+ strncpy(sec->cert_type, "P12", sizeof(sec->cert_type) - 1);
+ sec->cert_type[sizeof(sec->cert_type) - 1] = '\0';
+ /* Password via rdkssacli — same as getxpkiPass() in utils.sh */
+ if (runShellCmd(". /lib/rdk/utils.sh && getxpkiPass", sec->key_pas, sizeof(sec->key_pas)) == 0) {
+ RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "getMtlscert(): RDKC dynamic XPKI cert: %s\n", CERT_DYNAMIC);
+ return MTLS_SUCCESS;
+ }
+ RDK_LOG(RDK_LOG_ERROR, LOG_RFCMGR, "getMtlscert(): RDKC dynamic cert found but password retrieval failed\n");
+ }
+
+ /* Fall back to static XPKI cert — matches static path in checkxpki() */
+ if (stat(CERT_STATIC, &st) == 0 && st.st_size > 0) {
+ strncpy(sec->cert_name, CERT_STATIC, sizeof(sec->cert_name) - 1);
+ sec->cert_name[sizeof(sec->cert_name) - 1] = '\0';
+ strncpy(sec->cert_type, "P12", sizeof(sec->cert_type) - 1);
+ sec->cert_type[sizeof(sec->cert_type) - 1] = '\0';
+ /* Password via GetConfigFile — same as getstaticxpkiPass() in utils.sh */
+ if (runShellCmd(". /lib/rdk/utils.sh && getstaticxpkiPass", sec->key_pas, sizeof(sec->key_pas)) == 0) {
+ RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "getMtlscert(): RDKC static XPKI cert: %s\n", CERT_STATIC);
+ return MTLS_SUCCESS;
+ }
+ RDK_LOG(RDK_LOG_ERROR, LOG_RFCMGR, "getMtlscert(): RDKC static cert found but password retrieval failed\n");
+ }
+
+ /* No cert available — models without XPKI proceed without mTLS */
+ RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "getMtlscert(): RDKC no XPKI cert available, proceeding without mTLS\n");
+ return MTLS_FAILURE;
+}
#else
-/* Description: Use for get all mtls related certificate and key.
- * @param sec: This is a pointer hold the certificate, key and type of certificate.
- * @return : int Success 1 and failure -1
- * */
+/**
+ * @brief Fetch mTLS certificate and key (legacy / non-certselector path).
+ * @param[out] sec Populated mTLS auth structure.
+ * @return MTLS_SUCCESS (1) or MTLS_FAILURE (-1).
+ */
int getMtlscert(MtlsAuth_t *sec) {
/*
strncpy(sec->cert_name, STATE_RED_CERT, sizeof(sec->cert_name) - 1);
diff --git a/rfcMgr/mtlsUtils.h b/rfcMgr/mtlsUtils.h
index 9688bfad..de633a04 100644
--- a/rfcMgr/mtlsUtils.h
+++ b/rfcMgr/mtlsUtils.h
@@ -1,21 +1,23 @@
-/*##############################################################################
- # If not stated otherwise in this file or this component's LICENSE file the
- # following copyright and licenses apply:
- #
- # Copyright 2020 RDK Management
- #
- # 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.
- ##############################################################################
+/**
+ * @file mtlsUtils.h
+ * @brief mTLS certificate retrieval and state-red recovery utilities.
+ *
+ * If not stated otherwise in this file or this component's LICENSE file the
+ * following copyright and licenses apply:
+ *
+ * Copyright 2020 RDK Management
+ *
+ * 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.
*/
#ifndef VIDEO_REF_INTERFACE_MTLSUTILS_H_
@@ -35,29 +37,44 @@ extern "C" {
#ifdef LIBRDKCERTSELECTOR
#include "rdkcertselector.h"
-// Below macro is invoked if the getMtlscert API fails to retrieve all MTLS certificates.
+/** cURL error returned when the local certificate file is missing/broken. */
#define CURL_MTLS_LOCAL_CERTPROBLEM 58
+/**
+ * @brief mTLS certificate fetch status codes (librdkcertselector path).
+ */
typedef enum {
- STATE_RED_CERT_FETCH_FAILURE = -2, // Indicates failure in state red recovery
- MTLS_CERT_FETCH_FAILURE = -1, // Indicates general MTLS failure
- MTLS_CERT_FETCH_SUCCESS = 0 // Indicates success
+ STATE_RED_CERT_FETCH_FAILURE = -2, /**< State-red recovery itself failed. */
+ MTLS_CERT_FETCH_FAILURE = -1, /**< General mTLS cert fetch failure. */
+ MTLS_CERT_FETCH_SUCCESS = 0 /**< Certificate fetched successfully. */
} MtlsAuthStatus;
+/**
+ * @brief Fetch mTLS certificate and key via librdkcertselector.
+ * @param[out] sec Populated mTLS auth structure.
+ * @param[out] pthisCertSel Certificate-selector handle (caller frees).
+ * @return MtlsAuthStatus result code.
+ */
MtlsAuthStatus getMtlscert(MtlsAuth_t *sec, rdkcertselector_h* pthisCertSel);
#else
-#define MTLS_SUCCESS 1
-#define MTLS_FAILURE -1
+#define MTLS_SUCCESS 1 /**< mTLS success (non-librdkcertselector path). */
+#define MTLS_FAILURE -1 /**< mTLS failure (non-librdkcertselector path). */
+
+/**
+ * @brief Fetch mTLS certificate (legacy / non-certselector path).
+ * @param[out] sec Populated mTLS auth structure.
+ * @return MTLS_SUCCESS or MTLS_FAILURE.
+ */
int getMtlscert(MtlsAuth_t *sec);
#endif
-#define CERT_DYNAMIC "/opt/certs/devicecert_1.pk12"
-#define CERT_STATIC "/etc/ssl/certs/staticXpkiCrt.pk12"
+#define CERT_DYNAMIC "/opt/certs/devicecert_1.pk12" /**< Dynamic XPKI certificate path. */
+#define CERT_STATIC "/etc/ssl/certs/staticXpkiCrt.pk12" /**< Static XPKI certificate path. */
/**
- * Below macros are placeholders.
- * Users are free to override with their custom certs and verifier algorithms during compile time
- **/
+ * @name Certificate / key placeholders.
+ * Override at compile time with device-specific paths.
+ * @{ */
#define KEY_STATIC ""
#define STATE_RED_CERT ""
#define STATE_RED_KEY ""
@@ -67,14 +84,19 @@ int getMtlscert(MtlsAuth_t *sec);
#define SYS_CMD_GET_CONFIG_FILE ""
#define STATE_RED_SPRT_FILE ""
#define STATEREDFLAG ""
+/** @} */
#if defined(GTEST_ENABLE)
+/** @brief Check if state-red recovery is supported on this build. */
int isStateRedSupported(void);
+/** @brief Check if the device is currently in state-red. */
int isInStateRed(void);
#endif
#if defined(RDKB_SUPPORT)
+/** @brief Get the eRouter MAC address string. */
std::string getErouterMac();
+/** @brief Get the eCM (cable modem) MAC address string. */
std::string geteCMMac();
#endif
diff --git a/rfcMgr/rdkc_rfc_xconf_handler.cpp b/rfcMgr/rdkc_rfc_xconf_handler.cpp
new file mode 100644
index 00000000..20988ced
--- /dev/null
+++ b/rfcMgr/rdkc_rfc_xconf_handler.cpp
@@ -0,0 +1,216 @@
+/**
+ * If not stated otherwise in this file or this component's LICENSE
+ * file the following copyright and licenses apply:
+ *
+ * Copyright 2024 RDK Management
+ *
+ * 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.
+ *
+ * rdkc_rfc_xconf_handler.cpp
+ *
+ * RDKC-specific overrides of RuntimeFeatureControlProcessor.
+ * See rdkc_rfc_xconf_handler.h for the design rationale.
+ **/
+
+#ifdef RDKC
+
+#include "rdkc_rfc_xconf_handler.h"
+#include "rfc_common.h" /* read_RFCProperty, RFC_VALUE_BUF_SIZE, LOG_RFCMGR */
+#include "rdk_debug.h"
+#include
+#include
+
+/* -------------------------------------------------------------------------
+ * Constants
+ * ---------------------------------------------------------------------- */
+
+/** TR181 parameter holding the MD5 account hash on camera devices. */
+#define RFC_MD5_ACCOUNT_HASH \
+ "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.MD5AccountHash"
+
+/** RAM-backed directory used for transient RFC state on all platforms. */
+#define RFC_RAM_PATH "/tmp/RFC"
+
+/* =========================================================================
+ * GetAccountHash — lazy fetch, cached in _accountHash
+ * ====================================================================== */
+
+/**
+ * Read the MD5 account hash from the RFC parameter store.
+ * Called once (lazily) from CreateXconfHTTPUrl() before building the URL.
+ *
+ * Shell equivalent (XHC1 branch in RFCbase.sh):
+ * . $RDK_PATH/getAccountHash.sh
+ * JSONSTR='...&accountHash='$(getAccountHash)'&...'
+ */
+void RdkcRuntimeFeatureControlProcessor::GetAccountHash()
+{
+ if (!_accountHash.empty())
+ return; /* already populated */
+
+ /* RDKC: read account hash from /opt/usr_config/accounthash.txt.
+ * Shell equivalent: . $RDK_PATH/getAccountHash.sh → getAccountHash() */
+ std::ifstream ifs("/opt/usr_config/accounthash.txt");
+ if (ifs.is_open())
+ {
+ std::getline(ifs, _accountHash);
+ ifs.close();
+ if (!_accountHash.empty())
+ {
+ RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR,
+ "[%s][%d] RDKC AccountHash: %s\n",
+ __FUNCTION__, __LINE__, _accountHash.c_str());
+ return;
+ }
+ }
+
+ RDK_LOG(RDK_LOG_WARN, LOG_RFCMGR,
+ "[%s][%d] RDKC: /opt/usr_config/accounthash.txt not found or empty\n",
+ __FUNCTION__, __LINE__);
+}
+
+/* =========================================================================
+ * CreateXconfHTTPUrl — camera-specific query parameters
+ * ====================================================================== */
+
+/**
+ * Build the Xconf HTTP request URL for camera (XHC1) devices.
+ *
+ * Differences from the base implementation:
+ * - Adds : accountHash (camera-specific identity field)
+ * - Omits : manufacturer, ecmMacAddress, osClass, controllerId,
+ * channelMapId, vodId (not applicable on camera)
+ *
+ * Shell equivalent (XHC1 branch in sendHttpRequestToServer):
+ * JSONSTR='estbMacAddress='$(getEstbMacAddress)
+ * '&firmwareVersion='$(getFWVersion)
+ * '&env='$(getBuildType)
+ * '&model='$(getModel)
+ * '&accountHash='$(getAccountHash)
+ * '&partnerId='$(getPartnerId)
+ * '&accountId='$(getAccountId)
+ * '&experience='$(getExperience)
+ * '&version=2'
+ */
+std::stringstream RdkcRuntimeFeatureControlProcessor::CreateXconfHTTPUrl()
+{
+ GetAccountHash();
+
+ std::stringstream url;
+ url << _xconf_server_url << "?";
+ url << "estbMacAddress=" << _estb_mac_address << "&";
+ url << "firmwareVersion=" << _firmware_version << "&";
+ url << "env=" << _build_type_str << "&";
+ url << "model=" << _model_number << "&";
+ url << "accountHash=" << _accountHash << "&";
+ url << "partnerId=" << _partner_id << "&";
+ url << "accountId=" << _accountId << "&";
+ url << "experience=" << _experience << "&";
+ url << "version=2";
+
+ RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR,
+ "[%s][%d] RDKC Xconf request URL built\n",
+ __FUNCTION__, __LINE__);
+
+ return url;
+}
+
+/* =========================================================================
+ * RetrieveHashAndTimeFromPreviousDataSet — RAM files only
+ * ====================================================================== */
+
+/**
+ * Read configSetHash and configSetTime from RAM-backed files.
+ *
+ * RDKC devices (XHC1) never use the TR181 parameter database for
+ * hash/time storage. Both values are always written to and read from
+ * /tmp/RFC/.hashValue and /tmp/RFC/.timeValue.
+ *
+ * Shell equivalent (rfcGetHashAndTime, XHC1 branch):
+ * if [ "$DEVICE_TYPE" = "XHC1" ]; then
+ * valueHash=`cat $RFC_RAM_PATH/.hashValue`
+ * valueTime=`cat $RFC_RAM_PATH/.timeValue`
+ * fi
+ */
+void RdkcRuntimeFeatureControlProcessor::RetrieveHashAndTimeFromPreviousDataSet(
+ std::string &valueHash, std::string &valueTime)
+{
+ valueHash = "UPGRADE_HASH";
+ valueTime = "0";
+
+ const std::string hashFile = std::string(RFC_RAM_PATH) + "/.hashValue";
+ if (access(hashFile.c_str(), R_OK) == 0)
+ {
+ std::ifstream ifs(hashFile);
+ if (ifs.is_open())
+ {
+ std::getline(ifs, valueHash);
+ ifs.close();
+ RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR,
+ "[%s][%d] RDKC ConfigSetHash: %s\n",
+ __FUNCTION__, __LINE__, valueHash.c_str());
+ }
+ }
+ else
+ {
+ RDK_LOG(RDK_LOG_DEBUG, LOG_RFCMGR,
+ "[%s][%d] RDKC: hash file not found, using default\n",
+ __FUNCTION__, __LINE__);
+ }
+
+ const std::string timeFile = std::string(RFC_RAM_PATH) + "/.timeValue";
+ if (access(timeFile.c_str(), R_OK) == 0)
+ {
+ std::ifstream ifs(timeFile);
+ if (ifs.is_open())
+ {
+ std::getline(ifs, valueTime);
+ ifs.close();
+ RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR,
+ "[%s][%d] RDKC ConfigSetTime: %s\n",
+ __FUNCTION__, __LINE__, valueTime.c_str());
+ }
+ }
+ else
+ {
+ RDK_LOG(RDK_LOG_DEBUG, LOG_RFCMGR,
+ "[%s][%d] RDKC: time file not found, using default\n",
+ __FUNCTION__, __LINE__);
+ }
+
+ bkup_hash = valueHash; /* keep backup consistent */
+}
+
+/* =========================================================================
+ * StoreXconfEndpointMetadata — no-op for camera
+ * ====================================================================== */
+
+/**
+ * RDKC devices (XHC1) must NOT write XconfSelector or XconfUrl back
+ * to the parameter store after a successful Xconf sync.
+ *
+ * Shell equivalent (processJsonResponseV / sendHttpRequestToServer):
+ * if [ "$DEVICE_TYPE" != "XHC1" ]; then
+ * rfcSet ${XCONF_SELECTOR_TR181_NAME} string "$rfcSelectOpt"
+ * rfcSet ${XCONF_URL_TR181_NAME} string "$rfcSelectUrl"
+ * fi
+ */
+void RdkcRuntimeFeatureControlProcessor::StoreXconfEndpointMetadata()
+{
+ RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR,
+ "[%s][%d] RDKC (XHC1): skipping XconfSelector/XconfUrl storage\n",
+ __FUNCTION__, __LINE__);
+ /* Intentional no-op */
+}
+
+#endif /* RDKC */
diff --git a/rfcMgr/rdkc_rfc_xconf_handler.h b/rfcMgr/rdkc_rfc_xconf_handler.h
new file mode 100644
index 00000000..e4575ce6
--- /dev/null
+++ b/rfcMgr/rdkc_rfc_xconf_handler.h
@@ -0,0 +1,86 @@
+/**
+ * If not stated otherwise in this file or this component's LICENSE
+ * file the following copyright and licenses apply:
+ *
+ * Copyright 2024 RDK Management
+ *
+ * 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.
+ *
+ * rdkc_rfc_xconf_handler.h
+ *
+ * RDKC-specific (RDKC / XHC1) RFC handler.
+ *
+ * Inherits all common RFC request/response logic from
+ * RuntimeFeatureControlProcessor and overrides only the three methods
+ * whose behaviour differs on camera platforms:
+ *
+ * CreateXconfHTTPUrl()
+ * RDKC query string adds "accountHash" and omits
+ * manufacturer / ecmMacAddress / osClass.
+ *
+ * RetrieveHashAndTimeFromPreviousDataSet()
+ * RDKC devices store configSetHash / configSetTime in RAM
+ * files only (/tmp/RFC/.hashValue, /tmp/RFC/.timeValue).
+ * No TR181 DB lookup is performed.
+ *
+ * StoreXconfEndpointMetadata()
+ * XHC1 must NOT write XconfSelector / XconfUrl back to the
+ * data store after a successful sync — this is a no-op.
+ **/
+
+#pragma once
+#ifdef RDKC
+
+#include "rfc_xconf_handler.h"
+#include
+#include
+
+/**
+ * @class RdkcRuntimeFeatureControlProcessor
+ * @brief RDKC camera-specific RFC processor subclass.
+ *
+ * Inherits all common RFC logic from RuntimeFeatureControlProcessor
+ * and overrides only platform-specific methods.
+ */
+class RdkcRuntimeFeatureControlProcessor : public RuntimeFeatureControlProcessor
+{
+public:
+ /** @brief Default constructor. */
+ RdkcRuntimeFeatureControlProcessor() = default;
+
+ RdkcRuntimeFeatureControlProcessor(const RdkcRuntimeFeatureControlProcessor&) = delete; /**< Copy disabled. */
+ RdkcRuntimeFeatureControlProcessor& operator=(const RdkcRuntimeFeatureControlProcessor&) = delete; /**< Assignment disabled. */
+
+protected:
+ /** @brief Build RDKC-specific Xconf URL (adds accountHash, omits manufacturer). */
+ std::stringstream CreateXconfHTTPUrl() override;
+
+ /**
+ * @brief Read configSetHash/Time from RAM files (/tmp/RFC/).
+ * @param[out] valueHash Retrieved hash string.
+ * @param[out] valueTime Retrieved time string.
+ */
+ void RetrieveHashAndTimeFromPreviousDataSet(std::string &valueHash,
+ std::string &valueTime) override;
+
+ /** @brief No-op — RDKC must not persist XconfSelector/XconfUrl. */
+ void StoreXconfEndpointMetadata() override;
+
+private:
+ std::string _accountHash; /**< MD5 account hash, XHC1-specific query param. */
+
+ /** @brief Lazy-fetch the MD5 account hash from the RFC parameter store. */
+ void GetAccountHash();
+};
+
+#endif /* RDKC */
diff --git a/rfcMgr/rfc_common.cpp b/rfcMgr/rfc_common.cpp
index ae171058..6cdc3f00 100644
--- a/rfcMgr/rfc_common.cpp
+++ b/rfcMgr/rfc_common.cpp
@@ -1,21 +1,23 @@
-/*##############################################################################
- # If not stated otherwise in this file or this component's LICENSE file the
- # following copyright and licenses apply:
- #
- # Copyright 2024 RDK Management
- #
- # 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.
- ##############################################################################
+/**
+ * @file rfc_common.cpp
+ * @brief Common RFC utility functions — parameter reading, string helpers.
+ *
+ * If not stated otherwise in this file or this component's LICENSE file the
+ * following copyright and licenses apply:
+ *
+ * Copyright 2024 RDK Management
+ *
+ * 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.
*/
@@ -28,7 +30,11 @@
#include
#endif
-
+/**
+ * @brief Query a sysevent key via the CLI.
+ * @param[in] key Sysevent key name.
+ * @return Value string, or empty on failure.
+ */
std::string getSyseventValue(const std::string& key)
{
std::string cmd = "sysevent get " + key;
@@ -52,6 +58,12 @@ std::string getSyseventValue(const std::string& key)
return result;
}
+/**
+ * @brief Block until webconfig RFC blob processing completes (RDKB).
+ *
+ * Polls the "rfc_blob_processing" sysevent with 100 s retries
+ * (up to ~10 min total) before proceeding.
+ */
void waitForRfcCompletion()
{
// Check RFC blob processing status
@@ -90,12 +102,14 @@ void waitForRfcCompletion()
}
}
-/* Description: Reading rfc data
- * @param type : rfc type
- * @param key: rfc key
- * @param data : Store rfc value
- * @return int 1 READ_RFC_SUCCESS on success and READ_RFC_FAILURE -1 on failure
- * */
+/**
+ * @brief Read an RFC parameter from the data store.
+ * @param[in] type Caller ID / namespace (may be NULL on RDKB/RDKC).
+ * @param[in] key TR181 parameter name.
+ * @param[out] out_value Buffer to receive the value.
+ * @param[in] datasize Size of @p out_value buffer.
+ * @return READ_RFC_SUCCESS (1) or READ_RFC_FAILURE (-1).
+ */
int read_RFCProperty(const char* type, const char* key, char *out_value, int datasize)
{
int ret = READ_RFC_FAILURE;
@@ -170,6 +184,33 @@ int read_RFCProperty(const char* type, const char* key, char *out_value, int dat
}
rbus_close(handle);
+#elif defined(RDKC)
+ RFC_ParamData_t param;
+ memset(¶m, 0, sizeof(RFC_ParamData_t));
+ (void)type;
+
+ int data_len;
+ int status = getRFCParameter(key, ¶m);
+ if(status == SUCCESS)
+ {
+ data_len = strlen(param.value);
+ if(data_len >= 2 && (param.value[0] == '"') && (param.value[data_len - 1] == '"'))
+ {
+ snprintf(out_value, datasize, "%s", ¶m.value[1]);
+ *(out_value + data_len - 2) = 0;
+ }
+ else
+ {
+ snprintf(out_value, datasize, "%s", param.value);
+ }
+ RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] RFC name=%s,type=%d,value=%s,status=%d\n", __FUNCTION__, __LINE__, param.name, param.type, param.value, status);
+ ret = READ_RFC_SUCCESS;
+ }
+ else
+ {
+ RDK_LOG(RDK_LOG_ERROR, LOG_RFCMGR, "[%s][%d] RFC Read status= %d\n", __FUNCTION__, __LINE__, status);
+ *out_value = 0;
+ }
#else
RFC_ParamData_t param;
memset(¶m, 0, sizeof(RFC_ParamData_t));
diff --git a/rfcMgr/rfc_common.h b/rfcMgr/rfc_common.h
index 06f8c721..6d3a0997 100644
--- a/rfcMgr/rfc_common.h
+++ b/rfcMgr/rfc_common.h
@@ -1,4 +1,7 @@
/**
+ * @file rfc_common.h
+ * @brief Common utilities, macros, and helpers for the RFC Manager.
+ *
* If not stated otherwise in this file or this component's LICENSE
* file the following copyright and licenses apply:
*
@@ -15,14 +18,14 @@
* 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.
- **/
+ */
#ifndef RFC_MGR_COMMON_H
#define RFC_MGR_COMMON_H
-/*----------------------------------------------------------------------------*/
-/* Header File */
-/*----------------------------------------------------------------------------*/
+/** @addtogroup rfcMgr
+ * @{ */
+
#include "rdk_debug.h"
#include "rfcapi.h"
#include "rfc_mgr_key.h"
@@ -41,10 +44,10 @@
#include
#include
#include
-/*----------------------------------------------------------------------------*/
-/* Macros */
-/*----------------------------------------------------------------------------*/
-#define LOG_RFCMGR "LOG.RDK.RFCMGR"
+
+/** @name Macros
+ * @{ */
+#define LOG_RFCMGR "LOG.RDK.RFCMGR" /**< RDK Logger module name. */
#define FAILURE -1
#define SUCCESS 0
@@ -63,23 +66,75 @@
#define DEFAULT_DL_ALLOC 1024
+/** System command type selector for executeCommandAndGetOutput(). */
typedef enum {
- eRdkSsaCli,
- eWpeFrameworkSecurityUtility
+ eRdkSsaCli, /**< Use rdkssacli binary. */
+ eWpeFrameworkSecurityUtility /**< Use WPEFrameworkSecurityUtility binary. */
} SYSCMD;
#define WPEFRAMEWORKSECURITYUTILITY "/usr/bin/WPEFrameworkSecurityUtility"
#define RDKSSACLI_CMD "/usr/bin/rdkssacli %s"
#define KEY_GEN_BIN "/usr/bin/rdkssacli"
+/** @} */ /* end Macros */
+
+/**
+ * @brief Execute a system binary and capture its stdout.
+ * @param[in] eSysCmd Which binary to invoke.
+ * @param[in] pArgs Arguments passed to the binary.
+ * @param[out] result Captured standard output.
+ * @return SUCCESS (0) or FAILURE (-1).
+ */
int executeCommandAndGetOutput(SYSCMD, const char *, std::string&);
+
+/**
+ * @brief Read an RFC parameter from the data store.
+ * @param[in] type Caller ID / namespace (may be NULL on RDKB/RDKC).
+ * @param[in] key TR181 parameter name.
+ * @param[out] out_value Buffer to receive the value.
+ * @param[in] datasize Size of @p out_value buffer.
+ * @return READ_RFC_SUCCESS (1) or READ_RFC_FAILURE (-1).
+ */
int read_RFCProperty(const char* , const char* , char *, int );
+
+/**
+ * @brief Return true if @p str contains characters outside [a-zA-Z0-9._-].
+ */
bool CheckSpecialCharacters(const std::string&);
+
+/**
+ * @brief Case-insensitive string comparison.
+ */
bool StringCaseCompare(const std::string& , const std::string& );
+
+/**
+ * @brief Erase every occurrence of @p toRemove from @p str in-place.
+ */
void RemoveSubstring(std::string& str, const std::string& toRemove);
+
+/**
+ * @brief Block until webconfig RFC blob processing completes (RDKB).
+ */
void waitForRfcCompletion();
+
+/**
+ * @brief Retrieve the eRouter WAN IP address (IPv6 preferred).
+ */
std::string getErouterIPAddress();
+
+/**
+ * @brief Query a sysevent key via the CLI.
+ * @param[in] key Sysevent key name.
+ * @return Value string, or empty on failure.
+ */
std::string getSyseventValue(const std::string& key);
+
+/**
+ * @brief Parse the cron schedule from DCM settings.
+ * @return Five-field cron string.
+ */
std::string getCronFromDCMSettings();
+/** @} */ /* end rfcMgr group */
+
#endif
diff --git a/rfcMgr/rfc_main.cpp b/rfcMgr/rfc_main.cpp
index 57ce377d..deee34b2 100644
--- a/rfcMgr/rfc_main.cpp
+++ b/rfcMgr/rfc_main.cpp
@@ -1,4 +1,7 @@
/**
+ * @file rfc_main.cpp
+ * @brief RFC Manager daemon entry point.
+ *
* If not stated otherwise in this file or this component's LICENSE
* file the following copyright and licenses apply:
*
@@ -15,7 +18,7 @@
* 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.
- **/
+ */
#include "rfc_common.h"
#include "rfc_manager.h"
@@ -32,14 +35,14 @@ extern "C" {
#include
-// Cleanup function
+/** @brief Remove the service lock file on exit. */
void cleanup_lock_file(void)
{
RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] RFC: Completed service, deleting lock\n", __FUNCTION__, __LINE__);
unlink(RFC_MGR_SERVICE_LOCK_FILE);
}
-// Signal handler for graceful shutdown
+/** @brief Signal handler — clean up and exit gracefully. */
void signal_handler(int sig)
{
RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "RFC: Received signal %d, cleaning up lock file\n", sig);
@@ -47,6 +50,12 @@ void signal_handler(int sig)
exit(0);
}
+/**
+ * @brief Create a directory if it does not already exist.
+ * @param[in] path Absolute directory path.
+ * @retval true Directory exists or was created.
+ * @retval false Creation failed.
+ */
bool createDirectoryIfNotExists(const char* path) {
if (!path || *path == '\0') {
RDK_LOG(RDK_LOG_ERROR, LOG_RFCMGR, "[%s][%d] Invalid path\n", __FUNCTION__, __LINE__);
@@ -94,7 +103,14 @@ int main()
RDK_LOG(RDK_LOG_ERROR, LOG_RFCMGR, "[%s][%d] RFC: Failed to create RFC directory\n", __FUNCTION__, __LINE__);
exit(EXIT_FAILURE);
}
-
+
+#if defined(RDKB_SUPPORT) || defined(RDKC)
+ /* Create /tmp/RFC/ for hash/time RAM files (RDKB & RDKC only) */
+ if (!createDirectoryIfNotExists("/tmp/RFC")) {
+ RDK_LOG(RDK_LOG_WARN, LOG_RFCMGR, "[%s][%d] RFC: Failed to create /tmp/RFC directory\n", __FUNCTION__, __LINE__);
+ }
+#endif
+
RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] RFC: Starting service, creating lock \n", __FUNCTION__, __LINE__);
#if defined(RDKB_SUPPORT)
diff --git a/rfcMgr/rfc_manager.cpp b/rfcMgr/rfc_manager.cpp
index 99a99d85..68f9ea00 100644
--- a/rfcMgr/rfc_manager.cpp
+++ b/rfcMgr/rfc_manager.cpp
@@ -1,4 +1,7 @@
/**
+ * @file rfc_manager.cpp
+ * @brief RFC Manager implementation — device connectivity, IARM, Xconf lifecycle.
+ *
* If not stated otherwise in this file or this component's LICENSE
* file the following copyright and licenses apply:
*
@@ -15,22 +18,34 @@
* 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.
- **/
+ */
#include "rfc_manager.h"
#include "rfc_common.h"
#include "rfc_mgr_iarm.h"
#include "rfc_xconf_handler.h"
+#ifdef RDKC
+#include "rdkc_rfc_xconf_handler.h"
+#endif
#include
+#include
#include
#include
#include
+#ifdef RDKC
+#include
+#include
+#include
+#endif
namespace rfc {
#if defined(USE_IARMBUS)
+ /**
+ * @brief IARM event handler for RFC Manager events.
+ * @note Placeholder for future implementation.
+ */
void rfcMgrEventHandler(const char *owner, IARM_EventId_t eventId, void *data, size_t len)
{
- /* This is place holder for future */
owner = owner;
eventId = eventId;
data = data;
@@ -38,14 +53,15 @@ namespace rfc {
return;
}
#endif
+ /** @brief Construct and initialise the RFC Manager (logger + IARM). */
RFCManager ::RFCManager() {
#if defined(RDK_LOGGER)
-#if defined(RDKB_SUPPORT)
+#if defined(RDKB_SUPPORT) || defined(RDKC)
RDK_LOGGER_INIT();
-#else
+#else
/* Initialize RDK Logger */
static char RFCMGRLOG[] = "LOG.RDK.RFCMGR";
- rdk_logger_ext_config_t config = {
+ rdk_logger_ext_config_t config = {
.pModuleName = RFCMGRLOG, /* Module name */
.loglevel = RDK_LOG_INFO, /* Default log level */
.output = RDKLOG_OUTPUT_CONSOLE, /* Output to console (stdout/stderr) */
@@ -56,17 +72,17 @@ namespace rfc {
if (rdk_logger_ext_init(&config) != RDK_SUCCESS) {
printf("RFC : ERROR - Extended logger init failed\n");
}
-#endif
#endif
+#endif
+
/* Initialize IARM Bus */
InitializeIARM();
}
- /** Description: Check if Module is connected to IARM
- *
- * @param cur_event_name: event name.
- * @param event_status: Status Of the event.
- * @return void.
+ /**
+ * @brief Check if the IARM bus is connected.
+ * @retval true IARM bus is registered.
+ * @retval false IARM bus not available.
*/
bool RFCManager ::IsIarmBusConnected() {
#if defined(USE_IARMBUS)
@@ -128,11 +144,9 @@ namespace rfc {
#endif
}
- /** Description: This API UnRegister IARM event handlers in order to release
- * bus-facing resources.
- *
- * @param void
- * @return 0.
+ /**
+ * @brief Unregister IARM event handlers and clean up bus resources.
+ * @return 0 always.
*/
int term_event_handler(void) {
#if defined(USE_IARMBUS)
@@ -145,6 +159,10 @@ namespace rfc {
return 0;
}
+ /**
+ * @brief Retrieve the eRouter WAN address (IPv6 preferred, IPv4 fallback).
+ * @return IP address string, or empty on failure.
+ */
std::string RFCManager::getErouterIPAddress() {
std::string address;
@@ -181,6 +199,11 @@ namespace rfc {
return address;
}
+ /**
+ * @brief Check eRouter IP availability.
+ * @retval true eRouter IP address obtained.
+ * @retval false No IP address available.
+ */
bool RFCManager::CheckIPConnectivity(void)
{
bool ip_status = false;
@@ -201,12 +224,12 @@ namespace rfc {
return ip_status;
}
- /* Description: Checking IP route address and device is online or not.
- * Use IARM event provided by net service manager to check either
- * device is online or not.
- * @param: file_name : pointer to gateway iproute config file name
- * return :true = success
- * return :false = failure */
+ /**
+ * @brief Verify IP route connectivity via a gateway config file.
+ * @param[in] file_name Path to the gateway IP route file.
+ * @retval true IP route entry found.
+ * @retval false File missing or no valid IP entry.
+ */
bool RFCManager ::CheckIProuteConnectivity(const char *file_name) {
bool ip_status = false;
bool string_check = false;
@@ -283,10 +306,12 @@ namespace rfc {
return ip_status;
}
- /* Description: Checking dns nameserver ip is present or not.
- * @param: dns_file_name : pointer to dns config file name
- * return :true = success
- * return :false = failure */
+ /**
+ * @brief Check if DNS nameserver entries are present.
+ * @param[in] dns_file_name Path to the DNS resolver file.
+ * @retval true At least one nameserver found.
+ * @retval false File missing or no nameserver entry.
+ */
bool isDnsResolve(const char *dns_file_name)
{
bool dns_status = false;
@@ -334,7 +359,60 @@ namespace rfc {
{
RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR,"[%s][%d] Checking IP and Route configuration\n", __FUNCTION__,__LINE__);
rfc::DeviceStatus result = RFCMGR_DEVICE_OFFLINE;
-#if !defined(RDKB_SUPPORT)
+#ifdef RDKC
+ /* Camera (XHC1) IP acquisition — matches waitForIpAcquisition() in
+ * RFCbase.sh. Poll until a non-loopback IP address appears on any
+ * interface. The shell loops with 10s sleep; we do the same. */
+ {
+ char ipBuf[INET6_ADDRSTRLEN] = {0};
+ while (true)
+ {
+ struct ifaddrs *ifap = nullptr;
+ if (getifaddrs(&ifap) == 0)
+ {
+ for (struct ifaddrs *ifa = ifap; ifa; ifa = ifa->ifa_next)
+ {
+ if (!ifa->ifa_addr) continue;
+ int family = ifa->ifa_addr->sa_family;
+ if (family == AF_INET)
+ {
+ struct sockaddr_in *sa = (struct sockaddr_in *)ifa->ifa_addr;
+ uint32_t ip = ntohl(sa->sin_addr.s_addr);
+ /* Skip loopback 127.x.x.x */
+ if ((ip >> 24) == 127) continue;
+ /* Skip link-local / APIPA 169.254.x.x */
+ if ((ip >> 16) == 0xA9FE) continue;
+ inet_ntop(AF_INET, &sa->sin_addr, ipBuf, sizeof(ipBuf));
+ result = RFCMGR_DEVICE_ONLINE;
+ break;
+ }
+ else if (family == AF_INET6)
+ {
+ struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)ifa->ifa_addr;
+ /* Skip loopback ::1 and link-local fe80:: */
+ if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr)) continue;
+ if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr)) continue;
+ inet_ntop(AF_INET6, &sa6->sin6_addr, ipBuf, sizeof(ipBuf));
+ result = RFCMGR_DEVICE_ONLINE;
+ break;
+ }
+ }
+ freeifaddrs(ifap);
+ }
+ if (result == RFCMGR_DEVICE_ONLINE)
+ {
+ RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR,
+ "[%s][%d] RDKC: Acquired IP address: %s\n",
+ __FUNCTION__, __LINE__, ipBuf);
+ break;
+ }
+ RDK_LOG(RDK_LOG_DEBUG, LOG_RFCMGR,
+ "[%s][%d] RDKC: Waiting for IP address...\n",
+ __FUNCTION__, __LINE__);
+ sleep(10);
+ }
+ }
+#elif !defined(RDKB_SUPPORT) && !defined(RDKC)
if (true == CheckIProuteConnectivity(GATEWAYIP_FILE))
{
RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR,"[%s][%d] Checking IP and Route configuration found\n", __FUNCTION__,__LINE__);
@@ -367,11 +445,10 @@ namespace rfc {
}
#if !defined(RDKB_SUPPORT)
- /** Description: Send event to iarm event manager
- *
- * @param cur_event_name: event name.
- * @param main_mgr_event: Status Of the event.
- * @return void.
+ /**
+ * @brief Broadcast an IARM event to the Maintenance Manager.
+ * @param[in] cur_event_name IARM event owner name.
+ * @param[in] main_mgr_event Maintenance manager event code.
*/
void RFCManager::SendEventToMaintenanceManager(const char *cur_event_name, unsigned int main_mgr_event)
{
@@ -393,6 +470,10 @@ namespace rfc {
}
#endif
+ /**
+ * @brief Run post-processing scripts after RFC parameters are applied.
+ * @return SUCCESS (0) or FAILURE (-1).
+ */
int RFCManager::RFCManagerPostProcess()
{
// Check if the script exists before executing it
@@ -410,13 +491,38 @@ namespace rfc {
return SUCCESS;
}
+ /**
+ * @brief Core RFC fetch-and-apply logic.
+ *
+ * Creates the platform-appropriate RuntimeFeatureControlProcessor,
+ * initialises the Xconf handler, processes the feature-control request,
+ * and triggers reboot scheduling or maintenance-manager events.
+ *
+ * @return SUCCESS (0) or FAILURE (-1).
+ */
int RFCManager::RFCManagerProcess()
{
- /* Create Object for Xconf Handler */
+ /* Create the appropriate RFC processor for the target platform.
+ * On camera (RDKC/XHC1) use the derived class that overrides
+ * URL building, hash/time retrieval, and endpoint metadata storage.
+ * All shared RFC logic is inherited from RuntimeFeatureControlProcessor. */
+#ifdef RDKC
+ RuntimeFeatureControlProcessor *rfcObj = new RdkcRuntimeFeatureControlProcessor();
+#else
RuntimeFeatureControlProcessor *rfcObj = new RuntimeFeatureControlProcessor();
+#endif
int reqStatus = FAILURE;
+#ifdef RDKC
+ /* Camera devices wait 120 seconds before first Xconf query.
+ * Shell equivalent: sleep 120 (RFCbase.sh XHC1 branch) */
+ RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR,
+ "[%s][%d] RDKC: Waiting 120 seconds before querying xconf\n",
+ __FUNCTION__, __LINE__);
+ sleep(120);
+#endif
+
/* Initialize xconf Hanlder */
int result = rfcObj->InitializeRuntimeFeatureControlProcessor();
if(result == FAILURE)
@@ -431,6 +537,7 @@ namespace rfc {
#if !defined(RDKB_SUPPORT)
if(result == SUCCESS)
{
+#ifndef RDKC
SendEventToMaintenanceManager("MaintenanceMGR", MAINT_RFC_COMPLETE);
bool isRebootRequired = rfcObj->getRebootRequirement();
@@ -441,13 +548,39 @@ namespace rfc {
SendEventToMaintenanceManager("MaintenanceMGR", MAINT_CRITICAL_UPDATE);
SendEventToMaintenanceManager("MaintenanceMGR", MAINT_REBOOT_REQUIRED);
}
+#endif /* !RDKC */
reqStatus = SUCCESS;
}
else
{
+#ifndef RDKC
RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR,"[%s][%d] RFC: Posting RFC Error Event to MaintenanceMGR\n", __FUNCTION__,__LINE__);
rfcObj->NotifyTelemetry2Count("SYST_INFO_RFC_Error");
SendEventToMaintenanceManager("MaintenanceMGR", MAINT_RFC_ERROR);
+#endif /* !RDKC */
+ }
+#endif
+
+#ifdef RDKC
+ /* Camera reboot scheduling — equivalent to:
+ * if [ "$RfcRebootCronNeeded" = "1" ]; then
+ * sh /lib/rdk/RfcRebootCronschedule.sh &
+ * fi */
+ if (rfcObj->getRfcRebootCronNeeded())
+ {
+ RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR,
+ "[%s][%d] RDKC: RfcRebootCronNeeded=true, scheduling reboot in maintenance window\n",
+ __FUNCTION__, __LINE__);
+ if (access("/lib/rdk/RfcRebootCronschedule.sh", F_OK) == 0)
+ {
+ v_secure_system("sh /lib/rdk/RfcRebootCronschedule.sh &");
+ }
+ else
+ {
+ RDK_LOG(RDK_LOG_WARN, LOG_RFCMGR,
+ "[%s][%d] RDKC: RfcRebootCronschedule.sh not found\n",
+ __FUNCTION__, __LINE__);
+ }
}
#endif
int post_process_result = RFCManagerPostProcess();
@@ -465,6 +598,10 @@ namespace rfc {
return reqStatus;
}
+ /**
+ * @brief Entry point — run the full RFC Xconf request cycle.
+ * @return SUCCESS (0) or FAILURE (-1).
+ */
int RFCManager ::RFCManagerProcessXconfRequest()
{
int ret_status = FAILURE;
@@ -474,6 +611,15 @@ namespace rfc {
return ret_status;
}
+ /**
+ * @brief Configure the periodic cron job for rfcMgr execution.
+ *
+ * Parses a five-field cron string, adjusts the schedule back by
+ * three minutes, replaces any existing rfcMgr/RFCbase cron entry,
+ * and applies the new crontab.
+ *
+ * @param[in] cron Five-field cron schedule string from DCM.
+ */
void rfc::RFCManager::manageCronJob(const std::string& cron)
{
std::string tempFile = "/tmp/cron_tab_tmp_file";
@@ -528,7 +674,12 @@ namespace rfc {
RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] Configuring cron job: %s\n", __FUNCTION__, __LINE__, adjustedCron.c_str());
+#ifdef RDKC
+ /* Camera cron entry omits log redirect (matches XHC1 shell behaviour) */
+ std::string cronEntry = adjustedCron + " /usr/bin/rfcMgr";
+#else
std::string cronEntry = adjustedCron + " /usr/bin/rfcMgr >> /rdklogs/logs/dcmrfc.log.0 2>&1";
+#endif
// Export existing crontab using popen to avoid redirection issues
std::string exportCmd = "crontab -l -c " + crontabPath + " 2>&1";
diff --git a/rfcMgr/rfc_manager.h b/rfcMgr/rfc_manager.h
index 4a1ccd95..431870fc 100644
--- a/rfcMgr/rfc_manager.h
+++ b/rfcMgr/rfc_manager.h
@@ -1,4 +1,7 @@
/**
+ * @file rfc_manager.h
+ * @brief RFC Manager — orchestrates the RFC feature-control lifecycle.
+ *
* If not stated otherwise in this file or this component's LICENSE
* file the following copyright and licenses apply:
*
@@ -15,14 +18,13 @@
* 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.
- **/
+ */
#ifndef RFC_MGR_H
#define RFC_MGR_H
-/*----------------------------------------------------------------------------*/
-/* Header File */
-/*----------------------------------------------------------------------------*/
+/** @addtogroup rfcMgr
+ * @{ */
#include "rfc_mgr_iarm.h"
#include "rfc_common.h"
#include
@@ -31,9 +33,8 @@
#include "maintenanceMGR.h"
#endif
-/*----------------------------------------------------------------------------*/
-/* Macros */
-/*----------------------------------------------------------------------------*/
+/** @name Macros
+ * @{ */
#define DEBUG_INI_FILE "/etc/debug.ini"
#if !defined(RDKB_SUPPORT)
#define OVERIDE_DEBUG_INI_FILE "/opt/debug.ini"
@@ -50,25 +51,26 @@
#include
#endif
+/** @} */ /* end Macros */
-/*----------------------------------------------------------------------------*/
-/* Namespace */
-/*----------------------------------------------------------------------------*/
namespace rfc {
-/*----------------------------------------------------------------------------*/
-/* Enum */
-/*----------------------------------------------------------------------------*/
+
+/**
+ * @brief Device network connectivity status.
+ */
enum DeviceStatus {
RFCMGR_DEVICE_ONLINE,
RFCMGR_DEVICE_OFFLINE
};
-/* Maintenance Manager Events */
-#define MAINT_RFC_ERROR 3
-#define MAINT_RFC_INPROGRESS 14
-#define MAINT_RFC_COMPLETE 2
-#define MAINT_CRITICAL_UPDATE 11
-#define MAINT_REBOOT_REQUIRED 12
+/** @name Maintenance Manager Event Codes
+ * @{ */
+#define MAINT_RFC_ERROR 3 /**< RFC processing encountered an error. */
+#define MAINT_RFC_INPROGRESS 14 /**< RFC processing is in progress. */
+#define MAINT_RFC_COMPLETE 2 /**< RFC processing completed successfully. */
+#define MAINT_CRITICAL_UPDATE 11 /**< A critical firmware update is available. */
+#define MAINT_REBOOT_REQUIRED 12 /**< A device reboot is required. */
+/** @} */
#if !defined(RDKB_SUPPORT)
#define RFC_MGR_IPTBLE_INIT_SCRIPT "/lib/rdk/iptables_init"
@@ -83,20 +85,47 @@ enum DeviceStatus {
bool isDnsResolve(const char *);
#endif
-/*----------------------------------------------------------------------------*/
-/* Class */
-/*----------------------------------------------------------------------------*/
+/**
+ * @class RFCManager
+ * @brief Manages the Remote Feature Control (RFC) lifecycle.
+ *
+ * Coordinates device-online checks, Xconf feature queries, post-processing,
+ * maintenance-manager event notifications, and periodic cron scheduling.
+ * This class is non-copyable.
+ */
class RFCManager {
public:
+ /** @brief Construct and initialise RDK Logger + IARM bus. */
RFCManager();
- // We do not allow this class to be copied !!
- RFCManager(const RFCManager &) = delete;
- RFCManager &operator=(const RFCManager &) = delete;
+
+ RFCManager(const RFCManager &) = delete; /**< Copy construction disabled. */
+ RFCManager &operator=(const RFCManager &) = delete; /**< Copy assignment disabled. */
+
+ /**
+ * @brief Entry point — run the full RFC Xconf request cycle.
+ * @return SUCCESS (0) on success, FAILURE (-1) on error.
+ */
int RFCManagerProcessXconfRequest();
+
+ /**
+ * @brief Check whether the device has IP connectivity.
+ * @return RFCMGR_DEVICE_ONLINE or RFCMGR_DEVICE_OFFLINE.
+ */
rfc::DeviceStatus CheckDeviceIsOnline(void);
+
#if !defined(RDKB_SUPPORT)
+ /**
+ * @brief Broadcast an IARM event to the Maintenance Manager.
+ * @param[in] cur_event_name IARM event owner name.
+ * @param[in] main_mgr_event Maintenance manager event code.
+ */
void SendEventToMaintenanceManager(const char *, unsigned int);
#endif
+
+ /**
+ * @brief Configure a periodic cron job for rfcMgr execution.
+ * @param[in] cron Five-field cron schedule string.
+ */
void manageCronJob(const std::string& cron);
#if defined(GTEST_ENABLE)
@@ -104,15 +133,17 @@ class RFCManager {
#else
private:
#endif
- void InitializeIARM(void);
- bool isConnectedToInternet();
- bool CheckIProuteConnectivity(const char *);
- std::string getErouterIPAddress();
- bool CheckIPConnectivity(void);
- bool IsIarmBusConnected();
- int RFCManagerProcess();
- int RFCManagerPostProcess();
+ void InitializeIARM(void); /**< Register on the IARM bus. */
+ bool isConnectedToInternet(); /**< Quick internet-reachability probe. */
+ bool CheckIProuteConnectivity(const char *); /**< Verify IP route via gateway file. */
+ std::string getErouterIPAddress(); /**< Retrieve the eRouter WAN address. */
+ bool CheckIPConnectivity(void); /**< Check eRouter IP availability. */
+ bool IsIarmBusConnected(); /**< Query IARM connection state. */
+ int RFCManagerProcess(); /**< Core RFC fetch-and-apply logic. */
+ int RFCManagerPostProcess(); /**< Post-processing scripts (iptables, etc.). */
}; // end of RFCManager Class
+
+/** @} */ /* end rfcMgr group */
} // end of namespace RFC
#endif
diff --git a/rfcMgr/rfc_mgr_iarm.h b/rfcMgr/rfc_mgr_iarm.h
index 0885e962..6f494d5d 100644
--- a/rfcMgr/rfc_mgr_iarm.h
+++ b/rfcMgr/rfc_mgr_iarm.h
@@ -1,4 +1,7 @@
/**
+ * @file rfc_mgr_iarm.h
+ * @brief IARM bus definitions and event constants for RFC Manager.
+ *
* If not stated otherwise in this file or this component's LICENSE
* file the following copyright and licenses apply:
*
@@ -15,7 +18,7 @@
* 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.
- **/
+ */
#ifndef RFC_MGR_IARM_H
#define RFC_MGR_IARM_H
diff --git a/rfcMgr/rfc_mgr_json.h b/rfcMgr/rfc_mgr_json.h
index 5c5fb881..c59cb54b 100644
--- a/rfcMgr/rfc_mgr_json.h
+++ b/rfcMgr/rfc_mgr_json.h
@@ -1,34 +1,41 @@
/**
-* If not stated otherwise in this file or this component's LICENSE
-* file the following copyright and licenses apply:
-*
-* Copyright 2023 RDK Management
-*
-* 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.
-**/
+ * @file rfc_mgr_json.h
+ * @brief JSON tag constants for Xconf feature-control request/response.
+ *
+ * If not stated otherwise in this file or this component's LICENSE
+ * file the following copyright and licenses apply:
+ *
+ * Copyright 2023 RDK Management
+ *
+ * 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.
+ */
#ifndef RFC_JSON_H
#define RFC_JSON_H
-/* Items inside XConf Feature Control Request JSON Object */
-#define FEATURE_CONTROL_TAG "featureControl"
-#define FEATURES_TAG "features"
-#define CONFIG_DATA_TAG "configData"
+/** @name Xconf JSON tags
+ * @{ */
+#define FEATURE_CONTROL_TAG "featureControl" /**< Top-level feature control object. */
+#define FEATURES_TAG "features" /**< Array of feature entries. */
+#define CONFIG_DATA_TAG "configData" /**< Per-feature configuration data. */
+/** @} */
-
-#define RFC_FEATURES_NAME_STR "name"
-#define RFC_FEATURES_ENABLE_STR "enable"
-#define RFC_FEATURE_INSTANCE_STR "featureInstance"
-#define RFC_FEATURE_EFF_IMMD_STR "effectiveImmediate"
+/** @name RFC Feature JSON keys
+ * @{ */
+#define RFC_FEATURES_NAME_STR "name" /**< Feature name. */
+#define RFC_FEATURES_ENABLE_STR "enable" /**< Feature enable flag. */
+#define RFC_FEATURE_INSTANCE_STR "featureInstance" /**< Feature instance identifier. */
+#define RFC_FEATURE_EFF_IMMD_STR "effectiveImmediate" /**< Effective-immediate flag. */
+/** @} */
#endif
diff --git a/rfcMgr/rfc_mgr_key.h b/rfcMgr/rfc_mgr_key.h
index 726bad65..d6d2dcc4 100644
--- a/rfcMgr/rfc_mgr_key.h
+++ b/rfcMgr/rfc_mgr_key.h
@@ -1,21 +1,24 @@
/**
-* If not stated otherwise in this file or this component's LICENSE
-* file the following copyright and licenses apply:
-*
-* Copyright 2023 RDK Management
-*
-* 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.
-**/
+ * @file rfc_mgr_key.h
+ * @brief TR181 parameter-name constants used by the RFC Manager.
+ *
+ * If not stated otherwise in this file or this component's LICENSE
+ * file the following copyright and licenses apply:
+ *
+ * Copyright 2023 RDK Management
+ *
+ * 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.
+ */
#ifndef RFC_KEY_H
#define RFC_KEY_H
diff --git a/rfcMgr/rfc_xconf_handler.cpp b/rfcMgr/rfc_xconf_handler.cpp
index 69138e39..59ca491f 100644
--- a/rfcMgr/rfc_xconf_handler.cpp
+++ b/rfcMgr/rfc_xconf_handler.cpp
@@ -1,21 +1,24 @@
-/*##############################################################################
- # If not stated otherwise in this file or this component's LICENSE file the
- # following copyright and licenses apply:
- #
- # Copyright 2024 RDK Management
- #
- # 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.
- ##############################################################################
+/**
+ * @file rfc_xconf_handler.cpp
+ * @brief RuntimeFeatureControlProcessor implementation — Xconf query, JSON
+ * response parsing, and RFC parameter application.
+ *
+ * If not stated otherwise in this file or this component's LICENSE file the
+ * following copyright and licenses apply:
+ *
+ * Copyright 2024 RDK Management
+ *
+ * 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.
*/
@@ -24,6 +27,7 @@
#include "rfcapi.h"
#include "rfc_mgr_json.h"
#include
+#include
#include "mtlsUtils.h"
#include
#include
@@ -85,10 +89,11 @@ int RuntimeFeatureControlProcessor:: InitializeRuntimeFeatureControlProcessor(vo
{
std::string rfc_file;
+#ifndef RDKC
int rc = GetBootstrapXconfUrl(_boot_strap_xconf_url);
if(rc != 0)
RDK_LOG(RDK_LOG_ERROR, LOG_RFCMGR, "[%s][%d] Failed to get XCONF_BS_URL from Bootstrap config.\n", __FUNCTION__, __LINE__);
-
+#endif
if(0 != initializeXconfHandler())
{
return FAILURE;
@@ -874,6 +879,21 @@ void RuntimeFeatureControlProcessor::rfcCheckAccountId()
void RuntimeFeatureControlProcessor::GetAccountID()
{
+#ifdef RDKC
+ /* Camera: read account ID (service number) from
+ * /opt/usr_config/service_number.txt. */
+ {
+ std::ifstream ifs("/opt/usr_config/service_number.txt");
+ if (ifs.is_open())
+ {
+ std::getline(ifs, _accountId);
+ ifs.close();
+ }
+ if (_accountId.empty())
+ _accountId = "Unknown";
+ RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "GetAccountID: Camera AccountID = %s\n", _accountId.c_str());
+ }
+#else
int i = 0;
char tempbuf[1024] = {0};
int szBufSize = sizeof(tempbuf);
@@ -906,6 +926,7 @@ void RuntimeFeatureControlProcessor::GetAccountID()
}
return;
+#endif
}
void RuntimeFeatureControlProcessor::GetRFCPartnerID()
@@ -1409,8 +1430,10 @@ void RuntimeFeatureControlProcessor::rfcStashRetrieveParams(void)
WDMP_STATUS status = set_RFCProperty(std::move(name), RFC_ACCOUNT_ID_KEY_STR, stashAccountId);
if (status != WDMP_SUCCESS)
{
-#if !defined(RDKB_SUPPORT)
+#if !defined(RDKB_SUPPORT) && !defined(RDKC)
RDK_LOG(RDK_LOG_ERROR, LOG_RFCMGR, "[%s][%d] Failed to restore AccountID: %s\n", __FUNCTION__, __LINE__, getRFCErrorString(status));
+#else
+ RDK_LOG(RDK_LOG_ERROR, LOG_RFCMGR, "[%s][%d] Failed to restore AccountID: status=%d\n", __FUNCTION__, __LINE__, status);
#endif
}
else
@@ -1448,7 +1471,7 @@ void RuntimeFeatureControlProcessor::updateHashInDB(std::string configSetHash)
{
RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] Config Set Hash = %s\n", __FUNCTION__, __LINE__, configSetHash.c_str());
-#if !defined(RDKB_SUPPORT)
+#if !defined(RDKB_SUPPORT) && !defined(RDKC)
std::string ConfigSetHashName = "ConfigSetHash";
std::string ConfigSetHash_key = "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Control.ConfigSetHash";
set_RFCProperty(std::move(ConfigSetHashName), std::move(ConfigSetHash_key), configSetHash);
@@ -1476,7 +1499,7 @@ void RuntimeFeatureControlProcessor::updateHashInDB(std::string configSetHash)
void RuntimeFeatureControlProcessor::updateTimeInDB(std::string timestampString)
{
-#if !defined(RDKB_SUPPORT)
+#if !defined(RDKB_SUPPORT) && !defined(RDKC)
std::string ConfigSetTimeName = "ConfigSetTime";
std::string ConfigSetTime_Key = "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Control.ConfigSetTime";
set_RFCProperty(std::move(ConfigSetTimeName), std::move(ConfigSetTime_Key), timestampString);
@@ -1683,8 +1706,7 @@ int RuntimeFeatureControlProcessor::ProcessRuntimeFeatureControlReq()
#endif
RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] COMPLETED RFC PASS\n", __FUNCTION__, __LINE__);
NotifyTelemetry2Count("SYST_INFO_RFC_Complete");
- set_RFCProperty(XCONF_SELECTOR_NAME, XCONF_SELECTOR_KEY_STR, rfcSelectOpt.c_str());
- set_RFCProperty(XCONF_URL_TR181_NAME, XCONF_URL_KEY_STR, _xconf_server_url.c_str());
+ StoreXconfEndpointMetadata();
break;
}
@@ -1740,6 +1762,14 @@ void EncodeString(const std::string& key, const std::string& value, std::strings
}
}
+void RuntimeFeatureControlProcessor::StoreXconfEndpointMetadata()
+{
+ RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] Storing XconfSelector=%s and XconfUrl\n",
+ __FUNCTION__, __LINE__, rfcSelectOpt.c_str());
+ set_RFCProperty(XCONF_SELECTOR_NAME, XCONF_SELECTOR_KEY_STR, rfcSelectOpt.c_str());
+ set_RFCProperty(XCONF_URL_TR181_NAME, XCONF_URL_KEY_STR, _xconf_server_url.c_str());
+}
+
std::stringstream RuntimeFeatureControlProcessor::CreateXconfHTTPUrl()
{
std::stringstream url;
@@ -1834,6 +1864,11 @@ void RuntimeFeatureControlProcessor::GetStoredHashAndTime( std ::string &valueHa
{
RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] Last Image version %s and current image version %s are same \n", __FUNCTION__, __LINE__, _last_firmware.c_str(), _firmware_version.c_str());
/*Both the input strings are equal.*/
+#ifdef RDKC
+ /* Camera (XHC1) always retrieves hash/time from RAM files —
+ * it never checks XconfSelector slot. */
+ RetrieveHashAndTimeFromPreviousDataSet(valueHash, valueTime);
+#else
if((rfc_state == Init) && (isXconfSelectorSlotProd() == false))
{
RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] Received XconfSelector as Non Prod for RFC state as INIT \n", __FUNCTION__, __LINE__);
@@ -1844,6 +1879,7 @@ void RuntimeFeatureControlProcessor::GetStoredHashAndTime( std ::string &valueHa
{
RetrieveHashAndTimeFromPreviousDataSet(valueHash, valueTime);
}
+#endif
}
else
{
@@ -2038,6 +2074,20 @@ int RuntimeFeatureControlProcessor::DownloadRuntimeFeatutres(DownloadData *pDwnL
RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] RFC Xconf Connection Response cURL Return : %d HTTP Code : %d\n",__FUNCTION__, __LINE__, curl_ret_code, httpCode);
} while (rdkcertselector_setCurlStatus(thisCertSel, curl_ret_code, file_dwnl.url) == TRY_ANOTHER);
+#elif defined(RDKC)
+ {
+ MtlsAuth_t sec;
+ memset(&sec, '\0', sizeof(MtlsAuth_t));
+ int ret = getMtlscert(&sec);
+ if (ret == MTLS_SUCCESS) {
+ RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] RDKC mTLS creds fetched successfully\n", __FUNCTION__, __LINE__);
+ curl_ret_code = ExecuteRequest(&file_dwnl, &sec, &httpCode);
+ } else {
+ RDK_LOG(RDK_LOG_WARN, LOG_RFCMGR, "[%s][%d] RDKC mTLS creds not available, proceeding without mTLS\n", __FUNCTION__, __LINE__);
+ curl_ret_code = ExecuteRequest(&file_dwnl, NULL, &httpCode);
+ }
+ }
+ RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] RFC Xconf Connection Response cURL Return : %d HTTP Code : %d\n",__FUNCTION__, __LINE__, curl_ret_code, httpCode);
#else
RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] Executing request without cert selector\n", __FUNCTION__, __LINE__);
curl_ret_code = ExecuteRequest(&file_dwnl, NULL, &httpCode);
@@ -2453,10 +2503,50 @@ void RuntimeFeatureControlProcessor::processXconfResponseConfigDataPart(JSON *fe
RDK_LOG(RDK_LOG_ERROR, LOG_RFCMGR, "[%s][%d] Config Data Map is Empty\n", __FUNCTION__, __LINE__);
return;
}
-#if !defined(RDKB_SUPPORT)
+#if !defined(RDKB_SUPPORT) && !defined(RDKC)
clearDB();
#endif
+#ifdef RDKC
+ /* Build a set of config param names whose parent feature has
+ * effectiveImmediate=true. Used later for camera reboot evaluation. */
+ _effectiveImmediateParams.clear();
+ _rfcRebootCronNeeded = false;
+ {
+ int nf = GetJsonArraySize(features);
+ for (int idx = 0; idx < nf; idx++)
+ {
+ JSON *feat = GetJsonArrayItem(features, idx);
+ if (!feat) continue;
+ char effImmStr[] = RFC_FEATURE_EFF_IMMD_STR;
+ char buf[6] = {0};
+ int sz = GetJsonVal(feat, effImmStr, buf, sizeof(buf));
+ if (sz && (strcasecmp(buf, "true") == 0 || strcmp(buf, "1") == 0))
+ {
+ char cdStr[] = "configData";
+ JSON *cd = GetJsonItem(feat, cdStr);
+ if (cd)
+ {
+ JSON *ch = cd->child;
+ while (ch)
+ {
+ if (ch->string)
+ {
+ std::string k = ch->string;
+ RemoveSubstring(k, "tr181.");
+ _effectiveImmediateParams.insert(k);
+ }
+ ch = ch->next;
+ }
+ }
+ }
+ }
+ RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR,
+ "[%s][%d] RDKC: %zu params with effectiveImmediate=true\n",
+ __FUNCTION__, __LINE__, _effectiveImmediateParams.size());
+ }
+#endif
+
std::string newKey;
std::string newValue;
std::string currentValue;
@@ -2478,7 +2568,7 @@ void RuntimeFeatureControlProcessor::processXconfResponseConfigDataPart(JSON *fe
}
else
{
-#if !defined(RDKB_SUPPORT)
+#if !defined(RDKB_SUPPORT) && !defined(RDKC)
if (newValue.empty())
{
RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR, "[%s][%d] EMPTY value for %s is rejected\n", __FUNCTION__, __LINE__, newKey.c_str());
@@ -2499,7 +2589,7 @@ void RuntimeFeatureControlProcessor::processXconfResponseConfigDataPart(JSON *fe
WDMP_STATUS status = set_RFCProperty(name, newKey, newValue);
if (status != WDMP_SUCCESS)
{
-#if !defined(RDKB_SUPPORT)
+#if !defined(RDKB_SUPPORT) && !defined(RDKC)
RDK_LOG(RDK_LOG_DEBUG, LOG_RFCMGR,"[%s][%d] SET failed for key=%s with status=%s\n", __FUNCTION__, __LINE__, newKey.c_str(), getRFCErrorString(status));
#else
RDK_LOG(RDK_LOG_DEBUG, LOG_RFCMGR,"[%s][%d] SET failed for key=%s with status=%d\n", __FUNCTION__, __LINE__, newKey.c_str(), status);
@@ -2530,11 +2620,43 @@ void RuntimeFeatureControlProcessor::processXconfResponseConfigDataPart(JSON *fe
{
NotifyTelemetry2Count("SYST_INFO_ACCID_set");
}
-#if !defined(RDKB_SUPPORT)
+#if !defined(RDKB_SUPPORT) && !defined(RDKC)
if (isMaintenanceEnabled())
{
isRebootRequired = true;
}
+#endif
+#ifdef RDKC
+ /* Camera reboot evaluation:
+ * Schedule reboot if effectiveImmediate is true for this param's
+ * parent feature, the device is provisioned, and the param
+ * is not AccountID or MD5AccountHash. */
+ {
+ bool isEffImm = (_effectiveImmediateParams.count(newKey) > 0);
+ if (isEffImm)
+ {
+ char provBuf[16] = {0};
+ int provRet = getDevicePropertyData("RDKC_DEVICE_PROVISION_STATUS", provBuf, sizeof(provBuf));
+ bool provisioned = (provRet == 1 && strcmp(provBuf, "1") == 0);
+ if (provisioned)
+ {
+ std::string accountHashKey = "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.Feature.MD5AccountHash";
+ if (newKey != RFC_ACCOUNT_ID_KEY_STR && newKey != accountHashKey)
+ {
+ _rfcRebootCronNeeded = true;
+ RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR,
+ "[%s][%d] RDKC: Enabling RfcRebootCronNeeded for %s old=%s new=%s\n",
+ __FUNCTION__, __LINE__, newKey.c_str(), currentValue.c_str(), newValue.c_str());
+ }
+ else
+ {
+ RDK_LOG(RDK_LOG_INFO, LOG_RFCMGR,
+ "[%s][%d] RDKC: Skip scheduling reboot for Account Id/Hash change\n",
+ __FUNCTION__, __LINE__);
+ }
+ }
+ }
+ }
#endif
}
else
@@ -2549,7 +2671,7 @@ void RuntimeFeatureControlProcessor::processXconfResponseConfigDataPart(JSON *fe
}
updateTR181File(TR181_FILE_LIST, paramList);
-#if !defined(RDKB_SUPPORT)
+#if !defined(RDKB_SUPPORT) && !defined(RDKC)
clearDBEnd();
#endif
}
@@ -2735,6 +2857,65 @@ WDMP_STATUS RuntimeFeatureControlProcessor::set_RFCProperty(std::string name, st
// Close the rbus connection
rbus_close(handle);
+ return status;
+#elif defined(RDKC)
+ /* Camera (XHC1) writes parameters directly to the tr181store.ini
+ * flat file. Format: key=value (one per line) */
+ (void)name;
+ WDMP_STATUS status = WDMP_FAILURE;
+
+ std::string storePath = TR181STOREFILE;
+ std::ifstream inFile(storePath);
+ std::vector lines;
+ bool found = false;
+ std::string targetLine = key + "=" + value;
+
+ if (inFile.is_open())
+ {
+ std::string line;
+ while (std::getline(inFile, line))
+ {
+ size_t eq = line.find('=');
+ if (eq != std::string::npos)
+ {
+ std::string existingKey = line.substr(0, eq);
+ if (existingKey == key)
+ {
+ lines.push_back(targetLine);
+ found = true;
+ continue;
+ }
+ }
+ lines.push_back(line);
+ }
+ inFile.close();
+ }
+
+ if (!found)
+ {
+ lines.push_back(targetLine);
+ }
+
+ std::ofstream outFile(storePath, std::ios::trunc);
+ if (outFile.is_open())
+ {
+ for (const auto &l : lines)
+ {
+ outFile << l << "\n";
+ }
+ outFile.close();
+ RDK_LOG(RDK_LOG_DEBUG, LOG_RFCMGR,
+ "[%s][%d] RDKC: set_RFCProperty key=%s value=%s\n",
+ __FUNCTION__, __LINE__, key.c_str(), value.c_str());
+ status = WDMP_SUCCESS;
+ }
+ else
+ {
+ RDK_LOG(RDK_LOG_ERROR, LOG_RFCMGR,
+ "[%s][%d] RDKC: Failed to open %s for writing\n",
+ __FUNCTION__, __LINE__, storePath.c_str());
+ }
+
return status;
#else
RFC_ParamData_t param;
@@ -2808,7 +2989,11 @@ void RuntimeFeatureControlProcessor::NotifyTelemetry2RemoteFeatures(const char *
if (rfcstatus == "STAGING") {
v_secure_system("/usr/bin/telemetry2_0_client rfc_staging_split %s", line.c_str());
} else {
+#ifndef RDKC
v_secure_system("/usr/bin/telemetry2_0_client rfc_split %s", line.c_str());
+#else
+ RDK_LOG(RDK_LOG_DEBUG, LOG_RFCMGR, "[%s][%d] RDKC: Skipping rfc_split telemetry notification\n", __FUNCTION__, __LINE__);
+#endif
}
}
diff --git a/rfcMgr/rfc_xconf_handler.h b/rfcMgr/rfc_xconf_handler.h
index 9c0acfe1..90a0bd35 100644
--- a/rfcMgr/rfc_xconf_handler.h
+++ b/rfcMgr/rfc_xconf_handler.h
@@ -1,21 +1,24 @@
/**
-* If not stated otherwise in this file or this component's LICENSE
-* file the following copyright and licenses apply:
-*
-* Copyright 2023 RDK Management
-*
-* 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.
-**/
+ * @file rfc_xconf_handler.h
+ * @brief RuntimeFeatureControlProcessor — Xconf query, JSON parsing, and RFC application.
+ *
+ * If not stated otherwise in this file or this component's LICENSE
+ * file the following copyright and licenses apply:
+ *
+ * Copyright 2023 RDK Management
+ *
+ * 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.
+ */
#ifndef RFC_XCONF_HANDLER_H
#define RFC_XCONF_HANDLER_H
@@ -25,6 +28,10 @@
#include "rfc_mgr_key.h"
#include "rfc_mgr_json.h"
+#ifdef RDKC
+#include
+#endif
+
#if defined(GTEST_ENABLE)
#include
#endif
@@ -38,6 +45,10 @@ extern "C" {
#include
#include
+#ifdef __cplusplus
+}
+#endif
+
#ifndef GTEST_ENABLE
#define BOOTSTRAP_FILE "/opt/secure/RFC/bootstrap.ini"
#define PARTNER_ID_FILE "/opt/www/authService/partnerId3.dat"
@@ -76,71 +87,157 @@ extern "C" {
#define RFC_SYNC_DONE "/tmp/.rfcSyncDone"
+/**
+ * @brief RFC state-machine phases.
+ */
typedef enum
{
- Invalid,
- Init,
- Local,
- Redo,
- Redo_With_Valid_Data,
- Finish
+ Invalid, /**< Not initialised. */
+ Init, /**< Initial request. */
+ Local, /**< Local override. */
+ Redo, /**< Re-attempt needed. */
+ Redo_With_Valid_Data, /**< Re-attempt with updated data. */
+ Finish /**< Processing complete. */
} RfcState;
-#if defined(RDKB_SUPPORT)
+#if defined(RDKB_SUPPORT) || defined(RDKC)
+/**
+ * @brief Minimal WDMP status codes for RDKB / RDKC builds.
+ */
typedef enum {
- WDMP_SUCCESS = 0,
- WDMP_FAILURE,
+ WDMP_SUCCESS = 0, /**< Operation succeeded. */
+ WDMP_FAILURE, /**< Operation failed. */
} WDMP_STATUS;
#endif
+/**
+ * @class RuntimeFeatureControlProcessor
+ * @brief Queries Xconf, parses feature JSON, and applies RFC parameters.
+ *
+ * Inherits device-identity primitives from XconfHandler. On RDKC builds,
+ * virtual methods allow the RdkcRuntimeFeatureControlProcessor subclass
+ * to override URL building, hash/time storage, and endpoint metadata.
+ *
+ * Non-copyable.
+ */
class RuntimeFeatureControlProcessor : public xconf::XconfHandler
{
public :
+ /** @brief Construct with default state (reboot not required). */
RuntimeFeatureControlProcessor()
{
isRebootRequired = false;
}
- // We do not allow this class to be copied !!
- RuntimeFeatureControlProcessor(const RuntimeFeatureControlProcessor&) = delete;
+#ifdef RDKC
+ virtual ~RuntimeFeatureControlProcessor() = default;
+#else
+ ~RuntimeFeatureControlProcessor() = default;
+#endif
+ RuntimeFeatureControlProcessor(const RuntimeFeatureControlProcessor&) = delete; /**< Copy disabled. */
+ /**
+ * @brief Initialise the RFC processor (load device identity, server URL, etc.).
+ * @return SUCCESS (0) or FAILURE (-1).
+ */
int InitializeRuntimeFeatureControlProcessor(void);
+
+ /**
+ * @brief Execute the full Xconf feature-control request/response cycle.
+ * @return SUCCESS (0) or FAILURE (-1).
+ */
int ProcessRuntimeFeatureControlReq();
+
+ /**
+ * @brief Check whether an Xconf response flagged a required reboot.
+ * @retval true Reboot needed.
+ * @retval false No reboot.
+ */
bool getRebootRequirement();
+#ifdef RDKC
+ /** @brief On RDKC, query if the reboot cron job should be scheduled. */
+ bool getRfcRebootCronNeeded() const { return _rfcRebootCronNeeded; }
+#endif
+ /** @brief Send a telemetry-2 count marker. */
void NotifyTelemetry2Count(std ::string markerName);
+ /** @brief Send a telemetry-2 key/value marker. */
void NotifyTelemetry2Value(std ::string markerName, std ::string value);
- private:
+#ifdef RDKC
+ protected:
+#else
+ private:
+#endif
+ /* ---------------------------------------------------------------
+ * Members and methods accessible to platform-specific subclasses.
+ * Subclasses (e.g. RdkcRuntimeFeatureControlProcessor) override
+ * the virtual methods below to handle device-specific behaviour
+ * without duplicating the shared RFC request/response logic.
+ * --------------------------------------------------------------- */
+
+ std::string _accountId; /**< Device Account ID. */
+ std::string _experience; /**< Device experience string. */
+ std::string _osclass; /**< OS class identifier. */
+ std::string _xconf_server_url; /**< Active Xconf server URL. */
+ std::string rfcSelectOpt; /**< Xconf selector option. */
+ std::string bkup_hash; /**< Backup configSetHash. */
+#ifdef RDKC
+ bool _rfcRebootCronNeeded = false; /**< RDKC: schedule reboot cron. */
+ std::set _effectiveImmediateParams; /**< RDKC: params with effectiveImmediate=true. */
+#endif
+
+ /** Build the full HTTP query URL sent to the Xconf server.
+ * Override to change device-specific query parameters. */
+#ifdef RDKC
+ virtual std::stringstream CreateXconfHTTPUrl();
+#else
+ std::stringstream CreateXconfHTTPUrl();
+#endif
+
+ /** Read configSetHash / configSetTime from the backing store.
+ * Override to use a different storage medium (e.g. RAM files). */
+#ifdef RDKC
+ virtual void RetrieveHashAndTimeFromPreviousDataSet(std::string &valueHash,
+ std::string &valueTime);
+#else
+ void RetrieveHashAndTimeFromPreviousDataSet(std::string &valueHash,
+ std::string &valueTime);
+#endif
+
+ /** Persist XconfSelector and XconfUrl after a successful sync.
+ * Override as a no-op for platforms that must not write these. */
+#ifdef RDKC
+ virtual void StoreXconfEndpointMetadata();
+#else
+ void StoreXconfEndpointMetadata();
+#endif
+
+ private:
+ /** @brief Per-feature RFC object parsed from Xconf JSON. */
typedef struct RuntimeFeatureControlObject {
- std::string name;
- std::string featureInstance;
- bool enable;
- bool effectiveImmediate;
+ std::string name; /**< Feature name. */
+ std::string featureInstance; /**< Feature instance ID. */
+ bool enable; /**< Feature enable flag. */
+ bool effectiveImmediate; /**< Apply without reboot. */
}RuntimeFeatureControlObject;
- std::map _RFCKeyAndValueMap;
- RfcState rfc_state; /* RFC State */
- std::string _last_firmware; /* Last Firmware Version */
- std::string _xconf_server_url; /* Xconf server URL */
- std::string _boot_strap_xconf_url; /* Bootstrap XConf URL */
- std::string _valid_accountId; /* Valid Account ID*/
- std::string _valid_partnerId; /* Valid Partner ID*/
- std::string _accountId; /* Device Account ID */
- std::string stashAccountId;
- std::string _partnerId; /* Device Partner ID */
- std::string _bkPartnerId; /* Device Partner ID */
- std::string _accountMgmt;
- std::string _serialNumber;
- std::string _extendermacAddress;
- std::string _experience;
- std::string _osclass;
- bool isRebootRequired;
- std::string bkup_hash;
- bool _is_first_request = false;
- bool _url_validation_in_progress = false;
- std::string rfcSelectOpt;
- std:: string rfcSelectorSlot;
+ std::map _RFCKeyAndValueMap; /**< Parsed config key-value map. */
+ RfcState rfc_state; /**< Current RFC state-machine phase. */
+ std::string _last_firmware; /**< Last firmware version processed. */
+ std::string _boot_strap_xconf_url; /**< Bootstrap Xconf URL. */
+ std::string _valid_accountId; /**< Validated account ID. */
+ std::string _valid_partnerId; /**< Validated partner ID. */
+ std::string stashAccountId; /**< Stashed account ID for comparison. */
+ std::string _partnerId; /**< Device partner ID. */
+ std::string _bkPartnerId; /**< Backup partner ID. */
+ std::string _accountMgmt; /**< Account management flag. */
+ std::string _serialNumber; /**< Device serial number. */
+ std::string _extendermacAddress; /**< Extender MAC address. */
+ bool isRebootRequired; /**< True if Xconf requested reboot. */
+ bool _is_first_request = false; /**< First request after FW upgrade. */
+ bool _url_validation_in_progress = false; /**< URL validation in flight. */
+ std:: string rfcSelectorSlot; /**< Xconf selector slot (prod/ci). */
bool checkWhoamiSupport();
bool IsNewFirmwareFirstRequest(void);
@@ -149,7 +246,7 @@ class RuntimeFeatureControlProcessor : public xconf::XconfHandler
void GetRFCPartnerID();
bool isMaintenanceEnabled();
void GetOsClass( void );
- void GetSerialNumber( void );
+ void GetSerialNumber( void );
void GetExtenderMacAddress( void );
int GetExperience( void );
int GetServURL(const char *rfcPropertiesFile);
@@ -172,9 +269,7 @@ class RuntimeFeatureControlProcessor : public xconf::XconfHandler
void rfcStashRetrieveParams(void);
- std::stringstream CreateXconfHTTPUrl();
void GetStoredHashAndTime( std ::string &valueHash, std::string &valueTime );
- void RetrieveHashAndTimeFromPreviousDataSet(std ::string &valueHash, std::string &valueTime);
void InitDownloadData(DownloadData *pDwnData);
int DownloadRuntimeFeatutres(DownloadData *pDwnLoc, DownloadData *pHeaderDwnLoc, const std::string& url_str);
void NotifyTelemetry2ErrorCode(int CurlReturn);
@@ -313,7 +408,4 @@ class RuntimeFeatureControlProcessor : public xconf::XconfHandler
#endif
};
-#ifdef __cplusplus
-}
-#endif
#endif
diff --git a/rfcMgr/xconf_handler.cpp b/rfcMgr/xconf_handler.cpp
index 7d990d20..ce0f8258 100644
--- a/rfcMgr/xconf_handler.cpp
+++ b/rfcMgr/xconf_handler.cpp
@@ -1,25 +1,32 @@
-/*##############################################################################
- # If not stated otherwise in this file or this component's LICENSE file the
- # following copyright and licenses apply:
- #
- # Copyright 2024 RDK Management
- #
- # 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.
- ##############################################################################
+/**
+ * @file xconf_handler.cpp
+ * @brief XconfHandler implementation — device identity collection and HTTP downloads.
+ *
+ * If not stated otherwise in this file or this component's LICENSE file the
+ * following copyright and licenses apply:
+ *
+ * Copyright 2024 RDK Management
+ *
+ * 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.
*/
#include "xconf_handler.h"
+#if defined(RDKC)
+#include "rdk_debug.h"
+#define LOG_RFCMGR "LOG.RDK.RFCMGR"
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
@@ -59,6 +66,24 @@ int XconfHandler:: initializeXconfHandler()
tmpbuf[sizeof(tmpbuf) - 1] = '\0';
len = strlen(tmpbuf);
}
+#elif defined(RDKC)
+ /* Camera: get MAC address via MFR API (mfrApi_test 3 9).
+ * This matches the shell's getEstbMacAddress() for XHC1. */
+ {
+ FILE *fp = popen("mfrApi_test 3 9", "r");
+ if (fp)
+ {
+ if (fgets(tmpbuf, sizeof(tmpbuf), fp))
+ {
+ size_t mlen = strlen(tmpbuf);
+ if (mlen > 0 && tmpbuf[mlen - 1] == '\n') tmpbuf[mlen - 1] = '\0';
+ len = strlen(tmpbuf);
+ }
+ pclose(fp);
+ }
+ if (len == 0)
+ RDK_LOG(RDK_LOG_ERROR, LOG_RFCMGR, "[%s][%d] Camera: mfrApi_test failed to get MAC\n", __FUNCTION__, __LINE__);
+ }
#else
len = GetEstbMac(tmpbuf, sizeof(tmpbuf));
#endif
@@ -102,7 +127,7 @@ int XconfHandler:: initializeXconfHandler()
{
_ecm_mac_address = tmpbuf;
}
-#else
+#elif !defined(RDKC)
memset(tmpbuf, '\0', sizeof(tmpbuf));
len = GetMFRName( tmpbuf, sizeof(tmpbuf) );
if( len )
@@ -110,6 +135,25 @@ int XconfHandler:: initializeXconfHandler()
_manufacturer = tmpbuf;
}
#endif
+#ifdef RDKC
+ /* Camera: read partner ID from /opt/usr_config/partnerid.txt */
+ {
+ FILE *fp = fopen("/opt/usr_config/partnerid.txt", "r");
+ if (fp)
+ {
+ memset(tmpbuf, '\0', sizeof(tmpbuf));
+ if (fgets(tmpbuf, sizeof(tmpbuf), fp))
+ {
+ size_t plen = strlen(tmpbuf);
+ if (plen > 0 && tmpbuf[plen - 1] == '\n') tmpbuf[plen - 1] = '\0';
+ _partner_id = tmpbuf;
+ }
+ fclose(fp);
+ }
+ if (_partner_id.empty())
+ _partner_id = "Unknown";
+ }
+#else
memset(tmpbuf, '\0', sizeof(tmpbuf));
len = GetPartnerId( tmpbuf, sizeof(tmpbuf) );
if( len )
@@ -118,8 +162,9 @@ int XconfHandler:: initializeXconfHandler()
}
else
{
- _partner_id="Unkown";
+ _partner_id="Unknown";
}
+#endif
return 0;
}
diff --git a/rfcMgr/xconf_handler.h b/rfcMgr/xconf_handler.h
index f7e52ac2..7dd753cb 100644
--- a/rfcMgr/xconf_handler.h
+++ b/rfcMgr/xconf_handler.h
@@ -1,21 +1,24 @@
/**
-* If not stated otherwise in this file or this component's LICENSE
-* file the following copyright and licenses apply:
-*
-* Copyright 2023 RDK Management
-*
-* 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.
-**/
+ * @file xconf_handler.h
+ * @brief Base Xconf HTTP handler — device identity and download primitives.
+ *
+ * If not stated otherwise in this file or this component's LICENSE
+ * file the following copyright and licenses apply:
+ *
+ * Copyright 2023 RDK Management
+ *
+ * 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.
+ */
#ifndef XCONF_HANDLER_H
#define XCONF_HANDLER_H
@@ -34,28 +37,50 @@ extern "C" {
#include
namespace xconf {
+
+ /**
+ * @class XconfHandler
+ * @brief Collects device identity (MAC, FW version, model, etc.) and
+ * provides an HTTP download helper for Xconf communication.
+ *
+ * Non-copyable. Derived classes (RuntimeFeatureControlProcessor and its
+ * platform overrides) build on these primitives.
+ */
class XconfHandler {
public :
+ /** @brief Default constructor. */
XconfHandler(){ }
+
+ /**
+ * @brief Populate all device-identity fields.
+ * @return 0 on success.
+ */
int initializeXconfHandler(void);
-
- // We do not allow this class to be copied !!
- XconfHandler(const XconfHandler&) = delete;
- XconfHandler& operator=(const XconfHandler&) = delete;
+
+ XconfHandler(const XconfHandler&) = delete; /**< Copy disabled. */
+ XconfHandler& operator=(const XconfHandler&) = delete; /**< Assignment disabled. */
#if defined(GTEST_ENABLE)
public:
#else
protected :
#endif
- std::string _estb_mac_address; /* Device Mac Address*/
- std::string _firmware_version; /* Device Frimware version */
- BUILDTYPE _ebuild_type; /* Device Build Type */
- std::string _build_type_str;
- std::string _model_number; /* Device Model Number */
- std::string _manufacturer; /* Device Manufacturer */
- std::string _ecm_mac_address; /* Cable Modem Mac Address*/
- std::string _partner_id; /* Device Partner ID */
+ std::string _estb_mac_address; /**< Device eSTB MAC address. */
+ std::string _firmware_version; /**< Current firmware version. */
+ BUILDTYPE _ebuild_type; /**< Build type enum (DEV/VBN/PROD). */
+ std::string _build_type_str; /**< Build type as a string. */
+ std::string _model_number; /**< Device model number. */
+ std::string _manufacturer; /**< Device manufacturer name. */
+ std::string _ecm_mac_address; /**< Cable-modem MAC address. */
+ std::string _partner_id; /**< Syndication partner ID. */
+
+ /**
+ * @brief Execute an HTTP file download via cURL.
+ * @param[in,out] file_dwnl Download descriptor (URL, output buffer).
+ * @param[in] security mTLS certificate bundle.
+ * @param[out] httpCode Resulting HTTP status code.
+ * @return cURL return code (0 = OK).
+ */
int ExecuteRequest(FileDwnl_t *file_dwnl, MtlsAuth_t *security, int *httpCode);
};
}
diff --git a/rfcapi/Makefile.am b/rfcapi/Makefile.am
index 69d93831..4011b384 100644
--- a/rfcapi/Makefile.am
+++ b/rfcapi/Makefile.am
@@ -24,8 +24,13 @@ librfcapi_la_SOURCES = rfcapi.cpp
librfcapi_la_includedir = $(includedir)
librfcapi_la_include_HEADERS = rfcapi.h
if ENABLE_RDKC
-librfcapi_la_CPPFLAGS = "-std=c++11" -DLINUX -fPIC -g -O2 -Wall -DRDKC -I${top_srcdir}/../rdklogger/include/
-librfcapi_la_LIBADD = -L${top_srcdir}/../rdklogger/src/.libs -lrdkloggers
+if ENABLE_XCAM2
+librfcapi_la_CPPFLAGS = "-std=c++11" -DLINUX -fPIC -g -O2 -Wall -DRDKC -I${RDK_FSROOT_PATH}/usr/include/
+librfcapi_la_LIBADD = -L${RDK_FSROOT_PATH}/usr/lib/ -lrdkloggers
+else
+librfcapi_la_CPPFLAGS = "-std=c++11" -DLINUX -fPIC -g -O2 -Wall -DRDKC -I${STAGING_DIR_TARGET}/usr/include/
+librfcapi_la_LIBADD = -L${STAGING_DIR_TARGET}/usr/lib/ -lrdkloggers
+endif
else
librfcapi_la_CPPFLAGS = "-std=c++11" -DLINUX -fPIC -g -O2 -Wall -I=/usr/include/cjson -I=/usr/include/wdmp-c $(IARMBUS_EVENT_FLAG)
librfcapi_la_LIBADD = -lcurl -lcjson -lrdkloggers
diff --git a/rfcapi/rfcapi.cpp b/rfcapi/rfcapi.cpp
index 382feaaa..ae666700 100644
--- a/rfcapi/rfcapi.cpp
+++ b/rfcapi/rfcapi.cpp
@@ -1,4 +1,7 @@
-/*
+/**
+ * @file rfcapi.cpp
+ * @brief RFC parameter API implementation — get/set via hostif, rbus, or flat files.
+ *
* If not stated otherwise in this file or this component's LICENSE file the
* following copyright and licenses apply:
*
@@ -15,15 +18,16 @@
* 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.
-*/
+ */
#include
#include
-#ifndef RDKC
+#if !defined(RDKB_SUPPORT) && !defined(RDKC)
#include
#include "cJSON.h"
#endif
#include
+#include
#include
#include
#include
@@ -31,7 +35,7 @@
#include "rdk_debug.h"
using namespace std;
-#define LOG_RFCAPI "LOG.RDK.RFCAPI"
+#define LOG_RFCAPI "LOG.RDK.RFCAPI" /**< RDK Logger module name for rfcapi. */
#define TR181_RFC_PREFIX "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC"
#define BOOTSTRAP_FILE "/opt/secure/RFC/bootstrap.ini"
#define RFCDEFAULTS_FILE "/tmp/rfcdefaults.ini"
@@ -65,6 +69,11 @@ static string prefix()
}
#endif
+/**
+ * @brief Merge per-feature rfcdefaults ini files into a single combined file.
+ * @retval true Merge succeeded.
+ * @retval false /etc/rfcdefaults/ could not be opened.
+ */
bool init_rfcdefaults()
{
DIR *dir;
@@ -93,86 +102,14 @@ bool init_rfcdefaults()
return true;
}
-#if defined(RDKC)
-int getValue(const char* fileName, const char* pcParameterName, RFC_ParamData_t *pstParam)
-{
- ifstream ifs_rfcVar(fileName);
- if (!ifs_rfcVar.is_open())
- {
- RDK_LOG (RDK_LOG_ERROR, LOG_RFCAPI, "%s: Trying to open a non-existent file %s \n", __FUNCTION__, fileName);
- if ( strcmp(fileName, RFCDEFAULTS_FILE) == 0 && init_rfcdefaults() )
- {
- RDK_LOG(RDK_LOG_DEBUG, LOG_RFCAPI, "Trying to open %s after newly creating\n", RFCDEFAULTS_FILE);
- ifs_rfcVar.open(RFCDEFAULTS_FILE, ifstream::in);
- if (!ifs_rfcVar.is_open())
- return FAILURE;
- }
- else
- return FAILURE;
- }
- {
- string line;
- while (getline(ifs_rfcVar, line))
- {
- line=line.substr(line.find_first_of(" \t")+1);//Remove any export word that maybe before the key(for rfcVariable.ini)
- size_t splitterPos = line.find('=');
- if (splitterPos < line.length())
- {
- string key = line.substr(0, splitterPos);
- if ( !key.compare(pcParameterName) )
- {
- ifs_rfcVar.close();
- string value = line.substr(splitterPos+1, line.length());
- RDK_LOG(RDK_LOG_DEBUG, LOG_RFCAPI, "Found Key = %s : Value = %s\n", key.c_str(), value.c_str());
- if(value.length() > 0)
- {
- strncpy(pstParam->name, pcParameterName, MAX_PARAM_LEN);
- pstParam->name[MAX_PARAM_LEN - 1] = '\0';
-
- pstParam->type = NONE; //The caller must know what type they are expecting if they are requesting a param before the hostif is ready.
-
- strncpy(pstParam->value, value.c_str(), MAX_PARAM_LEN);
- pstParam->value[MAX_PARAM_LEN - 1] = '\0';
- return SUCCESS;
- }
- return EMPTY;
- }
- }
- }
- ifs_rfcVar.close();
- }
- return FAILURE;
-}
-
-int getRFCParameter(const char* pcParameterName, RFC_ParamData_t *pstParam)
-{
- int ret = FAILURE;
- if(!strcmp(pcParameterName+strlen(pcParameterName)-1,"."))
- {
- RDK_LOG (RDK_LOG_DEBUG, LOG_RFCAPI, "%s: RFC API doesn't support wildcard parameterName\n", __FUNCTION__);
- }
-
- if(strncmp(pcParameterName, "RFC_", 4) == 0 && strchr(pcParameterName, '.') == NULL)
- {
- return getValue(RFCVAR_FILE, pcParameterName, pstParam);
- }
-
- else
- {
- ret = getValue(TR181STORE_FILE, pcParameterName, pstParam);
- if (SUCCESS == ret)
- return SUCCESS;
-
- // If the param is not found in override files, find it in rfcdefaults.
- return getValue(RFCDEFAULTS_FILE, pcParameterName, pstParam);
-
- }
-}
-#endif
-
-#define FAILURE -1
-#define SUCCESS 0
-
+#if !defined(RDKB_SUPPORT) && !defined(RDKC)
+/**
+ * @brief Look up a parameter by name in an ini-style file (WDMP path).
+ * @param[in] fileName Path to the ini file.
+ * @param[in] pcParameterName Parameter name to search for.
+ * @param[out] pstParam Filled with name/value/type on success.
+ * @return WDMP_SUCCESS, WDMP_ERR_VALUE_IS_EMPTY, or WDMP_FAILURE.
+ */
WDMP_STATUS getValue(const char* fileName, const char* pcParameterName, RFC_ParamData_t *pstParam)
{
ifstream ifs_rfcVar(fileName);
@@ -222,7 +159,9 @@ WDMP_STATUS getValue(const char* fileName, const char* pcParameterName, RFC_Para
}
return WDMP_FAILURE;
}
+#endif
+/** @brief cURL write callback — appends received data to a std::string. */
static size_t writeCurlResponse(void *ptr, size_t size, size_t nmemb, string stream)
{
size_t realsize = size * nmemb;
@@ -231,30 +170,14 @@ static size_t writeCurlResponse(void *ptr, size_t size, size_t nmemb, string str
return realsize;
}
-int getRFCParameter(const char* pcParameterName, RFC_ParamData_t *pstParam)
-{
- int ret = FAILURE;
- if(!strcmp(pcParameterName+strlen(pcParameterName)-1,"."))
- {
- RDK_LOG (RDK_LOG_DEBUG, LOG_RFCAPI, "%s: RFC API doesn't support wildcard parameterName\n", __FUNCTION__);
- }
-
- if(strncmp(pcParameterName, "RFC_", 4) == 0 && strchr(pcParameterName, '.') == NULL)
- {
- return getValue(RFCVAR_FILE, pcParameterName, pstParam);
- }
- else
- {
- ret = getValue(TR181STORE_FILE, pcParameterName, pstParam);
- if (SUCCESS == ret)
- return SUCCESS;
-
- // If the param is not found in override files, find it in rfcdefaults.
- return getValue(RFCDEFAULTS_FILE, pcParameterName, pstParam);
-
- }
-}
-
+#if !defined(RDKB_SUPPORT) && !defined(RDKC)
+/**
+ * @brief Retrieve an RFC parameter via hostif HTTP (STB path).
+ * @param[in] pcCallerID Caller identifier.
+ * @param[in] pcParameterName TR181 parameter name.
+ * @param[out] pstParam Filled with name/value/type.
+ * @return WDMP_STATUS code.
+ */
WDMP_STATUS getRFCParameter(const char *pcCallerID, const char* pcParameterName, RFC_ParamData_t *pstParam)
{
#ifdef TEMP_LOGGING
@@ -452,6 +375,14 @@ WDMP_STATUS getRFCParameter(const char *pcCallerID, const char* pcParameterName,
return ret;
}
+/**
+ * @brief Set an RFC parameter via hostif HTTP.
+ * @param[in] pcCallerID Caller identifier.
+ * @param[in] pcParameterName TR181 parameter name.
+ * @param[in] pcParameterValue New value to set.
+ * @param[in] eDataType WDMP data type.
+ * @return WDMP_STATUS code.
+ */
WDMP_STATUS setRFCParameter(const char *pcCallerID, const char* pcParameterName, const char* pcParameterValue, DATA_TYPE eDataType)
{
#ifdef TEMP_LOGGING
@@ -568,10 +499,10 @@ WDMP_STATUS setRFCParameter(const char *pcCallerID, const char* pcParameterName,
}
/**
-* Return the textual description of error code from wdmp_status
-*@param [in] wdmp_status
-*@param [out] textual description of error code.
-*/
+ * @brief Return a human-readable error string for a WDMP status code.
+ * @param[in] code WDMP status code.
+ * @return Static error description string.
+ */
const char * getRFCErrorString(WDMP_STATUS code)
{
const char * err_string;
@@ -690,7 +621,105 @@ const char * getRFCErrorString(WDMP_STATUS code)
}
return err_string;
}
+#elif defined(RDKB_SUPPORT) || defined(RDKC)
+/**
+ * @brief Look up a parameter by name in an ini-style file (int return path).
+ * @param[in] fileName Path to the ini file.
+ * @param[in] pcParameterName Parameter name to search for.
+ * @param[out] pstParam Filled with name/value/type on success.
+ * @return SUCCESS (0), EMPTY, or FAILURE.
+ */
+int getValue(const char* fileName, const char* pcParameterName, RFC_ParamData_t *pstParam)
+{
+ ifstream ifs_rfcVar(fileName);
+ if (!ifs_rfcVar.is_open())
+ {
+ RDK_LOG (RDK_LOG_ERROR, LOG_RFCAPI, "%s: Trying to open a non-existent file %s \n", __FUNCTION__, fileName);
+ if ( strcmp(fileName, RFCDEFAULTS_FILE) == 0 && init_rfcdefaults() )
+ {
+ RDK_LOG(RDK_LOG_DEBUG, LOG_RFCAPI, "Trying to open %s after newly creating\n", RFCDEFAULTS_FILE);
+ ifs_rfcVar.open(RFCDEFAULTS_FILE, ifstream::in);
+ if (!ifs_rfcVar.is_open())
+ return FAILURE;
+ }
+ else
+ return FAILURE;
+ }
+ {
+ string line;
+ while (getline(ifs_rfcVar, line))
+ {
+ line=line.substr(line.find_first_of(" \t")+1);//Remove any export word that maybe before the key(for rfcVariable.ini)
+ size_t splitterPos = line.find('=');
+ if (splitterPos < line.length())
+ {
+ string key = line.substr(0, splitterPos);
+ if ( !key.compare(pcParameterName) )
+ {
+ ifs_rfcVar.close();
+ string value = line.substr(splitterPos+1, line.length());
+ RDK_LOG(RDK_LOG_DEBUG, LOG_RFCAPI, "Found Key = %s : Value = %s\n", key.c_str(), value.c_str());
+ if(value.length() > 0)
+ {
+ strncpy(pstParam->name, pcParameterName, MAX_PARAM_LEN);
+ pstParam->name[MAX_PARAM_LEN - 1] = '\0';
+ pstParam->type = NONE; //The caller must know what type they are expecting if they are requesting a param before the hostif is ready.
+
+ strncpy(pstParam->value, value.c_str(), MAX_PARAM_LEN);
+ pstParam->value[MAX_PARAM_LEN - 1] = '\0';
+ return SUCCESS;
+ }
+ return EMPTY;
+ }
+ }
+ }
+ ifs_rfcVar.close();
+ }
+ return FAILURE;
+}
+
+
+/**
+ * @brief Retrieve an RFC parameter from ini files (RDKB / RDKC path).
+ * @param[in] pcParameterName TR181 parameter name.
+ * @param[out] pstParam Filled with name/value/type.
+ * @return SUCCESS (0) or FAILURE.
+ */
+int getRFCParameter(const char* pcParameterName, RFC_ParamData_t *pstParam)
+{
+ int ret = FAILURE;
+ if(!strcmp(pcParameterName+strlen(pcParameterName)-1,"."))
+ {
+ RDK_LOG (RDK_LOG_DEBUG, LOG_RFCAPI, "%s: RFC API doesn't support wildcard parameterName\n", __FUNCTION__);
+ }
+
+ if(strncmp(pcParameterName, "RFC_", 4) == 0 && strchr(pcParameterName, '.') == NULL)
+ {
+ return getValue(RFCVAR_FILE, pcParameterName, pstParam);
+ }
+
+ else
+ {
+ ret = getValue(TR181STORE_FILE, pcParameterName, pstParam);
+ if (SUCCESS == ret)
+ return SUCCESS;
+
+ // If the param is not found in override files, find it in rfcdefaults.
+ return getValue(RFCDEFAULTS_FILE, pcParameterName, pstParam);
+
+ }
+}
+
+#endif
+
+#if !defined(RDKB_SUPPORT) && !defined(RDKC)
+/**
+ * @brief Check whether a named RFC feature is enabled.
+ * @param[in] feature Feature name (without "RFC_" prefix).
+ * @retval true Feature ini marker file exists.
+ * @retval false Feature not enabled.
+ */
bool isRFCEnabled(const char *feature)
{
struct stat buffer;
@@ -699,9 +728,10 @@ bool isRFCEnabled(const char *feature)
return (stat(fileName.c_str(), &buffer) == 0);
}
-// Define your write callback function
+/** @brief Expose writeCurlResponse for unit testing. */
#ifdef GTEST_ENABLE
size_t (*getWriteCurlResponse(void))(void *ptr, size_t size, size_t nmemb, std::string stream) {
return &writeCurlResponse;
}
#endif
+#endif
diff --git a/rfcapi/rfcapi.h b/rfcapi/rfcapi.h
index 2f5441a8..10d8cd58 100644
--- a/rfcapi/rfcapi.h
+++ b/rfcapi/rfcapi.h
@@ -1,4 +1,7 @@
-/*
+/**
+ * @file rfcapi.h
+ * @brief Public C API for reading and writing RFC parameters.
+ *
* If not stated otherwise in this file or this component's LICENSE file the
* following copyright and licenses apply:
*
@@ -15,7 +18,7 @@
* 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.
-*/
+ */
#ifndef RFCAPI_H_
#define RFCAPI_H_
@@ -23,53 +26,109 @@
#include
#include
-#define RFCVAR_FILE "/opt/secure/RFC/rfcVariable.ini"
-#define TR181STORE_FILE "/opt/secure/RFC/tr181store.ini"
+#define RFCVAR_FILE "/opt/secure/RFC/rfcVariable.ini" /**< RFC shell-variable store. */
+#define TR181STORE_FILE "/opt/secure/RFC/tr181store.ini" /**< TR181 parameter override store. */
#ifdef __cplusplus
extern "C"
{
#endif
-#if !defined(RDKB_SUPPORT)
+#if !defined(RDKB_SUPPORT) && !defined(RDKC)
#include
#endif
-#define MAX_PARAM_LEN (2*1024)
+#define MAX_PARAM_LEN (2*1024) /**< Maximum length of a parameter name or value. */
-#if defined(RDKB_SUPPORT)
+#if defined(RDKB_SUPPORT) || defined(RDKC)
+/**
+ * @brief Return-type / value-status codes (RDKB & RDKC path).
+ */
typedef enum
{
- SUCCESS=0,
- FAILURE,
- NONE,
- EMPTY
+ SUCCESS=0, /**< Operation succeeded. */
+ FAILURE, /**< Operation failed. */
+ NONE, /**< No type information available. */
+ EMPTY /**< Parameter value is empty. */
}DATA_TYPE;
#endif
+/**
+ * @struct _RFC_Param_t
+ * @brief Container for a single RFC parameter (name + value + type).
+ */
#if defined(USE_IARMBUS)
typedef struct _RFC_Param_t {
- char name[MAX_PARAM_LEN];
- char value[MAX_PARAM_LEN];
- DATA_TYPE type;
+ char name[MAX_PARAM_LEN]; /**< Parameter name. */
+ char value[MAX_PARAM_LEN]; /**< Parameter value. */
+ DATA_TYPE type; /**< WDMP data type. */
} RFC_ParamData_t;
#else
typedef struct _RFC_Param_t {
- char name[MAX_PARAM_LEN];
- char value[MAX_PARAM_LEN];
- DATA_TYPE type;
+ char name[MAX_PARAM_LEN]; /**< Parameter name. */
+ char value[MAX_PARAM_LEN]; /**< Parameter value. */
+ DATA_TYPE type; /**< WDMP data type. */
} RFC_ParamData_t;
#endif
-#if defined(RDKB_SUPPORT)
+#if defined(RDKB_SUPPORT) || defined(RDKC)
+/**
+ * @brief Retrieve an RFC parameter value (RDKB / RDKC — int return path).
+ * @param[in] pcParameterName TR181 parameter name.
+ * @param[out] pstParamData Filled with the retrieved name/value/type.
+ * @return SUCCESS (0) or FAILURE (1).
+ */
int getRFCParameter(const char* pcParameterName, RFC_ParamData_t *pstParamData);
#else
+/**
+ * @brief Retrieve an RFC parameter value (STB — WDMP_STATUS return path).
+ * @param[in] pcCallerID Caller identifier string.
+ * @param[in] pcParameterName TR181 parameter name.
+ * @param[out] pstParamData Filled with the retrieved name/value/type.
+ * @return WDMP_STATUS code.
+ */
WDMP_STATUS getRFCParameter(const char *pcCallerID, const char* pcParameterName, RFC_ParamData_t *pstParamData);
+
+/**
+ * @brief Set an RFC parameter value via hostif.
+ * @param[in] pcCallerID Caller identifier string.
+ * @param[in] pcParameterName TR181 parameter name.
+ * @param[in] pcParameterValue New value to set.
+ * @param[in] eDataType WDMP data type of the value.
+ * @return WDMP_STATUS code.
+ */
WDMP_STATUS setRFCParameter(const char *pcCallerID, const char* pcParameterName, const char* pcParameterValue, DATA_TYPE eDataType);
+
+/**
+ * @brief Return a human-readable error string for a WDMP status code.
+ * @param[in] code WDMP status code.
+ * @return Static error description string.
+ */
const char* getRFCErrorString(WDMP_STATUS code);
+
+/**
+ * @brief Check whether a named RFC feature is enabled.
+ * @param[in] feature Feature name (without "RFC_" prefix).
+ * @retval true Feature ini marker file exists.
+ * @retval false Feature not enabled.
+ */
bool isRFCEnabled(const char *);
+
+/**
+ * @brief Check whether a file exists in a given directory.
+ * @param[in] dir Directory path to search.
+ * @param[in] filename Filename to look for.
+ * @retval true File found.
+ * @retval false File not found.
+ */
bool isFileInDirectory(const char *, const char *);
+
#if defined(GTEST_ENABLE)
+/**
+ * @brief Merge per-feature rfcdefaults ini files into a single file.
+ * @retval true Merge succeeded.
+ * @retval false /etc/rfcdefaults/ could not be opened.
+ */
bool init_rfcdefaults();
#endif
#endif