# Firmware Upgrade System - Complete Guide ## Table of Contents 1. [Overview](#overview) 2. [Architecture](#architecture) 3. [Configuration Parameters](#configuration-parameters) 4. [Upgrade Methods](#upgrade-methods) 5. [Configuration Preservation](#configuration-preservation) 6. [Operator Configuration Guide](#operator-configuration-guide) 7. [Troubleshooting](#troubleshooting) 8. [API Reference](#api-reference) --- ## Overview The iopsys firmware upgrade system provides a robust, dual-bank firmware management solution with flexible configuration preservation options. The system supports multiple upgrade methods and protocols while maintaining backward compatibility. ### Key Features - **Dual-bank architecture** - Safe firmware upgrades with automatic fallback - **Multiple upgrade protocols** - USP/TR-369 (via GUI or controller), TR-069/CWMP, DHCP onboarding, CLI - **Selective configuration preservation** - Separate control for operator and user settings - **Async operations** - Non-blocking upgrades with progress tracking - **Scheduled activations** - Time-window based firmware activation - **Auto-rollback** - Automatic fallback on boot failure ### System Components ``` ┌─────────────────────────────────────────────────────────────────────────────┐ │ Upgrade Interfaces │ ├──────────┬──────────────────────────┬──────────────────┬────────────────────┤ │ TR-069 │ USP/TR-369 │ DHCP │ fwbank CLI │ │ (CWMP) │ │ Onboarding │ │ │ │ │ │ │ │ icwmp │ ┌─────────┬─────────┐ │ udhcpc hooks │ /etc/sysmngr/ │ │ Agent │ │ Sulu │ dmcli │ │ │ fwbank │ │ │ │ GUI │ CLI │ │ │ │ │ │ └────┬────┴────┬────┘ │ │ │ │ │ │ │ │ │ │ │ │ └────┬────┘ │ │ │ │ │ │ │ │ │ │ │ ┌─────▼──────┐ │ │ │ │ │ │ OB-USPa │ │ │ │ │ │ │ Agent │ │ │ │ └────┬─────┴──────┴────┬───────┴──────┴────┬─────────────┴──────┬─────────────┘ │ │ │ │ ├─────────────────┤ │ │ │ BBF Datamodel │ │ │ │ (sysmngr) │ │ │ │ Device.DeviceInfo │ │ │ .FirmwareImage.{i} │ │ │ Download()/Activate() │ │ └──────────┬──────┘ │ │ │ │ │ └────────────┬──────────────┴────────────────────┘ │ ┌───────▼────────┐ │ fwbank │ (UBUS: fwbank.upgrade) │ (Core logic) │ └───────┬────────┘ │ ┌────────────────┼────────────────┐ │ │ │ ┌─────▼─────┐ ┌──────▼──────┐ ┌─────▼─────┐ │ opconf │ │ sysupgrade │ │ ubus │ │ (config) │ │ (OpenWrt) │ │ (events) │ └───────────┘ └─────────────┘ └───────────┘ ``` **Protocol Paths:** - **TR-069/USP:** Use BBF datamodel → sysmngr → fwbank UBUS - **DHCP/fwbank CLI:** Call fwbank UBUS directly (bypass BBF datamodel) - **Sulu:** Web GUI using USP/TR-369 protocol via OB-USPa agent (WebSocket) - **dmcli:** CLI using BBF datamodel via local UBUS or remote USP (MQTT/WebSocket) --- ## Architecture ### Dual-Bank System The firmware is stored in two independent banks, allowing safe upgrades with automatic fallback. ``` ┌──────────────────────────────────────────────────┐ │ Flash Memory Layout │ ├────────────┬────────────┬─────────────────────────┤ │ Bank 1 │ Bank 2 │ /usr_data │ │ (Firmware) │ (Firmware) │ (Persistent Storage) │ ├────────────┼────────────┼─────────────────────────┤ │ Active │ Inactive │ - opconf.json │ │ Boot │ Upgrade │ - userconf.json │ │ │ │ - userconf/keep.d/ │ └────────────┴────────────┴─────────────────────────┘ ``` #### Bank States Each bank can have one of the following states: | State | Description | Can Upgrade | Can Activate | |-------|-------------|-------------|--------------| | **Active** | Currently running firmware | ❌ | N/A (already active) | | **Boot** | Will boot on next reboot | ❌ | N/A (will boot) | | **Upgrade** | Available for new firmware | ✅ | ✅ | | **Invalid** | Corrupted or unavailable | ❌ | ❌ | **Example Status:** ```json { "bank": [ { "id": 1, "fwver": "iop-v5.14.0", "swver": "5.14.0", "active": true, "boot": true, "upgrade": false, "status": "Active" }, { "id": 2, "fwver": "", "swver": "", "active": false, "boot": false, "upgrade": true, "status": "Available" } ] } ``` ### Core Components #### 1. fwbank (Shell Script) **Location:** `/etc/sysmngr/fwbank` **Purpose:** Core firmware bank management **Methods:** - `dump` - Get bank information - `upgrade` - Write firmware to bank - `set_bootbank` - Set which bank boots next - `copy_config` - Preserve configuration **UBUS Interface:** ```bash ubus call fwbank dump ubus call fwbank upgrade '{"path": "/tmp/fw.bin", "bank": 2, "auto_activate": true, "keep_settings": true}' ubus call fwbank set_bootbank '{"bank": 2}' ubus call fwbank copy_config '{"keep_settings": true, "keep_opconf": true, "config_scope": "UserOnly"}' ``` #### 2. sysmngr (C Daemon) **Location:** `/usr/sbin/sysmngr` **Purpose:** BBF TR-181 datamodel implementation **Key Files:** - `src/fw_images.c` - FirmwareImage object implementation - `src/fwbank.c` - fwbank integration - `src/utils.c` - Download/validation utilities **Datamodel Paths:** ``` Device.DeviceInfo. ├── ActiveFirmwareImage (Reference to active bank) ├── BootFirmwareImage (Reference to boot bank) ├── MaxNumberOfActivateTimeWindows (5) └── FirmwareImage.{i}. ├── Alias (e.g., "cpe-1") ├── Name (Firmware name) ├── Version (Software version) ├── Available (true/false) ├── Status (Active/Available/Invalid) ├── Download() (Async operation) └── Activate() (Async operation) ``` #### 3. opconf (Configuration Manager) **Location:** `/usr/sbin/opconf_conf_handler` **Purpose:** Manage operator and user configuration separation **Storage:** ``` /usr_data/ ├── opconf/ │ └── opconf.json # Operator configuration (ISP settings) └── userconf/ ├── userconf.json # User configuration (end-user settings) └── keep.d/ # Backup of specific files └── etc/config/ ├── wifi ├── firewall └── ... ``` --- ## Configuration Parameters ### 1. keep_config (KeepConfig) **Type:** Boolean (0/1 or "0"/"1") **Default:** `1` (preserve settings) **Purpose:** Master switch for configuration preservation **Behavior:** - `1` - Preserve configurations according to `config_scope` - `0` - Factory reset, discard ALL configurations **Usage:** ```json { "keep_settings": 1 } ``` or in BBF operations: ```json { "X_IOWRT_EU_KeepConfig": "1" } ``` ### 2. keep_opconf (KeepOpConf) **Type:** Boolean (0/1 or "0"/"1") **Default:** `1` (preserve operator config) **Purpose:** Control operator configuration preservation **Behavior:** - `1` - Keep `/usr_data/opconf/opconf.json` - `0` - Delete operator configuration (ISP reset) **Only effective when:** `keep_config=1` **Usage:** ```json { "keep_opconf": 1 } ``` or in BBF operations: ```json { "X_IOWRT_EU_KeepOpConf": "1" } ``` **Operator Configuration Contains:** - ACS/USP controller credentials - WAN interface settings - VLANs and firewall rules - Management protocol settings - Default WiFi credentials ### 3. config_scope (ConfigScope) **Type:** String enum **Default:** `"UserOnly"` **Possible Values:** - `"All"` - Full backup (sysupgrade.tgz + userconf.json) - `"UserOnly"` - Selective backup (userconf.json only) **Purpose:** Define granularity of configuration preservation **Only effective when:** `keep_config=1` **Usage:** ```json { "config_scope": "UserOnly" } ``` or in BBF operations: ```json { "X_IOWRT_EU_ConfigScope": "UserOnly" } ``` ### Configuration Matrix | keep_config | keep_opconf | config_scope | Result | |-------------|-------------|--------------|--------| | 0 | - | - | **Factory Reset** - All configs deleted | | 1 | 0 | UserOnly | **User Only** - Operator config deleted, user settings preserved via userconf.json | | 1 | 1 | UserOnly | **User+Operator (Lightweight)** - Both preserved, selective backup | | 1 | 0 | All | **User+System** - Operator config deleted, full system backup + userconf.json | | 1 | 1 | All | **Everything** - Full preservation, both userconf.json and sysupgrade.tgz created | ### User Configuration (userconf.json) **Generated by:** `/usr/sbin/genuserconf` **Applied on boot:** Via `/etc/init.d/opconf` init script **Contains:** - LAN network settings (IP, netmask, DHCP pool) - UPnP enable/disable - Firewall port forwarding rules - User account passwords - WiFi AP configuration (SSID, password, encryption) - VoIP SIP client settings - LED PWM settings **Example:** ```json { "network": { "lan": { "ipaddr": "192.168.1.1", "netmask": "255.255.255.0" } }, "wireless": { "wifi0": { "ssid": "MyHomeNetwork", "key": "SecurePassword123" } } } ``` ### System Backup (sysupgrade.tgz) **Created by:** `sysupgrade -b /tmp/sysupgrade.tgz` **Copied by:** `platform_copy_config` **Contains:** ALL UCI configs from `/etc/config/*` **Size:** Typically 500KB - 2MB **Only created when:** `config_scope="All"` --- ## Upgrade Methods The firmware upgrade system supports **four upgrade methods**: 1. **USP/TR-369** - Modern BBF protocol (via Sulu GUI or external controller) → Uses BBF datamodel 2. **TR-069/CWMP** - Legacy ACS protocol → Uses BBF datamodel 3. **DHCP Onboarding** - Zero-touch provisioning → Direct UBUS to fwbank 4. **CLI** - Direct command-line access → Direct UBUS to fwbank > **Important Notes:** > - **Sulu and dmcli** are clients that use **USP/TR-369 protocol** to access the BBF datamodel. They are not separate upgrade methods but rather different interfaces for USP operations. > - **Sulu:** Browser-based GUI with WebSocket to local OB-USPa agent > - **dmcli:** Command-line interface that can connect locally (UBUS) or remotely (USP) > - **DHCP and fwbank CLI** bypass the BBF datamodel layer and call fwbank UBUS methods directly, providing lower-level access but with limited protocol features (no async operations, no transfer complete events). ### Method 1: USP/TR-369 (Recommended) **Protocol:** BBF USP (User Services Platform) / TR-369 **Agent:** OB-USPa (Open Broadband - USP Agent) **Clients:** - **Sulu Web GUI** - Browser-based interface (WebSocket connection to OB-USPa) - **dmcli** - Command-line interface for BBF datamodel (local UBUS or remote USP) - **External USP Controller** - Remote management platform (STOMP/MQTT/WebSocket) **Configuration:** Per-operation parameters (highest flexibility) **Datamodel:** `Device.DeviceInfo.FirmwareImage.{i}.Download()` / `Activate()` #### USP Client 1: Sulu Web GUI **Interface:** React-based web application **Communication:** WebSocket to local OB-USPa agent **Configuration Control:** - **File Upload Mode:** `KeepConfig` toggle available - **URL Download Mode:** Uses system defaults (no config control in GUI) **GUI Configuration Options:** | Feature | File Upload | URL Download | |---------|-------------|--------------| | KeepConfig | ✅ User toggle | ❌ System default | | KeepOpConf | ❌ System default | ❌ System default | | ConfigScope | ❌ System default | ❌ System default | | Authentication | ❌ None | ✅ Username/Password | | Progress Tracking | ✅ Upload + Install | ❌ No | > **Note:** The Sulu GUI currently only exposes the `KeepConfig` toggle in file upload mode. To control `KeepOpConf` and `ConfigScope`, operators must use system defaults (configured in firmware) or use an external USP controller with full parameter support. ##### Example: Sulu GUI Firmware Upload ```javascript // Sulu GUI uploads firmware file in chunks await uploadFileChunked({ Filename: "firmware.itb", Content: "", Filesize: "52428800", Checksum: "a3f5e1d2..." }); // Trigger upgrade with config control await downloadToDevice({ URL: "file:///tmp/obuspa/firmware.itb", X_IOWRT_EU_KeepConfig: "1", // User toggle X_IOWRT_EU_KeepOpConf: "1", // Default X_IOWRT_EU_ConfigScope: "UserOnly", // Default AutoActivate: "1" }); ``` #### USP Client 2: External USP Controller ```json { "command": "Device.DeviceInfo.FirmwareImage.2.Download()", "input": { "URL": "https://firmware.isp.com/cpe/v5.15.0.itb", "Username": "fwuser", "Password": "secret123", "FileSize": "52428800", "CheckSumAlgorithm": "SHA-256", "CheckSum": "a3f5e1d2c4b6...", "AutoActivate": "1", "X_IOWRT_EU_KeepConfig": "1", "X_IOWRT_EU_KeepOpConf": "0", "X_IOWRT_EU_ConfigScope": "UserOnly" } } ``` **Result:** Operator config reset, user WiFi/network settings preserved #### USP Client 3: dmcli (Data Model CLI) **Interface:** Interactive command-line interface for BBF data models **Modes:** - **Local Mode:** Run directly on device via SSH/console (uses local UBUS to sysmngr) - **Remote Mode:** Run from computer and connect via USP (MQTT/WebSocket to OB-USPa) **Configuration:** Full control via operation parameters **Installation:** ```bash # On device (pre-installed) ssh operator@192.168.1.1 dmcli # On host computer (requires NodeJS) npm install -g @gnx/dmcli@latest ``` **Remote Connection Setup:** ```bash # Configure USP connection profile dmcli # set Settings.USP.ActiveConnectionProfile iowrt-gnx-operator # do Settings.USP.Connect() ``` ##### Example: Firmware Upgrade via dmcli **Interactive Mode:** ```bash # Start dmcli dmcli # Navigate to firmware object # cd Device.DeviceInfo.FirmwareImage.2 # Check current status # get Status Version Name # Download firmware # do Download() URL=https://firmware.isp.com/v5.15.0.itb AutoActivate=1 X_IOWRT_EU_KeepConfig=1 X_IOWRT_EU_KeepOpConf=0 X_IOWRT_EU_ConfigScope=UserOnly # For async operations, use -n flag to not wait # do -n Download() URL=https://firmware.isp.com/v5.15.0.itb AutoActivate=1 ``` **Non-Interactive Mode:** ```bash # Single command execution dmcli do Device.DeviceInfo.FirmwareImage.2.Download() \ URL=https://firmware.isp.com/v5.15.0.itb \ AutoActivate=1 \ X_IOWRT_EU_KeepConfig=1 \ X_IOWRT_EU_KeepOpConf=0 \ X_IOWRT_EU_ConfigScope=UserOnly # Activate previously downloaded firmware dmcli do Device.DeviceInfo.FirmwareImage.2.Activate() \ X_IOWRT_EU_KeepConfig=1 \ X_IOWRT_EU_KeepOpConf=1 \ X_IOWRT_EU_ConfigScope=All ``` **Configuration Control:** | Feature | dmcli Support | |---------|---------------| | KeepConfig | ✅ Full control via parameter | | KeepOpConf | ✅ Full control via parameter | | ConfigScope | ✅ Full control via parameter | | Authentication | ✅ HTTP auth in URL parameter | | Progress Tracking | ✅ Async mode with `-n` flag | | Auto-completion | ✅ Tab completion for paths and parameters | **Advantages:** - Full access to BBF datamodel with tab completion - Can be scripted for automation - Supports both local and remote operation - Comprehensive parameter control - Interactive exploration of data model #### Example: Scheduled Activation ```json { "command": "Device.DeviceInfo.FirmwareImage.2.Activate()", "input": { "TimeWindow.1.Start": "3600", // 1 hour from now "TimeWindow.1.End": "7200", // 2 hours from now "TimeWindow.1.Mode": "AnyTime", "TimeWindow.1.MaxRetries": "3", "TimeWindow.2.Start": "86400", // 24 hours from now "TimeWindow.2.End": "90000", // 25 hours from now "TimeWindow.2.Mode": "Immediately", "TimeWindow.2.MaxRetries": "-1", "X_IOWRT_EU_KeepConfig": "1", "X_IOWRT_EU_KeepOpConf": "1", "X_IOWRT_EU_ConfigScope": "All" } } ``` **Cron Jobs Created:** ```cron # Window 1: Between 14:00-16:00 today, up to 3 retries 0 14 26 11 * sh /usr/share/bbfdm/scripts/bbf_activate_handler.sh 'AnyTime' '2' '7200' 'false' '3' '1' '1' 'All' '' # Window 2: Between 14:00-15:00 tomorrow, infinite retries 0 14 27 11 * sh /usr/share/bbfdm/scripts/bbf_activate_handler.sh 'Immediately' '2' '3600' 'true' '-1' '1' '1' 'All' '' ``` ### Method 2: TR-069/CWMP **Controller:** ACS (Auto Configuration Server) **Configuration:** UCI defaults in `/etc/config/cwmp` **RPC:** `Download(1 Firmware Upgrade Image)` #### UCI Configuration **File:** `/etc/config/cwmp` ```uci config cpe 'cpe' option acs_url 'https://acs.isp.com/cwmp' option acs_user 'cpe-user' option acs_passwd 'secret' # Firmware upgrade config defaults option KeepConfig '1' option KeepOpConf '1' option ConfigScope 'UserOnly' ``` #### ACS Download RPC Flow 1. **ACS sends Download RPC:** ```xml fw-upgrade-20251126 1 Firmware Upgrade Image https://firmware.isp.com/cpe/v5.15.0.itb fwuser secret123 52428800 ``` 2. **icwmp processes download:** ```c // src/download.c:445-497 cwmp_apply_multiple_firmware(true) { // Read config from UCI keep_config = cwmp_ctx.conf.cpe_keep_config; keep_opconf = cwmp_ctx.conf.cpe_keep_opconf; config_scope = cwmp_ctx.conf.cpe_config_scope; // Call BBF datamodel via UBUS ubus_call("bbfdm", "operate", { "path": "Device.DeviceInfo.FirmwareImage.2.Download()", "input": { "URL": "file:///tmp/firmware.img", "AutoActivate": true, "X_IOWRT_EU_KeepConfig": keep_config, "X_IOWRT_EU_KeepOpConf": keep_opconf, "X_IOWRT_EU_ConfigScope": config_scope } }); } ``` 3. **CPE sends TransferComplete event back to ACS** #### Dynamic Configuration Override To change config behavior before upgrade: ```bash # ISP wants to reset operator config on next upgrade ubus call cwmp set '{"cpe.KeepOpConf": "0"}' uci set cwmp.cpe.KeepOpConf='0' uci commit cwmp # Then ACS initiates Download RPC ``` ### Method 3: DHCP Onboarding **Protocol:** Direct UBUS call to fwbank (does NOT use USP/TR-369 or BBF datamodel) **Server:** DHCP server (ISP infrastructure) **Client:** udhcpc hooks (`/etc/udhcpc.user.d/dhcp-on-boarding`) **Configuration:** `reset_mode` flag only (limited control) **DHCP Options:** Option 125 (sub-option 2) or Option 224 #### DHCP Option Format **Option 125 (Vendor-Specific):** ``` Enterprise-ID: 25167 (Genexis) Sub-option 2: Firmware upgrade URL Hex format: 00006250 # Genexis Enterprise ID 14 # Length 02 # Sub-option code (firmware) 12 # URL length 687474703a2f2f... # http://192.168.1.5/fw.bin ``` **Option 224 (Legacy):** ``` Raw hex-encoded URL: 687474703a2f2f3139322e3136382e312e352f66772e62696e ``` #### URL Syntax **Immediate upgrade, keep config:** ``` http://server.com/firmware.bin ``` **Immediate upgrade, factory reset:** ``` http://server.com/firmware.bin,reset_mode=full ``` **Scheduled upgrade:** ``` http://server.com/firmware.bin,20251215,02,4 # Upgrade on Dec 15, 2025, random time between 02:00-06:00 ``` **Scheduled with reset:** ``` http://server.com/firmware.bin,reset_mode=full,14,2 # Today at random time between 14:00-16:00, factory reset ``` #### Configuration Mapping ```bash # In dhcp_upgrade_handling.sh if [ "$reset_mode" = "full" ]; then keep_settings="0" else keep_settings="1" fi # Call fwbank ubus call fwbank upgrade '{ "path": "/tmp/firmware.bin", "bank": 2, "auto_activate": true, "reboot": true, "keep_settings": '$keep_settings' # Note: keep_opconf and config_scope NOT passed, use system defaults }' ``` **Limitation:** Cannot control `keep_opconf` or `config_scope` via DHCP **Workaround:** Pre-configure defaults in firmware ```uci # /rom/etc/config/cwmp (in firmware image) config cpe 'cpe' option KeepConfig '1' option KeepOpConf '1' option ConfigScope 'UserOnly' ``` #### DHCP Server Example (Kea) ```json { "subnet4": [{ "subnet": "192.168.100.0/24", "pools": [{"pool": "192.168.100.10 - 192.168.100.250"}], "option-data": [ { "name": "vendor-encapsulated-options", "code": 125, "data": "00006250 1E 02 1C 687474703a2f2f3139322e3136382e3130302e312f66772e69746220", "always-send": true } ] }] } ``` Decodes to: `http://192.168.100.1/fw.itb` ### Method 4: CLI (fwbank) **Protocol:** Direct UBUS call to fwbank (does NOT use USP/TR-369 or BBF datamodel) **Interface:** Direct shell script invocation **Script:** `/etc/sysmngr/fwbank` **Configuration:** Full control via parameters **Usage:** ```bash # Dump bank information /etc/sysmngr/fwbank call dump # Upgrade with full config control /etc/sysmngr/fwbank call upgrade '{ "path": "/tmp/firmware.itb", "bank": 2, "auto_activate": true, "reboot": false, "keep_settings": true, "keep_opconf": false, "config_scope": "UserOnly" }' # Copy config separately /etc/sysmngr/fwbank call copy_config '{ "keep_settings": true, "keep_opconf": true, "config_scope": "All" }' # Set boot bank /etc/sysmngr/fwbank call set_bootbank '{"bank": 2}' # Manual reboot reboot ``` --- ## Configuration Preservation ### Process Flow ``` ┌────────────────────────────────────────────────────────────┐ │ Upgrade Initiated │ └────────────────────┬───────────────────────────────────────┘ │ ▼ ┌───────────────────────┐ │ Parameters Received │ │ - keep_settings │ │ - keep_opconf │ │ - config_scope │ └───────────┬───────────┘ │ ▼ ┌──────────────┐ │ keep_config │ │ = 1? │ └──┬───────┬───┘ │ │ NO ──┘ └── YES │ │ ▼ ▼ ┌────────────┐ ┌──────────────────┐ │ Skip all │ │ opconf_conf_ │ │ config │ │ handler │ │ handling │ └────────┬─────────┘ └─────┬──────┘ │ │ ▼ │ ┌──────────────────┐ │ │ keep_opconf = 0?│ │ └────┬──────┬──────┘ │ │ │ │ YES ─┘ └─ NO │ │ │ │ ▼ │ │ ┌─────────────┐ │ │ │ Delete │ │ │ │ opconf.json │ │ │ └──────┬──────┘ │ │ │ │ │ └─────┬───────┘ │ │ │ ▼ │ ┌──────────────────────┐ │ │ config_scope = │ │ │ "All" / "UserOnly"? │ │ └────┬────────────┬────┘ │ │ │ │ All ─┘ └─ UserOnly │ │ │ │ ▼ ▼ │ ┌──────────┐ ┌─────────────┐ │ │ Generate │ │ Generate │ │ │userconf +│ │ userconf. │ │ │sysupgrade│ │ json only │ │ │ .tgz │ └──────┬──────┘ │ └────┬─────┘ │ │ └─────────┬─────────┘ │ │ └────────┬────────┘ │ ▼ ┌──────────────┐ │ sysupgrade │ │ executes │ └──────┬───────┘ │ ▼ ┌──────────────┐ │ Reboot │ └──────┬───────┘ │ ▼ ┌────────────────┐ │ Apply opconf │ │ (if exists) │ └────────┬───────┘ │ ▼ ┌────────────────┐ │ Apply userconf │ │ (if exists) │ └────────┬───────┘ │ ▼ ┌────────────────┐ │ Delete userconf│ │ .json │ └────────────────┘ ``` ### opconf_conf_handler Details **Location:** `/usr/sbin/opconf_conf_handler` **Called by:** fwbank script before sysupgrade **Parameters:** ```bash opconf_conf_handler -k -o -s ``` **Logic:** ```bash #!/bin/sh KEEP_CONFIG="$1" # 0 or 1 KEEP_OPCONF="$2" # 0 or 1 CONFIG_SCOPE="$3" # "All" or "UserOnly" # Step 1: Handle opconf.json if [ "$KEEP_OPCONF" -eq "0" ]; then rm -f /usr_data/opconf/opconf.json fi # Step 2: Handle userconf if [ "$KEEP_CONFIG" -eq "0" ]; then rm -f /usr_data/userconf/userconf.json rm -rf /usr_data/userconf/keep.d/ else if [ "$CONFIG_SCOPE" = "All" ] || [ "$CONFIG_SCOPE" = "UserOnly" ]; then # Generate userconf.json from current system state genuserconf > /usr_data/userconf/userconf.json # Backup specific config files copy_config_over_upgrade fi fi ``` ### genuserconf Script **Purpose:** Extract user-configurable settings into JSON **Source Files:** ```bash /etc/config/network → LAN settings /etc/config/wireless → WiFi settings /etc/config/firewall → Port forwarding /etc/config/upnpd → UPnP state /etc/config/voice → VoIP settings /etc/config/system → LED settings ``` **Example Output:** ```json { "network": { "lan": { "proto": "static", "ipaddr": "192.168.100.1", "netmask": "255.255.255.0", "ip6assign": "60" }, "lan_dhcp": { "start": "100", "limit": "150", "leasetime": "12h" } }, "wireless": { "radio0_ap0": { "ssid": "MyNetwork", "encryption": "psk2", "key": "MyPassword123" } }, "firewall": { "portforward_ssh": { "src": "wan", "dest": "lan", "proto": "tcp", "src_dport": "2222", "dest_ip": "192.168.100.50", "dest_port": "22" } } } ``` ### On-Boot Application **Init Script:** `/etc/init.d/opconf` **Boot Sequence:** ```bash #!/bin/sh /etc/rc.common START=19 # Early boot, before network start() { # Check if /usr_data is mounted if ! mountpoint -q /usr_data; then return 0 fi # Step 1: Apply opconf.json (if exists) if [ -f /usr_data/opconf/opconf.json ]; then opconf_apply /usr_data/opconf/opconf.json # Note: opconf.json is NOT deleted, persists across reboots fi # Step 2: Apply userconf.json (if exists) if [ -f /usr_data/userconf/userconf.json ]; then userconf_apply /usr_data/userconf/userconf.json # Delete after applying (one-time use) rm -f /usr_data/userconf/userconf.json fi # Step 3: Restore files from keep.d/ if [ -d /usr_data/userconf/keep.d ]; then cp -a /usr_data/userconf/keep.d/* / fi } ``` --- ## Operator Configuration Guide ### Scenario 1: ISP wants full control over CPE, no user customization preserved **Method:** TR-069 or USP Controller **Configuration:** **/etc/config/cwmp (firmware defaults):** ```uci config cpe 'cpe' option KeepConfig '0' # KeepOpConf and ConfigScope ignored when KeepConfig=0 ``` **Result:** Every firmware upgrade = factory reset **Use Case:** Managed CPE, ISP owns all settings ### Scenario 2: ISP wants to preserve user WiFi passwords but reset ISP settings **Method:** USP Controller (per-upgrade control) **Download RPC:** ```json { "command": "Device.DeviceInfo.FirmwareImage.2.Download()", "input": { "URL": "https://firmware.isp.com/v5.15.0.itb", "AutoActivate": "1", "X_IOWRT_EU_KeepConfig": "1", "X_IOWRT_EU_KeepOpConf": "0", "X_IOWRT_EU_ConfigScope": "UserOnly" } } ``` **Result:** - ✅ User WiFi SSID/password preserved - ✅ User LAN IP preserved - ✅ User port forwards preserved - ❌ ACS URL reset to firmware default - ❌ WAN settings reset to firmware default - ❌ VLAN settings reset to firmware default **Use Case:** ISP changing backend infrastructure, wants fresh provisioning ### Scenario 3: Home user upgrading via GUI, wants to keep everything **Method:** USP/TR-369 (Sulu Web GUI) **User Action:** 1. Navigate to System → Firmware 2. Upload firmware.itb 3. ✅ Enable "Keep Settings" toggle 4. Click "Start Upgrade" **Sulu sends USP Download() operation:** ```json { "URL": "file:///tmp/obuspa/firmware.itb", "X_IOWRT_EU_KeepConfig": "1", "AutoActivate": "1" } ``` **Result:** - ✅ All settings preserved (defaults to keep_opconf=1, config_scope="UserOnly") - ✅ WiFi, LAN, port forwards preserved - ✅ ACS/ISP settings preserved **Limitation:** Current Sulu GUI cannot selectively reset operator config. To control `KeepOpConf` and `ConfigScope`, use an external USP controller or configure system defaults in firmware. ### Scenario 4: DHCP onboarding in new deployment, zero-touch provisioning **Method:** DHCP Option 125 **DHCP Server sends:** ``` Option 125: http://bootstrap.isp.com/fw-v5.14.0.itb,reset_mode=full Option 125 Sub-3: http://bootstrap.isp.com/config-$MAC$.uci.enc ``` **CPE boots with factory firmware:** 1. Gets DHCP lease 2. Downloads firmware → factory reset (reset_mode=full) 3. Downloads encrypted config → applies ISP settings 4. Reboots into new firmware with ISP provisioning **Configuration:** Entirely driven by DHCP, no pre-config needed ### Scenario 5: Scheduled maintenance window upgrade **Method:** USP Controller with Activate() **Controller sends Download() first:** ```json { "command": "Device.DeviceInfo.FirmwareImage.2.Download()", "input": { "URL": "https://firmware.isp.com/v5.15.0.itb", "AutoActivate": "0" // Don't activate yet } } ``` **Then sends Activate() with time windows:** ```json { "command": "Device.DeviceInfo.FirmwareImage.2.Activate()", "input": { "TimeWindow.1.Start": "3600", // 1 hour from now "TimeWindow.1.End": "10800", // 3 hours from now "TimeWindow.1.Mode": "WhenIdle", "TimeWindow.1.MaxRetries": "5", "TimeWindow.2.Start": "86400", // 24 hours (fallback) "TimeWindow.2.End": "93600", "TimeWindow.2.Mode": "Immediately", "TimeWindow.2.MaxRetries": "-1", "X_IOWRT_EU_KeepConfig": "1", "X_IOWRT_EU_KeepOpConf": "1", "X_IOWRT_EU_ConfigScope": "All" } } ``` **Cron Jobs:** ```cron # Primary window: Tonight 01:00-04:00, activate when idle, up to 5 retries 0 1 27 11 * sh /usr/share/bbfdm/scripts/bbf_activate_handler.sh 'WhenIdle' '2' '10800' 'false' '5' '1' '1' 'All' '' # Fallback: Tomorrow night, force activation, infinite retries 0 1 28 11 * sh /usr/share/bbfdm/scripts/bbf_activate_handler.sh 'Immediately' '2' '7200' 'true' '-1' '1' '1' 'All' '' ``` **Use Case:** ISP wants to upgrade during low-traffic hours, with automatic fallback --- ## Troubleshooting ### Issue: Configuration not preserved after upgrade **Symptoms:** - WiFi password reset to default - LAN IP back to 192.168.1.1 - Port forwarding rules gone **Diagnosis:** 1. Check if `/usr_data` partition exists: ```bash mount | grep usr_data df -h | grep usr_data ``` 2. Check opconf_conf_handler was called: ```bash logread | grep opconf_conf_handler ``` 3. Check for userconf.json: ```bash ls -la /usr_data/userconf/ ``` 4. Check config parameters used: ```bash logread | grep -E "keep_settings|keep_opconf|config_scope" ``` **Solutions:** - **Missing /usr_data:** Partition not created, config preservation disabled ```bash # Check flash layout cat /proc/mtd ``` - **opconf not available:** System falls back to legacy mode ```bash which opconf_conf_handler # If missing: config_scope forced to "All" ``` - **Parameters not passed:** Check upgrade method's config support ```bash # DHCP upgrade - add reset_mode parameter # GUI upgrade - toggle "Keep Settings" # TR-069 - check /etc/config/cwmp defaults ``` ### Issue: Operator config deleted unexpectedly **Symptoms:** - ACS URL reset to default - WAN interface unconfigured - Need to re-provision device **Diagnosis:** ```bash # Check if opconf.json exists ls -la /usr_data/opconf/opconf.json # Check upgrade parameters logread | grep keep_opconf ``` **Possible Causes:** 1. **USP controller sent KeepOpConf=0:** - Check USP controller logs for Download() parameters 2. **TR-069 UCI default was 0:** ```bash uci show cwmp.cpe.KeepOpConf # Should be '1', if '0' → operator config deleted ``` 3. **DHCP upgrade with no opconf support:** - DHCP onboarding doesn't support keep_opconf - Pre-configure firmware with ISP settings baked in **Prevention:** ```uci # Set system-wide defaults in firmware cat > /rom/etc/config/cwmp << EOF config cpe 'cpe' option KeepConfig '1' option KeepOpConf '1' option ConfigScope 'UserOnly' EOF ``` ### Issue: Firmware upgrade stuck at "Downloading" **Symptoms:** - Bank status shows "Downloading" indefinitely - No "Available" status after 10+ minutes - Device not rebooted **Diagnosis:** ```bash # Check sysupgrade events ubus listen sysupgrade & # Check fwbank status ubus call fwbank dump # Check for hung sysupgrade process ps | grep sysupgrade ``` **Possible Causes:** 1. **Invalid firmware image:** ```bash sysupgrade -T /tmp/firmware.itb # Should output: Image check succeeded ``` 2. **Insufficient flash space:** ```bash df -h /tmp df -h /overlay ``` 3. **sysupgrade process crashed:** ```bash logread | grep sysupgrade | tail -50 ``` **Recovery:** ```bash # Kill hung sysupgrade killall sysupgrade # Clean up temp files rm -f /tmp/firmware-* # Reset bank status manually (if needed) ubus call fwbank set_bootbank '{"bank": 1}' # Back to current bank reboot ``` ### Issue: Device boots into wrong bank after upgrade **Symptoms:** - Upgraded bank 2, but still running bank 1 - Boot bank doesn't match expectation **Diagnosis:** ```bash # Check current running bank ubus call fwbank dump | jsonfilter -e '@.bank[@.active=true]' # Check boot bank ubus call fwbank dump | jsonfilter -e '@.bank[@.boot=true]' # Check bootloader environment fw_printenv boot_bank ``` **Possible Causes:** 1. **AutoActivate was 0:** - Download() completed but didn't set boot bank - Need to manually call Activate() 2. **Bootloader failed to switch:** - U-Boot issue - Environment not writable **Solution:** ```bash # Manually set boot bank ubus call fwbank set_bootbank '{"bank": 2}' # Copy config ubus call fwbank copy_config '{ "keep_settings": true, "keep_opconf": true, "config_scope": "All" }' # Reboot reboot ``` --- ## API Reference ### fwbank UBUS Methods #### fwbank.dump **Description:** Get firmware bank information **Parameters:** None **Returns:** ```json { "bank": [ { "id": 1, "fwver": "iop-v5.14.0", "swver": "5.14.0", "omci_swver": "5.14", "active": true, "boot": true, "upgrade": false, "status": "Active" }, { "id": 2, "fwver": "iop-v5.15.0", "swver": "5.15.0", "omci_swver": "5.15", "active": false, "boot": false, "upgrade": true, "status": "Available" } ] } ``` **Example:** ```bash ubus call fwbank dump ``` #### fwbank.upgrade **Description:** Upgrade firmware to specified bank **Parameters:** | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | path | string | ✅ | - | Path to firmware file | | bank | integer | ✅ | - | Target bank ID (1 or 2) | | auto_activate | boolean | ❌ | false | Set as boot bank after upgrade | | reboot | boolean | ❌ | false | Reboot after upgrade | | keep_settings | boolean | ❌ | true | Preserve configurations | | keep_opconf | boolean | ❌ | true | Preserve operator config | | config_scope | string | ❌ | "UserOnly" | Config scope ("All" or "UserOnly") | **Returns:** ```json { "result": "ok" } ``` or ```json { "result": "error", "message": "Invalid firmware image" } ``` **Example:** ```bash ubus call fwbank upgrade '{ "path": "/tmp/firmware.itb", "bank": 2, "auto_activate": true, "reboot": true, "keep_settings": true, "keep_opconf": false, "config_scope": "UserOnly" }' ``` #### fwbank.set_bootbank **Description:** Set which bank will boot on next reboot **Parameters:** | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | bank | integer | ✅ | Bank ID to boot (1 or 2) | **Returns:** ```json { "result": "ok" } ``` **Example:** ```bash ubus call fwbank set_bootbank '{"bank": 2}' ``` #### fwbank.copy_config **Description:** Copy configuration from active bank to boot bank **Parameters:** | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | keep_settings | boolean | ❌ | true | Copy user configs | | keep_opconf | boolean | ❌ | true | Copy operator config | | config_scope | string | ❌ | "UserOnly" | Scope ("All" or "UserOnly") | **Returns:** ```json { "result": "ok" } ``` **Example:** ```bash ubus call fwbank copy_config '{ "keep_settings": true, "keep_opconf": true, "config_scope": "All" }' ``` ### BBF Datamodel Operations #### Device.DeviceInfo.FirmwareImage.{i}.Download() **Description:** Download firmware to specified bank **Input Parameters:** | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | URL | string | ✅ | Firmware download URL | | AutoActivate | boolean | ❌ | Set as boot bank after download | | Username | string | ❌ | HTTP authentication username | | Password | string | ❌ | HTTP authentication password | | FileSize | unsignedInt | ❌ | Expected file size (bytes) | | CheckSumAlgorithm | string | ❌ | "MD5", "SHA-1", "SHA-256" | | CheckSum | string | ❌ | Expected checksum value | | X_IOWRT_EU_KeepConfig | boolean | ❌ | Preserve configurations | | X_IOWRT_EU_KeepOpConf | boolean | ❌ | Preserve operator config | | X_IOWRT_EU_ConfigScope | string | ❌ | "All" or "UserOnly" | **Returns:** Async operation, sends TransferComplete event when done **USP Example:** ```json { "command": "Device.DeviceInfo.FirmwareImage.2.Download()", "input": { "URL": "https://fw.example.com/firmware.itb", "AutoActivate": "1", "FileSize": "52428800", "CheckSumAlgorithm": "SHA-256", "CheckSum": "a3f5e1d2c4b6...", "X_IOWRT_EU_KeepConfig": "1", "X_IOWRT_EU_KeepOpConf": "0", "X_IOWRT_EU_ConfigScope": "UserOnly" } } ``` #### Device.DeviceInfo.FirmwareImage.{i}.Activate() **Description:** Activate downloaded firmware (optionally scheduled) **Input Parameters:** | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | TimeWindow.{i}.Start | unsignedInt | ❌ | Seconds from now to start | | TimeWindow.{i}.End | unsignedInt | ❌ | Seconds from now to end | | TimeWindow.{i}.Mode | string | ❌ | "AnyTime", "Immediately", "WhenIdle", "ConfirmationNeeded" | | TimeWindow.{i}.UserMessage | string | ❌ | Message to display to user | | TimeWindow.{i}.MaxRetries | int | ❌ | -1 (infinite) to 10 | | X_IOWRT_EU_KeepConfig | boolean | ❌ | Preserve configurations | | X_IOWRT_EU_KeepOpConf | boolean | ❌ | Preserve operator config | | X_IOWRT_EU_ConfigScope | string | ❌ | "All" or "UserOnly" | **Returns:** Immediate success, activation occurs at scheduled time **USP Example (immediate):** ```json { "command": "Device.DeviceInfo.FirmwareImage.2.Activate()", "input": { "X_IOWRT_EU_KeepConfig": "1", "X_IOWRT_EU_KeepOpConf": "1", "X_IOWRT_EU_ConfigScope": "All" } } ``` **USP Example (scheduled):** ```json { "command": "Device.DeviceInfo.FirmwareImage.2.Activate()", "input": { "TimeWindow.1.Start": "3600", "TimeWindow.1.End": "7200", "TimeWindow.1.Mode": "WhenIdle", "TimeWindow.1.MaxRetries": "3", "X_IOWRT_EU_KeepConfig": "1" } } ``` --- ## Appendices ### Appendix A: Configuration Files Reference | Path | Purpose | Format | |------|---------|--------| | `/etc/sysmngr/fwbank` | Bank management script | Shell script | | `/etc/config/cwmp` | TR-069 config defaults | UCI | | `/etc/config/dhcp-on-boarding` | DHCP upgrade settings | UCI | | `/usr_data/opconf/opconf.json` | Operator configuration | JSON | | `/usr_data/userconf/userconf.json` | User configuration (temp) | JSON | | `/usr_data/userconf/keep.d/` | Backed up config files | Directory tree | | `/tmp/sysupgrade.tgz` | Full config backup | Tarball | | `/tmp/firmware-XXXXXX` | Downloaded firmware | Binary | | `/etc/crontabs/root` | Scheduled activations | Crontab | ### Appendix B: Event Types | Event | Source | Payload | Purpose | |-------|--------|---------|---------| | `sysupgrade` | fwbank | `{"bank_id": "2", "status": "Available"}` | Upgrade progress | | `transfer_complete` | sysmngr | BBF TransferComplete format | Notify controller | **Example sysupgrade event:** ```bash ubus listen sysupgrade # Output during upgrade: { "sysupgrade": { "bank_id": "2", "status": "Downloading" } } { "sysupgrade": { "bank_id": "2", "status": "Available" } } ``` ### Appendix C: Error Codes | Code | Message | Cause | Solution | |------|---------|-------|----------| | 9001 | Command failure | Generic operation error | Check logs, retry | | 9007 | Invalid arguments | Bad parameter value | Validate input | | 9010 | Resources exceeded | Out of memory/storage | Free space, retry | | - | "Invalid firmware image" | sysupgrade -T failed | Check image format | | - | "Checksum mismatch" | File corrupted | Re-download | | - | "Download failed" | HTTP error | Check URL/credentials | ### Appendix D: Version History | Version | Date | Changes | |---------|------|---------| | 1.0 | 2024-01 | Initial dual-bank support | | 1.1 | 2024-06 | Added opconf/userconf separation | | 1.1.3 | 2024-11 | Enhanced BBF USP support, scheduled activation | --- ## Quick Reference ### Default Configuration Values ``` keep_config: 1 (preserve) keep_opconf: 1 (preserve) config_scope: "UserOnly" auto_activate: 0 (manual) reboot: 0 (manual) ``` ### Common Commands #### Using dmcli (BBF Datamodel - Recommended) ```bash # Check firmware status dmcli get Device.DeviceInfo.FirmwareImage. # Upgrade with full config preservation dmcli do Device.DeviceInfo.FirmwareImage.2.Download() \ URL=https://fw.example.com/firmware.itb \ AutoActivate=1 \ X_IOWRT_EU_KeepConfig=1 \ X_IOWRT_EU_KeepOpConf=1 \ X_IOWRT_EU_ConfigScope=All # Upgrade with operator reset, keep user settings dmcli do Device.DeviceInfo.FirmwareImage.2.Download() \ URL=https://fw.example.com/firmware.itb \ AutoActivate=1 \ X_IOWRT_EU_KeepConfig=1 \ X_IOWRT_EU_KeepOpConf=0 \ X_IOWRT_EU_ConfigScope=UserOnly # Factory reset upgrade dmcli do Device.DeviceInfo.FirmwareImage.2.Download() \ URL=https://fw.example.com/firmware.itb \ AutoActivate=1 \ X_IOWRT_EU_KeepConfig=0 ``` #### Using fwbank UBUS (Direct Access) ```bash # Check current status ubus call fwbank dump # Upgrade with full config preservation ubus call fwbank upgrade '{"path":"/tmp/fw.itb","bank":2,"auto_activate":true,"reboot":true,"keep_settings":true,"keep_opconf":true,"config_scope":"All"}' # Upgrade with operator reset, keep user settings ubus call fwbank upgrade '{"path":"/tmp/fw.itb","bank":2,"auto_activate":true,"keep_settings":true,"keep_opconf":false,"config_scope":"UserOnly"}' # Factory reset upgrade ubus call fwbank upgrade '{"path":"/tmp/fw.itb","bank":2,"auto_activate":true,"keep_settings":false}' # Check upgrade events logread -f | grep -E "sysupgrade|fwbank|opconf" ``` ### Decision Tree: Which Config Parameters? ``` Are you upgrading via... ├─ USP/TR-369 Protocol │ ├─ Sulu Web GUI │ │ └─ Toggle: "Keep Settings" checkbox in File Upload mode │ │ Basic control, KeepConfig only (URL download uses defaults) │ │ │ ├─ dmcli (Data Model CLI) │ │ └─ Use: X_IOWRT_EU_KeepConfig, X_IOWRT_EU_KeepOpConf, X_IOWRT_EU_ConfigScope │ │ Full control via operation parameters │ │ Works locally (UBUS) or remotely (USP) │ │ Example: dmcli do Device.DeviceInfo.FirmwareImage.2.Download() URL=... AutoActivate=1 X_IOWRT_EU_KeepConfig=1 │ │ │ └─ External USP Controller │ └─ Use: X_IOWRT_EU_KeepConfig, X_IOWRT_EU_KeepOpConf, X_IOWRT_EU_ConfigScope │ Per-operation control, full flexibility │ ├─ TR-069 ACS (CWMP) │ └─ Configure: /etc/config/cwmp (KeepConfig, KeepOpConf, ConfigScope) │ Firmware defaults, applies to all upgrades │ ├─ DHCP Onboarding │ └─ Use: reset_mode=full (or omit) │ Limited control, only factory reset vs preserve │ └─ CLI (fwbank) └─ Use: keep_settings, keep_opconf, config_scope parameters Direct control, all options available ``` --- **Document Version:** 1.0 **Last Updated:** 2025-11-26 **Author:** iopsys Technical Documentation **Contact:** support@iopsys.eu