# Netmode Developer Guide

## Table of Contents
1. [Development Environment Setup](#development-environment-setup)
2. [Package Build System](#package-build-system)
3. [Code Organization](#code-organization)
4. [API Reference](#api-reference)
5. [Mode Script Development](#mode-script-development)
6. [UCI Integration](#uci-integration)
7. [Data Model Development](#data-model-development)
8. [Debugging Techniques](#debugging-techniques)
9. [Testing Framework](#testing-framework)
10. [Release Process](#release-process)

---

## Development Environment Setup

### Prerequisites

```bash
# OpenWrt build environment
sudo apt-get install build-essential libncurses5-dev gawk git \
    subversion libssl-dev gettext unzip zlib1g-dev file python3

# Clone iopsys repository
git clone https://dev.iopsys.eu/iopsys/iopsyswrt.git
cd iopsyswrt

# Update feeds
./scripts/feeds update -a
./scripts/feeds install -a
```

### Building netmode Package

```bash
# Configure build
make menuconfig
# Navigate to: Utilities -> netmode

# Build package only
make package/feeds/iopsys/netmode/compile V=s

# Build with debug symbols
make package/feeds/iopsys/netmode/compile V=s CONFIG_DEBUG=y
```

### Installing to Device

```bash
# Copy to device
scp bin/packages/*/iopsys/netmode_*.ipk root@192.168.1.1:/tmp/

# Install on device
ssh root@192.168.1.1
opkg install /tmp/netmode_*.ipk
```

### Development Workflow

```bash
# Make changes to files in feeds/iopsys/netmode/files/

# Clean and rebuild
make package/feeds/iopsys/netmode/clean
make package/feeds/iopsys/netmode/compile V=s

# Test on device
scp bin/packages/*/iopsys/netmode_*.ipk root@192.168.1.1:/tmp/
ssh root@192.168.1.1 "opkg remove netmode; opkg install /tmp/netmode_*.ipk"
```

---

## Package Build System

### Makefile Analysis

```makefile
PKG_NAME:=netmode
PKG_VERSION:=1.1.11
PKG_RELEASE:=1
```

**Version Scheme**: `MAJOR.MINOR.PATCH`
- **MAJOR**: Breaking changes
- **MINOR**: New features, backward compatible
- **PATCH**: Bug fixes

### Build Configuration

```makefile
define Package/$(PKG_NAME)/config
    config NETMODE_VENDOR_PREFIX
        depends on PACKAGE_netmode
        string "Vendor Extension used for netmode datamodel"
        default ""
endef
```

**Usage in code**:
```json
"object": "{BBF_VENDOR_PREFIX}NetMode"
```

Replaced by `BBFDM_REGISTER_SERVICES` during build.

### Installation Targets

```makefile
define Package/netmode/install
    $(INSTALL_DIR) $(1)/etc
    $(INSTALL_DIR) $(1)/lib
    $(CP) ./files/etc/* $(1)/etc/
    $(CP) ./files/lib/* $(1)/lib/
    $(BBFDM_REGISTER_SERVICES) -v ${VENDOR_PREFIX} ./bbfdm_service.json $(1) $(PKG_NAME)
    $(BBFDM_INSTALL_MS_DM) -v ${VENDOR_PREFIX} ./files/datamodel.json $(1) $(PKG_NAME)
endef
```

**File Permissions**:
- Scripts in `/etc/init.d/`: `0755` (executable)
- UCI configs: `0644` (readable)
- Mode scripts: Must be made executable in postinst

---

## Code Organization

### Module Responsibilities

| Module | File | Responsibility |
|--------|------|----------------|
| **Init System** | `/etc/init.d/netmode` | Service lifecycle, mode switching orchestration |
| **Mode Scripts** | `/etc/netmodes/<mode>/scripts/*` | Mode-specific UCI configuration |
| **Pre-hooks** | `/lib/netmode/pre/*` | Pre-switch preparation |
| **Post-hooks** | `/lib/netmode/post/*` | Post-switch cleanup, reboot |
| **UCI Defaults** | `/etc/uci-defaults/*` | First-boot configuration |
| **Data Model** | `/files/datamodel.json` | BBF TR-181 mappings |
| **Service Def** | `bbfdm_service.json` | BBF service registration |

### Init Script Architecture

```
/etc/init.d/netmode
├── start_service()           # Main entry point
│   ├── configure_env_vars()  # Setup NETMODE_* vars
│   ├── libnetmode_exec("pre")
│   ├── Copy UCI files
│   ├── libnetmode_exec()     # Generic scripts
│   ├── Execute mode scripts
│   ├── libnetmode_exec("post")
│   └── cleanup_env_vars()
├── service_triggers()        # Procd reload trigger
└── Helper functions:
    ├── _log()
    ├── _get_modes_sec_name()
    ├── _set_env_args()
    └── cleanup_arg_values()
```

---

## API Reference

### Init Script Functions

#### `start_service()`

Main service entry point called by procd.

**Execution Conditions**:
- `/etc/config/netmode` exists
- `netmode.global.enabled = 1`
- `netmode.global.mode` is set
- Current mode differs from `.last_mode`

**Side Effects**:
- Modifies UCI configuration
- Exports environment variables
- Writes `.last_mode` file
- May trigger system reboot (via post-hook)

#### `configure_env_vars(mode)`

Exports mode arguments as environment variables.

**Parameters**:
- `mode`: Mode name (e.g., "routed-pppoe")

**Behavior**:
1. Find UCI section matching mode name
2. Iterate `supported_args` with matching `dm_parent`
3. Export `NETMODE_<name>=<value>` if value is non-empty
4. Exit if required arguments are missing

**Example**:
```bash
configure_env_vars "routed-pppoe"
# Exports:
# NETMODE_username="user@isp.com"
# NETMODE_password="secret123"
```

#### `cleanup_env_vars(mode)`

Unsets NETMODE_* environment variables and clears UCI values.

**Parameters**:
- `mode`: Current mode name

**Behavior**:
1. Unset all `NETMODE_*` environment variables
2. Clear `value` field in UCI for all arguments of current mode
3. Commit UCI changes

**Security Note**: Prevents leaking credentials to subsequent processes.

#### `libnetmode_exec(when)`

Executes hook scripts from `/lib/netmode/<when>/`.

**Parameters**:
- `when`: Hook type ("pre", "post", or empty for default)

**Execution**:
- Scripts executed in lexicographical order
- Runs in subshell via `sh <script>`
- Logs execution to syslog

**Example**:
```bash
libnetmode_exec "pre"
# Executes: /lib/netmode/pre/10-backup
#           /lib/netmode/pre/20-prepare
```

#### `_log(message)`

Logs message to syslog with netmode tag.

**Parameters**:
- `message`: Log message

**Implementation**:
```bash
logger -s -p user.info -t "netmode" "$*"
```

---

## Mode Script Development

### Script Template

```bash
#!/bin/sh
#
# Mode: <mode-name>
# Description: <brief description>
# Required Arguments: <list>
# Optional Arguments: <list>
#

. /lib/functions.sh
. /usr/share/libubox/jshn.sh

# Source device-specific info if available
[ -f /etc/device_info ] && source "/etc/device_info"

# Logging function
_log() {
    logger -s -p user.info -t "netmode-<mode>" "$*"
}

# Main configuration function
configure_network() {
    _log "Starting network configuration"

    # Get WAN device
    wandev="$(uci -q get network.WAN.ifname)"
    [ -z "$wandev" ] && wandev="eth0"  # Fallback

    # Validate required arguments
    if [ -z "$NETMODE_required_arg" ]; then
        _log "ERROR: Missing required argument: required_arg"
        return 1
    fi

    # Configure network interface
    uci -q set network.lan=interface
    uci -q set network.lan.device='br-lan'
    uci -q set network.lan.proto='static'
    uci -q set network.lan.ipaddr='192.168.1.1'
    uci -q set network.lan.netmask='255.255.255.0'

    # Mode-specific WAN configuration
    uci -q set network.wan=interface
    uci -q set network.wan.device="$wandev"
    # Add mode-specific settings here

    uci -q commit network

    _log "Network configuration complete"
}

# Configure DHCP server
configure_dhcp() {
    _log "Configuring DHCP"

    uci -q set dhcp.lan.ignore=0
    uci -q set dhcp.wan.ignore=1
    uci -q commit dhcp
}

# Configure firewall
configure_firewall() {
    _log "Configuring firewall"

    uci -q set firewall.globals.enabled="1"
    uci -q commit firewall
}

# Configure multicast
configure_multicast() {
    _log "Configuring multicast"

    # L3 or L2 multicast config
    rm -f /etc/config/mcast
    sh /rom/etc/uci-defaults/61-mcast_config_generate
    uci -q commit mcast
}

# Update service dependencies
configure_services() {
    _log "Updating service configurations"

    # CWMP WAN interface
    uci -q set cwmp.cpe.default_wan_interface="wan"
    uci -q commit cwmp

    # Gateway WAN interface
    uci -q set gateway.global.wan_interface="wan"
    uci -q commit gateway

    # SSDPD
    uci -q set ssdpd.ssdp.enabled="1"
    uci -q commit ssdpd
}

# Main execution
configure_network || exit 1
configure_dhcp
configure_firewall
configure_multicast
configure_services

_log "Mode configuration complete"
exit 0
```

### Common Patterns

#### VLAN Configuration

```bash
configure_vlan() {
    local wandev="$1"

    # Delete existing VLANs
    for vlandev_sec in $(uci show network | grep "type=.*8021q" | cut -d'.' -f1,2); do
        uci -q delete $vlandev_sec
    done

    # Create new VLAN if vlanid provided
    if [ -n "$wandev" ] && echo "$NETMODE_vlanid" | grep -Eq '^[0-9]+$' && [ "$NETMODE_vlanid" -ge 1 ]; then
        local vlandev="$wandev.$NETMODE_vlanid"
        local vlandev_sec=$(echo $vlandev | tr '.' '_')

        uci -q set network.${vlandev_sec}=device
        uci -q set network.${vlandev_sec}.type="8021q"
        uci -q set network.${vlandev_sec}.name="$vlandev"
        uci -q set network.${vlandev_sec}.ifname="$wandev"
        uci -q set network.${vlandev_sec}.vid=$NETMODE_vlanid

        echo "$vlandev"
    else
        echo "$wandev"
    fi
}

# Usage
wandev="$(uci -q get network.WAN.ifname)"
wandev=$(configure_vlan "$wandev")
uci -q set network.wan.device="$wandev"
```

#### DNS Server Configuration

```bash
configure_dns() {
    uci -q delete network.wan.dns

    if [ -n "$NETMODE_dns_servers" ]; then
        local dns_servers="$(echo $NETMODE_dns_servers | tr ',' ' ')"
        for server in $dns_servers; do
            # Validate IP address format
            if echo "$server" | grep -Eq '^([0-9]{1,3}\.){3}[0-9]{1,3}$'; then
                uci add_list network.wan.dns="$server"
            else
                _log "WARNING: Invalid DNS server: $server"
            fi
        done
    fi
}
```

#### Bridge Port Configuration

```bash
configure_bridge_ports() {
    uci -q delete network.br_lan.ports
    uci -q set network.br_lan.bridge_empty='1'

    add_port_to_br_lan() {
        local port="$1"
        [ -n "$port" -a -d /sys/class/net/$port ] || return
        uci add_list network.br_lan.ports="$port"
        _log "Added $port to br-lan"
    }

    if [ -f /etc/board.json ]; then
        json_load_file /etc/board.json
        json_select network

        # LAN ports
        json_select lan
        if json_is_a ports array; then
            json_for_each_item add_port_to_br_lan ports
        else
            json_get_var device device
            [ -n "$device" ] && add_port_to_br_lan "$device"
        fi
        json_select ..

        # WAN ports (for bridged mode)
        if [ "$1" = "bridged" ]; then
            json_select wan 2>/dev/null
            json_get_var device device
            [ -n "$device" ] && add_port_to_br_lan "$device"
        fi

        json_cleanup
    fi
}
```

### Error Handling

```bash
# Validate critical operations
configure_network() {
    if ! uci -q get network.WAN >/dev/null; then
        _log "ERROR: WAN interface not found in board config"
        return 1
    fi

    if [ -z "$NETMODE_required_param" ]; then
        _log "ERROR: Required parameter missing"
        return 1
    fi

    # Perform configuration
    uci -q set network.wan.setting="$NETMODE_required_param" || {
        _log "ERROR: Failed to set UCI option"
        return 1
    }

    uci -q commit network || {
        _log "ERROR: Failed to commit network config"
        return 1
    }

    return 0
}

# Check return value
if ! configure_network; then
    _log "Configuration failed, aborting mode switch"
    exit 1
fi
```

---

## UCI Integration

### Reading UCI Values

```bash
# Get single value
enabled=$(uci -q get netmode.global.enabled)

# Get with default
mode=$(uci -q get netmode.global.mode || echo "routed-dhcp")

# Check if option exists
if uci -q get network.wan >/dev/null; then
    echo "WAN interface exists"
fi

# Iterate sections
config_load netmode
config_foreach handle_mode supported_modes

handle_mode() {
    local section="$1"
    local name
    config_get name "$section" name
    echo "Found mode: $name"
}
```

### Writing UCI Values

```bash
# Set option
uci set network.wan.proto='dhcp'

# Delete option
uci delete network.wan.username

# Delete section
uci delete network.wan6

# Add list item
uci add_list network.wan.dns='8.8.8.8'

# Delete all list items
uci delete network.wan.dns

# Always commit after changes
uci commit network
```

### UCI Section References

```bash
# Reference by index
uci set netmode.@supported_modes[0].name='routed-dhcp'

# Reference by name (if section is named)
uci set netmode.global.mode='routed-pppoe'

# Get section index
idx=$(uci show netmode | grep "name='routed-pppoe'" | cut -d. -f2 | cut -d= -f1)
uci set "netmode.$idx.description='PPPoE Mode'"
```

### Advanced UCI Operations

```bash
# Create anonymous section
uci add netmode supported_modes

# Rename section
uci rename netmode.@supported_modes[0]=pppoe_mode

# Reorder sections
uci reorder netmode.pppoe_mode=1

# Batch operations
uci batch <<EOF
set network.wan=interface
set network.wan.proto='dhcp'
set network.wan.device='eth0'
delete network.wan.ipaddr
commit network
EOF
```

---

## Data Model Development

### Adding New Parameters

#### 1. Update datamodel.json

```json
{
    "Device.{BBF_VENDOR_PREFIX}NetMode.SupportedModes.{i}.": {
        "NewParameter": {
            "type": "string",
            "read": true,
            "write": true,
            "description": "New parameter description",
            "protocols": ["cwmp", "usp"],
            "mapping": [
                {
                    "type": "uci_sec",
                    "data": "@Parent",
                    "key": "new_param"
                }
            ]
        }
    }
}
```

#### 2. Update UCI Schema

Add to `/etc/config/netmode`:

```uci
config supported_modes
    option name 'mode-name'
    option new_param 'default-value'
```

#### 3. Handle in Mode Script

```bash
#!/bin/sh
new_value="$NETMODE_new_param"
if [ -n "$new_value" ]; then
    uci set some_config.section.option="$new_value"
fi
```

### Data Type Mappings

| BBF Type | UCI Type | Shell Validation |
|----------|----------|------------------|
| `string` | text | `[ -n "$var" ]` |
| `unsignedInt` | integer | `echo "$var" \| grep -Eq '^[0-9]+$'` |
| `boolean` | 0/1 | `[ "$var" = "1" ]` |
| `dateTime` | timestamp | `date -d "$var"` |
| `base64` | base64 | `echo "$var" \| base64 -d` |

### Mapping Types

#### `uci` Mapping (Static Section)

```json
{
    "mapping": [
        {
            "type": "uci",
            "uci": {
                "file": "netmode",
                "section": {
                    "name": "global"
                },
                "option": {
                    "name": "enabled"
                }
            }
        }
    ]
}
```

#### `uci_sec` Mapping (Dynamic Section)

```json
{
    "mapping": [
        {
            "type": "uci_sec",
            "data": "@Parent",
            "key": "name"
        }
    ]
}
```

### Special Flags

| Flag | Purpose | Example |
|------|---------|---------|
| `Linker` | Reference target | Mode name for linking |
| `Reference` | Reference source | Mode selection |
| `Unique` | Value must be unique | Mode names |
| `Secure` | Hidden from GET | Passwords |

---

## Debugging Techniques

### Enable Verbose Logging

```bash
# In mode script
set -x  # Enable shell tracing
trap 'set +x' EXIT

# Or use logger extensively
_log() {
    logger -s -p user.debug -t "netmode-debug" "$*"
}
```

### Live Log Monitoring

```bash
# Terminal 1: Monitor logs
logread -f | grep -E "netmode|network|firewall"

# Terminal 2: Trigger mode switch
service netmode restart
```

### Capture Environment State

```bash
#!/bin/sh
# Add to mode script for debugging

DEBUG_DIR="/tmp/netmode-debug"
mkdir -p "$DEBUG_DIR"

# Save environment
env > "$DEBUG_DIR/env.txt"

# Save UCI state
uci export network > "$DEBUG_DIR/network.uci"
uci export netmode > "$DEBUG_DIR/netmode.uci"

# Save script output
exec 2>&1 | tee "$DEBUG_DIR/script-output.log"
```

### Interactive Testing

```bash
# Manually execute mode script
sh -x /etc/netmodes/routed-pppoe/scripts/10-routed-pppoe

# Set environment manually
export NETMODE_username="test"
export NETMODE_password="test123"
sh /etc/netmodes/routed-pppoe/scripts/10-routed-pppoe

# Check UCI changes without commit
uci changes
```

### Common Debug Commands

```bash
# Check last mode
cat /etc/netmodes/.last_mode

# Check netmode UCI
uci show netmode

# Check network UCI
uci show network | grep -E "lan|wan"

# Check process environment
cat /proc/$(pgrep netmode)/environ | tr '\0' '\n' | grep NETMODE

# Check procd service status
ubus call service list '{"name":"netmode"}'
```

### Procd Debugging

```bash
# Check procd service state
procd_status() {
    ubus call service list '{"name":"netmode"}' | jsonfilter -e '@.netmode'
}

# Manual procd trigger
ubus call service event '{"type":"config.change","data":{"package":"netmode"}}'

# Check init script syntax
sh -n /etc/init.d/netmode
```

---

## Testing Framework

### Unit Test Template

```bash
#!/bin/sh
# test-mode-routed-dhcp.sh

. /lib/functions.sh

PASSED=0
FAILED=0

assert_equal() {
    local expected="$1"
    local actual="$2"
    local test_name="$3"

    if [ "$expected" = "$actual" ]; then
        echo "✓ PASS: $test_name"
        PASSED=$((PASSED + 1))
    else
        echo "✗ FAIL: $test_name"
        echo "  Expected: $expected"
        echo "  Actual:   $actual"
        FAILED=$((FAILED + 1))
    fi
}

assert_exists() {
    local path="$1"
    local test_name="$2"

    if [ -e "$path" ]; then
        echo "✓ PASS: $test_name"
        PASSED=$((PASSED + 1))
    else
        echo "✗ FAIL: $test_name (path not found: $path)"
        FAILED=$((FAILED + 1))
    fi
}

test_mode_applied() {
    local expected_mode="$1"
    local actual_mode=$(cat /etc/netmodes/.last_mode 2>/dev/null)
    assert_equal "$expected_mode" "$actual_mode" "Mode applied"
}

test_wan_proto() {
    local expected_proto="$1"
    local actual_proto=$(uci -q get network.wan.proto)
    assert_equal "$expected_proto" "$actual_proto" "WAN protocol"
}

test_dhcp_enabled() {
    local expected="$1"
    local actual=$(uci -q get dhcp.lan.ignore)
    [ "$expected" = "enabled" ] && expected="0" || expected="1"
    assert_equal "$expected" "$actual" "DHCP server state"
}

# Run tests
echo "Testing routed-dhcp mode..."

test_mode_applied "routed-dhcp"
test_wan_proto "dhcp"
test_dhcp_enabled "enabled"
assert_exists "/etc/config/network" "Network config exists"

echo ""
echo "Results: $PASSED passed, $FAILED failed"
[ $FAILED -eq 0 ] && exit 0 || exit 1
```

### Integration Test Script

```bash
#!/bin/sh
# test-mode-switch.sh

MODE="$1"
[ -z "$MODE" ] && { echo "Usage: $0 <mode>"; exit 1; }

echo "=== Mode Switch Test: $MODE ==="

# Backup config
cp /etc/config/network /tmp/network.backup
cp /etc/config/netmode /tmp/netmode.backup

# Set mode
echo "Setting mode to $MODE..."
uci set netmode.global.mode="$MODE"
uci commit netmode

# Trigger switch
echo "Applying mode..."
service netmode restart
sleep 2

# Verify
echo "Verifying..."
LAST_MODE=$(cat /etc/netmodes/.last_mode)

if [ "$LAST_MODE" = "$MODE" ]; then
    echo "✓ Mode switch successful"

    # Run mode-specific tests
    case "$MODE" in
        routed-dhcp)
            [ "$(uci -q get network.wan.proto)" = "dhcp" ] && echo "✓ WAN proto correct"
            ;;
        routed-pppoe)
            [ "$(uci -q get network.wan.proto)" = "pppoe" ] && echo "✓ WAN proto correct"
            ;;
        bridged)
            [ -z "$(uci -q get network.wan)" ] && echo "✓ WAN interface removed"
            ;;
    esac
else
    echo "✗ Mode switch failed"
    echo "  Expected: $MODE"
    echo "  Actual:   $LAST_MODE"
fi

# Restore config
echo "Restoring config..."
cp /tmp/network.backup /etc/config/network
cp /tmp/netmode.backup /etc/config/netmode
uci commit
```

### Automated Test Suite

```bash
#!/bin/sh
# run-all-tests.sh

TESTS_DIR="$(dirname $0)/tests"
RESULTS_DIR="/tmp/netmode-test-results"

mkdir -p "$RESULTS_DIR"

TOTAL=0
PASSED=0
FAILED=0

for test_script in "$TESTS_DIR"/test-*.sh; do
    [ -f "$test_script" ] || continue

    TOTAL=$((TOTAL + 1))
    test_name=$(basename "$test_script" .sh)

    echo "Running $test_name..."
    if sh "$test_script" > "$RESULTS_DIR/$test_name.log" 2>&1; then
        echo "✓ $test_name PASSED"
        PASSED=$((PASSED + 1))
    else
        echo "✗ $test_name FAILED"
        FAILED=$((FAILED + 1))
        cat "$RESULTS_DIR/$test_name.log"
    fi
done

echo ""
echo "=== Test Summary ==="
echo "Total:  $TOTAL"
echo "Passed: $PASSED"
echo "Failed: $FAILED"

[ $FAILED -eq 0 ] && exit 0 || exit 1
```

---

## Release Process

### Version Bump Procedure

1. **Update version in Makefile**:
   ```makefile
   PKG_VERSION:=1.2.0
   PKG_RELEASE:=1
   ```

2. **Update changelog**:
   ```bash
   # Create CHANGELOG.md if not exists
   echo "## [1.2.0] - $(date +%Y-%m-%d)" >> CHANGELOG.md
   echo "### Added" >> CHANGELOG.md
   echo "- New feature description" >> CHANGELOG.md
   ```

3. **Test on target hardware**:
   ```bash
   make package/feeds/iopsys/netmode/clean
   make package/feeds/iopsys/netmode/compile V=s
   # Deploy and test
   ```

4. **Commit changes**:
   ```bash
   git add Makefile CHANGELOG.md
   git commit -m "netmode: update to version 1.2.0"
   ```

5. **Tag release**:
   ```bash
   git tag -a netmode-1.2.0 -m "Release version 1.2.0"
   git push origin netmode-1.2.0
   ```

### Pre-release Checklist

- [ ] All tests passing
- [ ] Documentation updated
- [ ] CHANGELOG.md updated
- [ ] Version numbers bumped
- [ ] Tested on at least 2 different hardware platforms
- [ ] Backward compatibility verified
- [ ] Data model compatibility checked
- [ ] No hardcoded paths or device-specific code
- [ ] Logging is appropriate (not too verbose)
- [ ] UCI defaults handle upgrade scenarios

### Package Validation

```bash
# Check package structure
tar -tzf netmode_*.ipk

# Verify file permissions
tar -xzf netmode_*.ipk -O ./data.tar.gz | tar -tzv

# Check dependencies
opkg info netmode_*.ipk | grep Depends

# Validate UCI config syntax
tar -xzf netmode_*.ipk -O ./data.tar.gz | tar -xz ./etc/config/netmode
uci import netmode < netmode
```

---

## Best Practices Summary

### Code Quality

1. **Always use shellcheck**:
   ```bash
   shellcheck /etc/init.d/netmode
   shellcheck /etc/netmodes/*/scripts/*
   ```

2. **Use set -e for critical scripts**:
   ```bash
   #!/bin/sh
   set -e  # Exit on error
   ```

3. **Quote all variables**:
   ```bash
   # Good
   uci set network.wan.device="$wandev"

   # Bad
   uci set network.wan.device=$wandev
   ```

4. **Check return values**:
   ```bash
   if ! configure_network; then
       logger -t netmode "Configuration failed"
       exit 1
   fi
   ```

### Performance Optimization

1. **Minimize UCI commits**:
   ```bash
   # Bad: Multiple commits
   uci set network.lan.ipaddr='192.168.1.1'
   uci commit network
   uci set network.lan.netmask='255.255.255.0'
   uci commit network

   # Good: Single commit
   uci set network.lan.ipaddr='192.168.1.1'
   uci set network.lan.netmask='255.255.255.0'
   uci commit network
   ```

2. **Avoid unnecessary mode switches**:
   ```bash
   # Check .last_mode before proceeding
   [ "$mode" = "$(cat /etc/netmodes/.last_mode)" ] && return
   ```

3. **Use batch UCI operations**:
   ```bash
   uci batch <<EOF
   set network.wan=interface
   set network.wan.proto='dhcp'
   commit network
   EOF
   ```

### Security Hardening

1. **Validate all input**:
   ```bash
   # VLAN ID validation
   if ! echo "$NETMODE_vlanid" | grep -Eq '^[0-9]+$'; then
       logger -t netmode "Invalid VLAN ID"
       return 1
   fi
   ```

2. **Clear sensitive data**:
   ```bash
   # Automatic via cleanup_env_vars()
   # But also clear from UCI
   uci set netmode.@supported_args[X].value=''
   ```

3. **Use secure file permissions**:
   ```bash
   # Scripts should be 0755
   # Configs should be 0644
   # Never 0777
   ```

---

## Troubleshooting

### Build Issues

**Issue**: Package fails to build

**Solution**:
```bash
# Clean build
make package/feeds/iopsys/netmode/clean
rm -rf build_dir/target-*/netmode-*

# Rebuild with verbose output
make package/feeds/iopsys/netmode/compile V=s
```

**Issue**: Data model registration fails

**Solution**:
```bash
# Check vendor prefix
grep BBF_VENDOR_PREFIX .config

# Verify bbfdm is installed
opkg list-installed | grep bbfdm
```

### Runtime Issues

**Issue**: Mode not switching

**Debug**:
```bash
# Check service status
service netmode status

# Check logs
logread | grep netmode

# Verify UCI
uci show netmode
```

**Issue**: Environment variables not set

**Debug**:
```bash
# Check dm_parent references
uci show netmode | grep dm_parent

# Verify argument values
uci show netmode | grep value
```

---

## Contributing Guidelines

### Code Style

- Use tabs for indentation (OpenWrt standard)
- Max line length: 120 characters
- Function names: `lowercase_with_underscores`
- Variables: `lowercase` or `UPPERCASE` for constants

### Commit Messages

```
netmode: brief description (max 50 chars)

Detailed explanation of changes (wrap at 72 chars).
- Bullet points for multiple changes
- Reference issue numbers if applicable

Signed-off-by: Your Name <email@example.com>
```

### Pull Request Process

1. Fork the repository
2. Create feature branch: `git checkout -b feature/my-feature`
3. Make changes and test thoroughly
4. Update documentation
5. Submit PR with clear description
6. Address review comments

---

## Resources

- **OpenWrt Documentation**: https://openwrt.org/docs/
- **UCI Documentation**: https://openwrt.org/docs/guide-user/base-system/uci
- **Procd**: https://openwrt.org/docs/guide-developer/procd-init-scripts
- **Shell Style Guide**: https://google.github.io/styleguide/shellguide.html
- **iopsys Development**: https://dev.iopsys.eu/

---

**Maintainer**: iopsys Development Team
**License**: GPL-2.0-only
**Version**: 1.1.11
