# MAP Agent

[Map-agent](https://dev.iopsys.eu/iopsys/map-agent)


## Introduction

This package provides the mapagent daemon, which implements the WiFi Alliances
Easymesh Agent component.

## Overview

This README will show how to properly setup the mapagent configuration file
and explain some key features of map-agent:

* Onboarding
* AP-Autoconfiguration
* Controller Discovery
* Dynamic Controller Sync
* Dynamic Backhaul Upgrade
* Island Prevention

## UCI Configuration

For full documentation of UCI configuration options, see
[UCI docs](./docs/api/mapagent.md).

When starting map-agent, the only _mandated_ section is the global agent
section:

```
config agent 'agent'
	option enabled '1'
	option debug '0'
	option profile '2'
	option brcm_setup '1'
	option al_bridge 'br-lan'
	option netdev 'wl'
	option island_prevention '0'
	option eth_onboards_wifi_bhs '1'
	option guest_isolation '1'
	option scan_on_boot_only '0'
```

All the remaining mandatory (`radio`) and optionally mandatory (`ap`) may
be generated by map-agent at start-up. Whereas the non-mandatory sections may
use their default values.

The `ap` sections will be automatically generated based on the presence of a
`multi_ap` flag in the wireless configuration file under the `wifi-iface`
sections. If such a flag is set, map-agent assumes it is a multi_ap interface.
Nonetheless, it is recommended that the map-agent configuration is aligned
with the respective `ap` section for each interface that is to be a part of the
mesh and managed by map-agent. For more information on how to align the
map-agent and wireless configuration file, see the quick start [guide](./docs/QUICK_START.md).
Additional interfaces may be generated at runtime, as dictated by mapcontroller.

Existing interfaces *not* included in the configuration will not be a part of
the mesh, meaning no statistics will be gathered, clients steered and the
interface will never be torn down or otherwise configured by mapagent.

To summarize:
* Mapagent may automatically generate mandatory `radio` and optionally mandatory
`ap` sections
* Mapagent will manage all interface provided within its configuration file
* Mapagent will not touch interfaces not in its configuration file. They will
be left intact (and outside of the mesh) and be interleaved with any additional
interfaces provided by mapcontroller
* Mapagent will create interfaces as necessary, adding them to both mapagent
and wireless configuration files

**Some notes concerning multiap configuration files.**
While preparing the */etc/config/wireless* configuration, please note that some options may be changed during autoconfiguration proces.
Such options are wps_pushbutton and hidden of wifi-iface section. Actions taken and final value of those options depends mainly on type
of multi_ap interface (value of option multi_ap in current wifi-iface section).

For backhaul interfaces where
```
option multi_ap '1'
```
following rules apply:
* 'hidden' option when provided stays as it is,
* if 'hidden' option is not provided in that wifi-iface section, it is set to hidden=1 by adding
```
option hidden '1'
```

For fronthaul and combined interfaces where
```
option multi_ap '2'
or
option multi_ap '3'
```
following rules apply:
* 'wps_pushbutton' option when provided stays as it is,
* if 'wps_pushbutton' option is not provided in that wifi-iface section, it is set to wps_pushbutton=1 by adding
```
option wps_pushbutton '1'
```

Additional rule apply when traffic separation is enabled in */etc/config/mapcontroller* by
```
option enable_ts '1'
```
in controller section of that config.

Additional rule concerns guest network which should be added in */etc/config/mapcontroller* file always after already existing networks.
This rule is that guest network will always have wps_pushbutton disabled by
```
option wps_pushbutton '0'
```
always placed in that wifi-iface section.

### Example Start Configurations

A default configuration file may look as such:

```
config agent 'agent'
	option enabled '1'
	option debug '0'
	option profile '2'
	option brcm_setup '1'
	option al_bridge 'br-lan'
	option netdev 'wl'
	option island_prevention '0'

config dynamic_backhaul
	option missing_bh_timer '60'

config controller_select
	option local '0'
	option id 'auto'
	option probe_int '20'
	option retry_int '9'
	option autostart '1'

config ap
	option ifname 'wl0.1'
	option band '5'
	option device 'wl0'

config ap
	option ifname 'wl1.1'
	option band '2'
	option device 'wl1'

config bsta
	option ifname 'wl0'
	option band '5'
	option device 'wl0'
	option priority '1'

config bsta
	option ifname 'wl1'
	option band '2'
	option device 'wl1'
	option priority '2'

config bsta
	option ifname 'wl2'
	option band '5'
	option device 'wl2'
	option priority '0'

config radio
	option device 'wl2'
	option band '5'
	option dedicated_backhaul '1
```

The above example of a mapagent config would map properly against the
following wireless configuration file:

```
config wifi-device 'wl0'
	option type 'mac80211'
	option channel 'auto'
	option hwmode '11a'
	option country 'DE'
	option htmode 'HE80'
	option apsta '1'
	option phy 'phy0'

config wifi-iface 'default_wl0'
	option device 'wl0'
	option network 'lan'
	option ifname 'wl0.1'
	option mode 'ap'
	option ssid 'iopsysWrt-EC6C9A52ACB7'
	option encryption 'psk2'
	option key 'wifiEC6C9A52ACB7'
	option wps '1'
	option wps_pushbutton '1'
	option ieee80211k '1'
	option bss_transition '1'
	option multi_ap '2'

config wifi-device 'wl1'
	option type 'mac80211'
	option channel 'auto'
	option hwmode '11g'
	option country 'DE'
	option htmode 'HE20'
	option apsta '1'
	option phy 'phy1'

config wifi-iface 'default_wl1'
	option device 'wl1'
	option network 'lan'
	option ifname 'wl1.1'
	option mode 'ap'
	option ssid 'iopsysWrt-EC6C9A52ACB7'
	option encryption 'psk2'
	option key 'wifiEC6C9A52ACB7'
	option wps '1'
	option wps_pushbutton '1'
	option ieee80211k '1'
	option bss_transition '1'
	option multi_ap '2'

config wifi-device 'wl2'
	option type 'mac80211'
	option channel 'auto'
	option hwmode '11a'
	option country 'DE'
	option htmode 'HE80'
	option apsta '1'
	option phy 'phy2'

config wifi-iface 'default_sta_wl1'
	option device 'wl1'
	option mode 'sta'
	option ifname 'wl1'
	option multi_ap '1'
	option disabled '0'

config wifi-iface 'default_sta_wl0'
	option device 'wl0'
	option mode 'sta'
	option ifname 'wl0'
	option multi_ap '1'
	option disabled '0'

config wifi-iface 'default_sta_wl2'
	option device 'wl2'
	option mode 'sta'
	option ifname 'wl2'
	option multi_ap '1'
	option disabled '0'

```

### Radios

The `radio` section will primarily hold the band, device name and whether the
radio is a dedicated backhaul. Dedicated backhaul means no AP interfaces
will be configured on the radio via AP-Autoconfig.

Radio sections will be auto-generated on startup by mapagent if not present.

An example config:
```
config radio
	option device 'wl0'
	option band '5'
	option dedicated_backhaul '1'
```

More radio specific configuration and policies will by the map-controller within
the Multi-AP Policy Config Request CMDU.

### Interfaces

When specifying an interface in the mapagent configuration file, there are four
parameters that must be set.

Map-agent configuration divides interfaces into different section types, based
on the interface type. Backhaul station interfaces are defined with the section
type `bsta`:

```Minimum BSTA configuration
config bsta
	option ifname 'wl1'
	option band '2'
	option device 'wl1'
```

Fronthaul and backhaul BSS are created with the section type `ap`:

```Minimum AP configuration
config ap
	option ifname 'wl1.1'
	option band '2'
	option device 'wl1'
```

Each interface section must at minimum contain the options:
* `band` - Set `2` for 2.4GHz, `5` for 5GHz and `6` for 6GHz
* `ifname` - Interface name
* `device` - Device name (i.e. radio name)

An `ap` section may optionally include:
* `type` - Human readable multi_ap flag. (`backhaul`, `fronthaul`, `combined`)
* `ssid` - SSID of this AP
* `key` - Key of this AP
* `encryption` - Encryption used by this AP
* `vid` - VLAN ID handled by this AP, if any
* `enabled` - If interface is enabled and written to hostapd config.
* `disallow_bsta` - Disallow connections from certain Multi-AP profiles. Used as
bitmap.

All optional arguments will be provided within WSC M2 provided by
map-controller. If an AP is provided within a WSC M2 but there are no AP
sections available within map-agent configuration, map-agent will generate a new
interface section for it.

#### Fronthaul Interfaces

Fronthaul interfaces are `ap` sections with `type 'fronthaul'` set.

Applicable options: `ssid`, `key`, `encryption`, `vid`, `enabled`.

```
config ap
	option ifname 'wl0.1'
	option band '5'
	option device 'wl0'
	option ssid 'MAP-44D4376AF7F0-5GHz'
	option key 'IFJBD2RGYLZ3NE'
	option encryption 'psk2+aes'
	option type 'fronthaul'
	option vid '1'
	option enabled '1'
```

#### Backhaul Interfaces

Backhaul interfaces are `ap` sections with `type 'backhaul'` set.

Applicable options: `ssid`, `key`, `encryption`, `vid`, `enabled` and
`disallow_bsta`.

```
config ap
	option ifname 'wl0.2'
	option band '5'
	option device 'wl0'
	option ssid 'MAP-44D4376AF7F0-BH-5GHz'
	option key 'd6971d59b096ba3906d20f50dde7e19e7159dfe6eea1765a414e17c90aaefe7a'
	option encryption 'psk2+aes'
	option type 'backhaul'
	option disallow_bsta '0'
	option vid '1'
	option enabled '1'
```


#### Combined Front/Back Interfaces

Combined fronthaul/backhaul interfaces are `ap` sections with
`type 'combined'` set.

Applicable options: `ssid`, `key`, `encryption`, `vid`, `enabled` and
`disallow_bsta`.


```
config ap
	option ifname 'wl0.1'
	option band '5'
	option device 'wl0'
	option ssid 'MAP-44D4376AF7F0-COMBINED-5GHz'
	option key 'IFJBD2RGYLZ3NE'
	option encryption 'psk2+aes'
	option type 'combined'
	option disallow_bsta '0'
	option vid '1'
	option enabled '1'
```


#### Backhaul Station Interfaces

Backhaul station interfaces are `bsta` sections.

If not present in map-agent configuration, all interfaces in the wireless
configuration with `option mode 'sta'` will be automatically added to map-agent
configuration.

Once WPA onboarded, map-agent will set `option onboarded '1'` along with the
passed credentials.

An onboarded backhaul station may look as follows:

```
config bsta
	option ifname 'wl1'
	option band '2'
	option device 'wl1'
	option priority '2'
	option encryption 'sae-mixed'
	option ssid 'MAP-021000000001-BH-2.4GHz'
	option key '569dfdc9447e494da231d4def3441ed92c8f63985d8992cb521d77e1763c00d'
	option onboarded '1'
	option vid '1'
	option bssid '0e:10:00:00:00:04'	# set upon connection
	option enabled '1' 			# managed by mapagent for dynamic backhaul
```

### Multi-Link Operation

Map-agent supports Multi-Link Operation (MLO) as configured by map-controller
via Agent AP MLD Configuration TLVs and Backhaul STA MLD Configuration TLVs.

### Prerequisite
If the device supports MLO, as can be observed via wifimngr output:

```
root@iopsys:~# ubus call wifi.radio.radio0_band0 status
{
        "radio": "radio0_band0",
        "phyname": "phy0",
        "macaddr": "ac:91:9b:b7:03:ec",
	...
        "mlo_capable": true,
        "ap_caps": {
                "emlsr_supported": true,
                "emlmr_supported": false,
                "max_links": 4,
                "ttlm": 2
        },
        "sta_caps": {
                "emlsr_supported": false,
                "emlmr_supported": false,
                "max_links": 0,
                "ttlm": 0
        },
```

If MLO support is indicated by the driver as can be observed by
`"mlo_capable": true` the `ap_caps` and `sta_caps` array indicate the supported
MLO operational modes.

Additionally then, MLO must be configured in the repsective device's wireless
configuration:

```
config wifi-device 'radio0_band1'
	...
	option mlo '1'
	option mlo_capable '1'
```

#### Interfaces

#### Map-agent
If supported and the respective TLVs are provided by the map-controller,
map-agent will create an `mld` configuration section in its UCI configuration.

```
config mld
	option id '1'
	option ssid 'IOWRT-MLO-SSID'
	option key '1234567890'
	option type 'fronthaul'
```

Each interface provided via AP-Autoconfiguration WSC message that has the
same SSID as provided via the Agent AP MLD Configuration TLV will be added to
the MLD by adding the option `mld_id` with the corresponding id.

```
config ap
	option ifname 'wlan01-1'
	option band '5'
	option device 'radio0_band1'
	option ssid 'IOWRT-MLO-SSID'
	option key '1234567890'
	option encryption 'sae-mixed'
	option type 'fronthaul'
	option disallow_bsta '0'
	option vid '1'
	option enabled '1'
	option mld_id '1'
```

#### Wireless

Similarily in the wireless UCI configuration, map-agent will generate the
`wifi-mld` section with the respective configuration.

```
config wifi-mld 'mld1	'
	option ifname 'wlan0'
	option sae_pwe '2'
	option ssid 'IOWRT-MLO-SSID'
	option key '1234567890'
```

By adding the option `mld` to the interface configuration, the interface is
added to the MLD.

```
config wifi-iface 'default_wl0'
	option device 'wl0'
	option network 'lan'
	option ifname 'wl0.1'
	option mode 'ap'
	option ssid 'iopsysWrt-EC6C9A52ACB7'
	option encryption 'psk2'
	option key 'wifiEC6C9A52ACB7'
	option wps '1'
	option wps_pushbutton '1'
	option ieee80211k '1'
	option bss_transition '1'
	option multi_ap '2'
	option mld 'mld1'
```

## Onboarding

Onboarding includes backhaul credential exchange and establishment of the
wireless link between two devices.

This guide will focus on onboarding from a backhaul STA towards a
backhaul BSS. If using a combined fronthaul/backhaul interface the steps still
apply, with the exception of the uci options `multi_ap_backhaul_ssid` and
`multi_ap_backhaul_key` may be left out, and WPS be started directly on the
combined interface.

### Prerequisites

* To perform onboarding, mapagent must be running at both the registrar
and enrollee node.
* The registrar radio and enrollee radio must be running in a
compatible band
* The wireless uci configuration must have the backhaul credentials in the
fronthaul section under the keys `multi_ap_backhaul_ssid` and
`multi_ap_backhaul_key` (Automatically generated after AP-Autoconfiguration).
* The enrollee backhaul STA interface must not be a part of a bridge
* Enrollee and registrar interface must both have the multi_ap options properly
set in the wireless config (multi_ap '1' for STA and backhaul BSS, multi_ap '2'
for fronthaul BSS) for the multiap IE to be passed.
* It is recommended that `option channel 'auto'` is set for the backhaul STA
radio in its wireless configuration.

### How to Start

With the prerequisites in place, on the registrar, WPS must be started on the
fronthaul interface with role registrar (default), as backhaul BSS do not
support WPS. However, with the `multi_ap` options set appropriately in the
wireless configuration file a multiap IE will be passed with the WPS and the
backhaul credentials be provided to the enrollee.

Registrar:
* `ubus call wifi.wps start '{"ifname":"wl0"}'`

On the enrollee side, wps must be performed over the backhaul STA interface,
and the role `bsta` must be passed.

Enrollee:
* `ubus call wifi.wps start '{"ifname":"wl0", "role":"bsta"}'`

When the devices pair, the credentials will be published as ubus event:
```
{ "wps_credentials": {"ifname":"wl0","encryption":"psk2", "ssid":"iopsysWrt-BACKHAUL-5GHz","key":"12345678BACKHAUL" }}
```

Mapagent will pick up this ubus event and add these credential to the mapagent
and wireless configuration and load them in-memory to wpa_supplicant
(backhaul STA), after which wpa_supplicant will establish a connection.

When the `wifi.bsta` connection event comes over ubus:

```
{ "wifi.bsta": {"ifname":"wl0","event":"connected","data":{"macaddr":"0a:10:00:00:00:03","ssid":"iopsysWrt-BACKHAUL-5GHz"}} }

```
Mapagent will then wait till that interface has fully transitioned into 4address
mode before adding the backhaul station to the bridge.

Once the backhaul station is in the bridge, connectivity to the upstream device
is established and onboarding is complete.


## AP-Autoconfig

AP-Autoconfig includes the triggering of AP-Autoconfig Search, AP-Autoconfig
Response, AP-Autoconfig WSC and the configuration of the credentials provided
with the AP-Autoconfig WSC.

For how to configure mapcontroller for AP-Autoconfiguration, see
[Map-Controller](https://dev.iopsys.eu/iopsys/map-controller).

### Prerequisites

* Mapcontroller must be active in the network.

### Mechanics

Map-agent is periodically sending AP-Autoconfig Search messages, to find the
map-controller, as well as other agents in the mesh. When an
AP-Autoconfiguration Response with SupportedRole=Controller is received,
map-agent will send an AP-Autoconfig WSC M1 if it has not been configured
already.

The periodicity of AP-Autoconfig Search messages is set by `probe_int`
(defaults to 20s if not set) in the mapagent configuration. Once autoconfigured
an interval of 70s will be used as heartbeat timer.

#### Radio State

Map-agent maintains a radio state for each radio, to prevent redundent
configurations messages. A radio can be in one of two states:
* `AUTOCFG_ACTIVE` - If an AP-Autoconfig Response is received from a mapcontroller
in this state, map-agent will send back an AP-Autoconfig WSC M1
* `AUTOCFG_HEARTBEAT` - Map-agent is only sending AP-Autoconfig Searches in order
to establish that mapcontroller is still available. No further action upon
responses.

Some conditions that will set map-agent radios to an active state
* Upon mapagent (re)start
* Establishing a first-time connection over a backhaul STA
* No mapcontroller is observed for `probe_int` * `retry_int` seconds
* New mapcontroller is discovered (almac of controller changed)
* Connection was lost for `missing_bh_timer` + 15 seconds
* Backhaul STA connects to a different BSSID

#### Upon Receival of AP-Autoconfig WSC M2

After map-agent finds a controller and it has sent an AP-Autoconfig WSC (M1) to
which the mapcontroller will answer with an AP-Autoconfig WSC (M2).

Within the M2 map-agent will find credentials which it will write to the
mapagent and wireless configurations. After, it will schedule a wifi reload in 5
seconds. The timeout is to account for any delayed CMDUs and batch the
credentials rather than doing restarts one radio at a time. When a radio has
been configured via an M2 there will be an event published over ubus:

```
{ "map.agent": {"ifname":"wl0","event":"ap-autoconfiguration","data":{"status":"success","reason":"completed"}} }
```

After processing of the WSC CMDUs, mapagent config will have changed according
to the received WSC:

```
config agent 'agent'
	option enabled '1'
	option debug '0'
	option profile '2'
	option brcm_setup '1'
	option al_bridge 'br-lan'
	option netdev 'wl'
	option island_prevention '0'
	option controller_macaddr 'ee:6c:9a:52:b0:27'

config dynamic_backhaul
	option missing_bh_timer '60'

config controller_select
	option local '0'
	option id 'auto'
	option probe_int '20'
	option retry_int '9'
	option autostart '1'

config ap
	option ifname 'wl0.1'
	option band '5'
	option device 'wl0'
	option ssid 'MAP-EC6C9A52B027-5GHz'
	option key '7NTx-APvX-pba7-tvd7'
	option encryption 'sae-mixed+aes'
	option type 'fronthaul'
	option enabled '1'
	option vid '1'

config ap
	option ifname 'wl1.1'
	option band '2'
	option device 'wl1'
	option ssid 'MAP-EC6C9A52B027-2.4GHz'
	option key '7NTx-APvX-pba7-tvd7'
	option encryption 'sae-mixed+aes'
	option type 'fronthaul'
	option enabled '1'
	option vid '1'

config bsta
	option ifname 'wl0'
	option band '5'
	option device 'wl0'
	option priority '1'
	option enabled '0'

config bsta
	option ifname 'wl1'
	option band '2'
	option device 'wl1'
	option priority '2'
	option enabled '0'

config bsta
	option ifname 'wl2'
	option band '5'
	option device 'wl2'
	option priority '0'
	option encryption 'sae-mixed'
	option ssid 'MAP-EC6C9A52B027-BH-5GHz'
	option key '7NTx-APvX-pba7-tvd7'
	option default_disabled '0'
	option onboarded '1'
	option enabled '1'

config radio
	option device 'wl2'
	option band '5'
	option dedicated_backhaul '1'
	option onboarded '1'

config radio
	option device 'wl0'
	option band '5'

config radio
	option device 'wl1'
	option band '2'

config policy
	option pvid '1'
	option pcp_default '0'

config ap
	option ifname 'wl0.2'
	option band '5'
	option device 'wl0'
	option ssid 'MAP-EC6C9A52B027-BH-5GHz'
	option key '7NTx-APvX-pba7-tvd7'
	option encryption 'sae+aes'
	option type 'backhaul'
	option enabled '1'
	option disallow_bsta '0'
	option vid '1'

config ap
	option ifname 'wl1.2'
	option band '2'
	option device 'wl1'
	option ssid 'MAP-EC6C9A52B027-BH-2.4GHz'
	option key '7NTx-APvX-pba7-tvd7'
	option encryption 'sae+aes'
	option type 'backhaul'
	option enabled '1'
	option disallow_bsta '0'
	option vid '1'
```

And similarily the wireless config:


```
config wifi-device 'wl0'
	option type 'mac80211'
	option channel 'auto'
	option hwmode '11a'
	option country 'DE'
	option htmode 'HE80'
	option apsta '1'
	option phy 'phy0'

config wifi-iface 'default_wl0'
	option device 'wl0'
	option network 'lan'
	option ifname 'wl0.1'
	option mode 'ap'
	option wps '1'
	option wps_pushbutton '1'
	option ieee80211k '1'
	option bss_transition '1'
	option multi_ap '2'
	option ssid 'MAP-EC6C9A52B027-5GHz'
	option key '7NTx-APvX-pba7-tvd7'
	option encryption 'sae-mixed+aes'
	option ieee80211w '1'
	option start_disabled '0'
	option uuid 'cfa7df87-06a3-5daf-911f-ec6c9a52acb7'
	option multi_ap_backhaul_ssid 'MAP-EC6C9A52B027-BH-5GHz'
	option multi_ap_backhaul_key '7NTx-APvX-pba7-tvd7'

config wifi-device 'wl1'
	option type 'mac80211'
	option channel 'auto'
	option hwmode '11g'
	option country 'DE'
	option htmode 'HE20'
	option apsta '1'
	option phy 'phy1'

config wifi-iface 'default_wl1'
	option device 'wl1'
	option network 'lan'
	option ifname 'wl1.1'
	option mode 'ap'
	option wps '1'
	option wps_pushbutton '1'
	option ieee80211k '1'
	option bss_transition '1'
	option multi_ap '2'
	option ssid 'MAP-EC6C9A52B027-2.4GHz'
	option key '7NTx-APvX-pba7-tvd7'
	option encryption 'sae-mixed+aes'
	option ieee80211w '1'
	option start_disabled '0'
	option uuid 'cfa7df87-06a3-5daf-911f-ec6c9a52acb7'
	option multi_ap_backhaul_ssid 'MAP-EC6C9A52B027-BH-2.4GHz'
	option multi_ap_backhaul_key '7NTx-APvX-pba7-tvd7'

config wifi-device 'wl2'
	option type 'mac80211'
	option channel 'auto'
	option hwmode '11a'
	option country 'DE'
	option htmode 'HE80'
	option apsta '1'
	option phy 'phy2'

config wifi-iface 'default_sta_wl1'
	option device 'wl1'
	option mode 'sta'
	option ifname 'wl1'
	option multi_ap '1'
	option disabled '0'

config wifi-iface 'default_sta_wl0'
	option device 'wl0'
	option mode 'sta'
	option ifname 'wl0'
	option multi_ap '1'
	option ssid 'MAP-EC6C9A52B027-BH-5GHz'
	option key '7NTx-APvX-pba7-tvd7'
	option encryption 'sae-mixed'
	option disabled '1'

config wifi-iface 'default_sta_wl2'
	option device 'wl2'
	option mode 'sta'
	option ifname 'wl2'
	option multi_ap '1'
	option disabled '0'
	option ssid 'MAP-EC6C9A52B027-BH-5GHz'
	option key '7NTx-APvX-pba7-tvd7'
	option encryption 'sae-mixed'

config wifi-iface 'wl0_2_ap'
	option ifname 'wl0.2'
	option network 'lan'
	option ssid 'MAP-EC6C9A52B027-BH-5GHz'
	option key '7NTx-APvX-pba7-tvd7'
	option encryption 'sae+aes'
	option mode 'ap'
	option device 'wl0'
	option multi_ap '1'
	option ieee80211k '1'
	option ieee80211w '2'
	option start_disabled '0'
	option uuid 'cfa7df87-06a3-5daf-911f-ec6c9a52acb7'
	option hidden '0'

config wifi-iface 'wl1_2_ap'
	option ifname 'wl1.2'
	option network 'lan'
	option ssid 'MAP-EC6C9A52B027-BH-2.4GHz'
	option key '7NTx-APvX-pba7-tvd7'
	option encryption 'sae+aes'
	option mode 'ap'
	option device 'wl1'
	option multi_ap '1'
	option ieee80211k '1'
	option ieee80211w '2'
	option start_disabled '0'
	option uuid 'cfa7df87-06a3-5daf-911f-ec6c9a52acb7'
	option hidden '0'
```

## Controller Discovery


### UCI

The following UCI config section in "mapagent" config is used to control how a
MAP Controller is discovered and (auto)started/stopped on demand in a MAP
network.

```
config controller_select
	option local     'true'
	option id        'auto'
	option probe_int '20'
	option retry_int '3'
	option autostart 'true'
```

| Name	        | Type          | Required  | Default     | Description   |
| ------------- |---------------| ----------|-------------|---------------|
| local         | Boolean	| yes       | false	  | When set to true, the MAP Controller running in the same 1905 device as the MAP Agent, will be treated as the main or primary Controller. It takes precedence over others discovered in the network.		 |
| id            | Mac address   | no        | auto-detect | User can provide the 1905 ALID of the device that will have the MAP Controller service. When set to 'auto', the MAP Agent will discover the MAP Controller ID. OPTION NOT YET SUPPORTED.		 |
| probe_int     | Integer       | no        | 20s    	  |The time interval in seconds between controller discovery by the MAP Agent		 |
| retry_int     | Integer       | no        | 15    	  |After these many failed attempts to discover a controller in the network, the agent will infer that the controller is not available and accordingly takes the next action.		 |
| autostart     | Boolean       | no        | false    	  |When this is set to 'true', the agent will try to start the controller after not finding one in the network.		 |


### Algorithm

During startup and at run-time, the MAP Agent will probe for the presence of a
MAP Controller in the network.

If it finds another, then take one of the following actions:

1. If a MAP Controller is NOT running in the own device, then update its
Controller-ID and the last-seen timestamp.

2. If a MAP Controller is running in its own device, and local = true, then
notify the detected Controller to user (e.g.: over UBUS).

3. If a MAP controller is running in its own device, and local = false, then
stop the local Controller. Update the Controller-ID and the last-seen timestamp.


If after 'retry_int' number of times, the MAP Agent cannot discover a MAP
Controller in the network, then take one of the following actions:

1. When 'autostart' = true AND the compiler flag AGENT_DYNAMIC_CNTLR is set the
MAP Agent will try to start the MAP Controller locally (see 'Notes'). It'll
report status of the MAP Controller start to user (e.g.: over UBUS).

2. When 'autostart' = false OR the compiler flag AGENT_DYNAMIC_CNTLR is NOT set
the MAP Agent will simply report to user (over UBUS) that no Controller has been
detected in the network.

Notes:
    * The default time interval in seconds between controller discovery by the
    MAP Agent will increase to 70 seconds once Agent enters the heartbeat state
    (that is after controller discovery finished successfully).
    * Maximum time w/o controller in the network will be (probe_int * retry_int)
    - but not less than 75 seconds.
* After detecting no Controller in the network, the MAP-Agent will try to start
its local Controller after a random time chosen from a time window (10s). This
helps to reduce the chance of multiple MAP-Agents trying to run the controller
at the same time.

### Example

While the aim for this controller discovery is to support the same configuration
across all devices, one may want to have a designated mapcontroller device, then
the following configuration may be used:

Main Device: Controller to be run in a designated node only.

```
config controller_select
	option local 'true'
```

Repeater Device: Controller start/stop automatically if another is not detected
in the network.

```
config controller_select
	option local 'false'
	option autostart 'true'
```

## Dynamic Controller Sync

In a mesh where the controller node may change and taken up by any of the
nodes in the mesh, it is important to keep all mapcontroller configs in sync. If
not, when the controller role is taken by another node the credentials, polices
etc. may change resulting in disruption for the clients in the network.

This feature has to be compiled into multiple components by its compile-time
flags.

This compile-time flag are:
* map-agent - `AGENT_SYNC_DYNAMIC_CNTLR_CONFIG`
* map-controller - `CONTROLLER_SYNC_DYNAMIC_CNTLR_CONFIG`
* ieee1905 - `MULTIAP_DYNAMIC_CNTLR_SYNC_CONFIG`

This feature is additionally enabled or disabled via UCI configuration:

```
onfig agent 'agent'
	option dyn_cntlr_sync '1'
```

### Algorithm

Dynamic controller sync leverages Higher Layer Data CMDUs to sync the
credentials across the network. It uses a two or three step process, depending
on who initiates the communication.

If map-controller initiates the communication it will first send a message
letting the mapagent know that it has updated its configuration file. After
which the map-agent will generate an M1, similar to AP-Autoconfig. The
map-controller will then generate keys and encrypt the configuration file and
pass it to the map-agent in an M2 message.

The M2 is decrypted on the agent and written to its mapcontroller
configuration file, if any. While persisting its `enabled` option so it is not
re-enabled if it was previously disabled.

If sync is triggered via UBUS API of map-agent the first message is skipped.
```
root@iopsys-ec6c9a52acb7:~# ubus -v list map.agent
'map.agent' @be66d606
	...
	"sync":{}
	...
```

#### Summary

1. Mapcontroller configuration file is modified, send multicast HLD message
2. Mapagent responds with M1
3. Mapcontroller encrypts configuration file within M2, sends to agent
4. Mapagent decrypts configuration file and writes to file system

## Dynamic Backhaul Upgrade

Dynamic backhaul upgrade logic will make sure that if a backhaul link drops, it
will attempt to re-establish connection over other backhaul STAs. Additionally,
it will periodically try to upgrade an existing link to a better one, if
available.

### Backhaul Priority

Each backhaul STA can be assigned with a priority from its configuration:

```
config bsta
	option ifname 'wl0'
	option band '5'
	option device 'wl0'
	option priority '0'

config bsta
	option ifname 'wl1'
	option band '2'
	option device 'wl1'
	option priority '2'

```

Lower priority is better. This is the value which will decide which backhaul STA
is used, if multiple connections are available.

### Algorithm

#### Trigger - Onboarding

When WPS onboarding is performed, once the first credentials are received, if
any other backhaul STA has activated WPS, an additional 15 seconds are allows
for additional credentials to come through. After the 15 seconds pass, or till
all backhaul STAs has received credentials, they are written to the wireless
configuration and loaded in-memory to the supplicants, and they may begin
scanning and finding the APs.

Upon receiving the first connection from a now configured supplicant, map-agent
will write the BSSID to the configuration, locking the topology. Additionally,
another 15 second timer is triggered, which allows better connections to come
before map-agent locks this backhaul STA till next upgrade window.

Once the 15 second timer expires, map-agent will disable the other supplicants
and set `option enabled '0'` in the map-agent configuration for all the worse
priority backhaul STAs.

#### Trigger - Priority and Run-time Upgrade

Periodically, map-agent will start scanning on all backhaul STAs with a better
priority set than the one currently connected. This gives a 15 second window
for each backhaul STA with a better priority to find a connection, at the end
of the 15 seconds the best connected backhaul STA will be used and all others
disabled till next periodicity.

The upgrade logic gets triggered after a connection is made, at timeouts of
30 seconds, 4 minutes, 6 minutes and 30 minutes, after which it will remain at
30 minutes till a better connection is made.

The timers can be observed via the map-agent UBUS API, which has a
dynamic_backhaul object with time till next upgrade window, and how long ago
last one took place:
```
root@iopsys-ec6c9a52acb7:~# ubus call map.agent timers
{
	"autoconfig_trigger": 33603,
	"dynamic_backhaul": {
		"next_attempt": 997139,
		"last_attempt_start": 818163,
		"last_attempt_end": 802861
	},
	"bh_lost_timer": -1,
	"disable_unconnected_bstas_scheduler": -1,
	"onboarding_scheduler": -1
}
```

If another mesh device is wirelessly connected (i.e. forming a daisy chain),
link upgrade logic will not take place till it is removed.

#### Trigger - Link loss

If the active backhaul STA loses connectivity, map-agent will after some time
start scanning on all configured backhaul STAs to find another available band.
This timer can be set via configuration, and defaults to 60s if not set.

```
config dynamic_backhaul
	option missing_bh_timer '60'
```

The option will accept any value between 1 and 255.

This timer can also be observed via the timers UBUS API, as `"bh_lost_timer"`:

```
root@iopsys-ec6c9a52acb7:~# ubus call map.agent timers
{
	"autoconfig_trigger": 40774,
	"dynamic_backhaul": {
		"next_attempt": 421485,
		"last_attempt_start": 1393815,
		"last_attempt_end": 1378515
	},
	"bh_lost_timer": 222084,
	"disable_unconnected_bstas_scheduler": -1,
	"onboarding_scheduler": -1
}
```

#### Seamless Swapping Between Eth and Wi-Fi Uplink

When an ethernet WAN port is connected, as inferred either by dedicated WAN
port or by dynbhd (see
[dynbhd](https://dev.iopsys.eu/iopsys/map-agentsrc/dynbh/README)), it will take
priority and all backhaul STAs will be in-memory disabled in supplicant. While
the ethernet backhaul is active, all scanning by the backhaul STAs will be
stopped by map-agent, and any re-connection will be terminated.

If the ethernet backhaul is disconnected, the backhaul STAs are immediately
enabled and start scanning to find a connection.

## Island Prevention

In the case of a repeater device losing its connectivity to the master/controller
device it is no longer a part of the mesh. Therefore it is undesireable to keep
any Wi-Fi clients connected to this node, as well as beaconing to attract new
clients. This is where island prevention will kick in and disconnect any
associated clients and stop APs from beaconing.

Island prevention is compile-time selected and enabled via UCI configuration.
The compile-time flag is `AGENT_ISLAND_PREVENTION` and the uci option is:

```
config agent 'agent'
	option island_prevention '0'
```

### Algorithm

Once a the uplink is lost, the island prevention logic will allow some time for
the link to be re-established, based on the `missing_bh_timer`. After the time
configured has passed (default to 60s if not set), mapagent will trigger a BTM
request to all connected stations with imminent disassociation and incoming BSS
terminiation.

After an additional 30 seconds has passed and the link has not been
re-established, map-agent will disconnect the client directly via UBUS APIs.
Mapagent will then allow two seconds for all the clients to disassociate before
disabling all APs.

#### Summary
1. Uplink is lost
2. `missing_bh_timer` timer expires and BTM requests are issued
3. Additional 30 seconds pass and all clients are disconnected
4. Additonal 2 seconds pass and all APs are disabled

If at any time link is re-established the following step will not be triggered
and APs will be enabled.

## Neighbor list
Neighbor list (kept in driver) is being synchronized by agent based upon data
received from topology response, AP capabilities report and radio scan results.

### Algorithm
Agent will parse topology response and based on that update localy stored nbr
lists kept in agent's fronthaul (netif_fh) structures. Everytime the neighbor
is spoted in results, its 'last seen' timestamp gets updated.
There'll be check for outdated entries every 10 minutes or often - nbrs with
timestamp older than 30 min will be removed from the list and the driver.
If there's a new neighbor found in topology response it'll be added to the list.
The list kept in agent will be periodically synchronized with the list that is
stored in the driver.
* AP capability query/report are used to get HT & VHT bits of bssid info.
* Radio scan and scanresults will be used to update channel and opclass of the nbr.
In case any of subdata (HT, VHT, channel, opclass, etc) has changed in localy
stored list, driver entry will also get updated in a while (few seconds).

```
root@iopsys-ec6c9a52acb7:~# ubus call map.agent status
    ...
	"fronthaul": [
		{
			"name": "wl0.1",
			"enabled": true,
			"bssid": "3e:d4:37:6a:f4:c8",
			"ssid": "MAP-44D4376AF4C0-BH-5GHz",
			"channel": 36,
			"load": 0,
			"neighbor": [
				{
					"bssid": "7e:d4:37:6a:f7:d9",
					"channel": 36
				},
				{
					"bssid": "3e:d4:37:6a:f4:c8",
					"channel": 36
				}
			],
	...


root@eagle-44D4376AF4C0:~# ubus call wifi.ap.wl0.1 list_neighbor
{
	"neighbors": [
		{
			"bssid": "3E:D4:37:6A:F4:C8",
			"bss_info": 6319,
			"regulatory": 128,
			"channel": 36,
			"phy": 0
		},
		{
			"bssid": "7E:D4:37:6A:F7:D9",
			"bss_info": 6319,
			"regulatory": 128,
			"channel": 36,
			"phy": 0
		}
	]
}
```

## Eth Onboards WiFi Backhauls

With the ethernet onboarding feature, backhaul STAs will be configured upon
AP-Autoconfiguration completion based on the backhaul BSS credentials, if any.

This means, if a device is connected to the mesh with ethernet backhaul, it
will be able to transition to a wireless backhaul without triggering WPS.
Additionally, any backhaul STA that does not successfully onboard via WPS will
get configured regardless and that link may later be used upon dynamic backhaul
link upgrade.

This feature is enabled via configuration:

```
config agent 'agent'
	option eth_onboards_wifi_bhs '1'
```

## Fallback Backhaul Timer

When a connection is made, the BSSID of the upstream interface is written to
the wireless and supplicant configuration. This makes sure that the topology
does not change unexpectedly during run-time.

However, when the upstream device is powered off or removed from the network
the downstream device will be unable to connect to the mesh. To resolve this
a fallback timer has been introduced which will clean the BSSIDs written to
backhaul stations and allow the device to connect to any upstream
broadcasting the same credentials.

config dynamic_backhaul
	option bh_fallback_timer '120' # time after connection loss at which BSSIDs will be cleaned
					# defaults to 30 minutes


## Backhaul Blacklist Loop Prevention

When connecting the network in a daisy chain, and the connection drops
on i.e. the first hop, the mesh may form a loop, as the first hop may connect
to any of the downstream devices, as they are all broadcasting the same
credentials.

To prevent this topology response, multiap.backhaul file and wpa_supplicant
bssid_ignore features are leveraged.

### Algorithm

Rough pseudo-code describing algorithm.

```
topo_res_handler(cmdu)
	update = false
	downstream = (cmdu.src_port != /tmp/multiap.backhaul.src_port)
	for each bss in cmdu.bsss do
		bk = backhaul_ssid_configuration(bss.ssid)
		if bk != NULL then
			if downstream then
				update |= bk_blacklist_add(bss.bssid)
			else
				update |= bk_blacklist_del(bss.bssid)
			fi
		fi
	done

	if update = true then
		trigger_supplicant_update()
```

## Traffic Separation

For quick start guide see [here](./docs/QUICK_START.md#traffic-separation).

For more detailed guide see [here](./docs/README-Traffic_Separation.md).

For guest-to-guest isolation see [here](./docs/README-Traffic_Separation.md#wi-fi-guest-to-guest-isolation).

For layer 3 setup guide see [here](./docs/layer3_ts.md).

## DPP Easy Connect

### Wi-Fi QR COde based Onboarding

To enable URI generation and DPP chirping map-agent must have `dpp_chirp` UCI
configuration sections provided.

```
config dpp_chirp
	option device 'wl1'
	option band '2'
	option ifname 'wl1'
	list channel '1'
	list channel '11'
	option type 'qrcode'
	option chirp_interval '10'

config dpp_chirp
	option device 'wl0'
	option band '5'
	option ifname 'wl0'
	list channel '36'
	option type 'qrcode'
	option chirp_interval '10'
```

Map-agent will accordingly generate URIs for the respective bands and start
chirping.

The URI's can be retreived from the UBUS API
`ubus call map.agent dpp_enrollee_uri`:

```
root@eagle-44d43771bb20:~# ubus call map.agent dpp_enrollee_uri
{
	"uri": "DPP:M:44d43771bb2f;V:2;K:MDkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDIgAD/ebYNHPhud+3C/t47dLffnPCzKAI3RYsr7z0zz5pSHQ=;;",
}
```

Once DPP onboarding is completed the credentials are written to the wireless and
map-agent configuration and an event is published over UBUS:

```
{ "map.agent": {"event": "dpp", "data": { "status":"success", "reason":"completed"} }}

```

Today only legacy akms (i.e. sae, sae-mixed, psk2) are supported.

NOTE: Currently, `wpa_supplicant` will prioritize scanning over chirping. This
means 5GHz is much less reliable as it will scan a larger number of channels and
DPP chirp may get aborted. **For this reason is strongly recommended to use
2.4GHz for DPP onboarding.**

### Ethernet QR Code based Onboarding

DPP Ethernet onboarding is implemented leveraging
[libdpp](https://dev.iopsys.eu/multi-ap/libdpp).

For DPP Ethernet onboarding, no additional configuration sections needs to be
present, but map-agent must be compiled with the CLFAGS including `USE_LIBDPP`.

The Ethernet QR code used for onboarding can be found under the UBUS API
`dpp_enrollee_uri_eth`:
```
root@eagle-44d43771b930:~# ubus call map.agent dpp_enrollee_uri_eth
{
	"URI": "DPP:C:81/1,115/36;V:2;K:MDkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDIgACcwPoTjXxtZ2IJAjyZeH1kECGHXGhxhEEyPzcnpFo2ms=;;"
}
```

Once onboarding is completed, an event will be available over UBUS:
```
{ "map.agent": {"event":"dpp","data":{"status":"success","reason":"completed"}} }
```

## Misc

### Netdev Format

Some platforms require the base interface set to i.e. wl0_0, old format would
always assume wl0 as base interface. New format allows adding a '%' identifier
to the format which will explicitly be replaced with numerical values. This also
allows a separator to be set from configuration and not be assumed
(i.e. ".", "-", "_" etc.):
* wl%_% - wl1_0 and wl0_0 as base interfaces
* wl0_ - wl0 and wl1 as base interface, followed by wl0_1 and wl1_1
* wl0 - wl0 and wl1 as base interface, followed by wl0.1 and wl1.1

An example config:

```
config agent 'agent'
       option enabled '1'
       option debug '0'
       option profile '2'
       option brcm_setup '1'
       option al_bridge 'br-lan'
       option netdev 'wl%_%'
```

### AP Follow Backhaul STA DFS Status

In mac80211 based implementations, a Wi-Fi Repeater may not be able to start
beaconing on the 5GHz DFS channels on its fronthaul side interfaces, when the
backhaul STA is connected on a DFS channel, which has not cleared DFS.

A solution is implemented in the map-agent to circumvent the issue. When the
backhaul STA connects, map-agent in the Repeater will find the channel and
bandwidth of the upstream AP, and in the case of the channel/bandwidth not
having cleared the DFS, will disconnect its 5GHz backhaul,
and reconnect over 2.4GHz (if available). A fresh CAC is performed for the
desired channel/bandwidth. Upon CAC completion, the Repeater device swaps the
backhaul connection to 5GHz again, where the fronthaul can also start beaconing
on the just cleared channel/bandwidth.

This functionality is disabled by default, and is enabled through the
configuration option 'ap_follow_sta_dfs'.

NOTE: The option is recommended to be set only for mac80211 based driver.

```
config agent 'agent'
	option enabled '1'
	option profile '2'
	option al_bridge 'br-lan'
	option netdev 'wl'
	option ap_follow_sta_dfs '1'
```

## Objects and APIs

The Multi-AP Agent object along with the supported APIs is given below -

````bash
'map.agent' @c3a59d2f
        "apconfig":{"band":"Integer"}
        "steer_policy":{"vif":"String","rule":"String"}
        "steer":{"vif":"String","type":"String","sta":"String","to_bss":"Array","optime":"Integer"}
        "assoc_control":{"bssid":"String","stalist":"Array","mode":"Integer","validity_int":"Integer"}
        "toggle_fh":{"enable":"Boolean","prevent_island":"Boolean","ifname":"String"}
        "bcn_metrics_query":{"agent":"String","sta":"String","opclass":"Integer","channel":"Integer","bssid":"String","reporting_detail":"Integer","ssid":"String","channel_report":"Array","request_element":"Array"}
        "unassoc_sta_lm_query":{"agent":"String","opclass":"Integer","metrics":"Array"}
        "topology_query":{"agent":"String"}
        "higher_layer_data":{"agent":"String","protocol":"Integer","data":"String"}
        "backhaul_info":{}
        "status":{}
        "nodes":{}
        "info":{}
        "scan":{"radio":"String","band":"Integer","opclass":"Array","channel":"Array"}
        "scanresults":{"radio":"String","radio_mac":"String","band":"Integer","cache":"Boolean"}
        "assoc_notify":{"bss_status_list":"Array"}
        "WPSPBC":{}
        "reset":{}
        "sync":{}
        "timers":{}
        "dynamic_backhaul_upgrade":{}
        "backhaul_blacklist":{}
        "set_backhaul":{"band":"Integer","target_bssid":"String","force_disassoc":"Integer"}
        "bss_config_request":{}
        "dpp_enrollee_uri":{}
        "log":{"feature":"String","level":"Integer"}
````

## UBUS events

Map-agent generates following events over UBUS -

Event | Event Data
------|-----------
map.agent | {"event":"controller_detected","data":{"radio":"wl0","status":"success","reason":"completed"}} |
map.agent | {"event":"ap-autoconfiguration","data":{"status":"success","reason":"completed"}} |
map.agent | {"event":"sta_steering","data":{"sta_mac":"aa:bb:cc:dd:ee:ff","target_bssid":"11:22:33:44:55:66"}} |
map.agent | {"event":"backhaul_connect","data":{"bssid":"aa:bb:cc:dd:ee:ff","priority":50}} |
map.agent | {"event":"backhaul_disconnect","data":{"bssid":"aa:bb:cc:dd:ee:ff"}} |
map.agent | {"event":"dpp_onboard","data":{"status":"success","reason":"completed"}} |
map.agent | {"event":"uplink_change","data":{"type":"wifi"}} |
||
wifi.radio | {"event":"radio_status","data":{"radio":"wl0","status":"success","reason":"completed"}} |
||
wifi.iface | {"ifname":"wl0","event":"btm-resp","data":{"macaddr":"aa:bb:cc:dd:ee:ff","status":0}} |
wifi.iface | {"ifname":"wl0","event":"request_btm","data":{"macaddr":"aa:bb:cc:dd:ee:ff","target_bssid":"11:22:33:44:55:66"}} |
wifi.iface | {"ifname":"wl0","event":"sta_low_rcpi","data":{"macaddr":"aa:bb:cc:dd:ee:ff","rcpi":42}} |
wifi.iface | {"ifname":"wl0","event":"sta_high_rcpi","data":{"macaddr":"aa:bb:cc:dd:ee:ff","rcpi":42}} |
||
map.agent.higher_layer_data | {"protocol":5,"data":"12ab34"} |
||
---------------


