49 KiB
Firmware Upgrade System - Complete Guide
Table of Contents
- Overview
- Architecture
- Configuration Parameters
- Upgrade Methods
- Configuration Preservation
- Operator Configuration Guide
- Troubleshooting
- 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:
{
"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 informationupgrade- Write firmware to bankset_bootbank- Set which bank boots nextcopy_config- Preserve configuration
UBUS Interface:
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 implementationsrc/fwbank.c- fwbank integrationsrc/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 toconfig_scope0- Factory reset, discard ALL configurations
Usage:
{
"keep_settings": 1
}
or in BBF operations:
{
"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.json0- Delete operator configuration (ISP reset)
Only effective when: keep_config=1
Usage:
{
"keep_opconf": 1
}
or in BBF operations:
{
"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:
{
"config_scope": "UserOnly"
}
or in BBF operations:
{
"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:
{
"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:
- USP/TR-369 - Modern BBF protocol (via Sulu GUI or external controller) → Uses BBF datamodel
- TR-069/CWMP - Legacy ACS protocol → Uses BBF datamodel
- DHCP Onboarding - Zero-touch provisioning → Direct UBUS to fwbank
- 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:
KeepConfigtoggle 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
KeepConfigtoggle in file upload mode. To controlKeepOpConfandConfigScope, operators must use system defaults (configured in firmware) or use an external USP controller with full parameter support.
Example: Sulu GUI Firmware Upload
// Sulu GUI uploads firmware file in chunks
await uploadFileChunked({
Filename: "firmware.itb",
Content: "<base64-encoded-firmware>",
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
{
"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:
# 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:
# Configure USP connection profile
dmcli
# set Settings.USP.ActiveConnectionProfile iowrt-gnx-operator
# do Settings.USP.Connect()
Example: Firmware Upgrade via dmcli
Interactive Mode:
# 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:
# 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
{
"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:
# 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
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
-
ACS sends Download RPC:
<Download> <CommandKey>fw-upgrade-20251126</CommandKey> <FileType>1 Firmware Upgrade Image</FileType> <URL>https://firmware.isp.com/cpe/v5.15.0.itb</URL> <Username>fwuser</Username> <Password>secret123</Password> <FileSize>52428800</FileSize> </Download> -
icwmp processes download:
// 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 } }); } -
CPE sends TransferComplete event back to ACS
Dynamic Configuration Override
To change config behavior before upgrade:
# 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
# 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
# /rom/etc/config/cwmp (in firmware image)
config cpe 'cpe'
option KeepConfig '1'
option KeepOpConf '1'
option ConfigScope 'UserOnly'
DHCP Server Example (Kea)
{
"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:
# 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:
opconf_conf_handler -k <keep_config> -o <keep_opconf> -s <config_scope>
Logic:
#!/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:
/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:
{
"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:
#!/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):
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:
{
"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:
- Navigate to System → Firmware
- Upload firmware.itb
- ✅ Enable "Keep Settings" toggle
- Click "Start Upgrade"
Sulu sends USP Download() operation:
{
"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:
- Gets DHCP lease
- Downloads firmware → factory reset (reset_mode=full)
- Downloads encrypted config → applies ISP settings
- 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:
{
"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:
{
"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:
# 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:
-
Check if
/usr_datapartition exists:mount | grep usr_data df -h | grep usr_data -
Check opconf_conf_handler was called:
logread | grep opconf_conf_handler -
Check for userconf.json:
ls -la /usr_data/userconf/ -
Check config parameters used:
logread | grep -E "keep_settings|keep_opconf|config_scope"
Solutions:
-
Missing /usr_data: Partition not created, config preservation disabled
# Check flash layout cat /proc/mtd -
opconf not available: System falls back to legacy mode
which opconf_conf_handler # If missing: config_scope forced to "All" -
Parameters not passed: Check upgrade method's config support
# 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:
# Check if opconf.json exists
ls -la /usr_data/opconf/opconf.json
# Check upgrade parameters
logread | grep keep_opconf
Possible Causes:
-
USP controller sent KeepOpConf=0:
- Check USP controller logs for Download() parameters
-
TR-069 UCI default was 0:
uci show cwmp.cpe.KeepOpConf # Should be '1', if '0' → operator config deleted -
DHCP upgrade with no opconf support:
- DHCP onboarding doesn't support keep_opconf
- Pre-configure firmware with ISP settings baked in
Prevention:
# 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:
# Check sysupgrade events
ubus listen sysupgrade &
# Check fwbank status
ubus call fwbank dump
# Check for hung sysupgrade process
ps | grep sysupgrade
Possible Causes:
-
Invalid firmware image:
sysupgrade -T /tmp/firmware.itb # Should output: Image check succeeded -
Insufficient flash space:
df -h /tmp df -h /overlay -
sysupgrade process crashed:
logread | grep sysupgrade | tail -50
Recovery:
# 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:
# 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:
-
AutoActivate was 0:
- Download() completed but didn't set boot bank
- Need to manually call Activate()
-
Bootloader failed to switch:
- U-Boot issue
- Environment not writable
Solution:
# 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:
{
"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:
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:
{
"result": "ok"
}
or
{
"result": "error",
"message": "Invalid firmware image"
}
Example:
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:
{
"result": "ok"
}
Example:
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:
{
"result": "ok"
}
Example:
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:
{
"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):
{
"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):
{
"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:
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)
# 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)
# 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