diff --git a/.gitignore b/.gitignore
index 5d683094c4e71e7bd3deab18a6ebaa8ee20b9475..f37dd8d0c8564a934bdffcc31bc3c8e65febccd0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,3 +10,10 @@ tags
 wifimngr
 .configured_*
 .pkgdir
+*.html
+*.gcda
+*.gcov
+*.gcno
+*.log
+*.so
+*.xml
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 1578cf68f53ffe25ff25ccf97b19d2ca8077c7d1..9aa5d16459f791e992f421ac3920743b31ba85c4 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -4,7 +4,52 @@ include:
 
 stages:
     - static_code_analysis
-   
+    - unit_test
+    - functional_test
+    - api_test
+
 variables:
   DEBUG: 'TRUE'
   SOURCE_FOLDER: "."
+
+run_api_test:
+    stage: api_test
+    image: iopsys/code-analysis:0.7
+    allow_failure: true
+    script:
+        - "./gitlab-ci/setup.sh"
+        - "./gitlab-ci/functional-api-test.sh"
+
+    artifacts:
+        when: always
+        reports:
+            junit: ./report/tap.xml
+        paths:
+            - api-test-coverage.html
+            - api-test-memory-report.xml
+
+run_unit_test:
+    stage: unit_test
+    image: iopsys/code-analysis:0.7
+    allow_failure: true
+    script:
+        - "./gitlab-ci/setup.sh"
+        - "./gitlab-ci/unit-test.sh"
+
+    artifacts:
+        when: always
+        paths:
+            - unit-test-coverage.html
+
+run_functional_test:
+    stage: functional_test
+    image: iopsys/code-analysis:0.7
+    allow_failure: true
+    script:
+        - "./gitlab-ci/setup.sh"
+        - "./gitlab-ci/functional-test.sh"
+
+    artifacts:
+        when: always
+        paths:
+            - functional-test-coverage.html
diff --git a/Makefile b/Makefile
index 338959f786f958c3a1ebaa48408478a18a4e8661..abd25bb19b8c7dbc270ab9e22853b1e5996826d5 100644
--- a/Makefile
+++ b/Makefile
@@ -1,10 +1,13 @@
+CC=gcc # gcc || clang
 PROG = wifimngr
 OBJS = wifimngr.o wps.o wifimngr_event.o main.o
 
 PROG_CFLAGS = $(CFLAGS) -Wall -fstrict-aliasing
 PROG_LDFLAGS = $(LDFLAGS)
-PROG_LIBS = -leasy -lwifi-5
-PROG_LIBS += -luci -lubus -lubox -ljson-c -lblobmsg_json -lnl-genl-3 -lnl-3
+PROG_LIBS = -lwifi-5
+PROG_LIBS += -luci -lubus -lubox -ljson-c -lblobmsg_json -lnl-genl-3 -lnl-3 -lgcov -leasy
+GCOV		= gcov
+CODECOVERAGE_SRC = wifimngr.c
 
 %.o: %.c
 	$(CC) $(PROG_CFLAGS) $(FPIC) -c -o $@ $<
@@ -32,5 +35,25 @@ files.md5:
 wifimngr: $(OBJS)
 	$(CC) $(PROG_LDFLAGS) -o $@ $^ $(PROG_LIBS)
 
+test: CFLAGS += -fPIC
+test: ${OBJS}
+	${CC} ${LDFLAGS} -shared -o libwifimngr.so ${OBJS} ${LIBS}
+
+unit-test: coverage
+	make -C test/cmocka unit-test WIFIMNGR_LIB_DIR=$(PWD)
+
+functional-test: coverage
+	make -C test/cmocka functional-test WIFIMNGR_LIB_DIR=$(PWD)
+
+coverage: CFLAGS  += -g -O0 -fprofile-arcs -ftest-coverage
+coverage: LDFLAGS += --coverage
+coverage: test wifimngr
+	$(foreach testprog, $(CODECOVERAGE_SRC), $(GCOV) $(testprog);)
+
 clean:
-	rm -f *.o $(PROG)
+	rm -f *.o libwifimngr.so $(PROG)
+	rm -f *.xml *.html
+	find -name '*.gcda' -exec rm {} -fv \;
+	find -name '*.gcno' -exec rm {} -fv \;
+	find -name '*.gcov' -exec rm {} -fv \;
+	make -C test/cmocka clean
diff --git a/README.md b/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..876c34decb955233d8a63bb480cee9d74eccd4c1
--- /dev/null
+++ b/README.md
@@ -0,0 +1,249 @@
+# Wifimngr
+
+Wifimngr implements the wifi data model, publishing the wifi objects over ubus.
+In order to remain agnostic the vendor and underlying wifi modules present
+in the system, wifimngr uses the easy-soc-libs libwifi APIs to expose supported
+methods with its objects.
+
+<!--Wifimngr implements the wifi data model. It prepares the wifi objects and-->
+<!--publishes them over ubus, the exposed methods are agnostic to the underlying-->
+<!--wifi module present in the system. It uses the easy-soc-libs libwifi APIs to-->
+<!--present the APIs over ubus.-->
+
+## Overview
+
+Wifimngr manages three areas of wifi functionality:
+1. WiFi Statistics
+2. Access Points
+3. Radios
+4. WiFi Protected Setup (WPS)
+
+
+### UCI Config
+
+An example UCI wireless configuration file creating one access point interface,
+`test5`:
+
+````bash
+config wifi-device 'test5'
+    option channel 'auto'
+    option hwmode 'auto'
+    option country 'DE'
+    option band 'a'
+    option bandwidth '80'
+
+config wifi-iface
+    option device 'test5'
+    option ifname 'test5'
+    option mode 'ap'
+    option encryption 'psk2'
+````
+
+For more info on the UCI wireless configuration see [link](./docs/api/uci.wireless.md)
+
+### Ubus API
+
+This is a verbose print of all methods published to ubus on a device with one
+access point interface `test5`:
+
+````bash
+'wifi' @f2f72310
+	"status":{}
+'wifi.ap.test5' @57ac8570
+	"status":{}
+	"stats":{}
+	"assoclist":{}
+	"stations":{"sta":"String"}
+	"disconnect":{"sta":"String"}
+	"monitor":{"sta":"String","get":"Integer"}
+	"add_neighbor":{"bssid":"String","channel":"Integer","bssid_info":"String","reg":"Integer","phy":"Integer"}
+	"del_neighbor":{"bssid":"String"}
+	"list_neighbor":{"ssid":"String","client":"String"}
+	"request_neighbor":{"ssid":"String","client":"String"}
+	"request_transition":{"client":"String","bssid":"Array","timeout":"Integer"}
+	"add_vendor_ie":{"mgmt":"Integer","oui":"String","data":"String"}
+	"del_vendor_ie":{"mgmt":"Integer","oui":"String","data":"String"}
+'wifi.radio.test5' @e662e933
+	"status":{}
+	"stats":{}
+	"get":{"param":"String"}
+	"scan":{"ssid":"String","bssid":"String","channel":"Integer"}
+	"scanresults":{"bssid":"String"}
+	"autochannel":{"interval":"Integer","algo":"Integer","scans":"Integer"}
+'wifi.wps' @4eb8cbd8
+	"start":{"vif":"String","mode":"String","role":"String","pin":"String"}
+	"stop":{}
+	"status":{"vif":"String"}
+	"generate_pin":{}
+	"validate_pin":{"pin":"String"}
+	"showpin":{"vif":"String"}
+	"setpin":{"vif":"String","pin":"String"}
+````
+
+For more info on the Ubus API see
+[function specification](./docs/functionspec.md) or go directly to the generated
+[docs](./docs/ubus.splash.md).
+
+### Wifi Statistics
+
+The `wifi` object publishes gathered radio and interface statistics.
+
+```
+'wifi' @f2f72310
+	"status":{}
+```
+
+For info on the `wifi` API see [link](./docs/api/wifi.md#wifi)
+
+### Access Point
+
+An object will be published on ubus for each interface operating as an access
+point, managing operations and data for wifi clients, neighbor nodes
+and interface statistics.
+
+To parse access point interfaces, wifimngr reads the wireless
+configuration file (`/etc/config/wireless`), looking for `wifi-iface` sections,
+with the option `mode` specified as `ap`.
+
+```
+config wifi-iface
+	option device 'test5'
+	option ifname 'test5'
+	option mode 'ap'
+```
+
+Wifimngr will query libwifi to find available API calls for the driver, in order
+to dynamically publish available methods to ubus.
+
+```
+root@:/opt/work# ubus -v list wifi.ap.test5
+'wifi.ap.test5' @a939a75c
+	"status":{}
+	"stats":{}
+	"assoclist":{}
+	"stations":{"sta":"String"}
+	"disconnect":{"sta":"String"}
+	"monitor":{"sta":"String","get":"Integer"}
+	"add_neighbor":{"bssid":"String","channel":"Integer","bssid_info":"String","reg":"Integer","phy":"Integer"}
+	"del_neighbor":{"bssid":"String"}
+	"list_neighbor":{"ssid":"String","client":"String"}
+	"request_neighbor":{"ssid":"String","client":"String"}
+	"request_transition":{"client":"String","bssid":"Array","timeout":"Integer"}
+	"add_vendor_ie":{"mgmt":"Integer","oui":"String","data":"String"}
+	"del_vendor_ie":{"mgmt":"Integer","oui":"String","data":"String"}
+```
+
+For info on the access point API see [link](./docs/api/wifi.ap.md#wifiapname)
+
+### Radio
+
+Similarily to access point interfaces, wifimngr will publish one object per
+available radio, parsed from the wireless configuration, by `wifi-device`
+sections. The methods are added dynamically by quering for supported API calls
+from libwifi.
+
+```
+config wifi-device 'test5'
+	option channel 'auto'
+	option hwmode 'auto'
+	option country 'DE'
+	option band 'a'
+	option bandwidth '80'
+```
+
+The radio object manages radio data and statistics, channel selection and
+wifi scan operations.
+
+```
+root@:/opt/work# ubus -v list wifi.radio.test5
+'wifi.radio.test5' @fa7d185d
+	"status":{}
+	"stats":{}
+	"get":{"param":"String"}
+	"scan":{"ssid":"String","bssid":"String","channel":"Integer"}
+	"scanresults":{"bssid":"String"}
+	"autochannel":{"interval":"Integer","algo":"Integer","scans":"Integer"}
+```
+For info on the radio API see [link](./docs/api/wifi.radio.md#wifiradioname)
+
+### Wifi Protected Setup
+
+Lastly, wifimngr exposes WPS functionality to ubus.
+
+The configuration is read from the `/etc/config/wireless`. To enable WPS the
+`wps` option has to be set to `1`.
+
+```
+config wifi-iface
+	option wps '1'
+```
+
+To see more configuration options see [link](./docs/api/uci.wireless.md),
+under the `wifi-iface` section.
+
+
+```
+root@:/opt/work# ubus -v list wifi.wps
+'wifi.wps' @78c52f3b
+	"start":{"vif":"String","mode":"String","role":"String","pin":"String"}
+	"stop":{}
+	"status":{"vif":"String"}
+	"generate_pin":{}
+	"validate_pin":{"pin":"String"}
+	"showpin":{"vif":"String"}
+	"setpin":{"vif":"String","pin":"String"}
+```
+
+For info on the WPS API see [link](./docs/api/wifi.wps.md#wifiwps)
+
+
+## Tests
+
+This section will give a brief overview of the tests for wifimngr, for a more
+detailed report see [test specification](./docs/testspec.md)
+
+To test wifimngr, the scope of the tests has to be clearly defined, as wifimngr
+is heavily dependent on libwifi:
+
+1. Verify linkage between wifimngr and libwifi APIs
+2. Verify that the wifi structures are correctly prepared and return data is
+used correctly by wifimngr
+3. Verify that API calls successfully reach libwifi and if passed input is of
+correct format
+
+As the test environment runs in a ubuntu 16.04 docker environment, with little
+possibility to prepare wifi drivers and kernel version, the easy-soc-libs had to
+be extended to support APIs to run on a test platform, returning dummy data for
+getters, and for setters, logging that the call made with timestamp and
+arguments.
+
+To ensure full coverage, the getters are tested by the ubus-api-validation tool,
+using json-schemas to validate accurate output. The setters are tested by cmocka
+tests, creating a libwifimngr.so shared library, invoking its ubus API
+functions directly, verifying that the call went through, and that the arguments
+were passed correctly, by parsing the test log file found at `/tmp/test.log`.
+Additionally, the cmocka tests verify that netlink event callbacks are
+registered and invoked.
+
+## Dependencies ##
+
+To successfully build wifimngr, the following libraries are needed:
+
+| Dependency  		| Link                                       						| License        |
+| ----------------- | ---------------------------------------------------------------- 	| -------------- |
+| libuci      		| https://git.openwrt.org/project/uci.git     					 	| LGPL 2.1       |
+| libubox     		| https://git.openwrt.org/project/libubox.git 					 	| BSD            |
+| libubus     		| https://git.openwrt.org/project/ubus.git    					 	| LGPL 2.1       |
+| libjson-c   		| https://s3.amazonaws.com/json-c_releases    					 	| MIT            |
+| libwifi	  		| https://dev.iopsys.eu/iopsys/easy-soc-libs/tree/devel/libwifi    	| GNU GPL2       |
+| libnl3	  		| 											 					 	| 			     |
+| libblobmsg_json	| 											 					 	| 			     |
+| libnl-genl  		|                                             					 	|                |
+
+Additionally, in order to build with the tests, the following libraries are needed:
+
+| Dependency  				| Link                                       				| License		|
+| ------------------------- | --------------------------------------------------------- | ------------- |
+| libjson-schema-validator 	| https://github.com/pboettch/json-schema-validator     	| LGPL 2.1		|
+| libjson-validator			| https://dev.iopsys.eu/iopsys/json-schema-validator		| 				|
+| libjson-editor			| https://dev.iopsys.eu/iopsys/json-editor   				| 				|
diff --git a/docs/api/uci.wireless.md b/docs/api/uci.wireless.md
new file mode 100644
index 0000000000000000000000000000000000000000..f139af86b4975a126b6a479b6771f9902e1b2170
--- /dev/null
+++ b/docs/api/uci.wireless.md
@@ -0,0 +1 @@
+<tbody><tr><td colspan="2"><div class="td_head">wireless</div><table style="width:100%"><tbody><tr><td><div class="td_head">section</div></td><td><div class="td_head">description</div></td><td><div class="td_head">multi</div></td><td><div class="td_head">options</div></td></tr><tr><td class="td_row_even"><div class="td_row_even">wifi-device</div></td><td class="td_row_even"><div class="td_row_even">Wifi Device Settings</div></td><td class="td_row_even"><div class="td_row_even">true</div></td><td class="td_row_even"><table style="width:100%"><tbody><tr><td><div class="td_head">name</div></td><td><div class="td_head">type</div></td><td><div class="td_head">required</div></td><td><div class="td_head">default</div></td><td><div class="td_head">description</div></td></tr><tr><td class="td_row_even"><div class="td_row_even">channel</div></td><td class="td_row_even"><div class="td_row_even">integer or “auto”</div></td><td class="td_row_even"><div class="td_row_even">yes</div></td><td class="td_row_even"><div class="td_row_even">auto</div></td><td class="td_row_even"><div class="td_row_even">Specifies the wireless channel to use. “auto” defaults to the lowest available channel.</div></td></tr><tr><td class="td_row_odd"><div class="td_row_odd">hwmode</div></td><td class="td_row_odd"><div class="td_row_odd">string</div></td><td class="td_row_odd"><div class="td_row_odd">&nbsp;</div></td><td class="td_row_odd"><table style="width:100%"></table></td><td class="td_row_odd"><div class="td_row_odd">Selects the wireless protocol to use, possible values are 11b, 11g, and 11a. Note that 11ng and 11na are not available options.</div></td></tr><tr><td class="td_row_even"><div class="td_row_even">country</div></td><td class="td_row_even"><div class="td_row_even">varies</div></td><td class="td_row_even"><div class="td_row_even">&nbsp;</div></td><td class="td_row_even"><table style="width:100%"></table></td><td class="td_row_even"><div class="td_row_even">Specifies the country code, affects the available channels and transmission powers. For type broadcom a two letter country code is used (EN or DE). The madwifi driver expects a numeric code.</div></td></tr><tr><td class="td_row_odd"><div class="td_row_odd">band</div></td><td class="td_row_odd"><div class="td_row_odd">string</div></td><td class="td_row_odd"><div class="td_row_odd">&nbsp;</div></td><td class="td_row_odd"><table style="width:100%"></table></td><td class="td_row_odd"><div class="td_row_odd">Whether radio operates at 2.4GHz or 5GHz.</div></td></tr><tr><td class="td_row_even"><div class="td_row_even">bandwidth</div></td><td class="td_row_even"><div class="td_row_even">integer</div></td><td class="td_row_even"><div class="td_row_even">&nbsp;</div></td><td class="td_row_even"><div class="td_row_even">80</div></td><td class="td_row_even"><div class="td_row_even">Frequency at which the radio operates.</div></td></tr></tbody></table></td></tr><tr><td class="td_row_odd"><div class="td_row_odd">wifi-iface</div></td><td class="td_row_odd"><div class="td_row_odd">Wifi Interface Settings</div></td><td class="td_row_odd"><div class="td_row_odd">true</div></td><td class="td_row_odd"><table style="width:100%"><tbody><tr><td><div class="td_head">name</div></td><td><div class="td_head">type</div></td><td><div class="td_head">required</div></td><td><div class="td_head">default</div></td><td><div class="td_head">description</div></td></tr><tr><td class="td_row_even"><div class="td_row_even">device</div></td><td class="td_row_even"><div class="td_row_even">string</div></td><td class="td_row_even"><div class="td_row_even">yes</div></td><td class="td_row_even"><div class="td_row_even">(first device id)</div></td><td class="td_row_even"><div class="td_row_even">Specifies the used wireless adapter, must refer to one of the defined wifi-device sections</div></td></tr><tr><td class="td_row_odd"><div class="td_row_odd">ifname</div></td><td class="td_row_odd"><div class="td_row_odd">string</div></td><td class="td_row_odd"><div class="td_row_odd">no</div></td><td class="td_row_odd"><div class="td_row_odd">(driver default)</div></td><td class="td_row_odd"><div class="td_row_odd">Specifies a custom name for the Wi-Fi interface, which is otherwise automatically named.</div></td></tr><tr><td class="td_row_even"><div class="td_row_even">mode</div></td><td class="td_row_even"><div class="td_row_even">string</div></td><td class="td_row_even"><div class="td_row_even">yes</div></td><td class="td_row_even"><div class="td_row_even">ap</div></td><td class="td_row_even"><div class="td_row_even">Selects the operation mode of the wireless network interface controller. Possible values are ap, sta, adhoc, wds, monitor, mesh</div></td></tr><tr><td class="td_row_odd"><div class="td_row_odd">encryption</div></td><td class="td_row_odd"><div class="td_row_odd">string</div></td><td class="td_row_odd"><div class="td_row_odd">&nbsp;</div></td><td class="td_row_odd"><table style="width:100%"></table></td><td class="td_row_odd"><div class="td_row_odd">Wireless encryption method. Possible values are: none, wep, psk, psk2. For WEP station mode the default is “open system” authentication. Use wep+shared or wep+open to force a specific mode.</div></td></tr></tbody></table></td></tr></tbody></table></td></tr></tbody>
\ No newline at end of file
diff --git a/docs/api/wifi.ap.md b/docs/api/wifi.ap.md
new file mode 100644
index 0000000000000000000000000000000000000000..b16174307f6aec6c2bda2860578c50ca9937fd90
--- /dev/null
+++ b/docs/api/wifi.ap.md
@@ -0,0 +1,3646 @@
+# wifi.ap.&lt;name&gt; Schema
+
+```
+https://www.iopsys.eu/wifi.ap.json
+```
+
+| Custom Properties | Additional Properties |
+| ----------------- | --------------------- |
+| Forbidden         | Forbidden             |
+
+# wifi.ap.&lt;name&gt;
+
+| List of Methods                           |
+| ----------------------------------------- |
+| [add_neighbor](#add_neighbor)             | Method | wifi.ap.&lt;name&gt; (this schema) |
+| [add_vendor_ie](#add_vendor_ie)           | Method | wifi.ap.&lt;name&gt; (this schema) |
+| [assoclist](#assoclist)                   | Method | wifi.ap.&lt;name&gt; (this schema) |
+| [del_neighbor](#del_neighbor)             | Method | wifi.ap.&lt;name&gt; (this schema) |
+| [del_vendor_ie](#del_vendor_ie)           | Method | wifi.ap.&lt;name&gt; (this schema) |
+| [disconnect](#disconnect)                 | Method | wifi.ap.&lt;name&gt; (this schema) |
+| [list_neighbor](#list_neighbor)           | Method | wifi.ap.&lt;name&gt; (this schema) |
+| [monitor](#monitor)                       | Method | wifi.ap.&lt;name&gt; (this schema) |
+| [request_neighbor](#request_neighbor)     | Method | wifi.ap.&lt;name&gt; (this schema) |
+| [request_transition](#request_transition) | Method | wifi.ap.&lt;name&gt; (this schema) |
+| [stations](#stations)                     | Method | wifi.ap.&lt;name&gt; (this schema) |
+| [stats](#stats)                           | Method | wifi.ap.&lt;name&gt; (this schema) |
+| [status](#status)                         | Method | wifi.ap.&lt;name&gt; (this schema) |
+
+## add_neighbor
+
+`add_neighbor`
+
+- type: `Method`
+
+### add_neighbor Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `input`  | object | Optional |
+| `output` | object | Optional |
+
+#### input
+
+`input`
+
+- is optional
+- type: `object`
+
+##### input Type
+
+`object` with following properties:
+
+| Property     | Type    | Required     |
+| ------------ | ------- | ------------ |
+| `bssid`      | string  | **Required** |
+| `bssid_info` | string  | **Required** |
+| `channel`    | oneOf   | **Required** |
+| `phy`        | integer | **Required** |
+| `reg`        | integer | **Required** |
+
+#### bssid
+
+##### MAC Address
+
+`bssid`
+
+- is **required**
+- type: reference
+
+##### bssid Type
+
+`string`
+
+- minimum length: 17 characters
+- maximum length: 17 characters All instances must conform to this regular expression (test examples
+  [here](<https://regexr.com/?expression=%5E(%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D%3A)%7B5%7D%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D%24>)):
+
+```regex
+^([0-9a-fA-F][0-9a-fA-F]:){5}[0-9a-fA-F][0-9a-fA-F]$
+```
+
+#### bssid_info
+
+`bssid_info`
+
+- is **required**
+- type: `string`
+
+##### bssid_info Type
+
+`string`
+
+#### channel
+
+`channel`
+
+- is **required**
+- type: complex
+
+##### channel Type
+
+**One** of the following _conditions_ need to be fulfilled.
+
+#### Condition 1
+
+`integer`
+
+- minimum value: `1`
+- maximum value: `14`
+
+#### Condition 2
+
+`integer`
+
+- minimum value: `32`
+- maximum value: `200`
+
+#### phy
+
+`phy`
+
+- is **required**
+- type: `integer`
+
+##### phy Type
+
+`integer`
+
+- minimum value: `0`
+
+#### reg
+
+`reg`
+
+- is **required**
+- type: `integer`
+
+##### reg Type
+
+`integer`
+
+- minimum value: `0`
+
+### Ubus CLI Example
+
+```
+ubus call wifi.ap.<name> add_neighbor {"bssid":"7D:AF:d4:61:7D:15","channel":148,"bssid_info":"exercitation pariatur labore","reg":55128803,"phy":5160466}
+```
+
+### JSONRPC Example
+
+```json
+{
+  "jsonrpc": "2.0",
+  "id": 0,
+  "method": "call",
+  "params": [
+    "<SID>",
+    "wifi.ap.<name>",
+    "add_neighbor",
+    {
+      "bssid": "7D:AF:d4:61:7D:15",
+      "channel": 148,
+      "bssid_info": "exercitation pariatur labore",
+      "reg": 55128803,
+      "phy": 5160466
+    }
+  ]
+}
+```
+
+#### output
+
+`output`
+
+- is optional
+- type: `object`
+
+##### output Type
+
+`object` with following properties:
+
+| Property | Type | Required |
+| -------- | ---- | -------- |
+| None     | None | None     |
+
+### Output Example
+
+```json
+{}
+```
+
+## add_vendor_ie
+
+`add_vendor_ie`
+
+- type: `Method`
+
+### add_vendor_ie Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `input`  | object | Optional |
+| `output` | object | Optional |
+
+#### input
+
+`input`
+
+- is optional
+- type: `object`
+
+##### input Type
+
+`object` with following properties:
+
+| Property | Type    | Required     |
+| -------- | ------- | ------------ |
+| `data`   | string  | **Required** |
+| `mgmt`   | integer | **Required** |
+| `oui`    | string  | **Required** |
+
+#### data
+
+##### Hex String
+
+`data`
+
+- is **required**
+- type: reference
+
+##### data Type
+
+`string`
+
+All instances must conform to this regular expression (test examples
+[here](https://regexr.com/?expression=%5E%5B0-9a-fA-F%5D%2B)):
+
+```regex
+^[0-9a-fA-F]+
+```
+
+#### mgmt
+
+`mgmt`
+
+- is **required**
+- type: `integer`
+
+##### mgmt Type
+
+`integer`
+
+#### oui
+
+##### Three byte oui
+
+`oui`
+
+- is **required**
+- type: reference
+
+##### oui Type
+
+`string`
+
+- minimum length: 9 characters
+- maximum length: 9 characters All instances must conform to this regular expression (test examples
+  [here](<https://regexr.com/?expression=%5E(%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D)%7B3%7D%24>)):
+
+```regex
+^([0-9a-fA-F][0-9a-fA-F]){3}$
+```
+
+### Ubus CLI Example
+
+```
+ubus call wifi.ap.<name> add_vendor_ie {"mgmt":-95722701,"oui":"b79aaDC49","data":"aAb9"}
+```
+
+### JSONRPC Example
+
+```json
+{
+  "jsonrpc": "2.0",
+  "id": 0,
+  "method": "call",
+  "params": ["<SID>", "wifi.ap.<name>", "add_vendor_ie", { "mgmt": -95722701, "oui": "b79aaDC49", "data": "aAb9" }]
+}
+```
+
+#### output
+
+`output`
+
+- is optional
+- type: `object`
+
+##### output Type
+
+`object` with following properties:
+
+| Property | Type | Required |
+| -------- | ---- | -------- |
+| None     | None | None     |
+
+### Output Example
+
+```json
+{}
+```
+
+## assoclist
+
+`assoclist`
+
+- type: `Method`
+
+### assoclist Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `input`  | object | Optional |
+| `output` | object | Optional |
+
+#### input
+
+`input`
+
+- is optional
+- type: `object`
+
+##### input Type
+
+`object` with following properties:
+
+| Property | Type | Required |
+| -------- | ---- | -------- |
+| None     | None | None     |
+
+### Ubus CLI Example
+
+```
+ubus call wifi.ap.<name> assoclist {}
+```
+
+### JSONRPC Example
+
+```json
+{ "jsonrpc": "2.0", "id": 0, "method": "call", "params": ["<SID>", "wifi.ap.<name>", "assoclist", {}] }
+```
+
+#### output
+
+`output`
+
+- is optional
+- type: `object`
+
+##### output Type
+
+`object` with following properties:
+
+| Property    | Type  | Required     |
+| ----------- | ----- | ------------ |
+| `assoclist` | array | **Required** |
+
+#### assoclist
+
+`assoclist`
+
+- is **required**
+- type: `object[]`
+
+##### assoclist Type
+
+Array type: `object[]`
+
+All items must be of the type: `object` with following properties:
+
+| Property  | Type   | Required     |
+| --------- | ------ | ------------ |
+| `macaddr` | string | **Required** |
+| `wdev`    | string | **Required** |
+
+#### macaddr
+
+##### MAC Address
+
+`macaddr`
+
+- is **required**
+- type: reference
+
+##### macaddr Type
+
+`string`
+
+- minimum length: 17 characters
+- maximum length: 17 characters All instances must conform to this regular expression (test examples
+  [here](<https://regexr.com/?expression=%5E(%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D%3A)%7B5%7D%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D%24>)):
+
+```regex
+^([0-9a-fA-F][0-9a-fA-F]:){5}[0-9a-fA-F][0-9a-fA-F]$
+```
+
+#### wdev
+
+##### Interface
+
+`wdev`
+
+- is **required**
+- type: reference
+
+##### wdev Type
+
+`string`
+
+- minimum length: 1 characters
+- maximum length: 16 characters
+
+### Output Example
+
+```json
+{
+  "assoclist": [
+    { "wdev": "eu ex veniam", "macaddr": "95:BB:cd:F3:d8:6d" },
+    { "wdev": "nisi", "macaddr": "65:6C:7b:43:D3:FC" },
+    { "wdev": "commodo velit a", "macaddr": "9F:d4:4D:D0:F1:A4" },
+    { "wdev": "qui ", "macaddr": "ED:D7:49:aC:c5:10" },
+    { "wdev": "in et o", "macaddr": "14:69:A2:AC:f6:49" }
+  ]
+}
+```
+
+## del_neighbor
+
+`del_neighbor`
+
+- type: `Method`
+
+### del_neighbor Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `input`  | object | Optional |
+| `output` | object | Optional |
+
+#### input
+
+`input`
+
+- is optional
+- type: `object`
+
+##### input Type
+
+`object` with following properties:
+
+| Property | Type   | Required     |
+| -------- | ------ | ------------ |
+| `bssid`  | string | **Required** |
+
+#### bssid
+
+##### MAC Address
+
+`bssid`
+
+- is **required**
+- type: reference
+
+##### bssid Type
+
+`string`
+
+- minimum length: 17 characters
+- maximum length: 17 characters All instances must conform to this regular expression (test examples
+  [here](<https://regexr.com/?expression=%5E(%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D%3A)%7B5%7D%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D%24>)):
+
+```regex
+^([0-9a-fA-F][0-9a-fA-F]:){5}[0-9a-fA-F][0-9a-fA-F]$
+```
+
+### Ubus CLI Example
+
+```
+ubus call wifi.ap.<name> del_neighbor {"bssid":"7E:d5:c5:D2:a8:Bd"}
+```
+
+### JSONRPC Example
+
+```json
+{
+  "jsonrpc": "2.0",
+  "id": 0,
+  "method": "call",
+  "params": ["<SID>", "wifi.ap.<name>", "del_neighbor", { "bssid": "7E:d5:c5:D2:a8:Bd" }]
+}
+```
+
+#### output
+
+`output`
+
+- is optional
+- type: `object`
+
+##### output Type
+
+`object` with following properties:
+
+| Property | Type | Required |
+| -------- | ---- | -------- |
+| None     | None | None     |
+
+### Output Example
+
+```json
+{}
+```
+
+## del_vendor_ie
+
+`del_vendor_ie`
+
+- type: `Method`
+
+### del_vendor_ie Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `intput` | object | Optional |
+| `output` | object | Optional |
+
+#### intput
+
+`intput`
+
+- is optional
+- type: `object`
+
+##### intput Type
+
+`object` with following properties:
+
+| Property | Type    | Required     |
+| -------- | ------- | ------------ |
+| `data`   | string  | **Required** |
+| `mgmt`   | integer | **Required** |
+| `oui`    | string  | **Required** |
+
+#### data
+
+##### Hex String
+
+`data`
+
+- is **required**
+- type: reference
+
+##### data Type
+
+`string`
+
+All instances must conform to this regular expression (test examples
+[here](https://regexr.com/?expression=%5E%5B0-9a-fA-F%5D%2B)):
+
+```regex
+^[0-9a-fA-F]+
+```
+
+#### mgmt
+
+`mgmt`
+
+- is **required**
+- type: `integer`
+
+##### mgmt Type
+
+`integer`
+
+#### oui
+
+##### Three byte oui
+
+`oui`
+
+- is **required**
+- type: reference
+
+##### oui Type
+
+`string`
+
+- minimum length: 9 characters
+- maximum length: 9 characters All instances must conform to this regular expression (test examples
+  [here](<https://regexr.com/?expression=%5E(%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D)%7B3%7D%24>)):
+
+```regex
+^([0-9a-fA-F][0-9a-fA-F]){3}$
+```
+
+#### output
+
+`output`
+
+- is optional
+- type: `object`
+
+##### output Type
+
+`object` with following properties:
+
+| Property | Type | Required |
+| -------- | ---- | -------- |
+| None     | None | None     |
+
+### Output Example
+
+```json
+{}
+```
+
+## disconnect
+
+`disconnect`
+
+- type: `Method`
+
+### disconnect Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `input`  | object | Optional |
+| `output` | object | Optional |
+
+#### input
+
+`input`
+
+- is optional
+- type: `object`
+
+##### input Type
+
+`object` with following properties:
+
+| Property | Type   | Required     |
+| -------- | ------ | ------------ |
+| `sta`    | string | **Required** |
+
+#### sta
+
+##### MAC Address
+
+`sta`
+
+- is **required**
+- type: reference
+
+##### sta Type
+
+`string`
+
+- minimum length: 17 characters
+- maximum length: 17 characters All instances must conform to this regular expression (test examples
+  [here](<https://regexr.com/?expression=%5E(%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D%3A)%7B5%7D%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D%24>)):
+
+```regex
+^([0-9a-fA-F][0-9a-fA-F]:){5}[0-9a-fA-F][0-9a-fA-F]$
+```
+
+### Ubus CLI Example
+
+```
+ubus call wifi.ap.<name> disconnect {"sta":"62:Ec:Ff:09:FB:42"}
+```
+
+### JSONRPC Example
+
+```json
+{
+  "jsonrpc": "2.0",
+  "id": 0,
+  "method": "call",
+  "params": ["<SID>", "wifi.ap.<name>", "disconnect", { "sta": "62:Ec:Ff:09:FB:42" }]
+}
+```
+
+#### output
+
+`output`
+
+- is optional
+- type: `object`
+
+##### output Type
+
+`object` with following properties:
+
+| Property | Type | Required |
+| -------- | ---- | -------- |
+| None     | None | None     |
+
+### Output Example
+
+```json
+{}
+```
+
+## list_neighbor
+
+`list_neighbor`
+
+- type: `Method`
+
+### list_neighbor Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `input`  | object | Optional |
+| `output` | object | Optional |
+
+#### input
+
+`input`
+
+- is optional
+- type: `object`
+
+##### input Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `client` | string | Optional |
+| `ssid`   | string | Optional |
+
+#### client
+
+##### MAC Address
+
+`client`
+
+- is optional
+- type: reference
+
+##### client Type
+
+`string`
+
+- minimum length: 17 characters
+- maximum length: 17 characters All instances must conform to this regular expression (test examples
+  [here](<https://regexr.com/?expression=%5E(%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D%3A)%7B5%7D%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D%24>)):
+
+```regex
+^([0-9a-fA-F][0-9a-fA-F]:){5}[0-9a-fA-F][0-9a-fA-F]$
+```
+
+#### ssid
+
+##### SSID
+
+`ssid`
+
+- is optional
+- type: reference
+
+##### ssid Type
+
+`string`
+
+- maximum length: 32 characters
+
+### Ubus CLI Example
+
+```
+ubus call wifi.ap.<name> list_neighbor {"ssid":"est commodo c","client":"ed:4F:78:BB:F6:00"}
+```
+
+### JSONRPC Example
+
+```json
+{
+  "jsonrpc": "2.0",
+  "id": 0,
+  "method": "call",
+  "params": ["<SID>", "wifi.ap.<name>", "list_neighbor", { "ssid": "est commodo c", "client": "ed:4F:78:BB:F6:00" }]
+}
+```
+
+#### output
+
+`output`
+
+- is optional
+- type: `object`
+
+##### output Type
+
+`object` with following properties:
+
+| Property | Type | Required |
+| -------- | ---- | -------- |
+| None     | None | None     |
+
+### Output Example
+
+```json
+{ "neighbors": "dolore sint" }
+```
+
+## monitor
+
+`monitor`
+
+- type: `Method`
+
+### monitor Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `intput` | object | Optional |
+| `output` | object | Optional |
+
+#### intput
+
+`intput`
+
+- is optional
+- type: `object`
+
+##### intput Type
+
+`object` with following properties:
+
+| Property | Type    | Required     |
+| -------- | ------- | ------------ |
+| `get`    | integer | Optional     |
+| `sta`    | string  | **Required** |
+
+#### get
+
+`get`
+
+- is optional
+- type: `integer`
+
+##### get Type
+
+`integer`
+
+#### sta
+
+##### MAC Address
+
+`sta`
+
+- is **required**
+- type: reference
+
+##### sta Type
+
+`string`
+
+- minimum length: 17 characters
+- maximum length: 17 characters All instances must conform to this regular expression (test examples
+  [here](<https://regexr.com/?expression=%5E(%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D%3A)%7B5%7D%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D%24>)):
+
+```regex
+^([0-9a-fA-F][0-9a-fA-F]:){5}[0-9a-fA-F][0-9a-fA-F]$
+```
+
+#### output
+
+`output`
+
+- is optional
+- type: `object`
+
+##### output Type
+
+`object` with following properties:
+
+| Property | Type | Required |
+| -------- | ---- | -------- |
+| None     | None | None     |
+
+### Output Example
+
+```json
+{}
+```
+
+## request_neighbor
+
+`request_neighbor`
+
+- type: `Method`
+
+### request_neighbor Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `input`  | object | Optional |
+| `output` | object | Optional |
+
+#### input
+
+`input`
+
+- is optional
+- type: `object`
+
+##### input Type
+
+`object` with following properties:
+
+| Property | Type   | Required     |
+| -------- | ------ | ------------ |
+| `client` | string | **Required** |
+| `ssid`   | string | Optional     |
+
+#### client
+
+##### MAC Address
+
+`client`
+
+- is **required**
+- type: reference
+
+##### client Type
+
+`string`
+
+- minimum length: 17 characters
+- maximum length: 17 characters All instances must conform to this regular expression (test examples
+  [here](<https://regexr.com/?expression=%5E(%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D%3A)%7B5%7D%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D%24>)):
+
+```regex
+^([0-9a-fA-F][0-9a-fA-F]:){5}[0-9a-fA-F][0-9a-fA-F]$
+```
+
+#### ssid
+
+##### SSID
+
+`ssid`
+
+- is optional
+- type: reference
+
+##### ssid Type
+
+`string`
+
+- maximum length: 32 characters
+
+### Ubus CLI Example
+
+```
+ubus call wifi.ap.<name> request_neighbor {"client":"Fc:2A:3f:71:Bb:c4","ssid":"aliqua ut Excepteur"}
+```
+
+### JSONRPC Example
+
+```json
+{
+  "jsonrpc": "2.0",
+  "id": 0,
+  "method": "call",
+  "params": [
+    "<SID>",
+    "wifi.ap.<name>",
+    "request_neighbor",
+    { "client": "Fc:2A:3f:71:Bb:c4", "ssid": "aliqua ut Excepteur" }
+  ]
+}
+```
+
+#### output
+
+`output`
+
+- is optional
+- type: `object`
+
+##### output Type
+
+`object` with following properties:
+
+| Property | Type | Required |
+| -------- | ---- | -------- |
+| None     | None | None     |
+
+### Output Example
+
+```json
+{}
+```
+
+## request_transition
+
+`request_transition`
+
+- type: `Method`
+
+### request_transition Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `input`  | object | Optional |
+| `output` | object | Optional |
+
+#### input
+
+`input`
+
+- is optional
+- type: `object`
+
+##### input Type
+
+`object` with following properties:
+
+| Property  | Type    | Required     |
+| --------- | ------- | ------------ |
+| `bssid`   | array   | **Required** |
+| `client`  | string  | **Required** |
+| `timeout` | integer | Optional     |
+
+#### bssid
+
+`bssid`
+
+- is **required**
+- type: reference
+
+##### bssid Type
+
+Array type: reference
+
+All items must be of the type: `string`
+
+- minimum length: 17 characters
+- maximum length: 17 characters All instances must conform to this regular expression (test examples
+  [here](<https://regexr.com/?expression=%5E(%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D%3A)%7B5%7D%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D%24>)):
+
+```regex
+^([0-9a-fA-F][0-9a-fA-F]:){5}[0-9a-fA-F][0-9a-fA-F]$
+```
+
+#### client
+
+##### MAC Address
+
+`client`
+
+- is **required**
+- type: reference
+
+##### client Type
+
+`string`
+
+- minimum length: 17 characters
+- maximum length: 17 characters All instances must conform to this regular expression (test examples
+  [here](<https://regexr.com/?expression=%5E(%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D%3A)%7B5%7D%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D%24>)):
+
+```regex
+^([0-9a-fA-F][0-9a-fA-F]:){5}[0-9a-fA-F][0-9a-fA-F]$
+```
+
+#### timeout
+
+`timeout`
+
+- is optional
+- type: `integer`
+
+##### timeout Type
+
+`integer`
+
+### Ubus CLI Example
+
+```
+ubus call wifi.ap.<name> request_transition {"client":"b9:0B:De:Dd:8C:De","bssid":["13:a3:F7:32:cA:a1","68:7f:6f:d1:eb:A0","CB:0D:E8:BD:a7:e0","4F:cA:23:87:bC:96","8b:f8:dc:FD:1A:c7"],"timeout":-38008176}
+```
+
+### JSONRPC Example
+
+```json
+{
+  "jsonrpc": "2.0",
+  "id": 0,
+  "method": "call",
+  "params": [
+    "<SID>",
+    "wifi.ap.<name>",
+    "request_transition",
+    {
+      "client": "b9:0B:De:Dd:8C:De",
+      "bssid": [
+        "13:a3:F7:32:cA:a1",
+        "68:7f:6f:d1:eb:A0",
+        "CB:0D:E8:BD:a7:e0",
+        "4F:cA:23:87:bC:96",
+        "8b:f8:dc:FD:1A:c7"
+      ],
+      "timeout": -38008176
+    }
+  ]
+}
+```
+
+#### output
+
+`output`
+
+- is optional
+- type: `object`
+
+##### output Type
+
+`object` with following properties:
+
+| Property | Type | Required |
+| -------- | ---- | -------- |
+| None     | None | None     |
+
+### Output Example
+
+```json
+{}
+```
+
+## stations
+
+`stations`
+
+- type: `Method`
+
+### stations Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `input`  | object | Optional |
+| `output` | object | Optional |
+
+#### input
+
+`input`
+
+- is optional
+- type: `object`
+
+##### input Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `sta`    | string | Optional |
+
+#### sta
+
+##### MAC Address
+
+`sta`
+
+- is optional
+- type: reference
+
+##### sta Type
+
+`string`
+
+- minimum length: 17 characters
+- maximum length: 17 characters All instances must conform to this regular expression (test examples
+  [here](<https://regexr.com/?expression=%5E(%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D%3A)%7B5%7D%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D%24>)):
+
+```regex
+^([0-9a-fA-F][0-9a-fA-F]:){5}[0-9a-fA-F][0-9a-fA-F]$
+```
+
+### Ubus CLI Example
+
+```
+ubus call wifi.ap.<name> stations {"sta":"bD:a6:8E:e1:B1:0F"}
+```
+
+### JSONRPC Example
+
+```json
+{
+  "jsonrpc": "2.0",
+  "id": 0,
+  "method": "call",
+  "params": ["<SID>", "wifi.ap.<name>", "stations", { "sta": "bD:a6:8E:e1:B1:0F" }]
+}
+```
+
+#### output
+
+`output`
+
+- is optional
+- type: `object`
+
+##### output Type
+
+`object` with following properties:
+
+| Property   | Type  | Required     |
+| ---------- | ----- | ------------ |
+| `stations` | array | **Required** |
+
+#### stations
+
+`stations`
+
+- is **required**
+- type: `object[]`
+
+##### stations Type
+
+Array type: `object[]`
+
+All items must be of the type: `object` with following properties:
+
+| Property           | Type    | Required     |
+| ------------------ | ------- | ------------ |
+| `airtime`          | integer | **Required** |
+| `capabilities`     | object  | **Required** |
+| `frequency`        | string  | **Required** |
+| `idle`             | integer | **Required** |
+| `in_network`       | integer | **Required** |
+| `macaddr`          | string  | **Required** |
+| `max_rate`         | integer | **Required** |
+| `rssi`             | integer | **Required** |
+| `rssi_per_antenna` | array   | **Required** |
+| `rx_airtime`       | integer | **Required** |
+| `snr`              | integer | **Required** |
+| `stats`            | object  | **Required** |
+| `status`           | object  | **Required** |
+| `tx_airtime`       | integer | **Required** |
+| `wdev`             | string  | **Required** |
+
+#### airtime
+
+`airtime`
+
+- is **required**
+- type: `integer`
+
+##### airtime Type
+
+`integer`
+
+- minimum value: `0`
+- maximum value: `100`
+
+#### capabilities
+
+`capabilities`
+
+- is **required**
+- type: `object`
+
+##### capabilities Type
+
+`object` with following properties:
+
+| Property     | Type    | Required     |
+| ------------ | ------- | ------------ |
+| `2040coex`   | boolean | **Required** |
+| `apsd`       | boolean | **Required** |
+| `dot11ac`    | object  | Optional     |
+| `dot11h`     | boolean | **Required** |
+| `dot11k`     | object  | Optional     |
+| `dot11n`     | object  | Optional     |
+| `dot11v_btm` | boolean | **Required** |
+| `proxy_arp`  | boolean | **Required** |
+| `psmp`       | boolean | **Required** |
+| `shortslot`  | boolean | **Required** |
+| `wmm`        | boolean | **Required** |
+
+#### 2040coex
+
+`2040coex`
+
+- is **required**
+- type: `boolean`
+
+##### 2040coex Type
+
+`boolean`
+
+#### apsd
+
+`apsd`
+
+- is **required**
+- type: `boolean`
+
+##### apsd Type
+
+`boolean`
+
+#### dot11ac
+
+`dot11ac`
+
+- is optional
+- type: `object`
+
+##### dot11ac Type
+
+`object` with following properties:
+
+| Property                | Type    | Required     |
+| ----------------------- | ------- | ------------ |
+| `dot11ac_160`           | boolean | **Required** |
+| `dot11ac_8080`          | boolean | **Required** |
+| `dot11ac_mpdu_max`      | integer | **Required** |
+| `dot11ac_mu_beamformee` | boolean | **Required** |
+| `dot11ac_mu_beamformer` | boolean | **Required** |
+| `dot11ac_rx_ldpc`       | boolean | **Required** |
+| `dot11ac_rx_stbc_1ss`   | boolean | **Required** |
+| `dot11ac_rx_stbc_2ss`   | boolean | **Required** |
+| `dot11ac_rx_stbc_3ss`   | boolean | **Required** |
+| `dot11ac_rx_stbc_4ss`   | boolean | **Required** |
+| `dot11ac_sgi160`        | boolean | **Required** |
+| `dot11ac_sgi80`         | boolean | **Required** |
+| `dot11ac_su_beamformee` | boolean | **Required** |
+| `dot11ac_su_beamformer` | boolean | **Required** |
+| `dot11ac_tx_stbc`       | boolean | **Required** |
+
+#### dot11ac_160
+
+`dot11ac_160`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_160 Type
+
+`boolean`
+
+#### dot11ac_8080
+
+`dot11ac_8080`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_8080 Type
+
+`boolean`
+
+#### dot11ac_mpdu_max
+
+`dot11ac_mpdu_max`
+
+- is **required**
+- type: `integer`
+
+##### dot11ac_mpdu_max Type
+
+`integer`
+
+- minimum value: `0`
+- maximum value: `65535`
+
+#### dot11ac_mu_beamformee
+
+`dot11ac_mu_beamformee`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_mu_beamformee Type
+
+`boolean`
+
+#### dot11ac_mu_beamformer
+
+`dot11ac_mu_beamformer`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_mu_beamformer Type
+
+`boolean`
+
+#### dot11ac_rx_ldpc
+
+`dot11ac_rx_ldpc`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_rx_ldpc Type
+
+`boolean`
+
+#### dot11ac_rx_stbc_1ss
+
+`dot11ac_rx_stbc_1ss`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_rx_stbc_1ss Type
+
+`boolean`
+
+#### dot11ac_rx_stbc_2ss
+
+`dot11ac_rx_stbc_2ss`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_rx_stbc_2ss Type
+
+`boolean`
+
+#### dot11ac_rx_stbc_3ss
+
+`dot11ac_rx_stbc_3ss`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_rx_stbc_3ss Type
+
+`boolean`
+
+#### dot11ac_rx_stbc_4ss
+
+`dot11ac_rx_stbc_4ss`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_rx_stbc_4ss Type
+
+`boolean`
+
+#### dot11ac_sgi160
+
+`dot11ac_sgi160`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_sgi160 Type
+
+`boolean`
+
+#### dot11ac_sgi80
+
+`dot11ac_sgi80`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_sgi80 Type
+
+`boolean`
+
+#### dot11ac_su_beamformee
+
+`dot11ac_su_beamformee`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_su_beamformee Type
+
+`boolean`
+
+#### dot11ac_su_beamformer
+
+`dot11ac_su_beamformer`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_su_beamformer Type
+
+`boolean`
+
+#### dot11ac_tx_stbc
+
+`dot11ac_tx_stbc`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_tx_stbc Type
+
+`boolean`
+
+#### dot11h
+
+`dot11h`
+
+- is **required**
+- type: `boolean`
+
+##### dot11h Type
+
+`boolean`
+
+#### dot11k
+
+`dot11k`
+
+- is optional
+- type: `object`
+
+##### dot11k Type
+
+`object` with following properties:
+
+| Property             | Type    | Required     |
+| -------------------- | ------- | ------------ |
+| `dot11k_bcn_active`  | boolean | **Required** |
+| `dot11k_bcn_passive` | boolean | **Required** |
+| `dot11k_bcn_table`   | boolean | **Required** |
+| `dot11k_link_meas`   | boolean | **Required** |
+| `dot11k_nbr_report`  | boolean | **Required** |
+| `dot11k_rcpi`        | boolean | **Required** |
+| `dot11k_rsni`        | boolean | **Required** |
+
+#### dot11k_bcn_active
+
+`dot11k_bcn_active`
+
+- is **required**
+- type: `boolean`
+
+##### dot11k_bcn_active Type
+
+`boolean`
+
+#### dot11k_bcn_passive
+
+`dot11k_bcn_passive`
+
+- is **required**
+- type: `boolean`
+
+##### dot11k_bcn_passive Type
+
+`boolean`
+
+#### dot11k_bcn_table
+
+`dot11k_bcn_table`
+
+- is **required**
+- type: `boolean`
+
+##### dot11k_bcn_table Type
+
+`boolean`
+
+#### dot11k_link_meas
+
+`dot11k_link_meas`
+
+- is **required**
+- type: `boolean`
+
+##### dot11k_link_meas Type
+
+`boolean`
+
+#### dot11k_nbr_report
+
+`dot11k_nbr_report`
+
+- is **required**
+- type: `boolean`
+
+##### dot11k_nbr_report Type
+
+`boolean`
+
+#### dot11k_rcpi
+
+`dot11k_rcpi`
+
+- is **required**
+- type: `boolean`
+
+##### dot11k_rcpi Type
+
+`boolean`
+
+#### dot11k_rsni
+
+`dot11k_rsni`
+
+- is **required**
+- type: `boolean`
+
+##### dot11k_rsni Type
+
+`boolean`
+
+#### dot11n
+
+`dot11n`
+
+- is optional
+- type: `object`
+
+##### dot11n Type
+
+`object` with following properties:
+
+| Property         | Type    | Required     |
+| ---------------- | ------- | ------------ |
+| `dot11n_40`      | boolean | **Required** |
+| `dot11n_ldpc`    | boolean | **Required** |
+| `dot11n_ps`      | boolean | **Required** |
+| `dot11n_rx_stbc` | boolean | **Required** |
+| `dot11n_sgi20`   | boolean | **Required** |
+| `dot11n_sgi40`   | boolean | **Required** |
+| `dot11n_tx_stbc` | boolean | **Required** |
+
+#### dot11n_40
+
+`dot11n_40`
+
+- is **required**
+- type: `boolean`
+
+##### dot11n_40 Type
+
+`boolean`
+
+#### dot11n_ldpc
+
+`dot11n_ldpc`
+
+- is **required**
+- type: `boolean`
+
+##### dot11n_ldpc Type
+
+`boolean`
+
+#### dot11n_ps
+
+`dot11n_ps`
+
+- is **required**
+- type: `boolean`
+
+##### dot11n_ps Type
+
+`boolean`
+
+#### dot11n_rx_stbc
+
+`dot11n_rx_stbc`
+
+- is **required**
+- type: `boolean`
+
+##### dot11n_rx_stbc Type
+
+`boolean`
+
+#### dot11n_sgi20
+
+`dot11n_sgi20`
+
+- is **required**
+- type: `boolean`
+
+##### dot11n_sgi20 Type
+
+`boolean`
+
+#### dot11n_sgi40
+
+`dot11n_sgi40`
+
+- is **required**
+- type: `boolean`
+
+##### dot11n_sgi40 Type
+
+`boolean`
+
+#### dot11n_tx_stbc
+
+`dot11n_tx_stbc`
+
+- is **required**
+- type: `boolean`
+
+##### dot11n_tx_stbc Type
+
+`boolean`
+
+#### dot11v_btm
+
+`dot11v_btm`
+
+- is **required**
+- type: `boolean`
+
+##### dot11v_btm Type
+
+`boolean`
+
+#### proxy_arp
+
+`proxy_arp`
+
+- is **required**
+- type: `boolean`
+
+##### proxy_arp Type
+
+`boolean`
+
+#### psmp
+
+`psmp`
+
+- is **required**
+- type: `boolean`
+
+##### psmp Type
+
+`boolean`
+
+#### shortslot
+
+`shortslot`
+
+- is **required**
+- type: `boolean`
+
+##### shortslot Type
+
+`boolean`
+
+#### wmm
+
+`wmm`
+
+- is **required**
+- type: `boolean`
+
+##### wmm Type
+
+`boolean`
+
+#### frequency
+
+##### WiFi Band
+
+`frequency`
+
+- is **required**
+- type: reference
+
+##### frequency Type
+
+`string`
+
+The value of this property **must** be equal to one of the [known values below](#stations-known-values).
+
+##### frequency Known Values
+
+| Value |
+| ----- |
+| 2GHz  |
+| 5GHz  |
+
+#### idle
+
+`idle`
+
+- is **required**
+- type: `integer`
+
+##### idle Type
+
+`integer`
+
+- minimum value: `0`
+
+#### in_network
+
+`in_network`
+
+- is **required**
+- type: `integer`
+
+##### in_network Type
+
+`integer`
+
+- minimum value: `0`
+
+#### macaddr
+
+##### MAC Address
+
+`macaddr`
+
+- is **required**
+- type: reference
+
+##### macaddr Type
+
+`string`
+
+- minimum length: 17 characters
+- maximum length: 17 characters All instances must conform to this regular expression (test examples
+  [here](<https://regexr.com/?expression=%5E(%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D%3A)%7B5%7D%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D%24>)):
+
+```regex
+^([0-9a-fA-F][0-9a-fA-F]:){5}[0-9a-fA-F][0-9a-fA-F]$
+```
+
+#### max_rate
+
+`max_rate`
+
+- is **required**
+- type: `integer`
+
+##### max_rate Type
+
+`integer`
+
+- minimum value: `0`
+
+#### rssi
+
+##### RSSI
+
+`rssi`
+
+- is **required**
+- type: reference
+
+##### rssi Type
+
+`integer`
+
+- minimum value: `-128`
+- maximum value: `0`
+
+#### rssi_per_antenna
+
+`rssi_per_antenna`
+
+- is **required**
+- type: reference
+
+##### rssi_per_antenna Type
+
+Array type: reference
+
+All items must be of the type: `integer`
+
+- minimum value: `-128`
+- maximum value: `0`
+
+#### rx_airtime
+
+`rx_airtime`
+
+- is **required**
+- type: `integer`
+
+##### rx_airtime Type
+
+`integer`
+
+- minimum value: `0`
+- maximum value: `100`
+
+#### snr
+
+`snr`
+
+- is **required**
+- type: `integer`
+
+##### snr Type
+
+`integer`
+
+- minimum value: `0`
+- maximum value: `100`
+
+#### stats
+
+`stats`
+
+- is **required**
+- type: `object`
+
+##### stats Type
+
+`object` with following properties:
+
+| Property              | Type    | Required     |
+| --------------------- | ------- | ------------ |
+| `rate_of_last_rx_pkt` | integer | **Required** |
+| `rate_of_last_tx_pkt` | integer | **Required** |
+| `rx_data_bytes`       | integer | **Required** |
+| `rx_data_pkts`        | integer | **Required** |
+| `rx_failures`         | integer | **Required** |
+| `tx_failures`         | integer | **Required** |
+| `tx_pkts_retries`     | integer | **Required** |
+| `tx_total_bytes`      | integer | **Required** |
+| `tx_total_pkts`       | integer | **Required** |
+
+#### rate_of_last_rx_pkt
+
+`rate_of_last_rx_pkt`
+
+- is **required**
+- type: reference
+
+##### rate_of_last_rx_pkt Type
+
+`integer`
+
+- minimum value: `0`
+
+#### rate_of_last_tx_pkt
+
+`rate_of_last_tx_pkt`
+
+- is **required**
+- type: reference
+
+##### rate_of_last_tx_pkt Type
+
+`integer`
+
+- minimum value: `0`
+
+#### rx_data_bytes
+
+`rx_data_bytes`
+
+- is **required**
+- type: reference
+
+##### rx_data_bytes Type
+
+`integer`
+
+- minimum value: `0`
+
+#### rx_data_pkts
+
+`rx_data_pkts`
+
+- is **required**
+- type: reference
+
+##### rx_data_pkts Type
+
+`integer`
+
+- minimum value: `0`
+
+#### rx_failures
+
+`rx_failures`
+
+- is **required**
+- type: reference
+
+##### rx_failures Type
+
+`integer`
+
+- minimum value: `0`
+
+#### tx_failures
+
+`tx_failures`
+
+- is **required**
+- type: reference
+
+##### tx_failures Type
+
+`integer`
+
+- minimum value: `0`
+
+#### tx_pkts_retries
+
+`tx_pkts_retries`
+
+- is **required**
+- type: reference
+
+##### tx_pkts_retries Type
+
+`integer`
+
+- minimum value: `0`
+
+#### tx_total_bytes
+
+`tx_total_bytes`
+
+- is **required**
+- type: reference
+
+##### tx_total_bytes Type
+
+`integer`
+
+- minimum value: `0`
+
+#### tx_total_pkts
+
+`tx_total_pkts`
+
+- is **required**
+- type: reference
+
+##### tx_total_pkts Type
+
+`integer`
+
+- minimum value: `0`
+
+#### status
+
+`status`
+
+- is **required**
+- type: `object`
+
+##### status Type
+
+`object` with following properties:
+
+| Property | Type    | Required     |
+| -------- | ------- | ------------ |
+| `ps`     | boolean | **Required** |
+| `wmm`    | boolean | **Required** |
+
+#### ps
+
+`ps`
+
+- is **required**
+- type: `boolean`
+
+##### ps Type
+
+`boolean`
+
+#### wmm
+
+`wmm`
+
+- is **required**
+- type: `boolean`
+
+##### wmm Type
+
+`boolean`
+
+#### tx_airtime
+
+`tx_airtime`
+
+- is **required**
+- type: `integer`
+
+##### tx_airtime Type
+
+`integer`
+
+- minimum value: `0`
+- maximum value: `100`
+
+#### wdev
+
+##### Interface
+
+`wdev`
+
+- is **required**
+- type: reference
+
+##### wdev Type
+
+`string`
+
+- minimum length: 1 characters
+- maximum length: 16 characters
+
+### Output Example
+
+```json
+{
+  "stations": [
+    {
+      "macaddr": "3A:aC:2c:AA:03:C6",
+      "wdev": "se",
+      "frequency": "2GHz",
+      "rssi": -108,
+      "snr": 70,
+      "idle": 90053251,
+      "in_network": 43328099,
+      "tx_airtime": 56,
+      "rx_airtime": 93,
+      "airtime": 73,
+      "max_rate": 11517274,
+      "status": { "wmm": false, "ps": false },
+      "capabilities": {
+        "wmm": false,
+        "apsd": true,
+        "shortslot": false,
+        "dot11h": true,
+        "2040coex": false,
+        "psmp": true,
+        "proxy_arp": true,
+        "dot11v_btm": true,
+        "dot11k": {
+          "dot11k_link_meas": false,
+          "dot11k_nbr_report": true,
+          "dot11k_bcn_passive": false,
+          "dot11k_bcn_active": true,
+          "dot11k_bcn_table": true,
+          "dot11k_rcpi": false,
+          "dot11k_rsni": false
+        },
+        "dot11n": {
+          "dot11n_ldpc": true,
+          "dot11n_40": true,
+          "dot11n_ps": false,
+          "dot11n_sgi20": true,
+          "dot11n_sgi40": true,
+          "dot11n_tx_stbc": false,
+          "dot11n_rx_stbc": false
+        },
+        "dot11ac": {
+          "dot11ac_160": false,
+          "dot11ac_8080": false,
+          "dot11ac_mpdu_max": 57162,
+          "dot11ac_sgi80": true,
+          "dot11ac_sgi160": true,
+          "dot11ac_rx_ldpc": false,
+          "dot11ac_tx_stbc": false,
+          "dot11ac_rx_stbc_1ss": false,
+          "dot11ac_rx_stbc_2ss": false,
+          "dot11ac_rx_stbc_3ss": true,
+          "dot11ac_rx_stbc_4ss": true,
+          "dot11ac_su_beamformer": false,
+          "dot11ac_su_beamformee": false,
+          "dot11ac_mu_beamformer": true,
+          "dot11ac_mu_beamformee": true
+        }
+      },
+      "stats": {
+        "tx_total_pkts": 92281078,
+        "tx_total_bytes": 6455029,
+        "tx_failures": 15810512,
+        "tx_pkts_retries": 80187405,
+        "rx_data_pkts": 24413834,
+        "rx_data_bytes": 47228586,
+        "rx_failures": 10026617,
+        "rate_of_last_tx_pkt": 50344199,
+        "rate_of_last_rx_pkt": 60889706
+      },
+      "rssi_per_antenna": [-58, -46, -33, -104]
+    },
+    {
+      "macaddr": "5F:BD:b8:31:Ec:Dc",
+      "wdev": "amet sit",
+      "frequency": "2GHz",
+      "rssi": -69,
+      "snr": 63,
+      "idle": 24571654,
+      "in_network": 23076310,
+      "tx_airtime": 56,
+      "rx_airtime": 1,
+      "airtime": 88,
+      "max_rate": 55820450,
+      "status": { "wmm": false, "ps": false },
+      "capabilities": {
+        "wmm": false,
+        "apsd": false,
+        "shortslot": true,
+        "dot11h": true,
+        "2040coex": true,
+        "psmp": false,
+        "proxy_arp": true,
+        "dot11v_btm": true,
+        "dot11k": {
+          "dot11k_link_meas": true,
+          "dot11k_nbr_report": true,
+          "dot11k_bcn_passive": true,
+          "dot11k_bcn_active": false,
+          "dot11k_bcn_table": true,
+          "dot11k_rcpi": true,
+          "dot11k_rsni": false
+        },
+        "dot11n": {
+          "dot11n_ldpc": false,
+          "dot11n_40": false,
+          "dot11n_ps": false,
+          "dot11n_sgi20": true,
+          "dot11n_sgi40": true,
+          "dot11n_tx_stbc": false,
+          "dot11n_rx_stbc": false
+        },
+        "dot11ac": {
+          "dot11ac_160": false,
+          "dot11ac_8080": false,
+          "dot11ac_mpdu_max": 17677,
+          "dot11ac_sgi80": false,
+          "dot11ac_sgi160": false,
+          "dot11ac_rx_ldpc": false,
+          "dot11ac_tx_stbc": false,
+          "dot11ac_rx_stbc_1ss": false,
+          "dot11ac_rx_stbc_2ss": false,
+          "dot11ac_rx_stbc_3ss": false,
+          "dot11ac_rx_stbc_4ss": false,
+          "dot11ac_su_beamformer": false,
+          "dot11ac_su_beamformee": true,
+          "dot11ac_mu_beamformer": true,
+          "dot11ac_mu_beamformee": false
+        }
+      },
+      "stats": {
+        "tx_total_pkts": 51507224,
+        "tx_total_bytes": 33042446,
+        "tx_failures": 52189830,
+        "tx_pkts_retries": 80860394,
+        "rx_data_pkts": 31736684,
+        "rx_data_bytes": 59698555,
+        "rx_failures": 42673662,
+        "rate_of_last_tx_pkt": 86670792,
+        "rate_of_last_rx_pkt": 81522287
+      },
+      "rssi_per_antenna": [-110, -101, -83]
+    },
+    {
+      "macaddr": "27:71:6d:C0:C6:c8",
+      "wdev": "sit ",
+      "frequency": "2GHz",
+      "rssi": -115,
+      "snr": 3,
+      "idle": 49139566,
+      "in_network": 93630997,
+      "tx_airtime": 25,
+      "rx_airtime": 22,
+      "airtime": 45,
+      "max_rate": 36462522,
+      "status": { "wmm": true, "ps": false },
+      "capabilities": {
+        "wmm": false,
+        "apsd": false,
+        "shortslot": false,
+        "dot11h": true,
+        "2040coex": false,
+        "psmp": true,
+        "proxy_arp": true,
+        "dot11v_btm": false,
+        "dot11k": {
+          "dot11k_link_meas": true,
+          "dot11k_nbr_report": true,
+          "dot11k_bcn_passive": true,
+          "dot11k_bcn_active": true,
+          "dot11k_bcn_table": true,
+          "dot11k_rcpi": false,
+          "dot11k_rsni": false
+        },
+        "dot11n": {
+          "dot11n_ldpc": false,
+          "dot11n_40": true,
+          "dot11n_ps": true,
+          "dot11n_sgi20": true,
+          "dot11n_sgi40": true,
+          "dot11n_tx_stbc": false,
+          "dot11n_rx_stbc": false
+        },
+        "dot11ac": {
+          "dot11ac_160": true,
+          "dot11ac_8080": false,
+          "dot11ac_mpdu_max": 54602,
+          "dot11ac_sgi80": true,
+          "dot11ac_sgi160": false,
+          "dot11ac_rx_ldpc": true,
+          "dot11ac_tx_stbc": false,
+          "dot11ac_rx_stbc_1ss": false,
+          "dot11ac_rx_stbc_2ss": true,
+          "dot11ac_rx_stbc_3ss": false,
+          "dot11ac_rx_stbc_4ss": false,
+          "dot11ac_su_beamformer": true,
+          "dot11ac_su_beamformee": false,
+          "dot11ac_mu_beamformer": true,
+          "dot11ac_mu_beamformee": true
+        }
+      },
+      "stats": {
+        "tx_total_pkts": 22048245,
+        "tx_total_bytes": 32320728,
+        "tx_failures": 9765756,
+        "tx_pkts_retries": 11753890,
+        "rx_data_pkts": 96434769,
+        "rx_data_bytes": 75447112,
+        "rx_failures": 16276172,
+        "rate_of_last_tx_pkt": 16186367,
+        "rate_of_last_rx_pkt": 82849152
+      },
+      "rssi_per_antenna": [-69, -43, -11]
+    },
+    {
+      "macaddr": "bB:C8:2B:D4:4c:bF",
+      "wdev": "s",
+      "frequency": "2GHz",
+      "rssi": -30,
+      "snr": 46,
+      "idle": 92358887,
+      "in_network": 24006299,
+      "tx_airtime": 48,
+      "rx_airtime": 78,
+      "airtime": 3,
+      "max_rate": 51661001,
+      "status": { "wmm": true, "ps": true },
+      "capabilities": {
+        "wmm": true,
+        "apsd": true,
+        "shortslot": true,
+        "dot11h": false,
+        "2040coex": true,
+        "psmp": true,
+        "proxy_arp": false,
+        "dot11v_btm": false,
+        "dot11k": {
+          "dot11k_link_meas": true,
+          "dot11k_nbr_report": false,
+          "dot11k_bcn_passive": true,
+          "dot11k_bcn_active": true,
+          "dot11k_bcn_table": false,
+          "dot11k_rcpi": false,
+          "dot11k_rsni": false
+        },
+        "dot11n": {
+          "dot11n_ldpc": false,
+          "dot11n_40": true,
+          "dot11n_ps": false,
+          "dot11n_sgi20": false,
+          "dot11n_sgi40": true,
+          "dot11n_tx_stbc": false,
+          "dot11n_rx_stbc": true
+        },
+        "dot11ac": {
+          "dot11ac_160": false,
+          "dot11ac_8080": false,
+          "dot11ac_mpdu_max": 64314,
+          "dot11ac_sgi80": true,
+          "dot11ac_sgi160": false,
+          "dot11ac_rx_ldpc": true,
+          "dot11ac_tx_stbc": true,
+          "dot11ac_rx_stbc_1ss": true,
+          "dot11ac_rx_stbc_2ss": true,
+          "dot11ac_rx_stbc_3ss": false,
+          "dot11ac_rx_stbc_4ss": true,
+          "dot11ac_su_beamformer": true,
+          "dot11ac_su_beamformee": true,
+          "dot11ac_mu_beamformer": true,
+          "dot11ac_mu_beamformee": false
+        }
+      },
+      "stats": {
+        "tx_total_pkts": 32983808,
+        "tx_total_bytes": 3978506,
+        "tx_failures": 57206696,
+        "tx_pkts_retries": 72123612,
+        "rx_data_pkts": 45529189,
+        "rx_data_bytes": 48658043,
+        "rx_failures": 12011487,
+        "rate_of_last_tx_pkt": 12424747,
+        "rate_of_last_rx_pkt": 82682244
+      },
+      "rssi_per_antenna": [-92, -16]
+    },
+    {
+      "macaddr": "c6:09:c5:A1:4E:5E",
+      "wdev": "reprehenderit",
+      "frequency": "2GHz",
+      "rssi": -73,
+      "snr": 91,
+      "idle": 19060476,
+      "in_network": 4933515,
+      "tx_airtime": 17,
+      "rx_airtime": 27,
+      "airtime": 82,
+      "max_rate": 60339022,
+      "status": { "wmm": false, "ps": true },
+      "capabilities": {
+        "wmm": true,
+        "apsd": false,
+        "shortslot": true,
+        "dot11h": false,
+        "2040coex": true,
+        "psmp": true,
+        "proxy_arp": true,
+        "dot11v_btm": false,
+        "dot11k": {
+          "dot11k_link_meas": false,
+          "dot11k_nbr_report": false,
+          "dot11k_bcn_passive": false,
+          "dot11k_bcn_active": true,
+          "dot11k_bcn_table": true,
+          "dot11k_rcpi": false,
+          "dot11k_rsni": true
+        },
+        "dot11n": {
+          "dot11n_ldpc": false,
+          "dot11n_40": true,
+          "dot11n_ps": false,
+          "dot11n_sgi20": false,
+          "dot11n_sgi40": false,
+          "dot11n_tx_stbc": false,
+          "dot11n_rx_stbc": true
+        },
+        "dot11ac": {
+          "dot11ac_160": false,
+          "dot11ac_8080": false,
+          "dot11ac_mpdu_max": 24826,
+          "dot11ac_sgi80": false,
+          "dot11ac_sgi160": false,
+          "dot11ac_rx_ldpc": true,
+          "dot11ac_tx_stbc": true,
+          "dot11ac_rx_stbc_1ss": false,
+          "dot11ac_rx_stbc_2ss": true,
+          "dot11ac_rx_stbc_3ss": false,
+          "dot11ac_rx_stbc_4ss": true,
+          "dot11ac_su_beamformer": false,
+          "dot11ac_su_beamformee": false,
+          "dot11ac_mu_beamformer": false,
+          "dot11ac_mu_beamformee": true
+        }
+      },
+      "stats": {
+        "tx_total_pkts": 40473172,
+        "tx_total_bytes": 16285086,
+        "tx_failures": 19423488,
+        "tx_pkts_retries": 17748565,
+        "rx_data_pkts": 3840175,
+        "rx_data_bytes": 84968530,
+        "rx_failures": 13879729,
+        "rate_of_last_tx_pkt": 29702903,
+        "rate_of_last_rx_pkt": 44996704
+      },
+      "rssi_per_antenna": [-6, -90]
+    }
+  ]
+}
+```
+
+## stats
+
+`stats`
+
+- type: `Method`
+
+### stats Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `input`  | object | Optional |
+| `output` | object | Optional |
+
+#### input
+
+`input`
+
+- is optional
+- type: `object`
+
+##### input Type
+
+`object` with following properties:
+
+| Property | Type | Required |
+| -------- | ---- | -------- |
+| None     | None | None     |
+
+### Ubus CLI Example
+
+```
+ubus call wifi.ap.<name> stats {}
+```
+
+### JSONRPC Example
+
+```json
+{ "jsonrpc": "2.0", "id": 0, "method": "call", "params": ["<SID>", "wifi.ap.<name>", "stats", {}] }
+```
+
+#### output
+
+`output`
+
+- is optional
+- type: `object`
+
+##### output Type
+
+`object` with following properties:
+
+| Property                  | Type    | Required     |
+| ------------------------- | ------- | ------------ |
+| `ack_fail_packets`        | integer | **Required** |
+| `aggregate_packets`       | integer | **Required** |
+| `rx_broadcast_packets`    | integer | **Required** |
+| `rx_bytes`                | integer | **Required** |
+| `rx_dropped_packets`      | integer | **Required** |
+| `rx_error_packets`        | integer | **Required** |
+| `rx_multicast_packets`    | integer | **Required** |
+| `rx_packets`              | integer | **Required** |
+| `rx_unicast_packets`      | integer | **Required** |
+| `rx_unknown_packets`      | integer | **Required** |
+| `tx_broadcast_packets`    | integer | **Required** |
+| `tx_bytes`                | integer | **Required** |
+| `tx_dropped_packets`      | integer | **Required** |
+| `tx_error_packets`        | integer | **Required** |
+| `tx_multi_retry_packets`  | integer | **Required** |
+| `tx_multicast_packets`    | integer | **Required** |
+| `tx_packets`              | integer | **Required** |
+| `tx_retrans_fail_packets` | integer | **Required** |
+| `tx_retrans_packets`      | integer | **Required** |
+| `tx_retry_packets`        | integer | **Required** |
+| `tx_unicast_packets`      | integer | **Required** |
+
+#### ack_fail_packets
+
+`ack_fail_packets`
+
+- is **required**
+- type: reference
+
+##### ack_fail_packets Type
+
+`integer`
+
+- minimum value: `0`
+
+#### aggregate_packets
+
+`aggregate_packets`
+
+- is **required**
+- type: reference
+
+##### aggregate_packets Type
+
+`integer`
+
+- minimum value: `0`
+
+#### rx_broadcast_packets
+
+`rx_broadcast_packets`
+
+- is **required**
+- type: reference
+
+##### rx_broadcast_packets Type
+
+`integer`
+
+- minimum value: `0`
+
+#### rx_bytes
+
+`rx_bytes`
+
+- is **required**
+- type: reference
+
+##### rx_bytes Type
+
+`integer`
+
+- minimum value: `0`
+
+#### rx_dropped_packets
+
+`rx_dropped_packets`
+
+- is **required**
+- type: reference
+
+##### rx_dropped_packets Type
+
+`integer`
+
+- minimum value: `0`
+
+#### rx_error_packets
+
+`rx_error_packets`
+
+- is **required**
+- type: reference
+
+##### rx_error_packets Type
+
+`integer`
+
+- minimum value: `0`
+
+#### rx_multicast_packets
+
+`rx_multicast_packets`
+
+- is **required**
+- type: reference
+
+##### rx_multicast_packets Type
+
+`integer`
+
+- minimum value: `0`
+
+#### rx_packets
+
+`rx_packets`
+
+- is **required**
+- type: reference
+
+##### rx_packets Type
+
+`integer`
+
+- minimum value: `0`
+
+#### rx_unicast_packets
+
+`rx_unicast_packets`
+
+- is **required**
+- type: reference
+
+##### rx_unicast_packets Type
+
+`integer`
+
+- minimum value: `0`
+
+#### rx_unknown_packets
+
+`rx_unknown_packets`
+
+- is **required**
+- type: reference
+
+##### rx_unknown_packets Type
+
+`integer`
+
+- minimum value: `0`
+
+#### tx_broadcast_packets
+
+`tx_broadcast_packets`
+
+- is **required**
+- type: reference
+
+##### tx_broadcast_packets Type
+
+`integer`
+
+- minimum value: `0`
+
+#### tx_bytes
+
+`tx_bytes`
+
+- is **required**
+- type: reference
+
+##### tx_bytes Type
+
+`integer`
+
+- minimum value: `0`
+
+#### tx_dropped_packets
+
+`tx_dropped_packets`
+
+- is **required**
+- type: reference
+
+##### tx_dropped_packets Type
+
+`integer`
+
+- minimum value: `0`
+
+#### tx_error_packets
+
+`tx_error_packets`
+
+- is **required**
+- type: reference
+
+##### tx_error_packets Type
+
+`integer`
+
+- minimum value: `0`
+
+#### tx_multi_retry_packets
+
+`tx_multi_retry_packets`
+
+- is **required**
+- type: reference
+
+##### tx_multi_retry_packets Type
+
+`integer`
+
+- minimum value: `0`
+
+#### tx_multicast_packets
+
+`tx_multicast_packets`
+
+- is **required**
+- type: reference
+
+##### tx_multicast_packets Type
+
+`integer`
+
+- minimum value: `0`
+
+#### tx_packets
+
+`tx_packets`
+
+- is **required**
+- type: reference
+
+##### tx_packets Type
+
+`integer`
+
+- minimum value: `0`
+
+#### tx_retrans_fail_packets
+
+`tx_retrans_fail_packets`
+
+- is **required**
+- type: reference
+
+##### tx_retrans_fail_packets Type
+
+`integer`
+
+- minimum value: `0`
+
+#### tx_retrans_packets
+
+`tx_retrans_packets`
+
+- is **required**
+- type: reference
+
+##### tx_retrans_packets Type
+
+`integer`
+
+- minimum value: `0`
+
+#### tx_retry_packets
+
+`tx_retry_packets`
+
+- is **required**
+- type: reference
+
+##### tx_retry_packets Type
+
+`integer`
+
+- minimum value: `0`
+
+#### tx_unicast_packets
+
+`tx_unicast_packets`
+
+- is **required**
+- type: reference
+
+##### tx_unicast_packets Type
+
+`integer`
+
+- minimum value: `0`
+
+### Output Example
+
+```json
+{
+  "tx_bytes": 45898068,
+  "tx_packets": 22299868,
+  "tx_unicast_packets": 68790704,
+  "tx_multicast_packets": 21953717,
+  "tx_broadcast_packets": 51292406,
+  "tx_error_packets": 58416828,
+  "tx_retrans_packets": 62808550,
+  "tx_retrans_fail_packets": 54601227,
+  "tx_retry_packets": 6510836,
+  "tx_multi_retry_packets": 72654188,
+  "tx_dropped_packets": 46052254,
+  "ack_fail_packets": 87486133,
+  "aggregate_packets": 43478535,
+  "rx_bytes": 16018837,
+  "rx_packets": 9027848,
+  "rx_unicast_packets": 6370715,
+  "rx_multicast_packets": 58632,
+  "rx_broadcast_packets": 93325534,
+  "rx_error_packets": 57998201,
+  "rx_dropped_packets": 86018793,
+  "rx_unknown_packets": 49274524
+}
+```
+
+## status
+
+`status`
+
+- type: `Method`
+
+### status Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `input`  | object | Optional |
+| `output` | object | Optional |
+
+#### input
+
+`input`
+
+- is optional
+- type: `object`
+
+##### input Type
+
+`object` with following properties:
+
+| Property | Type | Required |
+| -------- | ---- | -------- |
+| None     | None | None     |
+
+### Ubus CLI Example
+
+```
+ubus call wifi.ap.<name> status {}
+```
+
+### JSONRPC Example
+
+```json
+{ "jsonrpc": "2.0", "id": 0, "method": "call", "params": ["<SID>", "wifi.ap.<name>", "status", {}] }
+```
+
+#### output
+
+`output`
+
+- is optional
+- type: `object`
+
+##### output Type
+
+`object` with following properties:
+
+| Property       | Type    | Required     |
+| -------------- | ------- | ------------ |
+| `adm_capacity` | integer | **Required** |
+| `bandwidth`    | oneOf   | **Required** |
+| `bssid`        | string  | **Required** |
+| `capabilities` | object  | **Required** |
+| `encryption`   | string  | **Required** |
+| `hidden`       | boolean | **Required** |
+| `ifname`       | string  | **Required** |
+| `max_stations` | integer | **Required** |
+| `num_stations` | integer | **Required** |
+| `ssid`         | string  | **Required** |
+| `standard`     | string  | **Required** |
+| `status`       | string  | **Required** |
+| `utilization`  | integer | **Required** |
+
+#### adm_capacity
+
+`adm_capacity`
+
+- is **required**
+- type: `integer`
+
+##### adm_capacity Type
+
+`integer`
+
+#### bandwidth
+
+`bandwidth`
+
+- is **required**
+- type: complex
+
+##### bandwidth Type
+
+**One** of the following _conditions_ need to be fulfilled.
+
+#### Condition 1
+
+`integer`
+
+#### Condition 2
+
+`integer`
+
+#### bssid
+
+##### MAC Address
+
+`bssid`
+
+- is **required**
+- type: reference
+
+##### bssid Type
+
+`string`
+
+- minimum length: 17 characters
+- maximum length: 17 characters All instances must conform to this regular expression (test examples
+  [here](<https://regexr.com/?expression=%5E(%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D%3A)%7B5%7D%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D%24>)):
+
+```regex
+^([0-9a-fA-F][0-9a-fA-F]:){5}[0-9a-fA-F][0-9a-fA-F]$
+```
+
+#### capabilities
+
+`capabilities`
+
+- is **required**
+- type: `object`
+
+##### capabilities Type
+
+`object` with following properties:
+
+| Property    | Type    | Required     |
+| ----------- | ------- | ------------ |
+| `apsd`      | boolean | **Required** |
+| `dot11ac`   | object  | Optional     |
+| `dot11h`    | boolean | **Required** |
+| `dot11k`    | object  | Optional     |
+| `dot11n`    | object  | Optional     |
+| `shortslot` | boolean | **Required** |
+| `wmm`       | boolean | **Required** |
+
+#### apsd
+
+`apsd`
+
+- is **required**
+- type: `boolean`
+
+##### apsd Type
+
+`boolean`
+
+#### dot11ac
+
+`dot11ac`
+
+- is optional
+- type: `object`
+
+##### dot11ac Type
+
+`object` with following properties:
+
+| Property                | Type    | Required     |
+| ----------------------- | ------- | ------------ |
+| `dot11ac_160`           | boolean | **Required** |
+| `dot11ac_8080`          | boolean | **Required** |
+| `dot11ac_mpdu_max`      | integer | **Required** |
+| `dot11ac_mu_beamformee` | boolean | **Required** |
+| `dot11ac_mu_beamformer` | boolean | **Required** |
+| `dot11ac_rx_ldpc`       | boolean | **Required** |
+| `dot11ac_rx_stbc_1ss`   | boolean | **Required** |
+| `dot11ac_rx_stbc_2ss`   | boolean | **Required** |
+| `dot11ac_rx_stbc_3ss`   | boolean | **Required** |
+| `dot11ac_rx_stbc_4ss`   | boolean | **Required** |
+| `dot11ac_sgi160`        | boolean | **Required** |
+| `dot11ac_sgi80`         | boolean | **Required** |
+| `dot11ac_su_beamformee` | boolean | **Required** |
+| `dot11ac_su_beamformer` | boolean | **Required** |
+| `dot11ac_tx_stbc`       | boolean | **Required** |
+
+#### dot11ac_160
+
+`dot11ac_160`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_160 Type
+
+`boolean`
+
+#### dot11ac_8080
+
+`dot11ac_8080`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_8080 Type
+
+`boolean`
+
+#### dot11ac_mpdu_max
+
+`dot11ac_mpdu_max`
+
+- is **required**
+- type: `integer`
+
+##### dot11ac_mpdu_max Type
+
+`integer`
+
+- minimum value: `0`
+- maximum value: `65535`
+
+#### dot11ac_mu_beamformee
+
+`dot11ac_mu_beamformee`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_mu_beamformee Type
+
+`boolean`
+
+#### dot11ac_mu_beamformer
+
+`dot11ac_mu_beamformer`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_mu_beamformer Type
+
+`boolean`
+
+#### dot11ac_rx_ldpc
+
+`dot11ac_rx_ldpc`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_rx_ldpc Type
+
+`boolean`
+
+#### dot11ac_rx_stbc_1ss
+
+`dot11ac_rx_stbc_1ss`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_rx_stbc_1ss Type
+
+`boolean`
+
+#### dot11ac_rx_stbc_2ss
+
+`dot11ac_rx_stbc_2ss`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_rx_stbc_2ss Type
+
+`boolean`
+
+#### dot11ac_rx_stbc_3ss
+
+`dot11ac_rx_stbc_3ss`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_rx_stbc_3ss Type
+
+`boolean`
+
+#### dot11ac_rx_stbc_4ss
+
+`dot11ac_rx_stbc_4ss`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_rx_stbc_4ss Type
+
+`boolean`
+
+#### dot11ac_sgi160
+
+`dot11ac_sgi160`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_sgi160 Type
+
+`boolean`
+
+#### dot11ac_sgi80
+
+`dot11ac_sgi80`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_sgi80 Type
+
+`boolean`
+
+#### dot11ac_su_beamformee
+
+`dot11ac_su_beamformee`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_su_beamformee Type
+
+`boolean`
+
+#### dot11ac_su_beamformer
+
+`dot11ac_su_beamformer`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_su_beamformer Type
+
+`boolean`
+
+#### dot11ac_tx_stbc
+
+`dot11ac_tx_stbc`
+
+- is **required**
+- type: `boolean`
+
+##### dot11ac_tx_stbc Type
+
+`boolean`
+
+#### dot11h
+
+`dot11h`
+
+- is **required**
+- type: `boolean`
+
+##### dot11h Type
+
+`boolean`
+
+#### dot11k
+
+`dot11k`
+
+- is optional
+- type: `object`
+
+##### dot11k Type
+
+`object` with following properties:
+
+| Property             | Type    | Required     |
+| -------------------- | ------- | ------------ |
+| `dot11k_bcn_active`  | boolean | **Required** |
+| `dot11k_bcn_passive` | boolean | **Required** |
+| `dot11k_bcn_table`   | boolean | **Required** |
+| `dot11k_link_meas`   | boolean | **Required** |
+| `dot11k_nbr_report`  | boolean | **Required** |
+| `dot11k_rcpi`        | boolean | **Required** |
+| `dot11k_rsni`        | boolean | **Required** |
+
+#### dot11k_bcn_active
+
+`dot11k_bcn_active`
+
+- is **required**
+- type: `boolean`
+
+##### dot11k_bcn_active Type
+
+`boolean`
+
+#### dot11k_bcn_passive
+
+`dot11k_bcn_passive`
+
+- is **required**
+- type: `boolean`
+
+##### dot11k_bcn_passive Type
+
+`boolean`
+
+#### dot11k_bcn_table
+
+`dot11k_bcn_table`
+
+- is **required**
+- type: `boolean`
+
+##### dot11k_bcn_table Type
+
+`boolean`
+
+#### dot11k_link_meas
+
+`dot11k_link_meas`
+
+- is **required**
+- type: `boolean`
+
+##### dot11k_link_meas Type
+
+`boolean`
+
+#### dot11k_nbr_report
+
+`dot11k_nbr_report`
+
+- is **required**
+- type: `boolean`
+
+##### dot11k_nbr_report Type
+
+`boolean`
+
+#### dot11k_rcpi
+
+`dot11k_rcpi`
+
+- is **required**
+- type: `boolean`
+
+##### dot11k_rcpi Type
+
+`boolean`
+
+#### dot11k_rsni
+
+`dot11k_rsni`
+
+- is **required**
+- type: `boolean`
+
+##### dot11k_rsni Type
+
+`boolean`
+
+#### dot11n
+
+`dot11n`
+
+- is optional
+- type: `object`
+
+##### dot11n Type
+
+`object` with following properties:
+
+| Property         | Type    | Required     |
+| ---------------- | ------- | ------------ |
+| `dot11n_40`      | boolean | **Required** |
+| `dot11n_ldpc`    | boolean | **Required** |
+| `dot11n_ps`      | boolean | **Required** |
+| `dot11n_rx_stbc` | boolean | **Required** |
+| `dot11n_sgi20`   | boolean | **Required** |
+| `dot11n_sgi40`   | boolean | **Required** |
+| `dot11n_tx_stbc` | boolean | **Required** |
+
+#### dot11n_40
+
+`dot11n_40`
+
+- is **required**
+- type: `boolean`
+
+##### dot11n_40 Type
+
+`boolean`
+
+#### dot11n_ldpc
+
+`dot11n_ldpc`
+
+- is **required**
+- type: `boolean`
+
+##### dot11n_ldpc Type
+
+`boolean`
+
+#### dot11n_ps
+
+`dot11n_ps`
+
+- is **required**
+- type: `boolean`
+
+##### dot11n_ps Type
+
+`boolean`
+
+#### dot11n_rx_stbc
+
+`dot11n_rx_stbc`
+
+- is **required**
+- type: `boolean`
+
+##### dot11n_rx_stbc Type
+
+`boolean`
+
+#### dot11n_sgi20
+
+`dot11n_sgi20`
+
+- is **required**
+- type: `boolean`
+
+##### dot11n_sgi20 Type
+
+`boolean`
+
+#### dot11n_sgi40
+
+`dot11n_sgi40`
+
+- is **required**
+- type: `boolean`
+
+##### dot11n_sgi40 Type
+
+`boolean`
+
+#### dot11n_tx_stbc
+
+`dot11n_tx_stbc`
+
+- is **required**
+- type: `boolean`
+
+##### dot11n_tx_stbc Type
+
+`boolean`
+
+#### shortslot
+
+`shortslot`
+
+- is **required**
+- type: `boolean`
+
+##### shortslot Type
+
+`boolean`
+
+#### wmm
+
+`wmm`
+
+- is **required**
+- type: `boolean`
+
+##### wmm Type
+
+`boolean`
+
+#### encryption
+
+`encryption`
+
+- is **required**
+- type: `string`
+
+##### encryption Type
+
+`string`
+
+#### hidden
+
+`hidden`
+
+- is **required**
+- type: `boolean`
+
+##### hidden Type
+
+`boolean`
+
+#### ifname
+
+##### Interface
+
+`ifname`
+
+- is **required**
+- type: reference
+
+##### ifname Type
+
+`string`
+
+- minimum length: 1 characters
+- maximum length: 16 characters
+
+#### max_stations
+
+##### Number of stations
+
+`max_stations`
+
+- is **required**
+- type: reference
+
+##### max_stations Type
+
+`integer`
+
+- minimum value: `0`
+- maximum value: `2007`
+
+#### num_stations
+
+##### Number of stations
+
+`num_stations`
+
+- is **required**
+- type: reference
+
+##### num_stations Type
+
+`integer`
+
+- minimum value: `0`
+- maximum value: `2007`
+
+#### ssid
+
+##### SSID
+
+`ssid`
+
+- is **required**
+- type: reference
+
+##### ssid Type
+
+`string`
+
+- maximum length: 32 characters
+
+#### standard
+
+`standard`
+
+- is **required**
+- type: `string`
+
+##### standard Type
+
+`string`
+
+#### status
+
+`status`
+
+- is **required**
+- type: `string`
+
+##### status Type
+
+`string`
+
+#### utilization
+
+`utilization`
+
+- is **required**
+- type: `integer`
+
+##### utilization Type
+
+`integer`
+
+- minimum value: `0`
+- maximum value: `100`
+
+### Output Example
+
+```json
+{
+  "ifname": "nostrud ",
+  "status": "cillum culpa ut voluptate fugiat",
+  "ssid": "dolore aute consequ",
+  "bssid": "8B:d9:Cb:bD:7e:5b",
+  "encryption": "proident",
+  "bandwidth": 20,
+  "standard": "culpa officia commodo",
+  "num_stations": 70,
+  "utilization": 61,
+  "adm_capacity": 87791482,
+  "hidden": false,
+  "max_stations": 125,
+  "capabilities": {
+    "wmm": true,
+    "apsd": true,
+    "shortslot": false,
+    "dot11h": false,
+    "dot11k": {
+      "dot11k_link_meas": true,
+      "dot11k_nbr_report": false,
+      "dot11k_bcn_passive": true,
+      "dot11k_bcn_active": false,
+      "dot11k_bcn_table": false,
+      "dot11k_rcpi": true,
+      "dot11k_rsni": false
+    },
+    "dot11n": {
+      "dot11n_ldpc": false,
+      "dot11n_40": false,
+      "dot11n_ps": false,
+      "dot11n_sgi20": false,
+      "dot11n_sgi40": true,
+      "dot11n_tx_stbc": true,
+      "dot11n_rx_stbc": true
+    },
+    "dot11ac": {
+      "dot11ac_160": false,
+      "dot11ac_8080": true,
+      "dot11ac_mpdu_max": 36284,
+      "dot11ac_sgi80": false,
+      "dot11ac_sgi160": false,
+      "dot11ac_rx_ldpc": true,
+      "dot11ac_tx_stbc": false,
+      "dot11ac_rx_stbc_1ss": false,
+      "dot11ac_rx_stbc_2ss": true,
+      "dot11ac_rx_stbc_3ss": false,
+      "dot11ac_rx_stbc_4ss": true,
+      "dot11ac_su_beamformer": true,
+      "dot11ac_su_beamformee": false,
+      "dot11ac_mu_beamformer": false,
+      "dot11ac_mu_beamformee": true
+    }
+  }
+}
+```
diff --git a/docs/api/wifi.md b/docs/api/wifi.md
new file mode 100644
index 0000000000000000000000000000000000000000..130d7f010378b33af7b9a807ec62e5844c27447e
--- /dev/null
+++ b/docs/api/wifi.md
@@ -0,0 +1,569 @@
+# wifi Schema
+
+```
+https://www.iopsys.eu/wifi.json
+```
+
+| Custom Properties | Additional Properties |
+| ----------------- | --------------------- |
+| Forbidden         | Forbidden             |
+
+# wifi
+
+| List of Methods   |
+| ----------------- |
+| [status](#status) | Method | wifi (this schema) |
+
+## status
+
+`status`
+
+- type: `Method`
+
+### status Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `input`  | object | Optional |
+| `output` | object | Optional |
+
+#### input
+
+`input`
+
+- is optional
+- type: `object`
+
+##### input Type
+
+`object` with following properties:
+
+| Property | Type | Required |
+| -------- | ---- | -------- |
+| None     | None | None     |
+
+### Ubus CLI Example
+
+```
+ubus call wifi status {}
+```
+
+### JSONRPC Example
+
+```json
+{ "jsonrpc": "2.0", "id": 0, "method": "call", "params": ["<SID>", "wifi", "status", {}] }
+```
+
+#### output
+
+`output`
+
+- is optional
+- type: `object`
+
+##### output Type
+
+`object` with following properties:
+
+| Property | Type  | Required     |
+| -------- | ----- | ------------ |
+| `radios` | array | **Required** |
+
+#### radios
+
+`radios`
+
+- is **required**
+- type: `object[]`
+
+##### radios Type
+
+Array type: `object[]`
+
+All items must be of the type: `object` with following properties:
+
+| Property       | Type    | Required     |
+| -------------- | ------- | ------------ |
+| `accesspoints` | array   | **Required** |
+| `backhauls`    | array   | **Required** |
+| `band`         | string  | **Required** |
+| `bandwidth`    | integer | **Required** |
+| `country`      | string  | **Required** |
+| `isup`         | boolean | **Required** |
+| `name`         | string  | **Required** |
+| `noise`        | integer | **Required** |
+| `rate`         | integer | **Required** |
+| `standard`     | string  | **Required** |
+
+#### accesspoints
+
+`accesspoints`
+
+- is **required**
+- type: reference
+
+##### accesspoints Type
+
+Array type: reference
+
+All items must be of the type: `object` with following properties:
+
+| Property | Type   | Required     |
+| -------- | ------ | ------------ |
+| `bssid`  |        | **Required** |
+| `ifname` | string | **Required** |
+| `ssid`   | string | **Required** |
+| `status` | string | **Required** |
+
+#### bssid
+
+`bssid`
+
+- is **required**
+- type: complex
+
+##### bssid Type
+
+Unknown type ``.
+
+```json
+{
+  "bssid": {
+    "$ref": "#/definitions/macaddr_t"
+  },
+  "simpletype": "complex"
+}
+```
+
+#### ifname
+
+`ifname`
+
+- is **required**
+- type: `string`
+
+##### ifname Type
+
+`string`
+
+- minimum length: 1 characters
+- maximum length: 16 characters
+
+#### ssid
+
+`ssid`
+
+- is **required**
+- type: `string`
+
+##### ssid Type
+
+`string`
+
+- maximum length: 32 characters
+
+#### status
+
+`status`
+
+- is **required**
+- type: `string`
+
+##### status Type
+
+`string`
+
+#### backhauls
+
+`backhauls`
+
+- is **required**
+- type: reference
+
+##### backhauls Type
+
+Array type: reference
+
+All items must be of the type: `object` with following properties:
+
+| Property | Type   | Required     |
+| -------- | ------ | ------------ |
+| `bssid`  |        | **Required** |
+| `ifname` | string | **Required** |
+| `ssid`   | string | **Required** |
+| `status` | string | **Required** |
+
+#### bssid
+
+`bssid`
+
+- is **required**
+- type: complex
+
+##### bssid Type
+
+Unknown type ``.
+
+```json
+{
+  "bssid": {
+    "$ref": "#/definitions/macaddr_t"
+  },
+  "simpletype": "complex"
+}
+```
+
+#### ifname
+
+`ifname`
+
+- is **required**
+- type: `string`
+
+##### ifname Type
+
+`string`
+
+- minimum length: 1 characters
+- maximum length: 16 characters
+
+#### ssid
+
+`ssid`
+
+- is **required**
+- type: `string`
+
+##### ssid Type
+
+`string`
+
+- maximum length: 32 characters
+
+#### status
+
+`status`
+
+- is **required**
+- type: `string`
+
+##### status Type
+
+`string`
+
+#### band
+
+##### WiFi Band
+
+`band`
+
+- is **required**
+- type: reference
+
+##### band Type
+
+`string`
+
+The value of this property **must** be equal to one of the [known values below](#status-known-values).
+
+##### band Known Values
+
+| Value |
+| ----- |
+| 2GHz  |
+| 5GHz  |
+
+#### bandwidth
+
+##### Bandwidth
+
+`bandwidth`
+
+- is **required**
+- type: reference
+
+##### bandwidth Type
+
+`integer`
+
+The value of this property **must** be equal to one of the [known values below](#status-known-values).
+
+##### bandwidth Known Values
+
+| Value |
+| ----- |
+| 20    |
+| 40    |
+| 80    |
+| 160   |
+
+#### country
+
+`country`
+
+- is **required**
+- type: `string`
+
+##### country Type
+
+`string`
+
+- minimum length: 2 characters
+- maximum length: 3 characters
+
+#### isup
+
+`isup`
+
+- is **required**
+- type: `boolean`
+
+##### isup Type
+
+`boolean`
+
+#### name
+
+##### Interface
+
+`name`
+
+- is **required**
+- type: reference
+
+##### name Type
+
+`string`
+
+- minimum length: 1 characters
+- maximum length: 16 characters
+
+#### noise
+
+##### Noise
+
+`noise`
+
+- is **required**
+- type: reference
+
+##### noise Type
+
+`integer`
+
+- minimum value: `-127`
+- maximum value: `0`
+
+#### rate
+
+`rate`
+
+- is **required**
+- type: `integer`
+
+##### rate Type
+
+`integer`
+
+- minimum value: `0`
+
+#### standard
+
+`standard`
+
+- is **required**
+- type: `string`
+
+##### standard Type
+
+`string`
+
+### Output Example
+
+```json
+{
+  "radios": [
+    {
+      "name": "voluptate rep",
+      "isup": false,
+      "standard": "sunt aliqua dolore laboris officia",
+      "country": "qui",
+      "band": "5GHz",
+      "bandwidth": 160,
+      "noise": -93,
+      "rate": 52420370,
+      "accesspoints": [
+        { "ifname": "culpa", "status": "esse", "ssid": "Lorem id magna", "bssid": { "bssid": "45:F6:98:d8:E2:dc" } },
+        {
+          "ifname": "adipisicing",
+          "status": "est id et ut irure",
+          "ssid": "minim sit mollit",
+          "bssid": { "bssid": "E9:eE:06:be:13:65" }
+        },
+        {
+          "ifname": "sit dolo",
+          "status": "laboris nulla qui",
+          "ssid": "officia commodo",
+          "bssid": { "bssid": "2D:F0:4F:EA:0D:eb" }
+        },
+        {
+          "ifname": "nostru",
+          "status": "officia dolor ea dolore occaecat",
+          "ssid": "qui sit ",
+          "bssid": { "bssid": "58:c8:97:d1:d1:9C" }
+        },
+        { "ifname": "es", "status": "ut sint ipsum Duis ex", "ssid": "ex ", "bssid": { "bssid": "63:Bc:eF:3d:c3:9d" } }
+      ],
+      "backhauls": [
+        {
+          "ifname": "labo",
+          "status": "nostrud ex amet",
+          "ssid": "dolore in eu",
+          "bssid": { "bssid": "5e:43:a7:9f:6c:01" }
+        },
+        {
+          "ifname": "id aliquip",
+          "status": "esse",
+          "ssid": "dolor consectetur",
+          "bssid": { "bssid": "ce:FA:92:fe:df:b4" }
+        },
+        {
+          "ifname": "i",
+          "status": "dolore mollit commodo",
+          "ssid": "minim",
+          "bssid": { "bssid": "Cf:aC:0A:Ed:b3:A6" }
+        },
+        {
+          "ifname": "inci",
+          "status": "consectetur id pariatur",
+          "ssid": "sed",
+          "bssid": { "bssid": "d8:aa:D5:23:eC:FD" }
+        },
+        { "ifname": "nisi", "status": "voluptate fugiat", "ssid": "sunt ", "bssid": { "bssid": "DB:B1:Fe:50:Cb:Eb" } }
+      ],
+      "channel": 24753590,
+      "channels": "ad minim eiusmod"
+    },
+    {
+      "name": "occaecat",
+      "isup": false,
+      "standard": "labore in dolor ad",
+      "country": "ni",
+      "band": "2GHz",
+      "bandwidth": 80,
+      "noise": -106,
+      "rate": 30910391,
+      "accesspoints": [
+        {
+          "ifname": "si",
+          "status": "aute occaecat laboris ut aliqua",
+          "ssid": "incididunt",
+          "bssid": { "bssid": "69:68:c5:6c:22:DA" }
+        },
+        {
+          "ifname": "fugiat ",
+          "status": "Lorem reprehenderit",
+          "ssid": "dolore min",
+          "bssid": { "bssid": "88:8f:87:F9:0C:B7" }
+        }
+      ],
+      "backhauls": [
+        {
+          "ifname": "nisi magna ",
+          "status": "officia in sed Lorem",
+          "ssid": "sit dolore ",
+          "bssid": { "bssid": "9f:F0:aD:3c:BF:af" }
+        },
+        { "ifname": "laborum", "status": "mollit", "ssid": "fugiat", "bssid": { "bssid": "D0:Ba:C5:83:D8:be" } }
+      ],
+      "channel": -99539458.64552729,
+      "channels": -53586837
+    },
+    {
+      "name": "dolore qu",
+      "isup": false,
+      "standard": "ut commodo",
+      "country": "pr",
+      "band": "2GHz",
+      "bandwidth": 20,
+      "noise": -87,
+      "rate": 59230503,
+      "accesspoints": [
+        {
+          "ifname": "cillum d",
+          "status": "sit occaecat dolor",
+          "ssid": "dolor",
+          "bssid": { "bssid": "De:5b:52:b1:ba:5a" }
+        },
+        { "ifname": "paria", "status": "magna ex", "ssid": "cupidatat ", "bssid": { "bssid": "BA:De:8B:fF:Fc:fC" } }
+      ],
+      "backhauls": [
+        {
+          "ifname": "Lorem ut Ut ",
+          "status": "ut cupidatat dolor in consequat",
+          "ssid": "ad nostrud commodo in in",
+          "bssid": { "bssid": "bA:21:C0:F4:d1:E7" }
+        }
+      ],
+      "channel": "dolor do minim",
+      "channels": 96257304.49025026
+    },
+    {
+      "name": "in ut",
+      "isup": false,
+      "standard": "et enim in",
+      "country": "vol",
+      "band": "5GHz",
+      "bandwidth": 80,
+      "noise": -90,
+      "rate": 66907094,
+      "accesspoints": [
+        {
+          "ifname": "reprehenderi",
+          "status": "commodo ex qui nostrud",
+          "ssid": "",
+          "bssid": { "bssid": "2E:cA:0b:ff:a3:3D" }
+        },
+        {
+          "ifname": "aute Exce",
+          "status": "cillum dolor",
+          "ssid": "Ut pariatur sun",
+          "bssid": { "bssid": "FD:06:B5:9c:Ea:39" }
+        },
+        {
+          "ifname": "officia con",
+          "status": "sint ullamco in nulla consequat",
+          "ssid": "dolor dol",
+          "bssid": { "bssid": "F0:2d:54:D2:b9:FE" }
+        }
+      ],
+      "backhauls": [
+        {
+          "ifname": "est deserunt",
+          "status": "tempor dolor dolor",
+          "ssid": "Duis laborum",
+          "bssid": { "bssid": "a1:Cb:F8:5f:F0:f4" }
+        },
+        {
+          "ifname": "mo",
+          "status": "dolor amet esse veniam",
+          "ssid": "cupidatat",
+          "bssid": { "bssid": "fa:9F:9a:C4:a2:cF" }
+        },
+        { "ifname": "d", "status": "", "ssid": "c", "bssid": { "bssid": "bc:88:7b:ab:cD:27" } },
+        { "ifname": "consequ", "status": "Duis", "ssid": "cupidatat", "bssid": { "bssid": "3A:FF:A7:BA:9A:dc" } },
+        {
+          "ifname": "dolo",
+          "status": "Lorem quis in aliqua occaecat",
+          "ssid": "q",
+          "bssid": { "bssid": "8D:6e:f7:fd:8C:e6" }
+        }
+      ],
+      "channel": "do ea sit labore est",
+      "channels": -76131712.30140434
+    }
+  ]
+}
+```
diff --git a/docs/api/wifi.radio.md b/docs/api/wifi.radio.md
new file mode 100644
index 0000000000000000000000000000000000000000..2018568dac00d78409d78d01f43bf90981aec098
--- /dev/null
+++ b/docs/api/wifi.radio.md
@@ -0,0 +1,937 @@
+# wifi.radio.&lt;name&gt; Schema
+
+```
+https://www.iopsys.eu/wifi.radio.json
+```
+
+WiFi Radio Object
+
+| Custom Properties | Additional Properties |
+| ----------------- | --------------------- |
+| Forbidden         | Forbidden             |
+
+# wifi.radio.&lt;name&gt;
+
+| List of Methods             |
+| --------------------------- |
+| [autochannel](#autochannel) | Method | wifi.radio.&lt;name&gt; (this schema) |
+| [get](#get)                 | Method | wifi.radio.&lt;name&gt; (this schema) |
+| [scan](#scan)               | Method | wifi.radio.&lt;name&gt; (this schema) |
+| [scanresults](#scanresults) | Method | wifi.radio.&lt;name&gt; (this schema) |
+| [stats](#stats)             | Method | wifi.radio.&lt;name&gt; (this schema) |
+| [status](#status)           | Method | wifi.radio.&lt;name&gt; (this schema) |
+
+## autochannel
+
+`autochannel`
+
+- type: `Method`
+
+### autochannel Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `input`  | object | Optional |
+| `output` | object | Optional |
+
+#### input
+
+`input`
+
+- is optional
+- type: `object`
+
+##### input Type
+
+`object` with following properties:
+
+| Property   | Type    | Required |
+| ---------- | ------- | -------- |
+| `algo`     | integer | Optional |
+| `interval` | integer | Optional |
+| `scans`    | integer | Optional |
+
+#### algo
+
+`algo`
+
+- is optional
+- type: `integer`
+
+##### algo Type
+
+`integer`
+
+#### interval
+
+`interval`
+
+- is optional
+- type: `integer`
+
+##### interval Type
+
+`integer`
+
+#### scans
+
+`scans`
+
+- is optional
+- type: `integer`
+
+##### scans Type
+
+`integer`
+
+### Ubus CLI Example
+
+```
+ubus call wifi.radio.<name> autochannel {"interval":-3947445,"algo":-79632421,"scans":-97118460}
+```
+
+### JSONRPC Example
+
+```json
+{
+  "jsonrpc": "2.0",
+  "id": 0,
+  "method": "call",
+  "params": [
+    "<SID>",
+    "wifi.radio.<name>",
+    "autochannel",
+    { "interval": -3947445, "algo": -79632421, "scans": -97118460 }
+  ]
+}
+```
+
+#### output
+
+##### wifi.radio.autochannel
+
+Auto channel selection
+
+`output`
+
+- is optional
+- type: `object`
+
+##### output Type
+
+`object` with following properties:
+
+| Property      | Type    | Required     |
+| ------------- | ------- | ------------ |
+| `code`        | integer | **Required** |
+| `new_channel` | oneOf   | **Required** |
+| `status`      | string  | **Required** |
+
+#### code
+
+`code`
+
+- is **required**
+- type: `integer`
+
+##### code Type
+
+`integer`
+
+#### new_channel
+
+`new_channel`
+
+- is **required**
+- type: complex
+
+##### new_channel Type
+
+**One** of the following _conditions_ need to be fulfilled.
+
+#### Condition 1
+
+`integer`
+
+- minimum value: `1`
+- maximum value: `14`
+
+#### Condition 2
+
+`integer`
+
+- minimum value: `32`
+- maximum value: `200`
+
+#### status
+
+`status`
+
+- is **required**
+- type: `string`
+
+##### status Type
+
+`string`
+
+### Output Example
+
+```json
+{ "code": -21368995, "new_channel": 139, "status": "quis se" }
+```
+
+## get
+
+`get`
+
+- type: `Method`
+
+### get Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `input`  | object | Optional |
+| `output` | object | Optional |
+
+#### input
+
+`input`
+
+- is optional
+- type: `object`
+
+##### input Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `param`  | string | Optional |
+
+#### param
+
+`param`
+
+- is optional
+- type: `string`
+
+##### param Type
+
+`string`
+
+### Ubus CLI Example
+
+```
+ubus call wifi.radio.<name> get {"param":"sunt"}
+```
+
+### JSONRPC Example
+
+```json
+{ "jsonrpc": "2.0", "id": 0, "method": "call", "params": ["<SID>", "wifi.radio.<name>", "get", { "param": "sunt" }] }
+```
+
+#### output
+
+`output`
+
+- is optional
+- type: `object`
+
+##### output Type
+
+`object` with following properties:
+
+| Property | Type    | Required |
+| -------- | ------- | -------- |
+| `status` | integer | Optional |
+| `values` | integer | Optional |
+
+#### status
+
+`status`
+
+- is optional
+- type: `integer`
+
+##### status Type
+
+`integer`
+
+#### values
+
+`values`
+
+- is optional
+- type: `integer`
+
+##### values Type
+
+`integer`
+
+### Output Example
+
+```json
+{ "status": -47928223, "values": 80011809 }
+```
+
+## scan
+
+`scan`
+
+- type: `Method`
+
+### scan Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `input`  | object | Optional |
+| `output` | object | Optional |
+
+#### input
+
+`input`
+
+- is optional
+- type: `object`
+
+##### input Type
+
+`object` with following properties:
+
+| Property  | Type   | Required |
+| --------- | ------ | -------- |
+| `bssid`   | string | Optional |
+| `channel` | oneOf  | Optional |
+| `ssid`    | string | Optional |
+
+#### bssid
+
+##### MAC Address
+
+`bssid`
+
+- is optional
+- type: reference
+
+##### bssid Type
+
+`string`
+
+- minimum length: 17 characters
+- maximum length: 17 characters All instances must conform to this regular expression (test examples
+  [here](<https://regexr.com/?expression=%5E(%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D%3A)%7B5%7D%5B0-9a-fA-F%5D%5B0-9a-fA-F%5D%24>)):
+
+```regex
+^([0-9a-fA-F][0-9a-fA-F]:){5}[0-9a-fA-F][0-9a-fA-F]$
+```
+
+#### channel
+
+`channel`
+
+- is optional
+- type: complex
+
+##### channel Type
+
+**One** of the following _conditions_ need to be fulfilled.
+
+#### Condition 1
+
+`integer`
+
+- minimum value: `1`
+- maximum value: `14`
+
+#### Condition 2
+
+`integer`
+
+- minimum value: `32`
+- maximum value: `200`
+
+#### ssid
+
+##### SSID
+
+`ssid`
+
+- is optional
+- type: reference
+
+##### ssid Type
+
+`string`
+
+- maximum length: 32 characters
+
+### Ubus CLI Example
+
+```
+ubus call wifi.radio.<name> scan {"ssid":"in","bssid":"6B:3B:df:a8:E8:bf","channel":8}
+```
+
+### JSONRPC Example
+
+```json
+{
+  "jsonrpc": "2.0",
+  "id": 0,
+  "method": "call",
+  "params": ["<SID>", "wifi.radio.<name>", "scan", { "ssid": "in", "bssid": "6B:3B:df:a8:E8:bf", "channel": 8 }]
+}
+```
+
+#### output
+
+Trigger a scan
+
+`output`
+
+- is optional
+- type: `object`
+
+##### output Type
+
+`object` with following properties:
+
+| Property | Type | Required |
+| -------- | ---- | -------- |
+| None     | None | None     |
+
+### Output Example
+
+```json
+{}
+```
+
+## scanresults
+
+`scanresults`
+
+- type: `Method`
+
+### scanresults Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `input`  | object | Optional |
+| `output` | object | Optional |
+
+#### input
+
+`input`
+
+- is optional
+- type: `object`
+
+##### input Type
+
+`object` with following properties:
+
+| Property | Type | Required |
+| -------- | ---- | -------- |
+| None     | None | None     |
+
+### Ubus CLI Example
+
+```
+ubus call wifi.radio.<name> scanresults {}
+```
+
+### JSONRPC Example
+
+```json
+{ "jsonrpc": "2.0", "id": 0, "method": "call", "params": ["<SID>", "wifi.radio.<name>", "scanresults", {}] }
+```
+
+#### output
+
+Show scan results
+
+`output`
+
+- is optional
+- type: `object`
+
+##### output Type
+
+`object` with following properties:
+
+| Property | Type | Required |
+| -------- | ---- | -------- |
+| None     | None | None     |
+
+### Output Example
+
+```json
+{}
+```
+
+## stats
+
+`stats`
+
+- type: `Method`
+
+### stats Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `input`  | object | Optional |
+| `output` | object | Optional |
+
+#### input
+
+`input`
+
+- is optional
+- type: `object`
+
+##### input Type
+
+`object` with following properties:
+
+| Property | Type | Required |
+| -------- | ---- | -------- |
+| None     | None | None     |
+
+### Ubus CLI Example
+
+```
+ubus call wifi.radio.<name> stats {}
+```
+
+### JSONRPC Example
+
+```json
+{ "jsonrpc": "2.0", "id": 0, "method": "call", "params": ["<SID>", "wifi.radio.<name>", "stats", {}] }
+```
+
+#### output
+
+##### wifi.radio.iface
+
+Radio statistics
+
+`output`
+
+- is optional
+- type: `object`
+
+##### output Type
+
+`object` with following properties:
+
+| Property               | Type    | Required     |
+| ---------------------- | ------- | ------------ |
+| `rx_bytes`             | integer | **Required** |
+| `rx_dropped_packets`   | integer | **Required** |
+| `rx_error_packets`     | integer | **Required** |
+| `rx_fcs_error_packets` | integer | **Required** |
+| `rx_packets`           | integer | **Required** |
+| `tx_bytes`             | integer | **Required** |
+| `tx_dropped_packets`   | integer | **Required** |
+| `tx_error_packets`     | integer | **Required** |
+| `tx_packets`           | integer | **Required** |
+
+#### rx_bytes
+
+`rx_bytes`
+
+- is **required**
+- type: reference
+
+##### rx_bytes Type
+
+`integer`
+
+- minimum value: `0`
+
+#### rx_dropped_packets
+
+`rx_dropped_packets`
+
+- is **required**
+- type: reference
+
+##### rx_dropped_packets Type
+
+`integer`
+
+- minimum value: `0`
+
+#### rx_error_packets
+
+`rx_error_packets`
+
+- is **required**
+- type: reference
+
+##### rx_error_packets Type
+
+`integer`
+
+- minimum value: `0`
+
+#### rx_fcs_error_packets
+
+`rx_fcs_error_packets`
+
+- is **required**
+- type: reference
+
+##### rx_fcs_error_packets Type
+
+`integer`
+
+- minimum value: `0`
+
+#### rx_packets
+
+`rx_packets`
+
+- is **required**
+- type: reference
+
+##### rx_packets Type
+
+`integer`
+
+- minimum value: `0`
+
+#### tx_bytes
+
+`tx_bytes`
+
+- is **required**
+- type: reference
+
+##### tx_bytes Type
+
+`integer`
+
+- minimum value: `0`
+
+#### tx_dropped_packets
+
+`tx_dropped_packets`
+
+- is **required**
+- type: reference
+
+##### tx_dropped_packets Type
+
+`integer`
+
+- minimum value: `0`
+
+#### tx_error_packets
+
+`tx_error_packets`
+
+- is **required**
+- type: reference
+
+##### tx_error_packets Type
+
+`integer`
+
+- minimum value: `0`
+
+#### tx_packets
+
+`tx_packets`
+
+- is **required**
+- type: reference
+
+##### tx_packets Type
+
+`integer`
+
+- minimum value: `0`
+
+### Output Example
+
+```json
+{
+  "tx_bytes": 62760043,
+  "tx_packets": 39487100,
+  "tx_error_packets": 4680682,
+  "tx_dropped_packets": 45656204,
+  "rx_bytes": 4906712,
+  "rx_packets": 27902438,
+  "rx_error_packets": 94647148,
+  "rx_dropped_packets": 95313119,
+  "rx_fcs_error_packets": 55108084
+}
+```
+
+## status
+
+`status`
+
+- type: `Method`
+
+### status Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `input`  | object | Optional |
+| `output` | object | Optional |
+
+#### input
+
+`input`
+
+- is optional
+- type: `object`
+
+##### input Type
+
+`object` with following properties:
+
+| Property | Type | Required |
+| -------- | ---- | -------- |
+| None     | None | None     |
+
+### Ubus CLI Example
+
+```
+ubus call wifi.radio.<name> status {}
+```
+
+### JSONRPC Example
+
+```json
+{ "jsonrpc": "2.0", "id": 0, "method": "call", "params": ["<SID>", "wifi.radio.<name>", "status", {}] }
+```
+
+#### output
+
+##### wifi.radio.iface
+
+Radio status
+
+`output`
+
+- is optional
+- type: `object`
+
+##### output Type
+
+`object` with following properties:
+
+| Property            | Type    | Required     | Default |
+| ------------------- | ------- | ------------ | ------- |
+| `band`              | string  | **Required** |         |
+| `beacon_int`        | integer | **Required** | `100`   |
+| `dtim_period`       | integer | **Required** | `1`     |
+| `frag_threshold`    | integer | **Required** | `2346`  |
+| `isup`              | boolean | **Required** |         |
+| `long_retry_limit`  | integer | **Required** |         |
+| `maxrate`           | integer | **Required** |         |
+| `noise`             | integer | **Required** |         |
+| `radio`             | string  | **Required** |         |
+| `rts_threshold`     | integer | **Required** | `2347`  |
+| `short_retry_limit` | integer | **Required** |         |
+
+#### band
+
+##### WiFi Band
+
+`band`
+
+- is **required**
+- type: reference
+
+##### band Type
+
+`string`
+
+The value of this property **must** be equal to one of the [known values below](#status-known-values).
+
+##### band Known Values
+
+| Value |
+| ----- |
+| 2GHz  |
+| 5GHz  |
+
+#### beacon_int
+
+`beacon_int`
+
+- is **required**
+- type: `integer`
+- default: `100`
+
+##### beacon_int Type
+
+`integer`
+
+- minimum value: `1`
+- maximum value: `65535`
+
+#### dtim_period
+
+`dtim_period`
+
+- is **required**
+- type: `integer`
+- default: `1`
+
+##### dtim_period Type
+
+`integer`
+
+- minimum value: `1`
+- maximum value: `255`
+
+#### frag_threshold
+
+`frag_threshold`
+
+- is **required**
+- type: `integer`
+- default: `2346`
+
+##### frag_threshold Type
+
+`integer`
+
+- minimum value: `256`
+- maximum value: `65535`
+
+#### isup
+
+`isup`
+
+- is **required**
+- type: `boolean`
+
+##### isup Type
+
+`boolean`
+
+#### long_retry_limit
+
+`long_retry_limit`
+
+- is **required**
+- type: `integer`
+
+##### long_retry_limit Type
+
+`integer`
+
+- minimum value: `1`
+- maximum value: `255`
+
+#### maxrate
+
+`maxrate`
+
+- is **required**
+- type: `integer`
+
+##### maxrate Type
+
+`integer`
+
+- minimum value: `0`
+
+#### noise
+
+##### Noise
+
+`noise`
+
+- is **required**
+- type: reference
+
+##### noise Type
+
+`integer`
+
+- minimum value: `-127`
+- maximum value: `0`
+
+#### radio
+
+##### Interface
+
+`radio`
+
+- is **required**
+- type: reference
+
+##### radio Type
+
+`string`
+
+- minimum length: 1 characters
+- maximum length: 16 characters
+
+#### rts_threshold
+
+`rts_threshold`
+
+- is **required**
+- type: `integer`
+- default: `2347`
+
+##### rts_threshold Type
+
+`integer`
+
+- minimum value: `0`
+- maximum value: `65535`
+
+#### short_retry_limit
+
+`short_retry_limit`
+
+- is **required**
+- type: `integer`
+
+##### short_retry_limit Type
+
+`integer`
+
+- minimum value: `1`
+- maximum value: `255`
+
+### Output Example
+
+```json
+{
+  "radio": "eiusmod sint",
+  "isup": true,
+  "band": "5GHz",
+  "noise": -80,
+  "maxrate": 69768222,
+  "beacon_int": 13308,
+  "dtim_period": 19,
+  "short_retry_limit": 220,
+  "long_retry_limit": 139,
+  "frag_threshold": 4365,
+  "rts_threshold": 17136,
+  "channel": false,
+  "bandwidth": "ex in Lorem pariatur velit"
+}
+```
diff --git a/docs/api/wifi.wps.md b/docs/api/wifi.wps.md
new file mode 100644
index 0000000000000000000000000000000000000000..dfdd2ec9d2c606bd275db430d003c6576b33991f
--- /dev/null
+++ b/docs/api/wifi.wps.md
@@ -0,0 +1,682 @@
+# wifi.wps Schema
+
+```
+https://www.iopsys.eu/wifi.wps
+```
+
+| Custom Properties | Additional Properties |
+| ----------------- | --------------------- |
+| Forbidden         | Forbidden             |
+
+# wifi.wps
+
+| List of Methods               |
+| ----------------------------- |
+| [generate_pin](#generate_pin) | Method | wifi.wps (this schema) |
+| [setpin](#setpin)             | Method | wifi.wps (this schema) |
+| [showpin](#showpin)           | Method | wifi.wps (this schema) |
+| [start](#start)               | Method | wifi.wps (this schema) |
+| [status](#status)             | Method | wifi.wps (this schema) |
+| [stop](#stop)                 | Method | wifi.wps (this schema) |
+| [validate_pin](#validate_pin) | Method | wifi.wps (this schema) |
+
+## generate_pin
+
+`generate_pin`
+
+- type: `Method`
+
+### generate_pin Type
+
+`object` with following properties:
+
+| Property | Type   | Required     |
+| -------- | ------ | ------------ |
+| `input`  | object | Optional     |
+| `output` | object | **Required** |
+
+#### input
+
+`input`
+
+- is optional
+- type: `object`
+
+##### input Type
+
+`object` with following properties:
+
+| Property | Type | Required |
+| -------- | ---- | -------- |
+| None     | None | None     |
+
+### Ubus CLI Example
+
+```
+ubus call wifi.wps generate_pin {}
+```
+
+### JSONRPC Example
+
+```json
+{ "jsonrpc": "2.0", "id": 0, "method": "call", "params": ["<SID>", "wifi.wps", "generate_pin", {}] }
+```
+
+#### output
+
+`output`
+
+- is **required**
+- type: `object`
+
+##### output Type
+
+`object` with following properties:
+
+| Property | Type   | Required     |
+| -------- | ------ | ------------ |
+| `pin`    | string | **Required** |
+
+#### pin
+
+`pin`
+
+- is **required**
+- type: reference
+
+##### pin Type
+
+`string`
+
+- minimum length: 8 characters
+- maximum length: 8 characters
+
+### Output Example
+
+```json
+{ "pin": "deserunt" }
+```
+
+## setpin
+
+`setpin`
+
+- type: `Method`
+
+### setpin Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `input`  | object | Optional |
+| `output` | object | Optional |
+
+#### input
+
+`input`
+
+- is optional
+- type: `object`
+
+##### input Type
+
+`object` with following properties:
+
+| Property | Type   | Required     |
+| -------- | ------ | ------------ |
+| `pin`    | string | **Required** |
+| `vif`    | string | Optional     |
+
+#### pin
+
+`pin`
+
+- is **required**
+- type: reference
+
+##### pin Type
+
+`string`
+
+- minimum length: 8 characters
+- maximum length: 8 characters
+
+#### vif
+
+##### Interface
+
+`vif`
+
+- is optional
+- type: reference
+
+##### vif Type
+
+`string`
+
+- minimum length: 1 characters
+- maximum length: 16 characters
+
+### Ubus CLI Example
+
+```
+ubus call wifi.wps setpin {"pin":"adelit e","vif":"in magn"}
+```
+
+### JSONRPC Example
+
+```json
+{
+  "jsonrpc": "2.0",
+  "id": 0,
+  "method": "call",
+  "params": ["<SID>", "wifi.wps", "setpin", { "pin": "adelit e", "vif": "in magn" }]
+}
+```
+
+#### output
+
+`output`
+
+- is optional
+- type: `object`
+
+##### output Type
+
+`object` with following properties:
+
+| Property | Type | Required |
+| -------- | ---- | -------- |
+| None     | None | None     |
+
+### Output Example
+
+```json
+{}
+```
+
+## showpin
+
+`showpin`
+
+- type: `Method`
+
+### showpin Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `input`  | object | Optional |
+| `output` | object | Optional |
+
+#### input
+
+`input`
+
+- is optional
+- type: `object`
+
+##### input Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `vif`    | string | Optional |
+
+#### vif
+
+##### Interface
+
+`vif`
+
+- is optional
+- type: reference
+
+##### vif Type
+
+`string`
+
+- minimum length: 1 characters
+- maximum length: 16 characters
+
+### Ubus CLI Example
+
+```
+ubus call wifi.wps showpin {"vif":"esse qu"}
+```
+
+### JSONRPC Example
+
+```json
+{ "jsonrpc": "2.0", "id": 0, "method": "call", "params": ["<SID>", "wifi.wps", "showpin", { "vif": "esse qu" }] }
+```
+
+#### output
+
+`output`
+
+- is optional
+- type: `object`
+
+##### output Type
+
+`object` with following properties:
+
+| Property | Type   | Required     |
+| -------- | ------ | ------------ |
+| `pin`    | string | **Required** |
+
+#### pin
+
+`pin`
+
+- is **required**
+- type: reference
+
+##### pin Type
+
+`string`
+
+- minimum length: 8 characters
+- maximum length: 8 characters
+
+### Output Example
+
+```json
+{ "pin": "Duis qui" }
+```
+
+## start
+
+`start`
+
+- type: `Method`
+
+### start Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `input`  | object | Optional |
+| `output` | object | Optional |
+
+#### input
+
+`input`
+
+- is optional
+- type: `object`
+
+##### input Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `mode`   | string | Optional |
+| `pin`    | string | Optional |
+| `role`   | string | Optional |
+| `vif`    | string | Optional |
+
+#### mode
+
+`mode`
+
+- is optional
+- type: `string`
+
+##### mode Type
+
+`string`
+
+#### pin
+
+`pin`
+
+- is optional
+- type: reference
+
+##### pin Type
+
+`string`
+
+- minimum length: 8 characters
+- maximum length: 8 characters
+
+#### role
+
+`role`
+
+- is optional
+- type: `enum`
+
+##### role Type
+
+`string`
+
+The value of this property **must** be equal to one of the [known values below](#start-known-values).
+
+##### role Known Values
+
+| Value     |
+| --------- |
+| registrar |
+| enrollee  |
+
+#### vif
+
+##### Interface
+
+`vif`
+
+- is optional
+- type: reference
+
+##### vif Type
+
+`string`
+
+- minimum length: 1 characters
+- maximum length: 16 characters
+
+### Ubus CLI Example
+
+```
+ubus call wifi.wps start {"vif":"ex commo","mode":"culpa","role":"enrollee","pin":"anim qui"}
+```
+
+### JSONRPC Example
+
+```json
+{
+  "jsonrpc": "2.0",
+  "id": 0,
+  "method": "call",
+  "params": [
+    "<SID>",
+    "wifi.wps",
+    "start",
+    { "vif": "ex commo", "mode": "culpa", "role": "enrollee", "pin": "anim qui" }
+  ]
+}
+```
+
+#### output
+
+`output`
+
+- is optional
+- type: `object`
+
+##### output Type
+
+`object` with following properties:
+
+| Property | Type | Required |
+| -------- | ---- | -------- |
+| None     | None | None     |
+
+### Output Example
+
+```json
+{}
+```
+
+## status
+
+`status`
+
+- type: `Method`
+
+### status Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `input`  | object | Optional |
+| `output` | object | Optional |
+
+#### input
+
+`input`
+
+- is optional
+- type: `object`
+
+##### input Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `vif`    | string | Optional |
+
+#### vif
+
+##### Interface
+
+`vif`
+
+- is optional
+- type: reference
+
+##### vif Type
+
+`string`
+
+- minimum length: 1 characters
+- maximum length: 16 characters
+
+### Ubus CLI Example
+
+```
+ubus call wifi.wps status {"vif":"laboru"}
+```
+
+### JSONRPC Example
+
+```json
+{ "jsonrpc": "2.0", "id": 0, "method": "call", "params": ["<SID>", "wifi.wps", "status", { "vif": "laboru" }] }
+```
+
+#### output
+
+`output`
+
+- is optional
+- type: `object`
+
+##### output Type
+
+`object` with following properties:
+
+| Property | Type    | Required     |
+| -------- | ------- | ------------ |
+| `code`   | integer | **Required** |
+| `status` | string  | **Required** |
+
+#### code
+
+`code`
+
+- is **required**
+- type: `integer`
+
+##### code Type
+
+`integer`
+
+- minimum value: `0`
+
+#### status
+
+`status`
+
+- is **required**
+- type: `string`
+
+##### status Type
+
+`string`
+
+### Output Example
+
+```json
+{ "code": 74811734, "status": "nisi Excepteur irure laboris ad" }
+```
+
+## stop
+
+`stop`
+
+- type: `Method`
+
+### stop Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `input`  | object | Optional |
+| `output` | object | Optional |
+
+#### input
+
+`input`
+
+- is optional
+- type: `object`
+
+##### input Type
+
+`object` with following properties:
+
+| Property | Type | Required |
+| -------- | ---- | -------- |
+| None     | None | None     |
+
+### Ubus CLI Example
+
+```
+ubus call wifi.wps stop {}
+```
+
+### JSONRPC Example
+
+```json
+{ "jsonrpc": "2.0", "id": 0, "method": "call", "params": ["<SID>", "wifi.wps", "stop", {}] }
+```
+
+#### output
+
+`output`
+
+- is optional
+- type: `object`
+
+##### output Type
+
+`object` with following properties:
+
+| Property | Type | Required |
+| -------- | ---- | -------- |
+| None     | None | None     |
+
+### Output Example
+
+```json
+{}
+```
+
+## validate_pin
+
+`validate_pin`
+
+- type: `Method`
+
+### validate_pin Type
+
+`object` with following properties:
+
+| Property | Type   | Required |
+| -------- | ------ | -------- |
+| `input`  | object | Optional |
+| `output` | object | Optional |
+
+#### input
+
+`input`
+
+- is optional
+- type: `object`
+
+##### input Type
+
+`object` with following properties:
+
+| Property | Type   | Required     |
+| -------- | ------ | ------------ |
+| `pin`    | string | **Required** |
+
+#### pin
+
+`pin`
+
+- is **required**
+- type: reference
+
+##### pin Type
+
+`string`
+
+- minimum length: 8 characters
+- maximum length: 8 characters
+
+### Ubus CLI Example
+
+```
+ubus call wifi.wps validate_pin {"pin":"ipsum am"}
+```
+
+### JSONRPC Example
+
+```json
+{ "jsonrpc": "2.0", "id": 0, "method": "call", "params": ["<SID>", "wifi.wps", "validate_pin", { "pin": "ipsum am" }] }
+```
+
+#### output
+
+`output`
+
+- is optional
+- type: `object`
+
+##### output Type
+
+`object` with following properties:
+
+| Property | Type    | Required     |
+| -------- | ------- | ------------ |
+| `valid`  | boolean | **Required** |
+
+#### valid
+
+`valid`
+
+- is **required**
+- type: `boolean`
+
+##### valid Type
+
+`boolean`
+
+### Output Example
+
+```json
+{ "valid": true }
+```
diff --git a/docs/functionspec.md b/docs/functionspec.md
new file mode 100644
index 0000000000000000000000000000000000000000..4c81d05e00cadff2e35a8b869c99541475a76dd6
--- /dev/null
+++ b/docs/functionspec.md
@@ -0,0 +1,316 @@
+# Function Specification
+
+The scope of wifimngr is to expose the libwifi APIs over ubus.
+
+```
+root@dc667cfd1b01:/builds/iopsys/wifimngr# ubus -v list
+'wifi' @0af621bb
+	"status":{}
+'wifi.ap.test5' @45e2e3f3
+	"status":{}
+	"stats":{}
+	"assoclist":{}
+	"stations":{"sta":"String"}
+	"disconnect":{"sta":"String"}
+	"monitor":{"sta":"String","get":"Integer"}
+	"add_neighbor":{"bssid":"String","channel":"Integer","bssid_info":"String","reg":"Integer","phy":"Integer"}
+	"del_neighbor":{"bssid":"String"}
+	"list_neighbor":{"ssid":"String","client":"String"}
+	"request_neighbor":{"ssid":"String","client":"String"}
+	"request_transition":{"client":"String","bssid":"Array","timeout":"Integer"}
+	"add_vendor_ie":{"mgmt":"Integer","oui":"String","data":"String"}
+	"del_vendor_ie":{"mgmt":"Integer","oui":"String","data":"String"}
+'wifi.radio.test5' @0806532f
+	"status":{}
+	"stats":{}
+	"get":{"param":"String"}
+	"scan":{"ssid":"String","bssid":"String","channel":"Integer"}
+	"scanresults":{"bssid":"String"}
+	"autochannel":{"interval":"Integer","algo":"Integer","scans":"Integer"}
+'wifi.wps' @e5b4e9d9
+	"start":{"vif":"String","mode":"String","role":"String","pin":"String"}
+	"stop":{}
+	"status":{"vif":"String"}
+	"generate_pin":{}
+	"validate_pin":{"pin":"String"}
+	"showpin":{"vif":"String"}
+	"setpin":{"vif":"String","pin":"String"}
+```
+
+# Contents
+* [wifi](#wifi)
+* [wifi.ap.\<name\>](#wifiapname)
+* [wifi.radio.\<name\>](#wifiradioname)
+* [wifi.wps](#wifiwps)
+
+## APIs
+
+Wifimngr publishes four different types objects, `wifi`, `wifi.ap.<name>`,
+`wifi.radio.<name>` and `wifi.wps`.
+
+### wifi
+
+An object that publishes wifi radio and interface information.
+
+| Method			| Function ID		|
+| :---				| :---        		|
+| [status](#status) | 1					|
+
+#### Methods
+
+Methods descriptions of the `wifi` object.
+
+##### status
+Exposes wifi radio statistics over ubus.
+
+* [status documentation](./api/wifi.md#status)
+
+### wifi.ap.\<name\>
+Object for wifi access point interface functionality. One object per access
+point interface will be published.
+````bash
+	"status":{}
+	"stats":{}
+	"assoclist":{}
+	"stations":{"sta":"String"}
+	"disconnect":{"sta":"String"}
+	"monitor":{"sta":"String","get":"Integer"}
+	"add_neighbor":{"bssid":"String","channel":"Integer","bssid_info":"String","reg":"Integer","phy":"Integer"}
+	"del_neighbor":{"bssid":"String"}
+	"list_neighbor":{"ssid":"String","client":"String"}
+	"request_neighbor":{"ssid":"String","client":"String"}
+	"request_transition":{"client":"String","bssid":"Array","timeout":"Integer"}
+	"add_vendor_ie":{"mgmt":"Integer","oui":"String","data":"String"}
+	"del_vendor_ie":{"mgmt":"Integer","oui":"String","data":"String"}
+````
+| Method      								|Function ID	|
+| :--- 	  									| :---        	|
+| [status](#status-1)						| 2				|
+| [stats](#stats)							| 3				|
+| [assoclist](#assoclist)					| 4				|
+| [stations](#stations)						| 5				|
+| [disconnect](#disconnect)					| 6				|
+| [monitor](#monitor)				 		| 7				|
+| [add_neighbor](#add_neighbor)		 		| 8				|
+| [del_neighbor](#del_neighbor)		 		| 9				|
+| [list_neighbor](#list_neighbor)			| 10			|
+| [request_neighbor](#request_neighbor)		| 11			|
+| [request_transition](#request_transition)	| 12			|
+| [add_vendor_ie](#add_vendor_ie)			| 13			|
+| [del_vendor_ie](#del_vendor_ie)			| 14			|
+
+#### Methods
+
+Method descriptions of the `wifi.ap.<name>` object.
+
+##### status
+
+Exposes access point interface statistics over ubus.
+
+* [status documentation](./api/wifi.ap.md#status)
+
+##### stats
+
+Exposes access point interface rx/tx statistics over ubus.
+
+* [stats documentation](./api/wifi.ap.md#stats)
+
+##### assoclist
+
+Exposes connected wireless clients over ubus.
+
+* [assoclist documentation](./api/wifi.ap.md#assoclist)
+
+##### stations
+
+Exposes client wifi client statistics over ubus.
+
+* [stations documentation](./api/wifi.ap.md#stations)
+
+##### disconnect
+
+Issue a deauthenticate to a wireles client.
+
+* [disconnect documentation](./api/wifi.ap.md#disconnect)
+
+##### monitor
+
+Monitor signal strength of unassociated station.
+
+* [monitor documentation](./api/wifi.ap.md#monitor)
+
+##### add_neighbor
+
+Add an access point to the neighbor list.
+
+* [add_neighbor documentation](./api/wifi.ap.md#add_neighbor)
+
+##### del_neighbor
+
+Delete an access point from the neighbor list
+
+* [del_neighbor documentation](./api/wifi.ap.md#del_neighbor)
+
+##### list_neighbor
+
+Prints neighbor access points in the network.
+
+* [list_neighbor documentation](./api/wifi.ap.md#list_neighbor)
+
+##### request_neighbor
+
+Triggers an 11k beacon report from an associated station.
+
+* [request_neighbor documentation](./api/wifi.ap.md#request_neighbor)
+
+##### request_transition
+
+Triggers an 11k beacon report from an associated station.
+
+* [request_transition documentation](./api/wifi.ap.md#request_transition)
+
+##### add_vendor_ie
+
+Appends vendor specific information element to an 802.11 management frame.
+
+* [add_vendor_ie documentation](./api/wifi.ap.md#add_vendor_ie)
+
+##### del_vendor_ie
+
+Remove vendor specific information element from an 802.11 management frame.
+
+* [del_vendor_ie documentation](./api/wifi.ap.md#del_vendor_ie)
+
+### wifi.radio.\<name\>
+
+Object for wifi device functionality. One object per device will be published to
+ubus.
+
+````bash
+'wifi.radio.test5' @0806532f
+	"status":{}
+	"stats":{}
+	"get":{"param":"String"}
+	"scan":{"ssid":"String","bssid":"String","channel":"Integer"}
+	"scanresults":{"bssid":"String"}
+	"autochannel":{"interval":"Integer","algo":"Integer","scans":"Integer"}
+````
+| Method     					| Function ID	|
+| :---							| :---        	|
+| [status](#status-2)			| 15			|
+| [stats](#stats-1)				| 16			|
+| [get](#get)					| 17			|
+| [scan](#scan)					| 18			|
+| [scanresults](#scanresults)	| 19			|
+| [autochannel](#autochannel)	| 20			|
+
+#### Methods
+
+Method descriptions of the `wifi.radio.<name>` object.
+
+##### status
+
+Exposes radio statistics over ubus.
+
+* [status documentation](./api/wifi.radio.md#status)
+
+##### stats
+
+Exposes radio stats over ubus.
+
+* [stats documentation](./api/wifi.radio.md#stats)
+
+##### get
+
+Exposes temperature of the WiFi card.
+
+* [get documentation](./api/wifi.radio.md#get)
+
+##### scan
+
+Scans the radio for broadcasted SSIDs.
+
+* [scan documentation](./api/wifi.radio.md#scan)
+
+##### scanresults
+
+Exposes available SSIDs from a radio scan over ubus.
+
+* [scanresults documentation](./api/wifi.radio.md#scanresults)
+
+##### autochannel
+
+Selects a channel for the radio to operate at.
+
+* [autochannel documentation](./api/wifi.radio.md#autochannel)
+
+### wifi.wps
+
+Object for WiFi Protected Setup functionality.
+
+````bash
+	"start":{"vif":"String","mode":"String","role":"String","pin":"String"}
+	"stop":{}
+	"status":{"vif":"String"}
+	"generate_pin":{}
+	"validate_pin":{"pin":"String"}
+	"showpin":{"vif":"String"}
+	"setpin":{"vif":"String","pin":"String"}
+````
+| Method     						| Function ID	|
+| :--- 								| :---       	|
+| [start](#start)					| 21			|
+| [stop](#stop)						| 22			|
+| [status](#status-3)				| 23			|
+| [generate_pin](#generate_pin)		| 24			|
+| [validate_pin](#show_pin)			| 25			|
+| [showpin](#validate_pin)			| 26			|
+| [setpin](#setpin)					| 27			|
+
+#### Methods
+
+Descriptions of `wifi.wps` methods.
+
+
+##### start
+
+Initiates WPS functionality, default uses push button configuration (PBC).
+
+* [start documentation](./api/wifi.wps.md#start)
+
+##### stop
+
+Stops any WPS functionality.
+
+* [stop documentation](./api/wifi.wps.md#stop)
+
+##### status
+
+Gives current state of the WPS.
+
+* [status documentation](./api/wifi.wps.md#status)
+
+##### generate_pin
+
+Method generating a valid pin for WPS.
+
+* [generate_pin documentation](./api/wifi.wps.md#generate_pin)
+
+##### show_pin
+
+Shows currently set PIN, if any.
+
+* [showpin documentation](./api/wifi.wps.md#showpin)
+
+
+##### validate_pin
+
+Takes a pin input and shows whether it is a valid PIN or not.
+
+* [validate_pin documentation](./api/wifi.wps.md#validate_pin)
+
+##### setpin
+
+Takes a pin input and sets it as the active WPS pin for the device.
+
+* [setpin documentation](./api/wifi.wps.md#setpin)
diff --git a/docs/testspec.md b/docs/testspec.md
new file mode 100644
index 0000000000000000000000000000000000000000..7cfc1edfbb64ef37e798b1dc5cf07eba081d5e1f
--- /dev/null
+++ b/docs/testspec.md
@@ -0,0 +1,715 @@
+# Test Specification
+
+Most of the functionality in wifimngr can be tested via its ubus API. Each
+API can be broken down into an individual test case to show full coverage is
+achieved.
+
+# Sections
+* [Preqreuisites](#prerequisites)
+* [Test Suites](#test-suites)
+* [Functional API Tests](#functional-api-tests)
+* [Unit Tests](#unit-tests)
+* [Functional Tests](#functional-tests)
+* [Writing New Tests](#writing-new-tests)
+
+
+## Prerequisites
+
+The only prerequisite for the wifimngr test suites is that libwifi has to be
+built for the TEST platform, a versionprepared to publish dummy data for getter
+API, and record setter API to a test logfile at `/tmp/test.log`.
+
+## Test Suites
+
+The wifimngr build pipe has three test suites, a functional-api suite, a unit
+testi suite and functional test suite.
+
+### Functional API Tests
+
+The functional API tests consists of four individual test suites, one per object
+Ubus under test. The functional API tests use the Ubus-API-validation
+command-line interface tool to invoke a method, programmatically through
+libubus, and validates it against the objects json-schema.
+
+#### wifi
+
+| Execution ID	| Method      	| Description 	| Function ID Coverage			|
+| :---			| :---	   		| :---			| :---							|
+| 1				| status     	| No argument  	| [1](./functionspec.md#status) |
+| 2				| dummy     	| Negative Test	| 								|
+
+#### wifi.ap.\<name\>
+
+| Execution ID	| Method      	| Description 			| Function ID Coverage					|
+| :---			| :--- 	  		| :---					| :---									|
+| 1				| status     	| No argument	  		| [2](./functionspec.md#status-1)		|
+| 2				| stats     	| No argument  			| [3](./functionspec.md#stats)			|
+| 3				| assoclist  	| No argument	  		| [4](./functionspec.md#assoclist)		|
+| 4				| stations   	| No argument  			| [5](./functionspec.md#stations)		|
+| 5				| stations   	| With sta argument 	| [5](./functionspec.md#stations)		|
+| 6				| list_neighbor	| No argument	  		| [10](./functionspec.md#list_neighbor)	|
+| 7				| list_neighbor	| With client argument	| [10](./functionspec.md#list_neighbor)	|
+| 8				| dummy     	| Negative Test			| 										|
+
+#### wifi.radio.\<name\>
+
+| Execution ID	| Method     	| Description 			| Function ID Coverage					|
+| :---			| :---			| :---					| :---									|
+| 1				| status    	| No argument	  		| [15](./functionspec.md#status-2)		|
+| 2				| stats     	| No argument  			| [16](./functionspec.md#stats-1)		|
+| 3				| scanresults	| No argument	  		| [19](./functionspec.md#scanresults)	|
+| 4				| scanresults 	| With bssid argument	| [19](./functionspec.md#scanresults)	|
+| 5				| get   		| No argument	  		| [17](./functionspec.md#get)			|
+| 6				| autochannel	| No argument	  		| [20](./functionspec.md#autochannel)	|
+| 7				| dummy			| Negative Test			| 										|
+
+#### wifi.wps
+
+| Execution ID	| Method     	| Description 					| Function ID Coverage					|
+| :---			| :--- 			| :---							| :---									|
+| 1				| status    	| No argument	  				| [23](./functionspec.md#status-3)		|
+| 2				| status     	| With vif argument				| [23](./functionspec.md#status-3)		|
+| 3				| generate_pin	| No argument	 				| [24](./functionspec.md#generate_pin)	|
+| 4				| validate_pin	| With invalid pin argument		| [26](./functionspec.md#validate_pin)	|
+| 5				| validate_pin	| With valid pin argument		| [26](./functionspec.md#validate_pin)	|
+| 6				| showpin		| No argument	 				| [25](./functionspec.md#showpin)		|
+| 7				| showpin		| With vif argument				| [25](./functionspec.md#showpin)		|
+| 8				| dummy			| Negative Test					| 	 									|
+
+### Unit Tests
+
+The wifimngr unit tests are written in cmocka, invoking the ubus callbacks
+directly from the source code, which is compiled into a shared library.
+This means mocking the arguments of a cli or libubus invoke in a
+`struct blob_attr *`. The results of the call will be logged to the logfile at
+`/tmp/test.log`.
+
+| Execution ID	| Method     			| Test Case Name												| Function ID Coverage						|
+| :---			| :--- 					| :---															| :---										|
+| 1				| disconnect    		| [test_api_radio_disconnect](#test_api_radio_disconnect)		| [6](./functionspec.md#disconnect)			|
+| 2				| request_transition	| [test_api_req_bss_transition](#test_api_req_bss_transition)	| [12](./functionspec.md#request_transition)|
+| 3				| request_neighbor		| [test_api_req_beacon_report](#test_api_req_beacon_report) 	| [11](./functionspec.md#request_neighbor)	|
+| 4				| add_neighbor 			| [test_api_add_nbr](#test_api_add_nbr)							| [8](./functionspec.md#add_neighbor)		|
+| 5				| start					| [test_api_wps_start](#test_api_wps_start) 		   			| [21](./functionspec.md#start)				|
+| 6				| stop					| [test_api_wps_stop](#test_api_wps_stop) 		   				| [22](./functionspec.md#stop)				|
+| 7				| add_vendor_ie			| [test_api_add_vendor_ie](#test_api_add_vendor_ie) 			| [13](./functionspec.md#add_vendor_ie)		|
+| 8				| del_vendor_ie 		| [test_api_del_vendor_ie](#test_api_del_vendor_ie) 			| [14](./functionspec.md#del_vendor_ie)		|
+| 9				| del_neighbor 			| [test_api_del_neighbor](#test_api_del_neighbor)				| [9](./functionspec.md#del_neighbor)		|
+| 10			| monitor   			| [test_api_monitor_sta](#test_api_monitor_sta) 				| [7](./functionspec.md#monitor)			|
+| 11			| scan					| [test_api_scan](#test_api_scan) 		   						| [18](./functionspec.md#scan)				|
+| 12			| setpin				| [test_set_wps_ap_pin](#test_set_wps_ap_pin) 				   	| [27](./functionspec.md#setpin)			|
+| 13			| autochannel			| [test_api_acs](#test_api_acs) 		   						| [20](./functionspec.md#autochannel)		|
+
+#### test_api_radio_disconnect
+
+##### Description
+
+Tests the wifimngr ubus API callback `sta_disconnect(5)`, publishing the method
+[disconnect](./functionspec.md#disconnect).
+
+##### Test Steps
+
+Prepare the arguments as:
+````bash
+{ "sta": "50:31:32:33:34:35" }
+````
+Iussing a deauthenticate to a 5GHz client from the libwifi test platform.
+
+Read the logfile and verify that the `sta` argument, and interface, was
+accurately logged.
+
+##### Test Expected Results
+
+The expected result is for the log file to have recorded a call to the
+disconnect function, through the interface `test5` and with the argument `sta`
+as `50:31:32:33:34:35`.
+
+````bash
+[2020-02-04 13:06:12] disconnect: { "ifname": "test5", "sta": "50:31:32:33:34:35" }
+````
+
+#### test_api_req_bss_transition
+
+##### Description
+
+Tests the wifimngr ubus API callback `nbr_transition(5)`, publishing the method
+[request_transition](./functionspec.md#request_transition).
+
+##### Test Steps
+
+Prepare the arguments as:
+
+````bash
+{ "client": "50:31:32:33:34:35", "bssid": ["22:22:22:22:22:22", "11:11:11:11:11:11" ] }
+````
+
+Requesting a 5GHz client, `50:31:32:33:34:35`, to transition from bssid
+`22:22:22:22:22:22` to bssid `11:11:11:11:11:11`.
+
+Read the logfile and verify that the interface and arguments were accurately
+logged.
+
+##### Test Expected Results
+
+The expected result is for the log file to have recorded a call to the
+req_bss_transition function, through the interface `test5` and with the argument `client`
+as `50:31:32:33:34:35` and an array `bssid` with the entries
+`"22:22:22:22:22:22","11:11:11:11:11:11"`.
+
+````bash
+[2020-02-04 13:06:12] req_bss_transition: { "ifname": "test5", "client": "50:31:32:33:34:35", "bssid": ["22:22:22:22:22:22","11:11:11:11:11:11",] }
+````
+
+
+#### test_api_req_beacon_report
+
+##### Description
+
+Tests the wifimngr ubus API callback `nbr_request(5)`, publishing the method
+[request_neighbor](./functionspec.md#request_neighbor).
+
+##### Test Steps
+
+Prepare the arguments as:
+
+````bash
+{ "client": "50:31:32:33:34:35", "ssid": "Test SSID 5GHz" }
+````
+
+Requesting the client `50:31:32:33:34:35` with the ssid `Test SSID 5GHz` as a
+neighbor.
+
+Read the logfile and verify that the interface and arguments were accurately
+logged.
+
+##### Test Expected Results
+
+The expected result is for the log file to have recorded a call to the
+`nbr_request` function, through the interface `test5` and with the argument
+`client` as `50:31:32:33:34:35`. Currently the `ssid` argument is ignored and
+not expected to be observed from the log file.
+
+````bash
+[2020-02-04 13:06:12] req_beacon_report: { "ifname": "test5", "client": "50:31:32:33:34:35" }
+````
+
+#### test_api_add_nbr
+
+##### Description
+
+Tests the wifimngr ubus API callback `nbr_add(5)`, publishing the method
+[add_neighbor](./functionspec.md#add_neighbor).
+
+##### Test Steps
+
+Prepare the arguments as:
+
+````bash
+{ "bssid": "00:11:12:13:14:15", "channel": 36, "bssid_info", "5", "reg": 5, "phy": 5 }
+````
+
+Requesting the neighbor bssid `00:11:12:13:14:15`, operating at channel 36 on
+registry 5 and phy 5 to be added to the neighbor list.
+
+Read the logfile and verify that the interface and arguments were accurately
+logged.
+
+##### Test Expected Results
+
+The expected result is for the log file to have recorded a call to the
+`add_neighbor` function, through the interface `test5` and with the arguments
+`bssid` as `00:11:12:13:14:15`, channel as 36, phy as 5, reg as 5, bssid_info as
+"5".
+
+````bash
+[2020-02-04 13:06:12] add_neighbor: { "ifname": "test5", "bssid_info": 5, "reg": 5, "channel": 36, "phy": 5, "bssid": "00:11:12:13:14:15" }
+````
+
+#### test_api_wps_start
+
+##### Description
+
+Tests the wifimngr ubus API callback `wps_start(5)`, publishing the method
+[start](./functionspec.md#start) to the `wifi.wps` object.
+
+##### Test Steps
+
+The test case has three steps, trying different argument inputs to reach as high
+coverage as possible.
+
+The first part of the test case tests the role registrar, with a pin, allowing
+others devices to connect via pin, over the 5GHz interface.
+
+````bash
+{ "vif": "test5", "pin": "24033848", "mode", "pin", "role": "registrar" }
+````
+
+The second part tests signing up with the role enrollee over the 2.4GHz
+interface.
+
+````bash
+{ "vif": "test2", "role": "enrollee" }`
+````
+
+The third part of the test case tests the mode pbc, allowing other devices to
+synchronize over via its own push button configuration, over the 2.4GHz
+interface.
+
+````bash
+{ "vif": "test2", "mode": "pbc" }`
+````
+
+Read the logfile and verify that the interface and arguments were accurately
+logged.
+
+##### Test Expected Results
+
+The expected result is for the log file to have recorded a call to the
+`start_wps` function, showing the arguments accordingly, note that role
+`registrar` is represented by 0, and `enrollee` by 1, whereas mode `pin` is
+represented by 1 and `pbc` by 0.
+
+
+````bash
+[2020-02-04 13:06:12] start_wps: { "ifname": "test5", "pin": "24033848", "role": 4, "mode": 1 }
+[2020-02-04 13:06:12] start_wps: { "ifname": "test2", "role": 1, "mode": 0 }
+[2020-02-04 13:06:12] start_wps: { "ifname": "test2", "role": 0, "mode": 0 }
+````
+
+#### test_api_wps_stop
+
+##### Description
+
+Tests the wifimngr ubus API callback `wps_stop(5)`, publishing the method
+[stop](./functionspec.md#stop) to the `wifi.wps` object.
+
+##### Test Steps
+
+Prepare the arguments as:
+
+````bash
+{ "ifname": "test5" }
+````
+
+Stopping any active WPS activity on the 5GHz interface.
+
+Read the logfile and verify that the interface and arguments were accurately
+logged.
+
+##### Test Expected Results
+
+As `wps_stop(5)` will call iterate all available interfaces and invoke the
+libwifi API `wifi_stop_wps(1)` for each and every one, we expect to see all
+(both) interfaces in the logs along with the function tag `stop_wps`.
+
+````bash
+[2020-02-04 13:06:12] stop_wps: { "ifname": "test2" }
+[2020-02-04 13:06:12] stop_wps: { "ifname": "test5" }
+````
+
+#### test_api_add_vendor_ie
+
+##### Description
+
+Tests the wifimngr ubus API callback `vsie_add(5)`, publishing the method
+[add_vendor_ie](./functionspec.md#add_vendor_ie) to the `wifi.ap.<name>` object.
+
+##### Test Steps
+
+Prepare the arguments:
+
+````bash
+{ "mgmt": 5, "oui": "112233", "data": "dd03efa567" }
+````
+
+Appending the vendor specific information to the management frame.
+
+##### Test Expected Results
+
+The expected result is to observe the function tag `add_vendor_ie` in the logs,
+along with the prepared arguments, verifying that they have been parsed
+correctly by wifimngr and libwifi.
+
+````bash
+[2020-02-04 13:06:12] add_vendor_ie: { "ifname": "test5", "mgmt": 5, "oui": "112233", "data": "dd03efa567" }
+````
+
+#### test_api_del_vendor_ie
+
+##### Description
+
+Tests the wifimngr ubus API callback `vsie_del(5)`, publishing the method
+[del_vendor_ie](./functionspec.md#del_vendor_ie) to the `wifi.ap.<name>` object.
+
+##### Test Steps
+
+Prepare the arguments:
+````bash
+{ "mgmt": 5, "oui": "112233", "data": "dd03efa567" }
+````
+
+Deleting the vendor specific information from the management frame.
+
+##### Test Expected Results
+The expected result is to observe the function tag `del_vendor_ie` in the logs,
+along with the prepared arguments, verifying that they have been parsed
+correctly by wifimngr and libwifi.
+
+````bash
+[2020-02-04 13:06:12] del_vendor_ie: { "ifname": "test5", "mgmt": 5, "oui": "112233", "data": "dd03efa567" }
+````
+
+#### test_api_del_neighbor
+
+##### Description
+
+Tests the wifimngr ubus API callback `nbr_del(5)`, publishing the method
+[del_neighbor](./functionspec.md#del_neighbor) to the `wifi.ap.<name>` object.
+
+##### Test Steps
+
+Prepare the arguments:
+
+````bash
+{ "bssid": "50:10:00:11:22:33" }
+````
+
+Removing the bssid from the neighbor list.
+
+##### Test Expected Results
+
+The expected result is to observe the function tag `del_neighbor` in the test
+logs, along with the arguments, verifying that they have been parsed correctly
+by wifimngr and libwifi.
+
+````bash
+[2020-02-04 13:06:12] del_neighbor: { "ifname": "test5", "bssid": "50:10:00:11:22:33" }
+````
+
+#### test_api_monitor_sta
+
+##### Description
+
+Tests the wifimngr ubus API callback `sta_monitor(5)`, publishing the method
+[monitor](./functionspec.md#monitor) to the `wifi.ap.<name>` object.
+
+##### Test Steps
+
+Prepare the arguments:
+
+````bash
+{ "sta": "00:00:00:11:22:33" }
+````
+
+Starting to monitor the unassociated wireless client with the mac address
+`00:00:00:11:22:33`.
+
+##### Test Expected Results
+
+The expected result is to observe the function tag `monitor_sta` in the test
+logs, along with the 5GHz interface and the argument `sta` as
+`00:00:00:11:22:33`.
+
+````bash
+[2020-02-04 13:06:12] monitor_sta: { "ifname": "test5", "sta": "00:00:00:11:22:33" }
+````
+#### test_api_scan
+
+##### Description
+
+Tests the wifimngr ubus API callback `wl_scan(5)`, publishing the method
+[scan](./functionspec.md#scan) to the `wifi.radio.<name>` object.
+
+##### Test Steps
+
+Prepare the arguments:
+
+````bash
+{ "ssid": "test", "bssid": "00:00:00:11:22:33", "channel": 36 }
+````
+
+Scanning the device using the ssid `test`.
+
+##### Test Expected Results
+
+The expected result is to observe the function tag `scan` in the test logs,
+along with the 5GHz interface and the argument `test5` as
+`ssid`, the remaining arguments are ignored as they are currently not
+implemented or passed to libwifi.
+
+````bash
+[2020-02-04 13:06:12] scan: { "ifname": "test5", "ssid": "test", "bssid": "00:00:00:00:00:00", "channel": 0, "type": 0 }
+````
+
+#### test_set_wps_ap_pin
+
+##### Description
+
+Tests the wifimngr ubus API callback `wps_set_ap_pin(5)`, publishing the method
+[setpin](./functionspec.md#setpin) to the `wifi.wps` object.
+
+##### Test Steps
+
+Prepare the arguments:
+
+````bash
+{ "ifname": "test5", "pin": "24033848" }
+````
+
+Setting the WPS pin of the 5GHz interface to 24033848.
+
+##### Test Expected Results
+
+The expected result is to observe the function tag `set_wps_ap_pin` in the test
+logs, along with the 5GHz interface and the pin.
+
+````bash
+[2020-02-04 13:06:12] set_wps_ap_pin: { "ifname": "test5", "pin": 24033848 }
+````
+
+#### test_api_acs
+
+##### Description
+
+Tests the wifimngr ubus API callback `wl_autochannel(5)`, publishing the method
+[autochannel](./functionspec.md#autochannel) to the `wifi.radio.<name>` object.
+
+##### Test Steps
+
+Prepare the arguments:
+
+````bash
+{ "ifname": "test5" }
+````
+
+Automatically selecting a channel to operate at. Currently no further arguments
+are passed as they are ignored programmatically.
+
+##### Test Expected Results
+
+The expected result is to observe the function tag `acs` in the test
+logs, along with the 5GHz interface.
+
+````bash
+[2020-02-04 13:06:12] acs: { "ifname": "test5" }
+````
+
+### Functional Tests
+
+| Serial ID		| Test Case Name	|
+| :---			| :---				|
+| 1				| test_api_events	|
+
+#### test_api_events
+
+##### Description
+
+Tests the event registration and receive process. Wifimngr will read the file
+`/etc/wifi.json` in order to register to netlink events, in this case the
+netlink family `easysoc` and the group `notify`.
+
+
+```
+{
+	"events" : [
+		{
+			"type": "wifi-event",
+			"name": "cfg09ac03",
+			"ifname": "test5",
+			"family": "easysoc",
+			"group": [
+					"notify"
+			]
+		}
+	]
+}
+```
+
+##### Test Steps
+
+As netlink events are not being published in the docker environment, the test
+will verify that a listener thread is created, registrates a listener and calls
+the libwifi API for receiving events.
+
+As in practice the listener thread is intended to listen for events for the
+entire lifetime of the process, there is no break condition for the listener
+loop. However, in order to get a more accurate memory management report, the
+event loop, `int wifimngr_recv_event(2)` is mocked to allow break on the return
+code -1.
+
+```
+int wifimngr_recv_event(const char *ifname, void *handle)
+{
+	int err;
+
+	for (;;) {
+		err = wifi_recv_event((char *)ifname, handle);
+		if (err < 0)
+			return -1;
+	}
+
+	return 0;
+}
+```
+
+##### Test Expected Results
+
+The expected results are that wifimngr will have attempted to register a listner
+with the family `easysoc`, the group `notify` under the interface `test5`, and
+attempted to receive events under the same interface, read from the test log
+file under the function tags `register_event` and `recv_event.`
+
+````bash
+[2020-02-05 09:38:40] register_event: { "ifname": "test5", "family": "easysoc", "group": "notify" }
+[2020-02-05 09:38:40] recv_event: { "ifname": "test5" }
+````
+
+## Writing New Tests
+
+On the addition of new APIs to wifimngr and libwifi, additional tests should be
+written to maintain the coverage and quality of the code.
+
+### Libwifi
+
+On a new addition to the libwifi API, the test platform for libwifi has to be
+extended. The test platform for libwifi consists of two files, `test.c` and
+`test.h`, found under the subdirectory `./libwifi/modules/` under the
+[easy-soc-libs](https://dev.iopsys.eu/iopsys/easy-soc-libs) repository.
+
+The following examples assume the existence of a `struct test`.
+
+```
+struct test {
+	unsigned char sta[6];
+}
+```
+
+#### Getter
+
+Assume the addition of the new API, `get_client(2)`, taking an interface,
+`char *` as first argument, and a `struct test *`, filling the
+struct with the mac address of the first client in the interface.
+
+The first step is to prepare some dummy data in the header file, in this case
+a dummy client of the type `struct test`. Two structs with static mac addresses
+are to be prepared, one for each test interface, holding static data to
+represent a mac address. Additionally, add a macro pointing to the address of
+the structs with the dummy data.
+
+```
+/* 5GHz dummy data */
+const struct test test5_test_data = {
+	.sta = {"\x66\x55\x44\x33\x22\x11"}
+};
+
+/* 5GHz "pointer" to dummy data */
+#define test5_test	&test5_test_data
+
+/* 2.4GHz dummy data */
+const struct test test2_test_data = {
+	.sta = {"\x11\x22\x33\x44\x55\x66"}
+};
+
+/* 2.4GHz "pointer" to dummy data */
+#define test2_test	&test2_test_data
+```
+
+With the dummy data prepared, the function can be implemented. The test platform
+has a set of macros prepared to use when filling variables with dummy data,
+ranging from primitive types, buffers, arrays and structs. For this example
+the helper macro `GET_TEST_BUF_TYPE(4)` will be used:
+
+```
+#define TESTDATA(band, attr)	test ## band ## _ ## attr
+
+...
+
+#define GET_TEST_BUF_TYPE(o, iface, attr, type)				\
+({									\
+	if (ifname_to_band(iface) == 5)					\
+		memcpy(o, TESTDATA(5, attr), sizeof(type));		\
+	else								\
+		memcpy(o, TESTDATA(2, attr), sizeof(type));		\
+})
+```
+
+The macro will fill the first argument, `o`, wth the data pointed to by the
+concatenated variable `test`, `5`, `_` and the `attr` argument, forming
+`test5_test`.
+
+Therefore, implementing our dummy getter, `test_get_client(2)`, becomes simple.
+
+```
+int get_client(char *ifname, struct test *t)
+{
+	GET_TEST_BUF_TYPE(t, name, test, struct test);
+
+	return 0;
+}
+```
+
+Lastly, it should be added to the driver, assuming the driver has been updated
+with a `get_client` function pointer:
+
+```
+const struct wifi_driver test_driver = {
+	.name = "test",
+	.get_client = test_get_client,
+	...
+};
+```
+
+#### Setter
+
+In the case of an addition of a new setter to the libwifi API. A log function
+is prepared in the test driver, logging a `char *` string to a test log file,
+`/tmp/test.log`, `log_test(2)`. The first argument to `log_test(2)` is the
+`char *` representing the format, and the second is a `va_list`; all the
+arguments of the format. It is important the the format follows the structure
+
+```
+<FUNCTION_IDENTIFIER>: { <RELEVANT_ARGS> }
+```
+
+Assume the addition of a `set_client(2)` API call, the function should be
+implemented in the test driver, calling `log_test(2)` to be able to verify the
+struct usage and library linkage. Let's assume that the exposed Ubus API
+takes an argument in the form of a mac address, that would be provded as an
+argument, `sta`.
+
+```
+int test_set_client(char *ifname, struct test *t)
+{
+	log_test("set_client: { \"ifname\": \"%s\", \"sta\": \"%02x%02x%02x%02x%02x%02x\" }",
+			ifname, t->sta[0], t->sta[0], t->sta[0],
+			t->sta[0], t->sta[0], t->sta[0]);
+
+	return 0;
+}
+```
+
+This will log the entry as:
+
+```
+[2020-02-04 13:06:12] set_client: { "ifname": "test5", "sta": "00:11:22:33:44:55" }
+```
+
+Which can then be read by the corresponding test case and verified.
+
+### Writing Tests
+
+When extending the test cases themselves, getters should be tested via the
+Ubus-API-validation tool for in the functional-api-test suite.
+
+Setters without any external dependencies (i.e. other processes) should be
+included in the unit tests (`./test/api_test_wifi_setters.c`), and remaining
+setters in the functional-test suite (`./test/function_test_wifi_event.c`).
+
+For the setter tests, a utility function has been prepared to parse the logfile
+for the latest occurrance of a function identifier tag, `poll_test_log(2)`,
+utility function have been prepared. The function takes a `FILE *` as first
+argument, found in the `struct test_env`, and the function identifier as
+second argument, returning the json payload found in the log file, if any.
+
+For more information on writing test cases see
+[Continuous Integration at IOPSYS](https://dev.iopsys.eu/training/iopsyswrt-module-development/blob/master/testing/README.md)
diff --git a/docs/ubus.splash.md b/docs/ubus.splash.md
new file mode 100644
index 0000000000000000000000000000000000000000..ab638842a12aa805414a7744b5e67e910d05a4c5
--- /dev/null
+++ b/docs/ubus.splash.md
@@ -0,0 +1,6 @@
+# Ubus Generated APIs
+
+* [WiFi](./api/wifi.md)
+* [Access Point](./api/wifi.ap.md)
+* [Radio](./api/wifi.radio.md)
+* [WiFi Protected Setup](./api/wifi.wps.md)
diff --git a/gitlab-ci/functional-api-test.sh b/gitlab-ci/functional-api-test.sh
new file mode 100755
index 0000000000000000000000000000000000000000..07fac0bcd8fda304629c739e49039cc54706ca85
--- /dev/null
+++ b/gitlab-ci/functional-api-test.sh
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+echo "preparation script"
+
+pwd
+
+make coverage -C ./
+supervisorctl status all
+supervisorctl update
+sleep 3
+supervisorctl status all
+
+# run API validation
+ubus-api-validator -d ./test/api/json/ > ./api-result.log
+supervisorctl stop all
+supervisorctl status
+
+#report part
+gcovr -r . --html --html-details -o ./api-test-coverage.html
+gcovr -r .
+cp /opt/work/memory-report.xml /builds/iopsys/wifimngr/api-test-memory-report.xml
+tap-junit --input ./api-result.log --output report
+
+
+
diff --git a/gitlab-ci/functional-test.sh b/gitlab-ci/functional-test.sh
new file mode 100755
index 0000000000000000000000000000000000000000..8b0829a07e8bdc9266cae69ebda131fe2fbf5922
--- /dev/null
+++ b/gitlab-ci/functional-test.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+echo "preparation script"
+
+pwd
+
+supervisorctl status all
+supervisorctl update
+sleep 3
+supervisorctl status all
+
+make functional-test -C ./
+
+supervisorctl stop all
+supervisorctl status
+
+#report part
+#GitLab-CI output
+gcovr -r .
+# Artefact
+gcovr -r . --html --html-details -o ./functional-test-coverage.html
+
diff --git a/gitlab-ci/iopsys-supervisord.conf b/gitlab-ci/iopsys-supervisord.conf
new file mode 100644
index 0000000000000000000000000000000000000000..c6749e4ee65eabb9c55d5c76e20ebe2e868f15b0
--- /dev/null
+++ b/gitlab-ci/iopsys-supervisord.conf
@@ -0,0 +1,5 @@
+[program:ubusd]
+command=/bin/bash -c "/usr/sbin/ubusd"
+
+[program:wifimngr]
+command=/bin/bash -c "/usr/bin/valgrind --xml=yes --xml-file=memory-report.xml --leak-check=full --show-reachable=yes --show-leak-kinds=all --errors-for-leak-kinds=all --error-exitcode=1 --track-origins=yes /builds/iopsys/wifimngr/wifimngr"
diff --git a/gitlab-ci/setup.sh b/gitlab-ci/setup.sh
new file mode 100755
index 0000000000000000000000000000000000000000..41b5c2c8fcf0370985e6d52e13838fa65333ca45
--- /dev/null
+++ b/gitlab-ci/setup.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+echo "preparation script"
+
+pwd
+
+cp -r ./test/files/etc/* /etc/
+cp -r ./schemas/ubus/* /usr/share/rpcd/schemas
+cp ./gitlab-ci/iopsys-supervisord.conf /etc/supervisor/conf.d/
+
+ls /etc/config/
+ls /usr/share/rpcd/schemas/
+ls /etc/supervisor/conf.d/
+
diff --git a/gitlab-ci/unit-test.sh b/gitlab-ci/unit-test.sh
new file mode 100755
index 0000000000000000000000000000000000000000..9dce6f3782705b9219e0d6eb0ca614738daeb268
--- /dev/null
+++ b/gitlab-ci/unit-test.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+echo "preparation script"
+
+pwd
+
+make unit-test -C ./
+
+#report part
+#GitLab-CI output
+gcovr -r .
+# Artefact
+gcovr -r . --html --html-details -o ./unit-test-coverage.html
diff --git a/main.c b/main.c
index f35a335c137cfb8aacded2c873dda5a8abbf6d79..7366cc6780e6592449f00103a396401bba4ca8cf 100644
--- a/main.c
+++ b/main.c
@@ -115,7 +115,7 @@ out_exit:
 	return -1;
 }
 
-static int wifimngr_event_main(const char *evmap_file)
+int wifimngr_event_main(const char *evmap_file)
 {
 	struct json_object *jevs, *jev_array;
 	int evproc = 0;
diff --git a/schemas/ubus/definitions/definitions.json b/schemas/ubus/definitions/definitions.json
new file mode 100644
index 0000000000000000000000000000000000000000..872f01ccd3559f1bd04c47a5f6586a7ce7dc373d
--- /dev/null
+++ b/schemas/ubus/definitions/definitions.json
@@ -0,0 +1,171 @@
+{
+	"$schema": "http://json-schema.org/draft-07/schema#",
+	"$id": "https://www.iopsys.eu/definitions.json",
+	"definitions": {
+		"channel_2_t": {
+			"title": "2.4GHz Channel",
+			"type": "integer",
+			"default": "auto",
+			"minimum": 1,
+			"maximum": 14
+		},
+		"channel_5_t": {
+			"title": "5GHz Channel",
+			"type": "integer",
+			"default": "auto",
+			"minimum": 32,
+			"maximum": 200
+		},
+		"channels_2_t": {
+			"title": "2.4GHz Channels",
+			"type": "array",
+			"items": { "$ref": "https://www.iopsys.eu/definitions.json#/definitions/channel_2_t"}
+		},
+		"channels_5_t": {
+			"title": "5GHz Channels",
+			"type": "array",
+			"items": { "$ref": "https://www.iopsys.eu/definitions.json#/definitions/channel_5_t"}
+		},
+		"macaddr_t": {
+			"title": "MAC Address",
+			"type": "string",
+			"minLength": 17,
+			"maxLength": 17,
+			"pattern":"^([0-9a-fA-F][0-9a-fA-F]:){5}[0-9a-fA-F][0-9a-fA-F]$"
+		},
+		"nasid_t": {
+			"title": "MAC Address",
+			"type": "string",
+			"minLength": 1,
+			"maxLength": 48,
+			"pattern":"^([0-9a-fA-F]){1,48}$"
+		},
+		"iface_t": {
+			"title": "Interface",
+			"type": "string",
+			"minLength": 1,
+			"maxLength": 16
+		},
+		"ssid_t": {
+			"title": "SSID",
+			"type": "string",
+			"minLength": 0,
+			"maxLength": 32
+		},
+		"nstations_t": {
+			"title": "Number of stations",
+			"type": "integer",
+			"minimum": 0,
+			"maximum": 2007
+		},
+		"bandwidth_2_t": {
+			"title": "Bandwidth",
+			"type": "integer",
+			"enum": [
+				20,
+				40
+			]
+		},
+		"bandwidth_5_t": {
+			"title": "Bandwidth",
+			"type": "integer",
+			"enum": [
+				20,
+				40,
+				80,
+				160
+			]
+		},
+		"rssi_t": {
+			"title": "RSSI",
+			"type": "integer",
+			"minimum": -128,
+			"maximum": 0
+		},
+		"noisepower_t": {
+			"title": "Noise",
+			"type": "integer",
+			"minimum": -127,
+			"maximum": 0
+		},
+		"band_t": {
+			"title": "WiFi Band",
+			"type": "string",
+			"enum": ["2.4GHz", "5GHz"]
+		},
+		"standards_2_t": {
+			"title": "2.4GHz WiFi Standards",
+			"type": "array",
+			"items": {
+				"type": "string",
+				"enum": ["b", "g", "n", "ax"]
+			}
+		},
+		"standards_5_t": {
+			"title": "5GHz WiFi Standards",
+			"type": "array",
+			"items": {
+				"type": "string",
+				"enum": ["a", "n", "ac", "ax"]
+			}
+		},
+		"rxtx_t": {
+			"type": "integer",
+			"minimum": 0
+		},
+		"pin_t": {
+			"type": "string",
+			"minLength": 8,
+			"maxLength": 8,
+			"pattern": "^[0-9]*$"
+		},
+		"bandwidth_t": {
+			"title": "Bandwidth",
+			"type": "integer",
+			"enum": [
+				20,
+				40,
+				80,
+				160
+			]
+		},
+		"aps_t": {
+			"type": "array",
+			"items": {
+				"type": "object",
+				"required": [
+					"ifname",
+					"status",
+					"ssid",
+					"bssid"
+				],
+				"properties": {
+					"ifname": {
+						"type": "string",
+						"minLength": 1,
+						"maxLength": 16
+					},
+					"status": { "type": "string" },
+					"ssid": {
+						"type": "string",
+						"minLength": 0,
+						"maxLength": 32
+					},
+					"bssid": { "bssid": { "$ref": "https://www.iopsys.eu/definitions.json#/definitions/macaddr_t" } }
+				}
+			}
+		},
+		"oui_t": {
+			"title": "Three byte oui",
+			"type": "string",
+			"minLength": 9,
+			"maxLength": 9,
+			"pattern":"^([0-9a-fA-F][0-9a-fA-F]){3}$"
+		},
+		"data_t": {
+			"title": "Hex String",
+			"type": "string",
+			"pattern": "^[0-9a-fA-F]+"
+		}
+	}
+}
diff --git a/schemas/ubus/wifi.ap.json b/schemas/ubus/wifi.ap.json
new file mode 100644
index 0000000000000000000000000000000000000000..c05d871578b81084fc30ec89785580c11cd22e1a
--- /dev/null
+++ b/schemas/ubus/wifi.ap.json
@@ -0,0 +1,1192 @@
+{
+    "definitions": {
+		"channel_2_t": {
+			"title": "2.4GHz Channel",
+			"type": "integer",
+			"default": "auto",
+			"minimum": 1,
+			"maximum": 14
+		},
+		"channel_5_t": {
+			"title": "5GHz Channel",
+			"type": "integer",
+			"default": "auto",
+			"minimum": 32,
+			"maximum": 200
+		},
+		"channels_2_t": {
+			"title": "2.4GHz Channels",
+			"type": "array",
+			"items": { "$ref": "#/definitions/channel_2_t"}
+		},
+		"channels_5_t": {
+			"title": "5GHz Channels",
+			"type": "array",
+			"items": { "$ref": "#/definitions/channel_5_t"}
+		},
+		"macaddr_t": {
+			"title": "MAC Address",
+			"type": "string",
+			"minLength": 17,
+			"maxLength": 17,
+			"pattern":"^([0-9a-fA-F][0-9a-fA-F]:){5}[0-9a-fA-F][0-9a-fA-F]$"
+		},
+		"nasid_t": {
+			"title": "MAC Address",
+			"type": "string",
+			"minLength": 1,
+			"maxLength": 48,
+			"pattern":"^([0-9a-fA-F]){1,48}$"
+		},
+		"iface_t": {
+			"title": "Interface",
+			"type": "string",
+			"minLength": 1,
+			"maxLength": 16
+		},
+		"ssid_t": {
+			"title": "SSID",
+			"type": "string",
+			"minLength": 0,
+			"maxLength": 32
+		},
+		"nstations_t": {
+			"title": "Number of stations",
+			"type": "integer",
+			"minimum": 0,
+			"maximum": 2007
+		},
+		"bandwidth_2_t": {
+			"title": "Bandwidth",
+			"type": "integer",
+			"enum": [
+				20,
+				40
+			]
+		},
+		"bandwidth_5_t": {
+			"title": "Bandwidth",
+			"type": "integer",
+			"enum": [
+				20,
+				40,
+				80,
+				160
+			]
+		},
+		"rssi_t": {
+			"title": "RSSI",
+			"type": "integer",
+			"minimum": -128,
+			"maximum": 0
+		},
+		"noisepower_t": {
+			"title": "Noise",
+			"type": "integer",
+			"minimum": -127,
+			"maximum": 0
+		},
+		"band_t": {
+			"title": "WiFi Band",
+			"type": "string",
+			"enum": ["2GHz", "5GHz"]
+		},
+		"standards_2_t": {
+			"title": "2.4GHz WiFi Standards",
+			"type": "array",
+			"items": {
+				"type": "string",
+				"enum": ["b", "g", "n", "ax"]
+			}
+		},
+		"standards_5_t": {
+			"title": "5GHz WiFi Standards",
+			"type": "array",
+			"items": {
+				"type": "string",
+				"enum": ["a", "n", "ac", "ax"]
+			}
+		},
+		"rxtx_t": {
+			"type": "integer",
+			"minimum": 0
+		},
+		"pin_t": {
+			"type": "string",
+			"minLength": 8,
+			"maxLength": 8,
+			"pattern": "^[0-9]*$"
+		},
+		"bandwidth_t": {
+			"title": "Bandwidth",
+			"type": "integer",
+			"enum": [
+				20,
+				40,
+				80,
+				160
+			]
+		},
+		"aps_t": {
+			"type": "array",
+			"items": {
+				"type": "object",
+				"required": [
+					"ifname",
+					"status",
+					"ssid",
+					"bssid"
+				],
+				"properties": {
+					"ifname": {
+						"type": "string",
+						"minLength": 1,
+						"maxLength": 16
+					},
+					"status": { "type": "string" },
+					"ssid": {
+						"type": "string",
+						"minLength": 0,
+						"maxLength": 32
+					},
+					"bssid": { "bssid": { "$ref": "#/definitions/macaddr_t" } }
+				}
+			}
+		},
+		"oui_t": {
+			"title": "Three byte oui",
+			"type": "string",
+			"minLength": 9,
+			"maxLength": 9,
+			"pattern":"^([0-9a-fA-F][0-9a-fA-F]){3}$"
+		},
+		"data_t": {
+			"title": "Hex String",
+			"type": "string",
+			"pattern": "^[0-9a-fA-F]+"
+		}
+	},
+    "title": "wifi.ap.<name>",
+    "regex": true,
+    "object": "^wifi\\.ap\\..*",
+    "$schema": "http://json-schema.org/draft-07/schema#",
+    "$id": "https://www.iopsys.eu/wifi.ap.json",
+    "additionalProperties": false,
+    "properties": {
+        "add_neighbor": {
+            "type": "object",
+            "properties": {
+                "input": {
+                    "type": "object",
+                    "required": [
+                        "bssid",
+                        "channel",
+                        "bssid_info",
+                        "reg",
+                        "phy"
+                    ],
+                    "properties": {
+                        "bssid": {
+                            "$ref": "#/definitions/macaddr_t"
+                        },
+                        "channel": {
+                            "oneOf": [
+                                {
+                                    "$ref": "#/definitions/channel_2_t"
+                                },
+                                {
+                                    "$ref": "#/definitions/channel_5_t"
+                                }
+                            ]
+                        },
+                        "bssid_info": {
+                            "type": "string"
+                        },
+                        "reg": {
+                            "type": "integer",
+                            "minimum": 0
+                        },
+                        "phy": {
+                            "type": "integer",
+                            "minimum": 0
+                        }
+                    }
+                },
+                "output": {
+                    "type": "object",
+                    "properties": {}
+                }
+            }
+        },
+        "del_neighbor": {
+            "type": "object",
+            "properties": {
+                "input": {
+                    "type": "object",
+                    "required": [
+                        "bssid"
+                    ],
+                    "properties": {
+                        "bssid": {
+                            "$ref": "#/definitions/macaddr_t"
+                        }
+                    }
+                },
+                "output": {
+                    "type": "object",
+                    "properties": {}
+                }
+            }
+        },
+        "request_neighbor": {
+            "type": "object",
+            "properties": {
+                "input": {
+                    "type": "object",
+                    "required": [
+                        "client"
+                    ],
+                    "properties": {
+                        "ssid": {
+                            "$ref": "#/definitions/ssid_t"
+                        },
+                        "client": {
+                            "$ref": "#/definitions/macaddr_t"
+                        }
+                    }
+                },
+                "output": {
+                    "type": "object",
+                    "properties": {}
+                }
+            }
+        },
+        "request_transition": {
+            "type": "object",
+            "properties": {
+                "input": {
+                    "type": "object",
+                    "required": [
+                        "client",
+                        "bssid"
+                    ],
+                    "properties": {
+                        "client": {
+                            "$ref": "#/definitions/macaddr_t"
+                        },
+                        "bssid": {
+                            "type": "array",
+                            "items": {
+                                "$ref": "#/definitions/macaddr_t"
+                            }
+                        },
+                        "timeout": {
+                            "type": "integer"
+                        }
+                    }
+                },
+                "output": {
+                    "type": "object",
+                    "properties": {}
+                }
+            }
+        },
+        "monitor": {
+            "type": "object",
+            "properties": {
+                "intput": {
+                    "type": "object",
+                    "required": [
+                        "sta"
+                    ],
+                    "properties": {
+                        "sta": {
+                            "$ref": "#/definitions/macaddr_t"
+                        },
+                        "get": {
+                            "type": "integer"
+                        }
+                    }
+                },
+                "output": {
+                    "type": "object",
+                    "properties": {}
+                }
+            }
+        },
+        "add_vendor_ie": {
+            "type": "object",
+            "properties": {
+                "input": {
+                    "type": "object",
+                    "required": [
+                        "mgmt",
+                        "oui",
+                        "data"
+                    ],
+                    "properties": {
+                        "mgmt": {
+                            "type": "integer"
+                        },
+                        "oui": {
+                            "$ref": "#/definitions/oui_t"
+                        },
+                        "data": {
+                            "$ref": "#/definitions/data_t"
+                        }
+                    }
+                },
+                "output": {
+                    "type": "object",
+                    "properties": {}
+                }
+            }
+        },
+        "del_vendor_ie": {
+            "type": "object",
+            "properties": {
+                "intput": {
+                    "type": "object",
+                    "required": [
+                        "mgmt",
+                        "oui",
+                        "data"
+                    ],
+                    "properties": {
+                        "mgmt": {
+                            "type": "integer"
+                        },
+                        "oui": {
+                            "$ref": "#/definitions/oui_t"
+                        },
+                        "data": {
+                            "$ref": "#/definitions/data_t"
+                        }
+                    }
+                },
+                "output": {
+                    "type": "object",
+                    "properties": {}
+                }
+            }
+        },
+        "disconnect": {
+            "type": "object",
+            "properties": {
+                "input": {
+                    "type": "object",
+                    "required": [
+                        "sta"
+                    ],
+                    "properties": {
+                        "sta": {
+                            "$ref": "#/definitions/macaddr_t"
+                        }
+                    }
+                },
+                "output": {
+                    "type": "object",
+                    "properties": {}
+                }
+            }
+        },
+        "status": {
+            "type": "object",
+            "properties": {
+                "input": {
+                    "type": "object",
+                    "properties": {}
+                },
+                "output": {
+                    "type": "object",
+                    "required": [
+                        "ifname",
+                        "status",
+                        "ssid",
+                        "bssid",
+                        "encryption",
+                        "bandwidth",
+                        "standard",
+                        "num_stations",
+                        "utilization",
+                        "adm_capacity",
+                        "hidden",
+                        "max_stations",
+                        "capabilities"
+                    ],
+                    "properties": {
+                        "ifname": {
+                            "$ref": "#/definitions/iface_t"
+                        },
+                        "status": {
+                            "type": "string"
+                        },
+                        "ssid": {
+                            "$ref": "#/definitions/ssid_t"
+                        },
+                        "bssid": {
+                            "$ref": "#/definitions/macaddr_t"
+                        },
+                        "encryption": {
+                            "type": "string"
+                        },
+                        "bandwidth": {
+                            "oneOf": [
+                                {
+                                    "$ref": "#/definitions/bandwidth_2_t"
+                                },
+                                {
+                                    "$ref": "#/definitions/bandwidth_5_t"
+                                }
+                            ]
+                        },
+                        "standard": {
+                            "type": "string"
+                        },
+                        "num_stations": {
+                            "$ref": "#/definitions/nstations_t"
+                        },
+                        "utilization": {
+                            "type": "integer",
+                            "minimum": 0,
+                            "maximum": 100
+                        },
+                        "adm_capacity": {
+                            "type": "integer"
+                        },
+                        "hidden": {
+                            "type": "boolean"
+                        },
+                        "max_stations": {
+                            "$ref": "#/definitions/nstations_t"
+                        },
+                        "capabilities": {
+                            "type": "object",
+                            "required": [
+                                "wmm",
+                                "apsd",
+                                "shortslot",
+                                "dot11h"
+                            ],
+                            "properties": {
+                                "wmm": {
+                                    "type": "boolean"
+                                },
+                                "apsd": {
+                                    "type": "boolean"
+                                },
+                                "shortslot": {
+                                    "type": "boolean"
+                                },
+                                "dot11h": {
+                                    "type": "boolean"
+                                },
+                                "dot11k": {
+                                    "required": [
+                                        "dot11k_link_meas",
+                                        "dot11k_nbr_report",
+                                        "dot11k_bcn_passive",
+                                        "dot11k_bcn_active",
+                                        "dot11k_bcn_table",
+                                        "dot11k_rcpi",
+                                        "dot11k_rsni"
+                                    ],
+                                    "type": "object",
+                                    "properties": {
+                                        "dot11k_link_meas": {
+                                            "type": "boolean"
+                                        },
+                                        "dot11k_nbr_report": {
+                                            "type": "boolean"
+                                        },
+                                        "dot11k_bcn_passive": {
+                                            "type": "boolean"
+                                        },
+                                        "dot11k_bcn_active": {
+                                            "type": "boolean"
+                                        },
+                                        "dot11k_bcn_table": {
+                                            "type": "boolean"
+                                        },
+                                        "dot11k_rcpi": {
+                                            "type": "boolean"
+                                        },
+                                        "dot11k_rsni": {
+                                            "type": "boolean"
+                                        }
+                                    }
+                                },
+                                "dot11n": {
+                                    "required": [
+                                        "dot11n_ldpc",
+                                        "dot11n_40",
+                                        "dot11n_ps",
+                                        "dot11n_sgi20",
+                                        "dot11n_sgi40",
+                                        "dot11n_tx_stbc",
+                                        "dot11n_rx_stbc"
+                                    ],
+                                    "type": "object",
+                                    "properties": {
+                                        "dot11n_ldpc": {
+                                            "type": "boolean"
+                                        },
+                                        "dot11n_40": {
+                                            "type": "boolean"
+                                        },
+                                        "dot11n_ps": {
+                                            "type": "boolean"
+                                        },
+                                        "dot11n_sgi20": {
+                                            "type": "boolean"
+                                        },
+                                        "dot11n_sgi40": {
+                                            "type": "boolean"
+                                        },
+                                        "dot11n_tx_stbc": {
+                                            "type": "boolean"
+                                        },
+                                        "dot11n_rx_stbc": {
+                                            "type": "boolean"
+                                        }
+                                    }
+                                },
+                                "dot11ac": {
+                                    "required": [
+                                        "dot11ac_160",
+                                        "dot11ac_8080",
+                                        "dot11ac_mpdu_max",
+                                        "dot11ac_sgi80",
+                                        "dot11ac_sgi160",
+                                        "dot11ac_rx_ldpc",
+                                        "dot11ac_tx_stbc",
+                                        "dot11ac_rx_stbc_1ss",
+                                        "dot11ac_rx_stbc_2ss",
+                                        "dot11ac_rx_stbc_3ss",
+                                        "dot11ac_rx_stbc_4ss",
+                                        "dot11ac_su_beamformer",
+                                        "dot11ac_su_beamformee",
+                                        "dot11ac_mu_beamformer",
+                                        "dot11ac_mu_beamformee"
+                                    ],
+                                    "type": "object",
+                                    "properties": {
+                                        "dot11ac_160": {
+                                            "type": "boolean"
+                                        },
+                                        "dot11ac_8080": {
+                                            "type": "boolean"
+                                        },
+                                        "dot11ac_mpdu_max": {
+                                            "type": "integer",
+                                            "minimum": 0,
+                                            "maximum": 65535
+                                        },
+                                        "dot11ac_sgi80": {
+                                            "type": "boolean"
+                                        },
+                                        "dot11ac_sgi160": {
+                                            "type": "boolean"
+                                        },
+                                        "dot11ac_rx_ldpc": {
+                                            "type": "boolean"
+                                        },
+                                        "dot11ac_tx_stbc": {
+                                            "type": "boolean"
+                                        },
+                                        "dot11ac_rx_stbc_1ss": {
+                                            "type": "boolean"
+                                        },
+                                        "dot11ac_rx_stbc_2ss": {
+                                            "type": "boolean"
+                                        },
+                                        "dot11ac_rx_stbc_3ss": {
+                                            "type": "boolean"
+                                        },
+                                        "dot11ac_rx_stbc_4ss": {
+                                            "type": "boolean"
+                                        },
+                                        "dot11ac_su_beamformer": {
+                                            "type": "boolean"
+                                        },
+                                        "dot11ac_su_beamformee": {
+                                            "type": "boolean"
+                                        },
+                                        "dot11ac_mu_beamformer": {
+                                            "type": "boolean"
+                                        },
+                                        "dot11ac_mu_beamformee": {
+                                            "type": "boolean"
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "stats": {
+            "type": "object",
+            "properties": {
+                "input": {
+                    "type": "object",
+                    "properties": {}
+                },
+                "output": {
+                    "type": "object",
+                    "required": [
+                        "tx_bytes",
+                        "tx_packets",
+                        "tx_unicast_packets",
+                        "tx_multicast_packets",
+                        "tx_broadcast_packets",
+                        "tx_error_packets",
+                        "tx_retrans_packets",
+                        "tx_retrans_fail_packets",
+                        "tx_retry_packets",
+                        "tx_multi_retry_packets",
+                        "tx_dropped_packets",
+                        "ack_fail_packets",
+                        "aggregate_packets",
+                        "rx_bytes",
+                        "rx_packets",
+                        "rx_unicast_packets",
+                        "rx_multicast_packets",
+                        "rx_broadcast_packets",
+                        "rx_error_packets",
+                        "rx_dropped_packets",
+                        "rx_unknown_packets"
+                    ],
+                    "properties": {
+                        "tx_bytes": {
+                            "$ref": "#/definitions/rxtx_t"
+                        },
+                        "tx_packets": {
+                            "$ref": "#/definitions/rxtx_t"
+                        },
+                        "tx_unicast_packets": {
+                            "$ref": "#/definitions/rxtx_t"
+                        },
+                        "tx_multicast_packets": {
+                            "$ref": "#/definitions/rxtx_t"
+                        },
+                        "tx_broadcast_packets": {
+                            "$ref": "#/definitions/rxtx_t"
+                        },
+                        "tx_error_packets": {
+                            "$ref": "#/definitions/rxtx_t"
+                        },
+                        "tx_retrans_packets": {
+                            "$ref": "#/definitions/rxtx_t"
+                        },
+                        "tx_retrans_fail_packets": {
+                            "$ref": "#/definitions/rxtx_t"
+                        },
+                        "tx_retry_packets": {
+                            "$ref": "#/definitions/rxtx_t"
+                        },
+                        "tx_multi_retry_packets": {
+                            "$ref": "#/definitions/rxtx_t"
+                        },
+                        "tx_dropped_packets": {
+                            "$ref": "#/definitions/rxtx_t"
+                        },
+                        "ack_fail_packets": {
+                            "$ref": "#/definitions/rxtx_t"
+                        },
+                        "aggregate_packets": {
+                            "$ref": "#/definitions/rxtx_t"
+                        },
+                        "rx_bytes": {
+                            "$ref": "#/definitions/rxtx_t"
+                        },
+                        "rx_packets": {
+                            "$ref": "#/definitions/rxtx_t"
+                        },
+                        "rx_unicast_packets": {
+                            "$ref": "#/definitions/rxtx_t"
+                        },
+                        "rx_multicast_packets": {
+                            "$ref": "#/definitions/rxtx_t"
+                        },
+                        "rx_broadcast_packets": {
+                            "$ref": "#/definitions/rxtx_t"
+                        },
+                        "rx_error_packets": {
+                            "$ref": "#/definitions/rxtx_t"
+                        },
+                        "rx_dropped_packets": {
+                            "$ref": "#/definitions/rxtx_t"
+                        },
+                        "rx_unknown_packets": {
+                            "$ref": "#/definitions/rxtx_t"
+                        }
+                    }
+                }
+            }
+        },
+        "stations": {
+            "type": "object",
+            "properties": {
+                "input": {
+                    "type": "object",
+                    "properties": {
+                        "sta": {
+                            "$ref": "#/definitions/macaddr_t"
+                        }
+                    }
+                },
+                "output": {
+                    "type": "object",
+                    "required": [
+                        "stations"
+                    ],
+                    "properties": {
+                        "stations": {
+                            "type": "array",
+                            "items": {
+                                "type": "object",
+                                "required": [
+                                    "macaddr",
+                                    "wdev",
+                                    "frequency",
+                                    "rssi",
+                                    "snr",
+                                    "idle",
+                                    "in_network",
+                                    "tx_airtime",
+                                    "rx_airtime",
+                                    "airtime",
+                                    "max_rate",
+                                    "status",
+                                    "capabilities",
+                                    "stats",
+                                    "rssi_per_antenna"
+                                ],
+                                "properties": {
+                                    "macaddr": {
+                                        "$ref": "#/definitions/macaddr_t"
+                                    },
+                                    "wdev": {
+                                        "$ref": "#/definitions/iface_t"
+                                    },
+                                    "frequency": {
+                                        "$ref": "#/definitions/band_t"
+                                    },
+                                    "rssi": {
+                                        "$ref": "#/definitions/rssi_t"
+                                    },
+                                    "snr": {
+                                        "type": "integer",
+                                        "minimum": 0,
+                                        "maximum": 100
+                                    },
+                                    "idle": {
+                                        "type": "integer",
+                                        "minimum": 0
+                                    },
+                                    "in_network": {
+                                        "type": "integer",
+                                        "minimum": 0
+                                    },
+                                    "tx_airtime": {
+                                        "type": "integer",
+                                        "minimum": 0,
+                                        "maximum": 100
+                                    },
+                                    "rx_airtime": {
+                                        "type": "integer",
+                                        "minimum": 0,
+                                        "maximum": 100
+                                    },
+                                    "airtime": {
+                                        "type": "integer",
+                                        "minimum": 0,
+                                        "maximum": 100
+                                    },
+                                    "max_rate": {
+                                        "type": "integer",
+                                        "minimum": 0
+                                    },
+                                    "status": {
+                                        "type": "object",
+                                        "required": [
+                                            "wmm",
+                                            "ps"
+                                        ],
+                                        "properties": {
+                                            "wmm": {
+                                                "type": "boolean"
+                                            },
+                                            "ps": {
+                                                "type": "boolean"
+                                            }
+                                        }
+                                    },
+                                    "capabilities": {
+                                        "type": "object",
+                                        "required": [
+                                            "wmm",
+                                            "apsd",
+                                            "shortslot",
+                                            "dot11h",
+                                            "2040coex",
+                                            "psmp",
+                                            "proxy_arp",
+                                            "dot11v_btm"
+                                        ],
+                                        "properties": {
+                                            "wmm": {
+                                                "type": "boolean"
+                                            },
+                                            "apsd": {
+                                                "type": "boolean"
+                                            },
+                                            "shortslot": {
+                                                "type": "boolean"
+                                            },
+                                            "dot11h": {
+                                                "type": "boolean"
+                                            },
+                                            "dot11k": {
+                                                "required": [
+                                                    "dot11k_link_meas",
+                                                    "dot11k_nbr_report",
+                                                    "dot11k_bcn_passive",
+                                                    "dot11k_bcn_active",
+                                                    "dot11k_bcn_table",
+                                                    "dot11k_rcpi",
+                                                    "dot11k_rsni"
+                                                ],
+                                                "type": "object",
+                                                "properties": {
+                                                    "dot11k_link_meas": {
+                                                        "type": "boolean"
+                                                    },
+                                                    "dot11k_nbr_report": {
+                                                        "type": "boolean"
+                                                    },
+                                                    "dot11k_bcn_passive": {
+                                                        "type": "boolean"
+                                                    },
+                                                    "dot11k_bcn_active": {
+                                                        "type": "boolean"
+                                                    },
+                                                    "dot11k_bcn_table": {
+                                                        "type": "boolean"
+                                                    },
+                                                    "dot11k_rcpi": {
+                                                        "type": "boolean"
+                                                    },
+                                                    "dot11k_rsni": {
+                                                        "type": "boolean"
+                                                    }
+                                                }
+                                            },
+                                            "2040coex": {
+                                                "type": "boolean"
+                                            },
+                                            "psmp": {
+                                                "type": "boolean"
+                                            },
+                                            "proxy_arp": {
+                                                "type": "boolean"
+                                            },
+                                            "dot11v_btm": {
+                                                "type": "boolean"
+                                            },
+                                            "dot11n": {
+                                                "required": [
+                                                    "dot11n_ldpc",
+                                                    "dot11n_40",
+                                                    "dot11n_ps",
+                                                    "dot11n_sgi20",
+                                                    "dot11n_sgi40",
+                                                    "dot11n_tx_stbc",
+                                                    "dot11n_rx_stbc"
+                                                ],
+                                                "type": "object",
+                                                "properties": {
+                                                    "dot11n_ldpc": {
+                                                        "type": "boolean"
+                                                    },
+                                                    "dot11n_40": {
+                                                        "type": "boolean"
+                                                    },
+                                                    "dot11n_ps": {
+                                                        "type": "boolean"
+                                                    },
+                                                    "dot11n_sgi20": {
+                                                        "type": "boolean"
+                                                    },
+                                                    "dot11n_sgi40": {
+                                                        "type": "boolean"
+                                                    },
+                                                    "dot11n_tx_stbc": {
+                                                        "type": "boolean"
+                                                    },
+                                                    "dot11n_rx_stbc": {
+                                                        "type": "boolean"
+                                                    }
+                                                }
+                                            },
+                                            "dot11ac": {
+                                                "required": [
+                                                    "dot11ac_160",
+                                                    "dot11ac_8080",
+                                                    "dot11ac_mpdu_max",
+                                                    "dot11ac_sgi80",
+                                                    "dot11ac_sgi160",
+                                                    "dot11ac_rx_ldpc",
+                                                    "dot11ac_tx_stbc",
+                                                    "dot11ac_rx_stbc_1ss",
+                                                    "dot11ac_rx_stbc_2ss",
+                                                    "dot11ac_rx_stbc_3ss",
+                                                    "dot11ac_rx_stbc_4ss",
+                                                    "dot11ac_su_beamformer",
+                                                    "dot11ac_su_beamformee",
+                                                    "dot11ac_mu_beamformer",
+                                                    "dot11ac_mu_beamformee"
+                                                ],
+                                                "type": "object",
+                                                "properties": {
+                                                    "dot11ac_160": {
+                                                        "type": "boolean"
+                                                    },
+                                                    "dot11ac_8080": {
+                                                        "type": "boolean"
+                                                    },
+                                                    "dot11ac_mpdu_max": {
+                                                        "type": "integer",
+                                                        "minimum": 0,
+                                                        "maximum": 65535
+                                                    },
+                                                    "dot11ac_sgi80": {
+                                                        "type": "boolean"
+                                                    },
+                                                    "dot11ac_sgi160": {
+                                                        "type": "boolean"
+                                                    },
+                                                    "dot11ac_rx_ldpc": {
+                                                        "type": "boolean"
+                                                    },
+                                                    "dot11ac_tx_stbc": {
+                                                        "type": "boolean"
+                                                    },
+                                                    "dot11ac_rx_stbc_1ss": {
+                                                        "type": "boolean"
+                                                    },
+                                                    "dot11ac_rx_stbc_2ss": {
+                                                        "type": "boolean"
+                                                    },
+                                                    "dot11ac_rx_stbc_3ss": {
+                                                        "type": "boolean"
+                                                    },
+                                                    "dot11ac_rx_stbc_4ss": {
+                                                        "type": "boolean"
+                                                    },
+                                                    "dot11ac_su_beamformer": {
+                                                        "type": "boolean"
+                                                    },
+                                                    "dot11ac_su_beamformee": {
+                                                        "type": "boolean"
+                                                    },
+                                                    "dot11ac_mu_beamformer": {
+                                                        "type": "boolean"
+                                                    },
+                                                    "dot11ac_mu_beamformee": {
+                                                        "type": "boolean"
+                                                    }
+                                                }
+                                            }
+                                        }
+                                    },
+                                    "stats": {
+                                        "type": "object",
+                                        "required": [
+                                            "tx_total_pkts",
+                                            "tx_total_bytes",
+                                            "tx_failures",
+                                            "tx_pkts_retries",
+                                            "rx_data_pkts",
+                                            "rx_data_bytes",
+                                            "rx_failures",
+                                            "rate_of_last_tx_pkt",
+                                            "rate_of_last_rx_pkt"
+                                        ],
+                                        "properties": {
+                                            "tx_total_pkts": {
+                                                "$ref": "#/definitions/rxtx_t"
+                                            },
+                                            "tx_total_bytes": {
+                                                "$ref": "#/definitions/rxtx_t"
+                                            },
+                                            "tx_failures": {
+                                                "$ref": "#/definitions/rxtx_t"
+                                            },
+                                            "tx_pkts_retries": {
+                                                "$ref": "#/definitions/rxtx_t"
+                                            },
+                                            "rx_data_pkts": {
+                                                "$ref": "#/definitions/rxtx_t"
+                                            },
+                                            "rx_data_bytes": {
+                                                "$ref": "#/definitions/rxtx_t"
+                                            },
+                                            "rx_failures": {
+                                                "$ref": "#/definitions/rxtx_t"
+                                            },
+                                            "rate_of_last_tx_pkt": {
+                                                "$ref": "#/definitions/rxtx_t"
+                                            },
+                                            "rate_of_last_rx_pkt": {
+                                                "$ref": "#/definitions/rxtx_t"
+                                            }
+                                        }
+                                    },
+                                    "rssi_per_antenna": {
+                                        "type": "array",
+                                        "items": {
+                                            "$ref": "#/definitions/rssi_t"
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        },
+        "list_neighbor": {
+            "type": "object",
+            "properties": {
+                "input": {
+                    "type": "object",
+                    "properties": {
+                        "ssid": {
+                            "$ref": "#/definitions/ssid_t"
+                        },
+                        "client": {
+                            "$ref": "#/definitions/macaddr_t"
+                        }
+                    }
+                },
+                "output": {
+                    "type": "object",
+                    "required": [
+                        "neighbors"
+                    ],
+                    "oneOf": [
+                        {
+                            "properties": {
+                                "neighbors": {
+                                    "type": "array",
+                                    "items": {
+                                        "type": "object",
+                                        "required": [
+                                            "bssid",
+                                            "bss_info",
+                                            "regulatory",
+                                            "channel",
+                                            "phy"
+                                        ],
+                                        "properties": {
+                                            "bssid": {
+                                                "$ref": "#/definitions/macaddr_t"
+                                            },
+                                            "bss_info": {
+                                                "type": "integer",
+                                                "minimum": 0
+                                            },
+                                            "regulatory": {
+                                                "type": "integer",
+                                                "minimum": 0
+                                            },
+                                            "channel": {
+                                                "oneOf": [
+                                                    {
+                                                        "$ref": "#/definitions/channel_2_t"
+                                                    },
+                                                    {
+                                                        "$ref": "#/definitions/channel_5_t"
+                                                    }
+                                                ]
+                                            },
+                                            "phy": {
+                                                "type": "integer",
+                                                "minimum": 0,
+                                                "maximum": 9
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        },
+                        {
+                            "properties": {
+                                "neighbors": {
+                                    "type": "array",
+                                    "items": {
+                                        "type": "object",
+                                        "required": [
+                                            "bssid",
+                                            "rssi",
+                                            "rsni"
+                                        ],
+                                        "properties": {
+                                            "bssid": {
+                                                "$ref": "#/definitions/macaddr_t"
+                                            },
+                                            "rssi": {
+                                                "$ref": "#/definitions/rssi_t"
+                                            },
+                                            "rsni": {
+                                                "type": "integer"
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    ]
+                }
+            }
+        },
+        "assoclist": {
+            "type": "object",
+            "properties": {
+                "input": {
+                    "type": "object",
+                    "properties": {}
+                },
+                "output": {
+                    "type": "object",
+                    "required": [
+                        "assoclist"
+                    ],
+                    "properties": {
+                        "assoclist": {
+                            "type": "array",
+                            "items": {
+                                "type": "object",
+                                "required": [
+                                    "wdev",
+                                    "macaddr"
+                                ],
+                                "properties": {
+                                    "wdev": {
+                                        "$ref": "#/definitions/iface_t"
+                                    },
+                                    "macaddr": {
+                                        "$ref": "#/definitions/macaddr_t"
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/schemas/ubus/wifi.json b/schemas/ubus/wifi.json
new file mode 100644
index 0000000000000000000000000000000000000000..f44aa038cb15b189b21ddd989a6579de73693fc1
--- /dev/null
+++ b/schemas/ubus/wifi.json
@@ -0,0 +1,276 @@
+{
+    "definitions": {
+		"channel_2_t": {
+			"title": "2.4GHz Channel",
+			"type": "integer",
+			"default": "auto",
+			"minimum": 1,
+			"maximum": 14
+		},
+		"channel_5_t": {
+			"title": "5GHz Channel",
+			"type": "integer",
+			"default": "auto",
+			"minimum": 32,
+			"maximum": 200
+		},
+		"channels_2_t": {
+			"title": "2.4GHz Channels",
+			"type": "array",
+			"items": { "$ref": "#/definitions/channel_2_t"}
+		},
+		"channels_5_t": {
+			"title": "5GHz Channels",
+			"type": "array",
+			"items": { "$ref": "#/definitions/channel_5_t"}
+		},
+		"macaddr_t": {
+			"title": "MAC Address",
+			"type": "string",
+			"minLength": 17,
+			"maxLength": 17,
+			"pattern":"^([0-9a-fA-F][0-9a-fA-F]:){5}[0-9a-fA-F][0-9a-fA-F]$"
+		},
+		"nasid_t": {
+			"title": "MAC Address",
+			"type": "string",
+			"minLength": 1,
+			"maxLength": 48,
+			"pattern":"^([0-9a-fA-F]){1,48}$"
+		},
+		"iface_t": {
+			"title": "Interface",
+			"type": "string",
+			"minLength": 1,
+			"maxLength": 16
+		},
+		"ssid_t": {
+			"title": "SSID",
+			"type": "string",
+			"minLength": 0,
+			"maxLength": 32
+		},
+		"nstations_t": {
+			"title": "Number of stations",
+			"type": "integer",
+			"minimum": 0,
+			"maximum": 2007
+		},
+		"bandwidth_2_t": {
+			"title": "Bandwidth",
+			"type": "integer",
+			"enum": [
+				20,
+				40
+			]
+		},
+		"bandwidth_5_t": {
+			"title": "Bandwidth",
+			"type": "integer",
+			"enum": [
+				20,
+				40,
+				80,
+				160
+			]
+		},
+		"rssi_t": {
+			"title": "RSSI",
+			"type": "integer",
+			"minimum": -128,
+			"maximum": 0
+		},
+		"noisepower_t": {
+			"title": "Noise",
+			"type": "integer",
+			"minimum": -127,
+			"maximum": 0
+		},
+		"band_t": {
+			"title": "WiFi Band",
+			"type": "string",
+			"enum": ["2GHz", "5GHz"]
+		},
+		"standards_2_t": {
+			"title": "2.4GHz WiFi Standards",
+			"type": "array",
+			"items": {
+				"type": "string",
+				"enum": ["b", "g", "n", "ax"]
+			}
+		},
+		"standards_5_t": {
+			"title": "5GHz WiFi Standards",
+			"type": "array",
+			"items": {
+				"type": "string",
+				"enum": ["a", "n", "ac", "ax"]
+			}
+		},
+		"rxtx_t": {
+			"type": "integer",
+			"minimum": 0
+		},
+		"pin_t": {
+			"type": "string",
+			"minLength": 8,
+			"maxLength": 8,
+			"pattern": "^[0-9]*$"
+		},
+		"bandwidth_t": {
+			"title": "Bandwidth",
+			"type": "integer",
+			"enum": [
+				20,
+				40,
+				80,
+				160
+			]
+		},
+		"aps_t": {
+			"type": "array",
+			"items": {
+				"type": "object",
+				"required": [
+					"ifname",
+					"status",
+					"ssid",
+					"bssid"
+				],
+				"properties": {
+					"ifname": {
+						"type": "string",
+						"minLength": 1,
+						"maxLength": 16
+					},
+					"status": { "type": "string" },
+					"ssid": {
+						"type": "string",
+						"minLength": 0,
+						"maxLength": 32
+					},
+					"bssid": { "bssid": { "$ref": "#/definitions/macaddr_t" } }
+				}
+			}
+		},
+		"oui_t": {
+			"title": "Three byte oui",
+			"type": "string",
+			"minLength": 9,
+			"maxLength": 9,
+			"pattern":"^([0-9a-fA-F][0-9a-fA-F]){3}$"
+		},
+		"data_t": {
+			"title": "Hex String",
+			"type": "string",
+			"pattern": "^[0-9a-fA-F]+"
+		}
+	},
+    "$schema": "http://json-schema.org/draft-07/schema#",
+    "$id": "https://www.iopsys.eu/wifi.json",
+    "type": "object",
+    "title": "wifi",
+    "object": "wifi",
+	"additionalProperties": false,
+    "properties": {
+        "status": {
+            "type": "object",
+            "properties": {
+                "input": {
+                    "type": "object",
+                    "properties": {}
+                },
+                "output": {
+                    "type": "object",
+                    "required": [
+                        "radios"
+                    ],
+                    "properties": {
+                        "radios": {
+                            "type": "array",
+                            "items": {
+                                "type": "object",
+                                "required": [
+                                    "name",
+                                    "isup",
+                                    "standard",
+                                    "country",
+                                    "band",
+                                    "channel",
+                                    "bandwidth",
+                                    "noise",
+                                    "rate",
+                                    "channels",
+                                    "accesspoints",
+                                    "backhauls"
+                                ],
+                                "if": {
+                                    "properties": {
+                                        "band": {
+                                            "const": "2GHz"
+                                        }
+                                    }
+                                },
+                                "then": {
+                                    "properties": {
+                                        "channel": {
+                                            "$ref": "#/definitions/channel_2_t"
+                                        },
+                                        "channels": {
+                                            "$ref": "#/definitions/channels_2_t"
+                                        }
+                                    }
+                                },
+                                "else": {
+                                    "properties": {
+                                        "channel": {
+                                            "$ref": "#/definitions/channel_5_t"
+                                        },
+                                        "channels": {
+                                            "$ref": "#/definitions/channels_5_t"
+                                        }
+                                    }
+                                },
+                                "properties": {
+                                    "name": {
+                                        "$ref": "#/definitions/iface_t"
+                                    },
+                                    "isup": {
+                                        "type": "boolean"
+                                    },
+                                    "standard": {
+                                        "type": "string"
+                                    },
+                                    "country": {
+                                        "type": "string",
+                                        "minLength": 2,
+                                        "maxLength": 3
+                                    },
+                                    "band": {
+                                        "$ref": "#/definitions/band_t"
+                                    },
+                                    "bandwidth": {
+                                        "$ref": "#/definitions/bandwidth_t"
+                                    },
+                                    "noise": {
+                                        "$ref": "#/definitions/noisepower_t"
+                                    },
+                                    "rate": {
+                                        "type": "integer",
+                                        "minimum": 0
+                                    },
+                                    "accesspoints": {
+                                        "$ref": "#/definitions/aps_t"
+                                    },
+                                    "backhauls": {
+                                        "$ref": "#/definitions/aps_t"
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/schemas/ubus/wifi.radio.json b/schemas/ubus/wifi.radio.json
new file mode 100644
index 0000000000000000000000000000000000000000..0d0030dab5a96c559b69e1f4dd5200de96f0d165
--- /dev/null
+++ b/schemas/ubus/wifi.radio.json
@@ -0,0 +1,569 @@
+{
+	"definitions": {
+		"channel_2_t": {
+			"title": "2.4GHz Channel",
+			"type": "integer",
+			"default": "auto",
+			"minimum": 1,
+			"maximum": 14
+		},
+		"channel_5_t": {
+			"title": "5GHz Channel",
+			"type": "integer",
+			"default": "auto",
+			"minimum": 32,
+			"maximum": 200
+		},
+		"channels_2_t": {
+			"title": "2.4GHz Channels",
+			"type": "array",
+			"items": {
+				"$ref": "#/definitions/channel_2_t"
+			}
+		},
+		"channels_5_t": {
+			"title": "5GHz Channels",
+			"type": "array",
+			"items": {
+				"$ref": "#/definitions/channel_5_t"
+			}
+		},
+		"macaddr_t": {
+			"title": "MAC Address",
+			"type": "string",
+			"minLength": 17,
+			"maxLength": 17,
+			"pattern": "^([0-9a-fA-F][0-9a-fA-F]:){5}[0-9a-fA-F][0-9a-fA-F]$"
+		},
+		"nasid_t": {
+			"title": "MAC Address",
+			"type": "string",
+			"minLength": 1,
+			"maxLength": 48,
+			"pattern": "^([0-9a-fA-F]){1,48}$"
+		},
+		"iface_t": {
+			"title": "Interface",
+			"type": "string",
+			"minLength": 1,
+			"maxLength": 16
+		},
+		"ssid_t": {
+			"title": "SSID",
+			"type": "string",
+			"minLength": 0,
+			"maxLength": 32
+		},
+		"nstations_t": {
+			"title": "Number of stations",
+			"type": "integer",
+			"minimum": 0,
+			"maximum": 2007
+		},
+		"bandwidth_2_t": {
+			"title": "Bandwidth",
+			"type": "integer",
+			"enum": [
+				20,
+				40
+			]
+		},
+		"bandwidth_5_t": {
+			"title": "Bandwidth",
+			"type": "integer",
+			"enum": [
+				20,
+				40,
+				80,
+				160
+			]
+		},
+		"rssi_t": {
+			"title": "RSSI",
+			"type": "integer",
+			"minimum": -128,
+			"maximum": 0
+		},
+		"noisepower_t": {
+			"title": "Noise",
+			"type": "integer",
+			"minimum": -127,
+			"maximum": 0
+		},
+		"band_t": {
+			"title": "WiFi Band",
+			"type": "string",
+			"enum": [
+				"2GHz",
+				"5GHz"
+			]
+		},
+		"standards_2_t": {
+			"title": "2.4GHz WiFi Standards",
+			"type": "string",
+			"enum": [
+				"802.11b",
+				"802.11g",
+				"802.11n",
+				"802.11ax"
+			]
+		},
+		"standards_5_t": {
+			"title": "5GHz WiFi Standards",
+			"type": "string",
+			"enum": [
+				"802.11a",
+				"802.11n",
+				"802.11ac",
+				"802.11ax"
+			]
+		},
+		"rxtx_t": {
+			"type": "integer",
+			"minimum": 0
+		},
+		"pin_t": {
+			"type": "string",
+			"minLength": 8,
+			"maxLength": 8,
+			"pattern": "^[0-9]*$"
+		},
+		"bandwidth_t": {
+			"title": "Bandwidth",
+			"type": "integer",
+			"enum": [
+				20,
+				40,
+				80,
+				160
+			]
+		},
+		"aps_t": {
+			"type": "array",
+			"items": {
+				"type": "object",
+				"required": [
+					"ifname",
+					"status",
+					"ssid",
+					"bssid"
+				],
+				"properties": {
+					"ifname": {
+						"type": "string",
+						"minLength": 1,
+						"maxLength": 16
+					},
+					"status": {
+						"type": "string"
+					},
+					"ssid": {
+						"type": "string",
+						"minLength": 0,
+						"maxLength": 32
+					},
+					"bssid": {
+						"bssid": {
+							"$ref": "#/definitions/macaddr_t"
+						}
+					}
+				}
+			}
+		},
+		"oui_t": {
+			"title": "Three byte oui",
+			"type": "string",
+			"minLength": 9,
+			"maxLength": 9,
+			"pattern": "^([0-9a-fA-F][0-9a-fA-F]){3}$"
+		},
+		"data_t": {
+			"title": "Hex String",
+			"type": "string",
+			"pattern": "^[0-9a-fA-F]+"
+		},
+		"scanresult_t": {
+			"type": "object",
+			"required": [
+				"standard",
+				"bandwidth",
+				"channel",
+				"ssid",
+				"bssid",
+				"encryption",
+				"band",
+				"rssi",
+				"load_stas",
+				"load_utilization",
+				"load_available"
+			],
+			"if": {
+				"properties": {
+					"band": {
+						"const": "2GHz"
+					}
+				}
+			},
+			"then": {
+				"properties": {
+					"standard": {
+						"$ref": "#/definitions/standards_2_t"
+					},
+					"bandwidth": {
+						"$ref": "#/definitions/bandwidth_2_t"
+					},
+					"channel": {
+						"$ref": "#/definitions/channel_2_t"
+					}
+				}
+			},
+			"else": {
+				"properties": {
+					"standard": {
+						"$ref": "#/definitions/standards_5_t"
+					},
+					"bandwidth": {
+						"$ref": "#/definitions/bandwidth_5_t"
+					},
+					"channel": {
+						"$ref": "#/definitions/channel_5_t"
+					}
+				}
+			},
+			"properties": {
+				"ssid": {
+					"$ref": "#/definitions/ssid_t"
+				},
+				"bssid": {
+					"$ref": "#/definitions/macaddr_t"
+				},
+				"encryption": {
+					"type": "string"
+				},
+				"band": {
+					"$ref": "#/definitions/band_t"
+				},
+				"rssi": {
+					"$ref": "#/definitions/rssi_t"
+				},
+				"load_stas": {
+					"type": "integer",
+					"minimum": 0
+				},
+				"load_utilization": {
+					"type": "integer",
+					"minimum": 0,
+					"maximum": 100
+				},
+				"load_available": {
+					"type": "integer",
+					"minimum": 0
+				}
+			}
+		}
+	},
+	"object": "^wifi\\.radio\\..*",
+	"regex": true,
+	"title": "wifi.radio.<name>",
+	"description": "WiFi Radio Object",
+	"$schema": "http://json-schema.org/draft-07/schema#",
+	"$id": "https://www.iopsys.eu/wifi.radio.json",
+	"additionalProperties": false,
+	"properties": {
+		"autochannel": {
+			"type": "object",
+			"properties": {
+				"input": {
+					"type": "object",
+					"properties": {
+						"interval": {
+							"type": "integer"
+						},
+						"algo": {
+							"type": "integer"
+						},
+						"scans": {
+							"type": "integer"
+						}
+					}
+				},
+				"output": {
+					"description": "Auto channel selection",
+					"type": "object",
+					"title": "wifi.radio.autochannel",
+					"required": [
+						"code",
+						"new_channel",
+						"status"
+					],
+					"properties": {
+						"code": {
+							"type": "integer"
+						},
+						"new_channel": {
+							"oneOf": [
+								{
+									"$ref": "#/definitions/channel_2_t"
+								},
+								{
+									"$ref": "#/definitions/channel_5_t"
+								}
+							]
+						},
+						"status": {
+							"type": "string"
+						}
+					}
+				}
+			}
+		},
+		"scan": {
+			"type": "object",
+			"properties": {
+				"input": {
+					"type": "object",
+					"properties": {
+						"ssid": {
+							"$ref": "#/definitions/ssid_t"
+						},
+						"bssid": {
+							"$ref": "#/definitions/macaddr_t"
+						},
+						"channel": {
+							"oneOf": [
+								{
+									"$ref": "#/definitions/channel_2_t"
+								},
+								{
+									"$ref": "#/definitions/channel_5_t"
+								}
+							]
+						}
+					}
+				},
+				"output": {
+					"description": "Trigger a scan",
+					"type": "object",
+					"properties": {}
+				}
+			}
+		},
+		"scanresults": {
+			"type": "object",
+			"properties": {
+				"input": {
+					"type": "object",
+					"properties": {}
+				},
+				"output": {
+					"description": "Show scan results",
+					"type": "object",
+					"oneOf": [
+						{
+							"required": [
+								"accesspoints"
+							],
+							"properties": {
+								"accesspoints": {
+									"type": "array",
+									"items": {
+										"$ref": "#/definitions/scanresult_t"
+									}
+								}
+							}
+						},
+						{
+							"$ref": "#/definitions/scanresult_t"
+						}
+					]
+				}
+			}
+		},
+		"stats": {
+			"type": "object",
+			"properties": {
+				"input": {
+					"type": "object",
+					"properties": {}
+				},
+				"output": {
+					"description": "Radio statistics",
+					"type": "object",
+					"title": "wifi.radio.iface",
+					"required": [
+						"tx_bytes",
+						"tx_packets",
+						"tx_error_packets",
+						"tx_dropped_packets",
+						"rx_bytes",
+						"rx_packets",
+						"rx_error_packets",
+						"rx_dropped_packets",
+						"rx_fcs_error_packets"
+					],
+					"properties": {
+						"tx_bytes": {
+							"$ref": "#/definitions/rxtx_t"
+						},
+						"tx_packets": {
+							"$ref": "#/definitions/rxtx_t"
+						},
+						"tx_error_packets": {
+							"$ref": "#/definitions/rxtx_t"
+						},
+						"tx_dropped_packets": {
+							"$ref": "#/definitions/rxtx_t"
+						},
+						"rx_bytes": {
+							"$ref": "#/definitions/rxtx_t"
+						},
+						"rx_packets": {
+							"$ref": "#/definitions/rxtx_t"
+						},
+						"rx_error_packets": {
+							"$ref": "#/definitions/rxtx_t"
+						},
+						"rx_dropped_packets": {
+							"$ref": "#/definitions/rxtx_t"
+						},
+						"rx_fcs_error_packets": {
+							"$ref": "#/definitions/rxtx_t"
+						}
+					}
+				}
+			}
+		},
+		"status": {
+			"type": "object",
+			"properties": {
+				"input": {
+					"type": "object",
+					"properties": {}
+				},
+				"output": {
+					"description": "Radio status",
+					"type": "object",
+					"title": "wifi.radio.iface",
+					"required": [
+						"radio",
+						"isup",
+						"band",
+						"channel",
+						"bandwidth",
+						"noise",
+						"maxrate",
+						"beacon_int",
+						"dtim_period",
+						"short_retry_limit",
+						"long_retry_limit",
+						"frag_threshold",
+						"rts_threshold"
+					],
+					"if": {
+						"properties": {
+							"band": {
+								"const": "2GHz"
+							}
+						}
+					},
+					"then": {
+						"properties": {
+							"bandwidth": {
+								"$ref": "#/definitions/bandwidth_2_t"
+							},
+							"channel": {
+								"$ref": "#/definitions/channel_2_t"
+							}
+						}
+					},
+					"else": {
+						"properties": {
+							"bandwidth": {
+								"$ref": "#/definitions/bandwidth_5_t"
+							},
+							"channel": {
+								"$ref": "#/definitions/channel_5_t"
+							}
+						}
+					},
+					"properties": {
+						"radio": {
+							"$ref": "#/definitions/iface_t"
+						},
+						"isup": {
+							"type": "boolean"
+						},
+						"band": {
+							"$ref": "#/definitions/band_t"
+						},
+						"noise": {
+							"$ref": "#/definitions/noisepower_t"
+						},
+						"maxrate": {
+							"type": "integer",
+							"minimum": 0
+						},
+						"beacon_int": {
+							"type": "integer",
+							"default": 100,
+							"minimum": 1,
+							"maximum": 65535
+						},
+						"dtim_period": {
+							"type": "integer",
+							"default": 1,
+							"minimum": 1,
+							"maximum": 255
+						},
+						"short_retry_limit": {
+							"type": "integer",
+							"minimum": 1,
+							"maximum": 255
+						},
+						"long_retry_limit": {
+							"type": "integer",
+							"minimum": 1,
+							"maximum": 255
+						},
+						"frag_threshold": {
+							"type": "integer",
+							"default": 2346,
+							"minimum": 256,
+							"maximum": 65535
+						},
+						"rts_threshold": {
+							"type": "integer",
+							"default": 2347,
+							"minimum": 0,
+							"maximum": 65535
+						}
+					}
+				}
+			}
+		},
+		"get": {
+			"type": "object",
+			"properties": {
+				"input": {
+					"type": "object",
+					"properties": {
+						"param": {
+							"type": "string"
+						}
+					}
+				},
+				"output": {
+					"type": "object",
+					"properties": {
+						"status": {
+							"type": "integer"
+						},
+						"values": {
+							"type": "integer"
+						}
+					}
+				}
+			}
+		}
+	}
+}
\ No newline at end of file
diff --git a/schemas/uci/wireless.json b/schemas/uci/wireless.json
new file mode 100644
index 0000000000000000000000000000000000000000..37a78806c04cf5b969b13d7afba5ac49e2b3d324
--- /dev/null
+++ b/schemas/uci/wireless.json
@@ -0,0 +1,121 @@
+{
+    "wireless": [{
+            "section": "wifi-device",
+            "description": "Wifi Device Settings",
+            "multi": true,
+            "options": [{
+                    "name": "channel",
+                    "type": "integer or “auto”",
+                    "required": "yes",
+                    "default": "auto",
+                    "description": "Specifies the wireless channel to use. “auto” defaults to the lowest available channel."
+                },
+                {
+                    "name": "hwmode",
+                    "default": null,
+                    "description": "Selects the wireless protocol to use, possible values are 11b, 11g, and 11a. Note that 11ng and 11na are not available options.",
+                    "type": "string"
+                },
+                {
+                    "name": "country",
+                    "default": null,
+                    "description": "Specifies the country code, affects the available channels and transmission powers. For type broadcom a two letter country code is used (EN or DE). The madwifi driver expects a numeric code.",
+                    "type": "varies"
+                },
+                {
+                    "name": "band",
+                    "default": null,
+                    "description": "Whether radio operates at 2.4GHz or 5GHz.",
+                    "type": "string"
+                },
+                {
+                    "name": "bandwidth",
+                    "default": "80",
+                    "description": "Frequency at which the radio operates.",
+                    "type": "integer"
+                }
+            ]
+        },
+        {
+            "section": "wifi-iface",
+            "description": "Wifi Interface Settings",
+            "multi": true,
+            "options": [{
+                    "name": "device",
+                    "type": "string",
+                    "required": "yes",
+                    "default": "(first device id)",
+                    "description": "Specifies the used wireless adapter, must refer to one of the defined wifi-device sections"
+                },
+                {
+                    "name": "ifname",
+                    "type": "string",
+                    "required": "no",
+                    "default": "(driver default)",
+                    "description": "Specifies a custom name for the Wi-Fi interface, which is otherwise automatically named."
+                },
+                {
+                    "name": "mode",
+                    "required": "yes",
+                    "default": "ap",
+                    "description": "Selects the operation mode of the wireless network interface controller. Possible values are ap, sta, adhoc, wds, monitor, mesh",
+                    "type": "string"
+                },
+                {
+                    "name": "encryption",
+                    "default": null,
+                    "description": "Wireless encryption method. Possible values are: none, wep, psk, psk2. For WEP station mode the default is “open system” authentication. Use wep+shared or wep+open to force a specific mode.",
+                    "type": "string"
+                },
+                {
+                    "name": "wps",
+                    "description": "Enable wps_pushbutton and wps_label.",
+                    "type": "boolean",
+                    "default": true
+                },
+                {
+                    "name": "wps_config",
+                    "description": "List of configuration methods. Currentlly supported methods are: push_button.",
+                    "default": null,
+                    "type": "list"
+                },
+                {
+                    "name": "wps_device_name",
+                    "description": "User-friendly description of device; up to 32 octets encoded in UTF-8.",
+                    "type": "string",
+                    "default": "LEDE AP"
+                },
+                {
+                    "name": "wps_device_type",
+                    "description": "Primary device type. Examples: 1-0050F204-1 (Computer / PC), 1-0050F204-2 (Computer / Server), 5-0050F204-1 (Storage / NAS), 6-0050F204-1 (Network Infrastructure / AP)",
+                    "type": "string",
+                    "default": "6-0050F204-1"
+                },
+                {
+                    "name": "wps_label",
+                    "description": "Enable label configuration method.",
+                    "type": "boolean",
+                    "default": true
+                },
+                {
+                    "name": "wps_manufacturer",
+                    "description": "The manufacturer of the device (up to 64 ASCII characters).",
+                    "type": "string",
+                    "default": "lede-project.org"
+                },
+                {
+                    "name": "wps_pushbutton",
+                    "description": "Enable push-button configuration method.",
+                    "type": "boolean",
+                    "default": true
+                },
+                {
+                    "name": "wps_pin",
+                    "description": "The PIN to use with WPS-PIN (only in external registrar mode?)",
+                    "type": "string",
+                    "default": null
+                }
+            ]
+        }
+    ]
+}
\ No newline at end of file
diff --git a/test/api/json/wifi.ap.validation.json b/test/api/json/wifi.ap.validation.json
new file mode 100644
index 0000000000000000000000000000000000000000..ec72478aba0724f37f94a0858e8d9e4c313e177d
--- /dev/null
+++ b/test/api/json/wifi.ap.validation.json
@@ -0,0 +1,46 @@
+{
+  "object": "wifi.ap.test5",
+  "methods": [
+    {
+      "method": "status",
+      "rc": 0
+    },
+    {
+      "method": "stats",
+      "rc": 0
+    },
+    {
+      "method": "assoclist",
+      "rc": 0
+    },
+    {
+      "method": "stations",
+      "rc": 0
+    },
+    {
+      "method": "stations",
+      "args": {
+         "sta":"50:31:32:33:34:35"
+      },
+      "rc": 0
+    },
+    {
+      "method": "list_neighbor"
+    },
+    {
+      "method": "list_neighbor",
+      "args": {
+         "client": "50:31:32:33:34:35"
+      },
+      "rc": 0
+    },
+    {
+      "method": "hello",
+      "args": {
+         "bssid": "50:31:32:33:34:35"
+      },
+      "rc": 3
+    }
+  ]
+}
+
diff --git a/test/api/json/wifi.radio.validation.json b/test/api/json/wifi.radio.validation.json
new file mode 100644
index 0000000000000000000000000000000000000000..cb51aa9ef8d86a7711f4408c47b12771dda0a0b2
--- /dev/null
+++ b/test/api/json/wifi.radio.validation.json
@@ -0,0 +1,37 @@
+{
+  "object": "wifi.radio.test5",
+  "methods": [
+    {
+      "method": "status",
+      "rc": 0
+    },
+    {
+      "method": "stats",
+      "rc": 0
+    },
+    {
+      "method": "scanresults",
+      "rc": 0
+    },
+    {
+      "method": "scanresults",
+      "args": {
+          "bssid": "00:61:62:63:64:65"
+      },
+      "rc": 0
+    },
+    {
+      "method": "get",
+      "rc": 0
+    },
+    {
+      "method": "autochannel",
+      "rc": 0
+    },
+    {
+      "method": "hello",
+      "rc": 3
+    } 
+  ]
+}
+
diff --git a/test/api/json/wifi.validation.json b/test/api/json/wifi.validation.json
new file mode 100644
index 0000000000000000000000000000000000000000..4253b5bbcac3c54fe5120559ffa5df6f635e0055
--- /dev/null
+++ b/test/api/json/wifi.validation.json
@@ -0,0 +1,14 @@
+{
+  "object": "wifi",
+  "methods": [
+    {
+      "method": "status",
+      "rc": 0
+    },
+    {
+      "method": "hello",
+      "rc": 3
+    }
+  ]
+}
+
diff --git a/test/api/json/wifi.wps.validation.json b/test/api/json/wifi.wps.validation.json
new file mode 100644
index 0000000000000000000000000000000000000000..e945fb0fc0b3ed92b1c18baf0d316a1e56f03a3d
--- /dev/null
+++ b/test/api/json/wifi.wps.validation.json
@@ -0,0 +1,49 @@
+{
+    "object": "wifi.wps",
+    "methods": [
+        {
+            "method": "status",
+            "rc": 0
+        },
+        {
+            "method": "status",
+            "args": {
+                "vif": "test2"
+            },
+            "rc": 0
+        },
+        {
+            "method": "generate_pin",
+            "rc": 0
+        },
+        {
+            "method": "validate_pin",
+            "args": {
+                "pin": "1111111"
+            },
+            "rc": 0
+        },
+        {
+            "method": "validate_pin",
+            "args": {
+                "pin": "37780906"
+            },
+            "rc": 0
+        },
+        {
+            "method": "showpin",
+            "rc": 0
+        },
+        {
+            "method": "showpin",
+            "args": {
+                "vif": "test2"
+            },
+            "rc": 0
+        },
+        {
+            "method": "hello",
+            "rc": 3
+        }
+    ]
+}
\ No newline at end of file
diff --git a/test/cmocka/Makefile b/test/cmocka/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..3b416d8e1aaf975049c16dc413bb4314dc2ef37d
--- /dev/null
+++ b/test/cmocka/Makefile
@@ -0,0 +1,30 @@
+CC		= gcc
+WIFIMNGR_LIB_DIR	?= $(shell dirname $(PWD))
+WIFIMNGR_LIB	= -lwifimngr -L$(WIFIMNGR_LIB_DIR)
+CMOCKA_LIB	= -l cmocka
+LIBS		= $(WIFIMNGR_LIB) $(CMOCKA_LIB) -lwifi-5 -pthread -luci -lubus -lubox -ljson-c -lblobmsg_json -lnl-genl-3 -lnl-3 -ljson-validator -ljson-schema-validator -ljson-editor
+CFLAGS		= -g -Wall -I../..
+LDFLAGS		= $(LIBS) -Wl,-rpath=$(WIFIMNGR_LIB_DIR) -I$(WIFIMNGR_LIB_DIR)
+UNIT_TESTS	= unit_test_wifi
+FUNCTIONAL_TESTS	= functional_test_wifi
+UTILS 		= test_utils.o
+
+VALGRIND	= valgrind --leak-check=full --show-reachable=no \
+	--show-leak-kinds=all --errors-for-leak-kinds=all \
+	--error-exitcode=1 --track-origins=yes
+
+unit_test_wifi: $(UTILS) unit_test_wifi.o
+	$(CC) -o $@ $^ $(LDFLAGS)
+
+functional_test_wifi: $(UTILS) functional_test_wifi.o
+	$(CC) -o $@ $^ $(LDFLAGS)
+
+unit-test: $(UNIT_TESTS)
+	$(foreach testprog, $(UNIT_TESTS), sudo $(VALGRIND) ./$(testprog);)
+
+functional-test: $(FUNCTIONAL_TESTS)
+	$(foreach testprog, $(FUNCTIONAL_TESTS), sudo $(VALGRIND) ./$(testprog);)
+
+.PHONY: clean
+clean:
+	rm $(UNIT_TESTS) $(FUNCTIONAL_TESTS) *.o -fv
diff --git a/test/cmocka/functional_test_wifi.c b/test/cmocka/functional_test_wifi.c
new file mode 100644
index 0000000000000000000000000000000000000000..ae383f809a814c0ad6d84de8a4692933d7ef9e8a
--- /dev/null
+++ b/test/cmocka/functional_test_wifi.c
@@ -0,0 +1,113 @@
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <libubus.h>
+#include <libubox/blobmsg_json.h>
+#include <libubox/blobmsg.h>
+
+#include <json-validator.h>
+#include <json-c/json.h>
+#include <json-editor.h>
+
+#include <json-c/json_tokener.h>
+#include <wifi.h>
+
+#include "wifimngr.h"
+#include "test_utils.h"
+
+struct test_ctx {
+	FILE *fp;
+};
+
+int wifimngr_event_main(const char *evmap_file);
+
+int wifimngr_recv_event(const char *ifname, void *handle)
+{
+	int err;
+
+	for (;;) {
+		err = wifi_recv_event((char *)ifname, handle);
+		if (err < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+
+static void test_api_events(void **state)
+{
+	struct test_ctx *ctx = (struct test_ctx *) *state;
+	struct json_object *jobj, *tmp;
+	const char *prefix = "register_event";
+
+	wifimngr_event_main("/etc/wifi.json");
+
+	jobj = poll_test_log(ctx->fp, prefix);
+	assert_non_null(jobj);
+
+	tmp = json_object_get_by_string(jobj, "ifname");
+	assert_string_equal(json_object_get_string(tmp), FIVE_IFACE);
+
+	tmp = json_object_get_by_string(jobj, "family");
+	assert_string_equal(json_object_get_string(tmp), "easysoc");
+
+	tmp = json_object_get_by_string(jobj, "group");
+	assert_string_equal(json_object_get_string(tmp), "notify");
+
+	json_object_put(jobj);
+
+	prefix = "recv_event";
+
+	jobj = poll_test_log(ctx->fp, prefix);
+	assert_non_null(jobj);
+
+	tmp = json_object_get_by_string(jobj, "ifname");
+	assert_string_equal(json_object_get_string(tmp), FIVE_IFACE);
+
+	json_object_put(jobj);
+}
+
+static int group_setup(void **state)
+{
+	struct test_ctx *ctx = calloc(1, sizeof(struct test_ctx));
+
+	if (!ctx)
+		return -1;
+
+	remove("/tmp/test.log");
+
+	*state = ctx;
+	return 0;
+}
+
+static int group_teardown(void **state)
+{
+	struct test_ctx *ctx = (struct test_ctx *) *state;
+
+	free(ctx);
+	remove("/tmp/test.log");
+
+	/* TODO: fix event poll file */
+	//if (ctx->fp)
+		//fclose(ctx->fp);
+	return 0;
+}
+
+static int setup(void **state)
+{
+	struct test_ctx *ctx = (struct test_ctx *) *state;
+
+	return 0;
+}
+
+int main(void)
+{
+	const struct CMUnitTest tests[] = {
+		cmocka_unit_test_setup(test_api_events, setup),
+	};
+
+	return cmocka_run_group_tests(tests, group_setup, group_teardown);
+}
diff --git a/test/cmocka/test_utils.c b/test/cmocka/test_utils.c
new file mode 100644
index 0000000000000000000000000000000000000000..92922ac303f39b81e39df119b60ee3db97cc3ad3
--- /dev/null
+++ b/test/cmocka/test_utils.c
@@ -0,0 +1,70 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <json-c/json.h>
+
+#include "test_utils.h"
+
+char *multi_tok(char *input, char *delimiter)
+{
+    static char *string;
+	char *end, temp;
+
+    if (input)
+        string = input;
+
+    if (!string)
+        return string;
+
+    end = strstr(string, delimiter);
+
+    if (!end) {
+        char *temp = string;
+
+        string = NULL;
+        return temp;
+    }
+
+    temp = string;
+
+    *end = '\0';
+    string = end + strlen(delimiter);
+
+    return temp;
+}
+
+/* TODO: how to fix events without fopen and fclose every poll? */
+struct json_object *poll_test_log(FILE *fp, const char *prefix)
+{
+	char line[256] = {0};
+	char msg[256] = {0};
+	struct json_object *obj = NULL;
+
+	//if (!fp) {
+    fp = fopen("/tmp/test.log", "r");
+    if (!fp)
+        return NULL;
+	//}
+
+	while (fgets(line, 256, fp))  {
+		char *ptr, *s;
+		char appended[32];
+
+		snprintf(appended, sizeof(appended), "%s:", prefix);
+
+		ptr = strstr(line, appended);
+		if (!ptr)
+			continue;
+
+		s = multi_tok(ptr, appended);
+		s = multi_tok(NULL, appended);
+		strncpy(msg, s, sizeof(msg));
+	}
+
+	if (strlen(msg))
+		obj = json_tokener_parse(msg);
+
+	fclose(fp);
+	return obj;
+}
\ No newline at end of file
diff --git a/test/cmocka/test_utils.h b/test/cmocka/test_utils.h
new file mode 100644
index 0000000000000000000000000000000000000000..22f4a54bde294e297d2ffc20761c6fcff40a08ce
--- /dev/null
+++ b/test/cmocka/test_utils.h
@@ -0,0 +1,13 @@
+#ifndef TEST_UTILS_H
+#define TEST_UTILS_H
+
+#define FIVE_IFACE "test5"
+#define TWO_IFACE "test2"
+
+#define FIVE_CLIENT "50:31:32:33:34:35"
+#define PIN "24033848"
+
+char *multi_tok(char *input, char *delimiter);
+struct json_object *poll_test_log(FILE *fp, const char *prefix);
+
+#endif
\ No newline at end of file
diff --git a/test/cmocka/unit_test_wifi.c b/test/cmocka/unit_test_wifi.c
new file mode 100644
index 0000000000000000000000000000000000000000..196a3e9fdb0be99e8ee74194c5f21798742dae66
--- /dev/null
+++ b/test/cmocka/unit_test_wifi.c
@@ -0,0 +1,597 @@
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+
+#include <libubus.h>
+#include <libubox/blobmsg_json.h>
+#include <libubox/blobmsg.h>
+
+#include <json-validator.h>
+#include <json-c/json.h>
+#include <json-editor.h>
+
+#include <json-c/json_tokener.h>
+#include <wifi.h>
+
+#include "wifimngr.h"
+#include "test_utils.h"
+
+struct test_ctx {
+	struct blob_buf bb;
+	struct ubus_object radio;
+	struct ubus_object ap;
+	FILE *fp;
+};
+
+/* declare wifimngr functions */
+int wl_radio_status(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method,
+		struct blob_attr *msg);
+
+
+int wl_radio_get_param(struct ubus_context *ctx, struct ubus_object *obj,
+		  struct ubus_request_data *req, const char *method,
+		  struct blob_attr *msg);
+
+int sta_disconnect(struct ubus_context *ctx, struct ubus_object *obj,
+		      struct ubus_request_data *req, const char *method,
+		      struct blob_attr *msg);
+
+int nbr_transition(struct ubus_context *ctx, struct ubus_object *obj,
+		      struct ubus_request_data *req, const char *method,
+		      struct blob_attr *msg);
+
+int nbr_request(struct ubus_context *ctx, struct ubus_object *obj,
+		      struct ubus_request_data *req, const char *method,
+		      struct blob_attr *msg);
+
+int nbr_add(struct ubus_context *ctx, struct ubus_object *obj,
+		      struct ubus_request_data *req, const char *method,
+		      struct blob_attr *msg);
+
+int wps_start(struct ubus_context *ctx, struct ubus_object *obj,
+		  struct ubus_request_data *req, const char *method,
+		  struct blob_attr *msg);
+
+int wps_stop(struct ubus_context *ctx, struct ubus_object *obj,
+		  struct ubus_request_data *req, const char *method,
+		  struct blob_attr *msg);
+
+int vsie_add(struct ubus_context *ctx, struct ubus_object *obj,
+		      struct ubus_request_data *ureq, const char *method,
+		      struct blob_attr *msg);
+
+int vsie_del(struct ubus_context *ctx, struct ubus_object *obj,
+		      struct ubus_request_data *ureq, const char *method,
+		      struct blob_attr *msg);
+
+int nbr_del(struct ubus_context *ctx, struct ubus_object *obj,
+		      struct ubus_request_data *req, const char *method,
+		      struct blob_attr *msg);
+
+int sta_monitor(struct ubus_context *ctx, struct ubus_object *obj,
+		      struct ubus_request_data *req, const char *method,
+		      struct blob_attr *msg);
+
+int wl_scan(struct ubus_context *ctx, struct ubus_object *obj,
+		  struct ubus_request_data *req, const char *method,
+		  struct blob_attr *msg);
+
+int wl_autochannel(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method,
+		struct blob_attr *msg);
+
+int wps_set_ap_pin(struct ubus_context *ctx, struct ubus_object *obj,
+		  struct ubus_request_data *req, const char *method,
+		  struct blob_attr *msg);
+
+int wifimngr_event_main(const char *evmap_file);
+
+/* overload ubus_send_reply to prevent segfault*/
+int ubus_send_reply(struct ubus_context *ctx, struct ubus_request_data *req,
+		    struct blob_attr *msg)
+{
+	return 0;
+}
+
+static void test_api_radio_disconnect(void **state)
+{
+	struct test_ctx *ctx = (struct test_ctx *) *state;
+	struct blob_buf *bb = &ctx->bb;
+	struct ubus_object *obj = &ctx->ap;
+	struct json_object *jobj, *tmp;
+	const char *prefix = "disconnect";
+
+	blobmsg_add_string(bb, "sta", FIVE_CLIENT);
+
+	sta_disconnect(NULL, obj, NULL, NULL, bb->head);
+	jobj = poll_test_log(ctx->fp, prefix);
+	assert_non_null(jobj);
+
+	tmp = json_object_get_by_string(jobj, "ifname");
+	assert_string_equal(json_object_get_string(tmp), FIVE_IFACE);
+
+	tmp = json_object_get_by_string(jobj, "sta");
+	assert_string_equal(json_object_get_string(tmp), FIVE_CLIENT);
+
+	json_object_put(jobj);
+	return;
+}
+
+static void test_api_req_bss_transition(void **state)
+{
+	struct test_ctx *ctx = (struct test_ctx *) *state;
+	struct blob_buf *bb = &ctx->bb;
+	struct ubus_object *obj = &ctx->ap;
+	struct json_object *jobj, *tmp;
+	const char *prefix = "req_bss_transition";
+	void *arr;
+
+	blobmsg_add_string(bb, "client", FIVE_CLIENT);
+	arr = blobmsg_open_array(bb, "bssid");
+	blobmsg_add_string(bb, "NULL", "22:22:22:22:22:22");
+	blobmsg_add_string(bb, "NULL", "11:11:11:11:11:11");
+	blobmsg_close_array(bb, arr);
+
+	nbr_transition(NULL, obj, NULL, NULL, bb->head);
+	jobj = poll_test_log(ctx->fp, prefix);
+	assert_non_null(jobj);
+
+	tmp = json_object_get_by_string(jobj, "ifname");
+	assert_string_equal(json_object_get_string(tmp), FIVE_IFACE);
+
+	tmp = json_object_get_by_string(jobj, "client");
+	assert_string_equal(json_object_get_string(tmp), FIVE_CLIENT);
+
+	tmp = json_object_get_by_string(jobj, "bssid");
+	assert_string_equal(json_object_get_string(tmp), "[ \"22:22:22:22:22:22\", \"11:11:11:11:11:11\" ]");
+
+	json_object_put(jobj);
+	return;
+}
+
+static void test_api_req_beacon_report(void **state)
+{
+	struct test_ctx *ctx = (struct test_ctx *) *state;
+	struct blob_buf *bb = &ctx->bb;
+	struct ubus_object *obj = &ctx->ap;
+	struct json_object *jobj, *tmp;
+	const char *prefix = "req_beacon_report";
+
+	blobmsg_add_string(bb, "client", FIVE_CLIENT);
+	blobmsg_add_string(bb, "ssid", "Test SSID 5Ghz");
+
+	nbr_request(NULL, obj, NULL, NULL, bb->head);
+	jobj = poll_test_log(ctx->fp, prefix);
+	assert_non_null(jobj);
+
+	/* TODO: not implemented? */
+	//tmp = json_object_get_by_string(jobj, "ssid");
+	//assert_string_equal(json_object_get_string(tmp), FIVE_IFACE);
+
+	tmp = json_object_get_by_string(jobj, "client");
+	assert_string_equal(json_object_get_string(tmp), FIVE_CLIENT);
+
+	json_object_put(jobj);
+	return;
+}
+
+static void test_api_add_nbr(void **state)
+{
+	struct test_ctx *ctx = (struct test_ctx *) *state;
+	struct blob_buf *bb = &ctx->bb;
+	struct ubus_object *obj = &ctx->ap;
+	struct json_object *jobj, *tmp;
+	const char *prefix = "add_neighbor";
+
+	blobmsg_add_string(bb, "bssid", "00:11:12:13:14:15");
+	blobmsg_add_u32(bb, "channel", 36);
+	blobmsg_add_string(bb, "bssid_info", "5");
+	blobmsg_add_u32(bb, "reg", 5);
+	blobmsg_add_u32(bb, "phy", 5);
+
+	nbr_add(NULL, obj, NULL, NULL, bb->head);
+	jobj = poll_test_log(ctx->fp, prefix);
+	assert_non_null(jobj);
+
+	tmp = json_object_get_by_string(jobj, "ifname");
+	assert_string_equal(json_object_get_string(tmp), FIVE_IFACE);
+
+	tmp = json_object_get_by_string(jobj, "bssid");
+	assert_string_equal(json_object_get_string(tmp), "00:11:12:13:14:15");
+
+	tmp = json_object_get_by_string(jobj, "channel");
+	assert_int_equal(json_object_get_int(tmp), 36);
+
+	tmp = json_object_get_by_string(jobj, "bssid_info");
+	assert_int_equal(json_object_get_int(tmp), 5);
+
+	tmp = json_object_get_by_string(jobj, "reg");
+	assert_int_equal(json_object_get_int(tmp), 5);
+
+	tmp = json_object_get_by_string(jobj, "phy");
+	assert_int_equal(json_object_get_int(tmp), 5);
+
+	json_object_put(jobj);
+	return;
+}
+
+static void test_api_wps_start(void **state)
+{
+	struct test_ctx *ctx = (struct test_ctx *) *state;
+	struct blob_buf *bb = &ctx->bb;
+	struct ubus_object *obj = &ctx->ap;
+	struct json_object *jobj, *tmp;
+	const char *prefix = "start_wps";
+
+	/* test pin & registrar */
+	blobmsg_add_string(bb, "vif", "test5");
+	blobmsg_add_string(bb, "mode", "pin");
+	blobmsg_add_string(bb, "role", "registrar");
+	blobmsg_add_string(bb, "pin", PIN);
+	wps_start(NULL, obj, NULL, NULL, bb->head);
+	jobj = poll_test_log(ctx->fp, prefix);
+	assert_non_null(jobj);
+
+	tmp = json_object_get_by_string(jobj, "ifname");
+	assert_string_equal(json_object_get_string(tmp), FIVE_IFACE);
+
+	tmp = json_object_get_by_string(jobj, "role");
+	assert_int_equal(json_object_get_int(tmp), WPS_REGISTRAR);
+
+	tmp = json_object_get_by_string(jobj, "mode");
+	assert_int_equal(json_object_get_int(tmp), WPS_MODE_PIN);
+
+	tmp = json_object_get_by_string(jobj, "pin");
+	assert_int_equal(json_object_get_int64(tmp), strtoul(PIN, NULL, 10));
+
+	json_object_put(jobj);
+
+	/* test enrollee and iface test2 */
+	blob_buf_init(bb, 0);
+	blobmsg_add_string(bb, "vif", "test2");
+	blobmsg_add_string(bb, "role", "enrollee");
+	wps_start(NULL, obj, NULL, NULL, bb->head);
+	jobj = poll_test_log(ctx->fp, prefix);
+	assert_non_null(jobj);
+
+	tmp = json_object_get_by_string(jobj, "ifname");
+	assert_string_equal(json_object_get_string(tmp), TWO_IFACE);
+
+	tmp = json_object_get_by_string(jobj, "role");
+	assert_int_equal(json_object_get_int(tmp), WPS_ENROLLEE);
+
+	/* test pbc and iface test2 */
+	blob_buf_init(bb, 0);
+	blobmsg_add_string(bb, "vif", "test2");
+	blobmsg_add_string(bb, "mode", "pbc");
+	wps_start(NULL, obj, NULL, NULL, bb->head);
+
+	json_object_put(jobj);
+
+	jobj = poll_test_log(ctx->fp, prefix);
+	assert_non_null(jobj);
+
+	tmp = json_object_get_by_string(jobj, "ifname");
+	assert_string_equal(json_object_get_string(tmp), TWO_IFACE);
+
+	tmp = json_object_get_by_string(jobj, "mode");
+	assert_int_equal(json_object_get_int(tmp), WPS_MODE_PBC);
+
+	json_object_put(jobj);
+
+	return;
+}
+
+/* TODO: this test works "by chance" because we are looking for 5ghz,
+ * how can we fix this? */
+static void test_api_wps_stop(void **state)
+{
+	struct test_ctx *ctx = (struct test_ctx *) *state;
+	struct blob_buf *bb = &ctx->bb;
+	struct ubus_object *obj = &ctx->ap;
+	struct json_object *jobj, *tmp;
+	const char *prefix = "stop_wps";
+
+	wps_stop(NULL, obj, NULL, NULL, bb->head);
+	jobj = poll_test_log(ctx->fp, prefix);
+	assert_non_null(jobj);
+
+	tmp = json_object_get_by_string(jobj, "ifname");
+	assert_string_equal(json_object_get_string(tmp), FIVE_IFACE);
+
+	json_object_put(jobj);
+	return;
+}
+
+static void test_api_add_vendor_ie(void **state)
+{
+	struct test_ctx *ctx = (struct test_ctx *) *state;
+	struct blob_buf *bb = &ctx->bb;
+	struct ubus_object *obj = &ctx->ap;
+	struct json_object *jobj, *tmp;
+	const char *prefix = "add_vendor_ie";
+
+	blobmsg_add_u32(bb, "mgmt", 5);
+	blobmsg_add_string(bb, "oui", "112233");
+	blobmsg_add_string(bb, "data", "efa567");
+	vsie_add(NULL, obj, NULL, NULL, bb->head);
+	jobj = poll_test_log(ctx->fp, prefix);
+	assert_non_null(jobj);
+
+	tmp = json_object_get_by_string(jobj, "ifname");
+	assert_string_equal(json_object_get_string(tmp), FIVE_IFACE);
+
+	tmp = json_object_get_by_string(jobj, "oui");
+	assert_string_equal(json_object_get_string(tmp), "112233");
+
+	tmp = json_object_get_by_string(jobj, "data");
+	/* hex data, prepend dd+len in hex fmt */
+	assert_string_equal(json_object_get_string(tmp), "dd03efa567");
+
+	json_object_put(jobj);
+	return;
+}
+
+static void test_api_del_vendor_ie(void **state)
+{
+	struct test_ctx *ctx = (struct test_ctx *) *state;
+	struct blob_buf *bb = &ctx->bb;
+	struct ubus_object *obj = &ctx->ap;
+	struct json_object *jobj, *tmp;
+	const char *prefix = "del_vendor_ie";
+
+	blobmsg_add_u32(bb, "mgmt", 5);
+	blobmsg_add_string(bb, "oui", "112233");
+	blobmsg_add_string(bb, "data", "efa567");
+	vsie_del(NULL, obj, NULL, NULL, bb->head);
+	jobj = poll_test_log(ctx->fp, prefix);
+	assert_non_null(jobj);
+
+	tmp = json_object_get_by_string(jobj, "ifname");
+	assert_string_equal(json_object_get_string(tmp), FIVE_IFACE);
+
+	tmp = json_object_get_by_string(jobj, "oui");
+	assert_string_equal(json_object_get_string(tmp), "112233");
+
+	tmp = json_object_get_by_string(jobj, "data");
+	assert_string_equal(json_object_get_string(tmp), "dd03efa567"); // hex data, prepend dd+len in hex fmt
+
+	json_object_put(jobj);
+	return;
+}
+
+static void test_api_del_neighbor(void **state)
+{
+	struct test_ctx *ctx = (struct test_ctx *) *state;
+	struct blob_buf *bb = &ctx->bb;
+	struct ubus_object *obj = &ctx->ap;
+	struct json_object *jobj, *tmp;
+	const char *prefix = "del_neighbor";
+
+	blobmsg_add_string(bb, "bssid", "50:10:00:11:22:33");
+	nbr_del(NULL, obj, NULL, NULL, bb->head);
+	jobj = poll_test_log(ctx->fp, prefix);
+	assert_non_null(jobj);
+
+	tmp = json_object_get_by_string(jobj, "ifname");
+	assert_string_equal(json_object_get_string(tmp), FIVE_IFACE);
+
+	tmp = json_object_get_by_string(jobj, "bssid");
+	assert_string_equal(json_object_get_string(tmp), "50:10:00:11:22:33");
+
+	json_object_put(jobj);
+	return;
+}
+
+static void test_api_monitor_sta(void **state)
+{
+	struct test_ctx *ctx = (struct test_ctx *) *state;
+	struct blob_buf *bb = &ctx->bb;
+	struct ubus_object *obj = &ctx->ap;
+	struct json_object *jobj, *tmp;
+	const char *prefix = "monitor_sta";
+
+	blobmsg_add_string(bb, "sta", "00:00:00:11:22:33");
+	sta_monitor(NULL, obj, NULL, NULL, bb->head);
+	jobj = poll_test_log(ctx->fp, prefix);
+	assert_non_null(jobj);
+
+	tmp = json_object_get_by_string(jobj, "ifname");
+	assert_string_equal(json_object_get_string(tmp), FIVE_IFACE);
+
+	tmp = json_object_get_by_string(jobj, "sta");
+	assert_string_equal(json_object_get_string(tmp), "00:00:00:11:22:33");
+
+	json_object_put(jobj);
+	return;
+}
+
+static void test_api_scan(void **state)
+{
+	struct test_ctx *ctx = (struct test_ctx *) *state;
+	struct blob_buf *bb = &ctx->bb;
+	struct ubus_object *obj = &ctx->radio;
+	struct json_object *jobj, *tmp;
+	const char *prefix = "scan";
+
+	blobmsg_add_string(bb, "bssid", "00:00:00:11:22:33");
+	blobmsg_add_string(bb, "ssid", "test");
+	blobmsg_add_u32(bb, "channel", 36);
+	wl_scan(NULL, obj, NULL, NULL, bb->head);
+	jobj = poll_test_log(ctx->fp, prefix);
+	assert_non_null(jobj);
+
+	tmp = json_object_get_by_string(jobj, "ifname");
+	assert_string_equal(json_object_get_string(tmp), FIVE_IFACE);
+
+	/* TODO: unused?
+	tmp = json_object_get_by_string(jobj, "bssid");
+	assert_string_equal(json_object_get_string(tmp), "00:00:00:11:22:33");
+	*/
+
+	tmp = json_object_get_by_string(jobj, "ssid");
+	assert_string_equal(json_object_get_string(tmp), "test");
+
+	/* TODO: unused?
+	tmp = json_object_get_by_string(jobj, "channel");
+	assert_int_equal(json_object_get_int(tmp), 36);
+	*/
+
+	json_object_put(jobj);
+	return;
+}
+
+static void test_set_wps_ap_pin(void **state)
+{
+	struct test_ctx *ctx = (struct test_ctx *) *state;
+	struct blob_buf *bb = &ctx->bb;
+	struct ubus_object *obj = &ctx->ap;
+	struct json_object *jobj, *tmp;
+	const char *prefix = "set_wps_ap_pin";
+
+	blobmsg_add_string(bb, "ifname", FIVE_IFACE);
+	blobmsg_add_string(bb, "pin", PIN);
+	wps_set_ap_pin(NULL, obj, NULL, NULL, bb->head);
+	jobj = poll_test_log(ctx->fp, prefix);
+	assert_non_null(jobj);
+
+	tmp = json_object_get_by_string(jobj, "ifname");
+	assert_string_equal(json_object_get_string(tmp), FIVE_IFACE);
+
+	tmp = json_object_get_by_string(jobj, "pin");
+	assert_int_equal(json_object_get_int64(tmp), strtoul(PIN, NULL, 10));
+
+	json_object_put(jobj);
+	return;
+}
+
+static int group_setup(void **state)
+{
+	struct test_ctx *ctx = calloc(1, sizeof(struct test_ctx));
+
+	if (!ctx)
+		return -1;
+
+	remove("/tmp/test.log");
+
+	ctx->radio.name = "wifi.radio.test5";
+	ctx->ap.name = "wifi.ap.test5";
+
+	memset(&ctx->bb, 0, sizeof(struct blob_buf));
+
+	*state = ctx;
+	return 0;
+}
+
+static void test_api_acs(void **state)
+{
+	struct test_ctx *ctx = (struct test_ctx *) *state;
+	struct blob_buf *bb = &ctx->bb;
+	struct ubus_object *obj = &ctx->radio;
+	struct json_object *jobj, *tmp;
+	const char *prefix = "acs";
+
+
+	blobmsg_add_string(bb, "ifname", FIVE_IFACE);
+	wl_autochannel(NULL, obj, NULL, NULL, bb->head);
+	jobj = poll_test_log(ctx->fp, prefix);
+	assert_non_null(jobj);
+
+	tmp = json_object_get_by_string(jobj, "ifname");
+	assert_string_equal(json_object_get_string(tmp), FIVE_IFACE);
+
+	json_object_put(jobj);
+	return;
+}
+
+int wifimngr_recv_event(const char *ifname, void *handle)
+{
+	int err;
+
+	for (;;) {
+		err = wifi_recv_event((char *)ifname, handle);
+		if (err < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
+static void test_api_events(void **state)
+{
+	struct test_ctx *ctx = (struct test_ctx *) *state;
+	struct json_object *jobj, *tmp;
+	const char *prefix = "register_event";
+
+	wifimngr_event_main("/etc/wifi.json");
+
+	jobj = poll_test_log(ctx->fp, prefix);
+	assert_non_null(jobj);
+
+	tmp = json_object_get_by_string(jobj, "ifname");
+	assert_string_equal(json_object_get_string(tmp), FIVE_IFACE);
+
+	tmp = json_object_get_by_string(jobj, "family");
+	assert_string_equal(json_object_get_string(tmp), "easysoc");
+
+	tmp = json_object_get_by_string(jobj, "group");
+	assert_string_equal(json_object_get_string(tmp), "notify");
+
+	json_object_put(jobj);
+
+	prefix = "recv_event";
+
+	jobj = poll_test_log(ctx->fp, prefix);
+	assert_non_null(jobj);
+
+	tmp = json_object_get_by_string(jobj, "ifname");
+	assert_string_equal(json_object_get_string(tmp), FIVE_IFACE);
+
+	json_object_put(jobj);
+}
+
+static int group_teardown(void **state)
+{
+	struct test_ctx *ctx = (struct test_ctx *) *state;
+
+	blob_buf_free(&ctx->bb);
+	free(ctx);
+	remove("/tmp/test.log");
+
+	/* TODO: fix event poll file */
+	//if (ctx->fp)
+		//fclose(ctx->fp);
+	return 0;
+}
+
+static int setup(void **state)
+{
+	struct test_ctx *ctx = (struct test_ctx *) *state;
+
+	blob_buf_init(&ctx->bb, 0);
+
+	return 0;
+}
+
+int main(void)
+{
+	const struct CMUnitTest tests[] = {
+		cmocka_unit_test_setup(test_api_radio_disconnect, setup),
+		cmocka_unit_test_setup(test_api_req_bss_transition, setup),
+		cmocka_unit_test_setup(test_api_req_beacon_report, setup),
+		cmocka_unit_test_setup(test_api_add_nbr, setup),
+		cmocka_unit_test_setup(test_api_wps_start, setup),
+		cmocka_unit_test_setup(test_api_wps_stop, setup),
+		cmocka_unit_test_setup(test_api_add_vendor_ie, setup),
+		cmocka_unit_test_setup(test_api_del_vendor_ie, setup),
+		cmocka_unit_test_setup(test_api_del_neighbor, setup),
+		cmocka_unit_test_setup(test_api_monitor_sta, setup),
+		cmocka_unit_test_setup(test_api_scan, setup),
+		cmocka_unit_test_setup(test_set_wps_ap_pin, setup),
+		cmocka_unit_test_setup(test_api_acs, setup),
+	};
+
+	return cmocka_run_group_tests(tests, group_setup, group_teardown);
+}
diff --git a/test/files/etc/config/wireless b/test/files/etc/config/wireless
new file mode 100644
index 0000000000000000000000000000000000000000..93ad34d8352c25c8717880b9c5c2c3776228b0b7
--- /dev/null
+++ b/test/files/etc/config/wireless
@@ -0,0 +1,25 @@
+config wifi-device 'test2'
+    option channel 'auto'
+    option hwmode 'auto'
+    option country 'DE'
+    option band 'a'
+    option bandwidth '80'
+
+config wifi-iface
+    option device 'test2'
+    option ifname 'test2'
+    option mode 'ap'
+    option encryption 'psk2'
+
+config wifi-device 'test5'
+    option channel 'auto'
+    option hwmode 'auto'
+    option country 'DE'
+    option band 'a'
+    option bandwidth '80'
+
+config wifi-iface
+    option device 'test5'
+    option ifname 'test5'
+    option mode 'ap'
+    option encryption 'psk2'
\ No newline at end of file
diff --git a/test/files/etc/wifi.json b/test/files/etc/wifi.json
new file mode 100644
index 0000000000000000000000000000000000000000..f4ef67bf78fe8c1450ab34b18d4181bc8613f8ff
--- /dev/null
+++ b/test/files/etc/wifi.json
@@ -0,0 +1,13 @@
+{
+        "events" : [
+                {
+                        "type": "wifi-event",
+                        "name": "cfg09ac03",
+                        "ifname": "test5",
+                        "family": "easysoc",
+                        "group": [
+                                "notify"
+                        ]
+                }
+        ]
+}
diff --git a/wifimngr.c b/wifimngr.c
index 069c8adcbf01132c6dbbc48ad03e0b123882b20a..ee6bf445d2731eb851a341167bce8a0923f7eff7 100644
--- a/wifimngr.c
+++ b/wifimngr.c
@@ -374,7 +374,7 @@ static void wl_dump_capabilities(struct blob_buf *bb, struct wifi_caps *caps, ui
 	blobmsg_add_u8(bb, "apsd", wifi_cap_isset(bitmap, WIFI_CAP_APSD) ? true : false);
 	blobmsg_add_u8(bb, "shortslot", wifi_cap_isset(bitmap, WIFI_CAP_SHORT_SLOT) ? true : false);
 	blobmsg_add_u8(bb, "dot11h", wifi_cap_isset(bitmap, WIFI_CAP_SPECTRUM_MGMT) ? true : false);
-	blobmsg_add_u8(bb, "dot11k", wifi_cap_isset(bitmap, WIFI_CAP_RADIO_MEAS) ? true : false);
+	//blobmsg_add_u8(bb, "dot11k", wifi_cap_isset(bitmap, WIFI_CAP_RADIO_MEAS) ? true : false);
 
 	if (!!(caps->valid & WIFI_CAP_EXT_VALID)) {
 		blobmsg_add_u8(bb, "2040coex", wifi_cap_isset(bitmap, WIFI_CAP_2040_COEX) ? true : false);
@@ -384,7 +384,9 @@ static void wl_dump_capabilities(struct blob_buf *bb, struct wifi_caps *caps, ui
 	}
 
 	if (!!(caps->valid & WIFI_CAP_HT_VALID)) {
-		blobmsg_add_u8(bb, "dot11n", true);
+		void *n;
+
+		n = blobmsg_open_table(bb, "dot11n");
 		blobmsg_add_u8(bb, "dot11n_ldpc", wifi_cap_isset(bitmap, WIFI_CAP_HT_LDPC) ? true : false);
 		blobmsg_add_u8(bb, "dot11n_40", wifi_cap_isset(bitmap, WIFI_CAP_2040) ? true : false);
 		blobmsg_add_u8(bb, "dot11n_ps", wifi_cap_isset(bitmap, WIFI_CAP_HT_SMPS) ? true : false);
@@ -392,12 +394,15 @@ static void wl_dump_capabilities(struct blob_buf *bb, struct wifi_caps *caps, ui
 		blobmsg_add_u8(bb, "dot11n_sgi40", wifi_cap_isset(bitmap, WIFI_CAP_SGI40) ? true : false);
 		blobmsg_add_u8(bb, "dot11n_tx_stbc", wifi_cap_isset(bitmap, WIFI_CAP_HT_TX_STBC) ? true : false);
 		blobmsg_add_u8(bb, "dot11n_rx_stbc", wifi_cap_isset(bitmap, WIFI_CAP_HT_RX_STBC) ? true : false);
-	} else {
+		blobmsg_close_table(bb, n);
+	}/* else {
 		blobmsg_add_u8(bb, "dot11n", false);
-	}
+	}*/
 
 	if (!!(caps->valid & WIFI_CAP_VHT_VALID)) {
-		blobmsg_add_u8(bb, "dot11ac", true);
+		void *ac;
+
+		ac = blobmsg_open_table(bb, "dot11ac");
 		blobmsg_add_u8(bb, "dot11ac_160", wifi_cap_isset(bitmap, WIFI_CAP_160) ? true : false);
 		blobmsg_add_u8(bb, "dot11ac_8080", wifi_cap_isset(bitmap, WIFI_CAP_8080) ? true : false);
 		if (wifi_cap_isset(bitmap, WIFI_CAP_VHT_MPDU_11454))
@@ -418,12 +423,15 @@ static void wl_dump_capabilities(struct blob_buf *bb, struct wifi_caps *caps, ui
 		blobmsg_add_u8(bb, "dot11ac_su_beamformee", wifi_cap_isset(bitmap, WIFI_CAP_VHT_SU_BFE) ? true : false);
 		blobmsg_add_u8(bb, "dot11ac_mu_beamformer", wifi_cap_isset(bitmap, WIFI_CAP_VHT_MU_BFR) ? true : false);
 		blobmsg_add_u8(bb, "dot11ac_mu_beamformee", wifi_cap_isset(bitmap, WIFI_CAP_VHT_MU_BFE) ? true : false);
-	} else {
+		blobmsg_close_table(bb, ac);
+	}/* else {
 		blobmsg_add_u8(bb, "dot11ac", false);
-	}
+	}*/
 
 	if (!!(caps->valid & WIFI_CAP_RM_VALID)) {
-		blobmsg_add_u8(bb, "dot11k", true);
+		void *k;
+
+		k = blobmsg_open_table(bb, "dot11k");
 		blobmsg_add_u8(bb, "dot11k_link_meas", wifi_cap_isset(bitmap, WIFI_CAP_RM_LINK) ? true : false);
 		blobmsg_add_u8(bb, "dot11k_nbr_report", wifi_cap_isset(bitmap, WIFI_CAP_RM_NBR_REPORT) ? true : false);
 		blobmsg_add_u8(bb, "dot11k_bcn_passive", wifi_cap_isset(bitmap, WIFI_CAP_RM_BCN_PASSIVE) ? true : false);
@@ -431,6 +439,7 @@ static void wl_dump_capabilities(struct blob_buf *bb, struct wifi_caps *caps, ui
 		blobmsg_add_u8(bb, "dot11k_bcn_table", wifi_cap_isset(bitmap, WIFI_CAP_RM_BCN_TABLE) ? true : false);
 		blobmsg_add_u8(bb, "dot11k_rcpi", wifi_cap_isset(bitmap, WIFI_CAP_RM_RCPI) ? true : false);
 		blobmsg_add_u8(bb, "dot11k_rsni", wifi_cap_isset(bitmap, WIFI_CAP_RM_RSNI) ? true : false);
+		blobmsg_close_table(bb, k);
 	} /* else
 		blobmsg_add_u8(bb, "dot11k", false); */
 
@@ -467,7 +476,7 @@ static void wifi_print_radio_diagnostics(struct blob_buf *bb,
 	blobmsg_add_u32(bb, "false_cca_count", d->false_cca_count);
 }
 
-static int wl_radio_status(struct ubus_context *ctx, struct ubus_object *obj,
+int wl_radio_status(struct ubus_context *ctx, struct ubus_object *obj,
 		struct ubus_request_data *req, const char *method,
 		struct blob_attr *msg)
 {
@@ -485,8 +494,8 @@ static int wl_radio_status(struct ubus_context *ctx, struct ubus_object *obj,
 	void *c;
 	int i;
 
-	memset(&bb, 0, sizeof(bb));
 
+	memset(&bb, 0, sizeof(bb));
 	wldev = ubus_radio_to_ifname(obj);
 
 	wifi_get_ifstatus(wldev, &ifs);
@@ -528,6 +537,7 @@ static int wl_radio_status(struct ubus_context *ctx, struct ubus_object *obj,
 	for (i = 0; i < 32 && radio.supp_rates[i] != 0; i++) {
 		blobmsg_add_u32(&bb, "", radio.supp_rates[i]);
 	}
+
 	blobmsg_close_array(&bb, c);
 	c = blobmsg_open_array(&bb, "basic_rates");
 	for (i = 0; i < 32 && radio.basic_rates[i] != 0; i++) {
@@ -960,7 +970,7 @@ static const struct blobmsg_policy wl_scan_policy[__SCAN_MAX] = {
 	/* [SCAN_TYPE] = { .name = "type", .type = BLOBMSG_TYPE_INT32 }, */
 };
 
-static int wl_scan(struct ubus_context *ctx, struct ubus_object *obj,
+int wl_scan(struct ubus_context *ctx, struct ubus_object *obj,
 		  struct ubus_request_data *req, const char *method,
 		  struct blob_attr *msg)
 {
@@ -1138,7 +1148,7 @@ static const struct blobmsg_policy wl_acs_policy[__ACS_MAX] = {
 	[ACS_NUM_SCANS] = { .name = "scans", .type = BLOBMSG_TYPE_INT32 },
 };
 
-static int wl_autochannel(struct ubus_context *ctx, struct ubus_object *obj,
+int wl_autochannel(struct ubus_context *ctx, struct ubus_object *obj,
 		struct ubus_request_data *req, const char *method,
 		struct blob_attr *msg)
 {
@@ -1261,7 +1271,7 @@ static const struct blobmsg_policy btmreq_policy[__NBR_TRANS_MAX] = {
 	[NBR_TRANS_TIMEOUT] = { .name = "timeout", .type = BLOBMSG_TYPE_INT32 },
 };
 
-static int sta_disconnect(struct ubus_context *ctx, struct ubus_object *obj,
+int sta_disconnect(struct ubus_context *ctx, struct ubus_object *obj,
 		      struct ubus_request_data *req, const char *method,
 		      struct blob_attr *msg)
 {
@@ -1291,7 +1301,7 @@ static int sta_disconnect(struct ubus_context *ctx, struct ubus_object *obj,
 	return UBUS_STATUS_OK;
 }
 
-static int sta_monitor(struct ubus_context *ctx, struct ubus_object *obj,
+int sta_monitor(struct ubus_context *ctx, struct ubus_object *obj,
 		      struct ubus_request_data *req, const char *method,
 		      struct blob_attr *msg)
 {
@@ -1357,7 +1367,7 @@ static int sta_monitor(struct ubus_context *ctx, struct ubus_object *obj,
 	return UBUS_STATUS_OK;
 }
 
-static int nbr_add(struct ubus_context *ctx, struct ubus_object *obj,
+int nbr_add(struct ubus_context *ctx, struct ubus_object *obj,
 		      struct ubus_request_data *req, const char *method,
 		      struct blob_attr *msg)
 {
@@ -1418,7 +1428,7 @@ static int nbr_add(struct ubus_context *ctx, struct ubus_object *obj,
 	return UBUS_STATUS_OK;
 }
 
-static int nbr_del(struct ubus_context *ctx, struct ubus_object *obj,
+int nbr_del(struct ubus_context *ctx, struct ubus_object *obj,
 		      struct ubus_request_data *req, const char *method,
 		      struct blob_attr *msg)
 {
@@ -1567,7 +1577,7 @@ static int nbr_list(struct ubus_context *ctx, struct ubus_object *obj,
 	return UBUS_STATUS_OK;
 }
 
-static int nbr_request(struct ubus_context *ctx, struct ubus_object *obj,
+int nbr_request(struct ubus_context *ctx, struct ubus_object *obj,
 		      struct ubus_request_data *req, const char *method,
 		      struct blob_attr *msg)
 {
@@ -1593,7 +1603,7 @@ static int nbr_request(struct ubus_context *ctx, struct ubus_object *obj,
 	return UBUS_STATUS_OK;
 }
 
-static int nbr_transition(struct ubus_context *ctx, struct ubus_object *obj,
+int nbr_transition(struct ubus_context *ctx, struct ubus_object *obj,
 		      struct ubus_request_data *req, const char *method,
 		      struct blob_attr *msg)
 {
@@ -1662,7 +1672,7 @@ static const struct blobmsg_policy vsie_policy[__VSIE_MAX] = {
 	[VSIE_DATA] = { .name = "data", .type = BLOBMSG_TYPE_STRING},
 };
 
-static int vsie_add(struct ubus_context *ctx, struct ubus_object *obj,
+int vsie_add(struct ubus_context *ctx, struct ubus_object *obj,
 		      struct ubus_request_data *ureq, const char *method,
 		      struct blob_attr *msg)
 {
@@ -1711,13 +1721,15 @@ static int vsie_add(struct ubus_context *ctx, struct ubus_object *obj,
 	data[1] = data_len;
 	req->ie.ie_hdr.len += 2 + data_len;
 
+
+
 	if (wifi_add_vendor_ie(ifname, req) != 0)
 		return UBUS_STATUS_UNKNOWN_ERROR;
 
 	return UBUS_STATUS_OK;
 }
 
-static int vsie_del(struct ubus_context *ctx, struct ubus_object *obj,
+int vsie_del(struct ubus_context *ctx, struct ubus_object *obj,
 		      struct ubus_request_data *ureq, const char *method,
 		      struct blob_attr *msg)
 {
@@ -2038,7 +2050,7 @@ static const struct blobmsg_policy radio_get_param_policy[__GET_MAX] = {
 	[GET_PNAME] = { .name = "param", .type = BLOBMSG_TYPE_STRING },
 };
 
-static int wl_radio_get_param(struct ubus_context *ctx, struct ubus_object *obj,
+int wl_radio_get_param(struct ubus_context *ctx, struct ubus_object *obj,
 		  struct ubus_request_data *req, const char *method,
 		  struct blob_attr *msg)
 {
@@ -2147,13 +2159,13 @@ static int add_radio_methods(struct ubus_object *radio_obj,
 	//UBUS_METHOD_ADD(radio_methods, n_methods,
 	//	UBUS_METHOD_NOARG("temperature", wl_temperature));
 
-	if (libwifi_supports(radioname, "wifi_scan")) {
+//	if (libwifi_supports(radioname, "wifi_scan")) {
 		UBUS_METHOD_ADD(radio_methods, n_methods,
 			UBUS_METHOD("scan", wl_scan, wl_scan_policy));
 
 		UBUS_METHOD_ADD(radio_methods, n_methods,
 			UBUS_METHOD("scanresults", wl_scanresults, wl_scanres_policy));
-	}
+//	}
 
 	UBUS_METHOD_ADD(radio_methods, n_methods,
 		UBUS_METHOD("autochannel", wl_autochannel, wl_acs_policy));
diff --git a/wps.c b/wps.c
index 91494e94772b0890e05a719add4d083d72d88c8d..b851fbc4ada1741012749370670345d95829b820 100644
--- a/wps.c
+++ b/wps.c
@@ -248,12 +248,15 @@ static int wps_status(struct ubus_context *ctx, struct ubus_object *obj,
 	return 0;
 }
 
-static int wps_start(struct ubus_context *ctx, struct ubus_object *obj,
+int wps_start(struct ubus_context *ctx, struct ubus_object *obj,
 		  struct ubus_request_data *req, const char *method,
 		  struct blob_attr *msg)
 {
 	struct blob_attr *tb[__WPS_START_ATTR_MAX];
-	struct wps_param wps;
+	struct wps_param wps = {
+		.role = WPS_REGISTRAR,
+		.mode = WPS_MODE_PBC
+	};
 	char ifname[16] = {0};
 	char role[16] = {0};
 	char mode[8] = {0};
@@ -288,7 +291,7 @@ static int wps_start(struct ubus_context *ctx, struct ubus_object *obj,
 		strncpy(role, blobmsg_data(tb[WPS_START_ATTR_ROLE]), 10);
 		if (!strcasecmp(role, "registrar"))
 			wps.role = WPS_REGISTRAR;
-		else if (!strcasecmp(mode, "enrollee"))
+		else if (!strcasecmp(role, "enrollee"))
 			wps.role = WPS_ENROLLEE;
 		else
 			return UBUS_STATUS_INVALID_ARGUMENT;
@@ -354,7 +357,7 @@ static int wps_checkpin(struct ubus_context *ctx, struct ubus_object *obj,
 	return UBUS_STATUS_OK;
 }
 
-static int wps_set_ap_pin(struct ubus_context *ctx, struct ubus_object *obj,
+int wps_set_ap_pin(struct ubus_context *ctx, struct ubus_object *obj,
 		  struct ubus_request_data *req, const char *method,
 		  struct blob_attr *msg)
 {
@@ -414,7 +417,7 @@ static int wps_show_ap_pin(struct ubus_context *ctx, struct ubus_object *obj,
 	return UBUS_STATUS_OK;
 }
 
-static int wps_stop(struct ubus_context *ctx, struct ubus_object *obj,
+int wps_stop(struct ubus_context *ctx, struct ubus_object *obj,
 		  struct ubus_request_data *req, const char *method,
 		  struct blob_attr *msg)
 {