diff --git a/README.md b/README.md
index 8ff44e3e2b09f2a3b863dab03adc3adde242528b..a48901e188db4225f6cfc0ef49362827c5bc3f5e 100644
--- a/README.md
+++ b/README.md
@@ -65,15 +65,25 @@ config ptm-device 'ptm0'
 This is a verbose print of all methods published to ubus on a device.
 
 ```bash
-'dsl' @d35e2f41
-	"status":{}
-	"stats":{}
-'dsl.channel.0' @9f3ca1b2
-	"status":{}
-	"stats":{"interval":"String"}
-'dsl.line.0' @c01eec72
-	"status":{}
-	"stats":{"interval":"String"}
+'atm.link.0' @607d41d6
+        "status":{}
+        "stats":{}
+        "configure":{"link_type":"String","vpi":"Integer","vci":"Integer","encapsulation":"String","qos_class":"String","peak_cell_rate":"Integer","max_burst_size":"Integer","sustainable_cell_rate":"Integer"}
+'dsl' @8e73ca86
+        "status":{}
+        "stats":{}
+'dsl.channel.0' @e76e0883
+        "status":{}
+        "stats":{"interval":"String"}
+'dsl.line.0' @3a06e2d2
+        "status":{}
+        "stats":{"interval":"String"}
+        "configure":{"xtse":"String","vdsl2_profiles":"String","fast_profiles":"String","data_gathering":"Boolean","limit_mask":"Integer","us0_mask":"Integer"}
+'fast.line.0' @bc51c0a7
+        "status":{}
+        "stats":{"interval":"String"}
+'ptm.link.0' @35822197
+        "status":{}
 ```
 
 For more info on the Ubus API see [link](./docs/ubus.splash.md)
diff --git a/docs/api/atm.link.md b/docs/api/atm.link.md
new file mode 100644
index 0000000000000000000000000000000000000000..1266d323ba7892ebadc6a3f935e80c05c5bbc28c
--- /dev/null
+++ b/docs/api/atm.link.md
@@ -0,0 +1,157 @@
+# atm.link.<number>
+
+| List of Methods                   |
+| --- |
+| [status](#status)                 |
+| [stats](#stats)                   |
+| [configure](#configure)           |
+
+## status
+
+`status`
+
+Type: `Method`
+
+### Ubus CLI Example
+
+```bash
+ubus call atm.link.0 status
+```
+
+### JSONRPC Example
+
+```json
+{
+  "jsonrpc": "2.0",
+  "id": 0,
+  "method": "call",
+  "params": ["<SID>", "atm.link.0", "status"]
+}
+```
+
+### Input
+
+None
+
+### Output
+
+- type: `object`
+- Example as below
+```json
+{
+        "status": "up",
+        "link_type": "eoa",
+        "auto_config": true,
+        "dest_addr": {
+                "vpi": 8,
+                "vci": 35
+        },
+        "encapsulation": "llc",
+        "fcs_preserved": true,
+        "vc_search_list": [
+                {
+                        "vpi": 8,
+                        "vci": 36
+                },
+                {
+                        "vpi": 8,
+                        "vci": 37
+                }
+        ],
+        "aal": "aal5",
+        "qos": {
+                "qos_class": "ubr",
+                "peak_cell_rate": 18867,
+                "max_burst_size": 22640,
+                "sustainable_cell_rate": 15093
+        }
+}
+```
+
+## stats
+
+`stats`
+
+Type: `Method`
+
+### Ubus CLI Example
+
+```bash
+ubus call atm.link.0 stats
+```
+
+### JSONRPC Example
+
+```json
+{
+  "jsonrpc": "2.0",
+  "id": 0,
+  "method": "call",
+  "params": ["<SID>", "atm.link.0", "stats"]
+}
+```
+
+### Input
+
+None
+
+### Output
+
+- type: `object`
+- Example as below
+```json
+{
+        "transmitted_blocks": 12345678,
+        "received_blocks": 87654321,
+        "crc_errors": 12
+}
+```
+
+## configure
+
+`configure {...}`
+
+Type: `Method`
+
+### Ubus CLI Example
+
+```bash
+ubus call atm.link.0 configure "{'link_type':'eoa','vpi':8,'vci':35,'encapsulation':'llc',\
+    'qos_class':'ubr','peak_cell_rate':10240,'max_burst_size':8124,'sustainable_cell_rate':9600}"
+```
+
+### JSONRPC Example
+
+```json
+{
+  "jsonrpc": "2.0",
+  "id": 0,
+  "method": "call",
+  "params": ["<SID>", "atm.link.0", "configure", "{'link_type':'eoa','vpi':8,'vci':35,'encapsulation':'llc'}"]
+}
+```
+
+### Input
+
+- Type: `object`
+- Parameter: `link_type`
+- Value: ATM link type with one of values "eoa", "ipoa", "pppoa" and "cip"
+- Parameer:`vpi`
+- Value: unsigned int as virtual path index
+- Parameer:`vci`
+- Value: unsigned int as virtual circuit index
+- Parameer:`encapsulation`
+- Value: ATM link encapsulation with one of values "llc" and "vcmux"
+- Parameer:`qos_class`
+- Value: ATM QoS class with one of values "ubr", "cbr", "gfr", "vbr_nrt", "vbr_rt", "ubr_plus" and "abr"
+- Parameer:`peak_cell_rate`
+- Value: unsigned integer
+- Parameer:`max_burst_size`
+- Value: unsigned integer
+- Parameer:`sustainable_cell_rate`
+- Value: unsigned integer
+
+### Output
+
+None
+
diff --git a/docs/api/dsl.line.md b/docs/api/dsl.line.md
index a1904115a120c48633b5b154b25694612f4a4512..8620141a3eb5d20e9bafe79881645efe49a927cd 100644
--- a/docs/api/dsl.line.md
+++ b/docs/api/dsl.line.md
@@ -5,6 +5,7 @@
 | [status](#status)                 |
 | [stats](#stats)                   |
 | [stats_interval](#stats_interval) |
+| [configure](#configure)           |
 
 ## status
 
@@ -247,3 +248,50 @@ ubus call dsl.line.0 stats "{ 'interval': 'total'}"
     "severely_errored_secs": 0
 }
 ```
+
+## configure
+
+`configure {...}`
+
+Type: `Method`
+
+### Ubus CLI Example
+
+```bash
+ubus call dsl.line.0 configure "{'xtse':'01,02,ab,cd,41,52,f8,6e',\
+    'vdsl2_profiles':'8a,8b,8c,8d,17a,30a,35b',\
+    'fast_profiles':'106a,212a','data_gathering':true,'limit_mask':255,'us0_mask':511}"
+```
+
+### JSONRPC Example
+
+```json
+{
+  "jsonrpc": "2.0",
+  "id": 0,
+  "method": "call",
+  "params": ["<SID>", "dsl.line.0", "configure", "{'xtse':'01,02,ab,cd,41,52,f8,6e','vdsl2_profiles':'8a,8b,8c,8d,17a,30a,35b'}"]
+}
+```
+
+### Input
+
+- Type: `object`
+- Parameter: `xtse`
+- Value: 8 octects which include all modes supported by the DSL line
+- Parameer:`vdsl2_profiles`
+- Value: Sub/full set of "8a,8b,8c,8d,17a,30a,35b" of VDSL2 profiles
+- Parameer:`fast_profiles`
+- Value: Sub/full set of "106a,212a" of FAST profiles
+- Parameer:`data_gathering`
+- Value: true or false to enale/disable data gathering
+- Parameer:`limit_mask`
+- Value: unsigned integer as limit mask
+- Parameer:`us0_mask`
+- Value: unsigned integer as us0 mask
+
+
+### Output
+
+None
+
diff --git a/docs/api/fast.line.md b/docs/api/fast.line.md
new file mode 100644
index 0000000000000000000000000000000000000000..9a90ad9444b2ab67c0f40e1bbee350ec7aded48e
--- /dev/null
+++ b/docs/api/fast.line.md
@@ -0,0 +1,264 @@
+# fast.line.&lt;number&gt;
+
+| List of Methods                   |
+| --- |
+| [status](#status)                 |
+| [stats](#stats)                   |
+| [stats_interval](#stats_interval) |
+
+## status
+
+`status`
+
+Type: `Method`
+
+### Ubus CLI Example
+
+```bash
+ubus call fast.line.0 status
+```
+
+### JSONRPC Example
+
+```json
+{
+  "jsonrpc": "2.0",
+  "id": 0,
+  "method": "call",
+  "params": ["<SID>", "fast.line.0", "status"]
+}
+```
+
+### Input
+
+None
+
+### Output
+
+- type: `object`
+- Example as below
+```json
+{
+        "status": "up",
+        "upstream": true,
+        "firmware_version": "A2pvfbH045k.d28a",
+        "link_status": "up",
+        "current_profile": "106a",
+        "power_management_state": "l0",
+        "max_bit_rate": {
+                "us": 201000,
+                "ds": 402000
+        },
+        "allowed_profiles": [
+                "106a",
+                "212a"
+        ],
+        "success_failure_cause": 0,
+        "upbokler": 180,
+        "last_transmitted_signal": {
+                "us": 100,
+                "ds": 200
+        },
+        "upbokle": 160,
+        "line_number": 1,
+        "noise_margin": {
+                "us": 146,
+                "ds": 177
+        },
+        "attenuation": {
+                "us": 0,
+                "ds": 48
+        },
+        "power": {
+                "us": 123,
+                "ds": 106
+        },
+        "snrm_rmc": {
+                "us": 12,
+                "ds": 14
+        },
+        "bits_rmc_ps": [
+                1,
+                3,
+                5,
+                7
+        ],
+        "fext_to_cancel_enable": {
+                "us": true,
+                "ds": true
+        },
+        "etr": {
+                "us": 250000,
+                "ds": 350000
+        },
+        "att_etr": {
+                "us": 225000,
+                "ds": 325000
+        },
+        "min_eftr": {
+                "us": 200000,
+                "ds": 300000
+        }
+}
+```
+
+## stats
+
+`stats`
+
+Type: `Method`
+
+### Ubus CLI Example
+
+```bash
+ubus call fast.line.0 stats
+```
+
+### JSONRPC Example
+
+```json
+{
+  "jsonrpc": "2.0",
+  "id": 0,
+  "method": "call",
+  "params": ["<SID>", "fast.line.0", "stats"]
+}
+```
+
+### Input
+
+None
+
+### Output
+
+- type: `object`
+- Example as below
+```json
+{
+        "total_start": 397,
+        "showtime_start": 349,
+        "last_showtime_start": 349,
+        "current_day_start": 397,
+        "quarter_hour_start": 397,
+        "total": {
+                "errored_secs": 20,
+                "severely_errored_secs": 5,
+                "loss": 1,
+                "lors": 4294967295,
+                "uas": 1,
+                "rtx_uc": 4294967295,
+                "rtx_tx": 0,
+                "success_bsw": 1024,
+                "success_sra": 2048,
+                "success_fra": 1024,
+                "success_rpa": 2048,
+                "success_tiga": 1024
+        },
+        "showtime": {
+                "errored_secs": 20,
+                "severely_errored_secs": 5,
+                "loss": 1,
+                "lors": 4294967295,
+                "uas": 1,
+                "rtx_uc": 4294967295,
+                "rtx_tx": 0,
+                "success_bsw": 1024,
+                "success_sra": 2048,
+                "success_fra": 1024,
+                "success_rpa": 2048,
+                "success_tiga": 1024
+        },
+        "lastshowtime": {
+                "errored_secs": 20,
+                "severely_errored_secs": 5,
+                "loss": 1,
+                "lors": 4294967295,
+                "uas": 1,
+                "rtx_uc": 4294967295,
+                "rtx_tx": 0,
+                "success_bsw": 1024,
+                "success_sra": 2048,
+                "success_fra": 1024,
+                "success_rpa": 2048,
+                "success_tiga": 1024
+        },
+        "currentday": {
+                "errored_secs": 20,
+                "severely_errored_secs": 5,
+                "loss": 1,
+                "lors": 4294967295,
+                "uas": 1,
+                "rtx_uc": 4294967295,
+                "rtx_tx": 0,
+                "success_bsw": 1024,
+                "success_sra": 2048,
+                "success_fra": 1024,
+                "success_rpa": 2048,
+                "success_tiga": 1024
+        },
+        "quarterhour": {
+                "errored_secs": 20,
+                "severely_errored_secs": 5,
+                "loss": 1,
+                "lors": 4294967295,
+                "uas": 1,
+                "rtx_uc": 4294967295,
+                "rtx_tx": 0,
+                "success_bsw": 1024,
+                "success_sra": 2048,
+                "success_fra": 1024,
+                "success_rpa": 2048,
+                "success_tiga": 1024
+        }
+}
+```
+
+## stats_interval
+
+`stats <interval>`
+
+Type: `Method`
+
+### Ubus CLI Example
+
+```bash
+ubus call fast.line.0 stats "{ 'interval': 'total'}"
+```
+
+### JSONRPC Example
+
+```json
+{
+  "jsonrpc": "2.0",
+  "id": 0,
+  "method": "call",
+  "params": ["<SID>", "fast.line.0", "stats", "{ 'interval': 'total'}"]
+}
+```
+
+### Input
+
+- Type: `object`
+- Parameter: `interval`
+- Value: `total`, `showtime`, `lastshowtime`, `currentday`, or `quarterhour`
+
+### Output
+
+- type: `object`
+- Example as below
+```json
+{
+        "errored_secs": 20,
+        "severely_errored_secs": 5,
+        "loss": 1,
+        "lors": 4294967295,
+        "uas": 1,
+        "rtx_uc": 4294967295,
+        "rtx_tx": 0,
+        "success_bsw": 1024,
+        "success_sra": 2048,
+        "success_fra": 1024,
+        "success_rpa": 2048,
+        "success_tiga": 1024
+}
+```
diff --git a/docs/api/ptm.link.md b/docs/api/ptm.link.md
new file mode 100644
index 0000000000000000000000000000000000000000..5e8ecbff8937f58da8070fb223039e829a9b21c5
--- /dev/null
+++ b/docs/api/ptm.link.md
@@ -0,0 +1,43 @@
+# ptm.link.&lt;number&gt;
+
+| List of Methods                   |
+| --- |
+| [status](#status)                 |
+
+## status
+
+`status`
+
+Type: `Method`
+
+### Ubus CLI Example
+
+```bash
+ubus call ptm.link.0 status
+```
+
+### JSONRPC Example
+
+```json
+{
+  "jsonrpc": "2.0",
+  "id": 0,
+  "method": "call",
+  "params": ["<SID>", "ptm.link.0", "status"]
+}
+```
+
+### Input
+
+None
+
+### Output
+
+- type: `object`
+- Example as below
+```json
+{
+        "status": "up",
+        "mac_addr": "00:11:22:33:44:55"
+}
+```
diff --git a/docs/testspec.md b/docs/testspec.md
index b937640bcf52c5bc5ee64f048120e332ff671f9a..68844b8bf04881c92fae87f84c46bdd623a1d523 100644
--- a/docs/testspec.md
+++ b/docs/testspec.md
@@ -29,6 +29,7 @@ using JSON-C library APIs.
 | 1				| status     	| No argument  	| [1](./api/dsl.line.md#status) |
 | 2				| stats     	| No argument	  | [2](./api/dsl.line.md#stats)  |
 | 3				| stats     	| Interval	    | [3](./api/dsl.line.md#stats_interval) |
+| 9                             | configure     | DSL_config          | [9](./api/dsl.line.md#configure) |
 
 #### dsl.channel.&lt;number&gt;
 
@@ -45,6 +46,28 @@ using JSON-C library APIs.
 | 7				| status     	| No argument  	| [7](./api/dsl.md#status) |
 | 8				| stats     	| No argument	  | [8](./api/dsl.md#stats)  |
 
+#### fast.line.&lt;number&gt;
+
+| Execution ID  | Method        | Description   | Function ID Coverage                  |
+| :---                  | :---                  | :---                  | :---                                                  |
+| 10                             | status        | No argument   | [10](./api/fast.line.md#status) |
+| 11                             | stats         | No argument     | [11](./api/fast.line.md#stats)  |
+| 12                             | stats         | Interval          | [12](./api/fast.line.md#stats_interval) |
+
+#### atm.link.&lt;number&gt;
+
+| Execution ID  | Method        | Description   | Function ID Coverage                  |
+| :---                  | :---                  | :---                  | :---                                                  |
+| 13                             | status        | No argument   | [13](./api/atm.link.md#status) |
+| 14                             | stats         | No argument     | [14](./api/atm.link.md#stats)  |
+| 15                            | configure     | ATM_config          | [15](./api/atm.link.md#configure) |
+
+#### ptm.link.&lt;number&gt;
+
+| Execution ID  | Method        | Description   | Function ID Coverage                  |
+| :---                  | :---                  | :---                  | :---                                                  |
+| 16                             | status        | No argument   | [16](./api/ptm.link.md#status) |
+
 ### Unit Tests
 
 The *dslmngr* unit tests are written in CMocka, invoking the UBUS callbacks directly from the source code, which is compiled
@@ -53,16 +76,20 @@ into a shared library. This means mocking the arguments of a CLI or libubus invo
 The output of the UBUS callbacks are retrieved by manipulation of the function ubus_send_reply(). Then the output is analyzed
 and verified by each test case.
 
-| Execution ID	| Method      	   | Test Case Name 	                   | Function ID Coverage			                     |
+| Execution ID	| Method      	   | Test Case Name 	                   | Function ID Coverage			                  |
 | :---    | :---                   | :---                                | :---                                          |
-| 1				| line_status     	     | test_api_dsl_line_status            | [1](./api/dsl.line.md#status)            |
-| 2				| line_stats     	       | test_api_dsl_line_stats             | [2](./api/dsl.line.md#stats)             |
+| 1				| line_status     	 | test_api_dsl_line_status            | [1](./api/dsl.line.md#status)            |
+| 2				| line_stats     	 | test_api_dsl_line_stats             | [2](./api/dsl.line.md#stats)             |
 | 3				| line_stats_interval  	 | test_api_dsl_line_stats_interval    | [3](./api/dsl.line.md#stats_interval)    |
 | 4				| channel_status         | test_api_dsl_channel_status         | [4](./api/dsl.channel.md#status)         |
-| 5				| channel_stats     	   | test_api_dsl_channel_stats          | [5](./api/dsl.channel.md#stats)          |
+| 5				| channel_stats     	 | test_api_dsl_channel_stats          | [5](./api/dsl.channel.md#stats)          |
 | 6				| channel_stats_interval | test_api_dsl_channel_stats_interval | [6](./api/dsl.channel.md#stats_interval) |
 | 7				| dsl_status             | test_api_dsl_status                 | [7](./api/dsl.md#status)                 |
 | 8				| dsl_stats              | test_api_dsl_stats                  | [8](./api/dsl.md#stats)                  |
+| 9                             | dsl_configure          | test_api_dsl_configure              | [9](./api/dsl.line.md#configure)         |
+| 10                            | dsl_configure_fail     | test_api_dsl_configure_fail         | [9](./api/dsl.line.md#configure)         |
+| 11                            | atm_configure          | test_api_atm_configure              | [15](./api/atm.link.md#configure)        |
+| 12                            | atm_configure_fail     | test_api_atm_configure_fai          | [15](./api/atm.link.md#configure)        |
 
 #### test_api_dsl_line_status
 
@@ -191,3 +218,72 @@ Test the *dslmngr* UBUS API callback `dsl_stats_all()`, providing the method [ds
 
 Parameters' values included in the returned JSON object of the output shall be equal to those returned by the corresponding
 stub API in *libdsl* building for TEST platform.
+
+#### dsl_configure
+
+##### Description
+
+Test the *dslmngr* UBUS API callback `dsl_line_configure()`, providing the method [dsl configure](./api/dsl.line.md#configure).
+
+##### Test Steps
+
+- Prepare valid input parameters
+- Call `dsl_line_configure()`
+- Analyze and verify the output
+
+##### Expected Results
+
+The dumped input parameters by the corresponding libdsl API must be as same as those prepared in th first step. And the
+returned value must indicate success.
+
+#### dsl_configure_fail
+
+##### Description
+
+Test the *dslmngr* UBUS API callback `dsl_line_configure()`, providing the method [dsl configure](./api/dsl.line.md#configure).
+
+##### Test Steps
+
+- Prepare invalid input parameters
+- Call `dsl_line_configure()`
+- Analyze and verify the output
+
+##### Expected Results
+
+The dumped input parameters by the corresponding libdsl API must be as same as those prepared in th first step. And the
+returned value must indicate failure.
+
+#### atm_configure
+
+##### Description
+
+Test the *dslmngr* UBUS API callback `atm_link_configure()`, providing the method [atm configure](./api/atm.link.md#configure).
+
+##### Test Steps
+
+- Prepare valid input parameters
+- Call `atm_link_configure()`
+- Analyze and verify the output
+
+##### Expected Results
+
+The dumped input parameters by the corresponding libdsl API must be as same as those prepared in th first step. And the
+returned value must indicate success.
+
+#### atm_configure_fail
+
+##### Description
+
+Test the *dslmngr* UBUS API callback `atm_link_configure()`, providing the method [atm configure](./api/atm.link.md#configure).
+
+##### Test Steps
+
+- Prepare valid input parameters
+- Call `atm_link_configure()`
+- Analyze and verify the output
+
+##### Expected Results
+
+The dumped input parameters by the corresponding libdsl API must be as same as those prepared in th first step. And the
+returned value must indicate failure.
+
diff --git a/docs/ubus.splash.md b/docs/ubus.splash.md
index 98388171ba8a620f027bc970c2c9e2394c4b0f7c..643fdfd3f087c8ed4c8cf6dee5915fe66f362346 100644
--- a/docs/ubus.splash.md
+++ b/docs/ubus.splash.md
@@ -3,3 +3,6 @@
 * [DSL](./api/dsl.md)
 * [DSL Line](./api/dsl.line.md)
 * [DSL Channel](./api/dsl.channel.md)
+* [FAST Line](./api/fast.line.md)
+* [ATM Link](./api/atm.link.md)
+* [PTM Link](./api/ptm.link.md)
diff --git a/dslmngr.c b/dslmngr.c
index c08ed7468b27205c52bff45bddf13ff5a682fe8a..aa42c2c3f3d80fcc7908488f24635d98f96dd733 100644
--- a/dslmngr.c
+++ b/dslmngr.c
@@ -32,6 +32,7 @@
 #include <uci.h>
 
 #include "xdsl.h"
+#include "xtm.h"
 #include "dslmngr.h"
 
 #define DSL_OBJECT_LINE "line"
@@ -42,6 +43,8 @@ struct value2text {
 	char *text;
 };
 
+int current_log_level = LOG_WARNING;
+
 enum {
 	DSL_STATS_INTERVAL,
 	__DSL_STATS_MAX,
@@ -51,6 +54,25 @@ static const struct blobmsg_policy dsl_stats_policy[__DSL_STATS_MAX] = {
 	[DSL_STATS_INTERVAL] = { .name = "interval", .type = BLOBMSG_TYPE_STRING },
 };
 
+enum {
+	DSL_CONFIGURE_XTSE,
+	DSL_CONFIGURE_VDSL2_PROFILES,
+	DSL_CONFIGURE_FAST_PROFILES,
+	DSL_CONFIGURE_ENABLE_DATA_GATHERING,
+	DSL_CONFIGURE_LIMIT_MASK,
+	DSL_CONFIGURE_US0_MASK,
+	__DSL_CONFIGURE_MAX
+};
+
+static const struct blobmsg_policy dsl_configure_policy[] = {
+	[DSL_CONFIGURE_XTSE] = { .name = "xtse", .type = BLOBMSG_TYPE_STRING },
+	[DSL_CONFIGURE_VDSL2_PROFILES] = { .name = "vdsl2_profiles", .type = BLOBMSG_TYPE_STRING },
+	[DSL_CONFIGURE_FAST_PROFILES] = { .name = "fast_profiles", .type = BLOBMSG_TYPE_STRING },
+	[DSL_CONFIGURE_ENABLE_DATA_GATHERING] = { .name = "data_gathering", .type = BLOBMSG_TYPE_BOOL },
+	[DSL_CONFIGURE_LIMIT_MASK] = { .name = "limit_mask", .type = BLOBMSG_TYPE_INT32 },
+	[DSL_CONFIGURE_US0_MASK] = { .name = "us0_mask", .type = BLOBMSG_TYPE_INT32 }
+};
+
 static const char *dsl_if_status_str(enum itf_status status)
 {
 	switch (status) {
@@ -203,18 +225,22 @@ static const char *dsl_line_encoding_str(enum dsl_line_encoding encoding)
 
 static const char *dsl_profile_str(enum dsl_profile profile)
 {
-	switch (profile) {
-	case VDSL2_8a: return "8a";
-	case VDSL2_8b: return "8b";
-	case VDSL2_8c: return "8c";
-	case VDSL2_8d: return "8d";
-	case VDSL2_12a: return "12a";
-	case VDSL2_12b: return "12b";
-	case VDSL2_17a: return "17a";
-	case VDSL2_30a: return "30a";
-	case VDSL2_35b: return "35b";
-	default: return "unknown";
-	}
+	const char *str = dsl_get_string_value(vdsl2_profiles, profile);
+
+	if (!str)
+		return "unknown";
+
+	return str;
+};
+
+static const char *fast_profile_str(enum fast_profile profile)
+{
+	const char *str = dsl_get_string_value(fast_profiles, profile);
+
+	if (!str)
+		return "unknown";
+
+	return str;
 };
 
 static const char *dsl_power_state_str(enum dsl_power_state power_state)
@@ -656,18 +682,16 @@ __ret:
 	return retval;
 }
 
-static struct ubus_method dsl_main_methods[] = {
+static struct ubus_method dsl_methods[] = {
 	{ .name = "status", .handler = dsl_status_all },
 	{ .name = "stats", .handler = dsl_stats_all }
 };
-
-static struct ubus_object_type dsl_main_type = UBUS_OBJECT_TYPE("dsl", dsl_main_methods);
-
-static struct ubus_object dsl_main_object = {
+static struct ubus_object_type dsl_type = UBUS_OBJECT_TYPE("dsl", dsl_methods);
+static struct ubus_object dsl_object = {
 	.name = "dsl",
-	.type = &dsl_main_type,
-	.methods = dsl_main_methods,
-	.n_methods = ARRAY_SIZE(dsl_main_methods),
+	.type = &dsl_type,
+	.methods = dsl_methods,
+	.n_methods = ARRAY_SIZE(dsl_methods),
 };
 
 int dsl_line_status(struct ubus_context *ctx, struct ubus_object *obj,
@@ -777,7 +801,8 @@ __ret:
 
 static struct ubus_method dsl_line_methods[] = {
 	{ .name = "status", .handler = dsl_line_status },
-	UBUS_METHOD("stats", dsl_line_stats, dsl_stats_policy )
+	UBUS_METHOD("stats", dsl_line_stats, dsl_stats_policy),
+	UBUS_METHOD("configure", dsl_line_configure,  dsl_configure_policy)
 };
 
 static struct ubus_object_type dsl_line_type = UBUS_OBJECT_TYPE("dsl.line", dsl_line_methods);
@@ -894,16 +919,692 @@ static struct ubus_method dsl_channel_methods[] = {
 
 static struct ubus_object_type dsl_channel_type = UBUS_OBJECT_TYPE("dsl.channel", dsl_channel_methods);
 
+static void fast_line_status_to_blob(const struct fast_line *line, struct blob_buf *bb)
+{
+	void *array;
+	int i, j, count;
+	unsigned long opt;
+	char str[64];
+	enum itf_status if_status = line->status;
+
+	/*
+	 * Put most important information at the beginning
+	 */
+	if (if_status == IF_UP && line->link_status != LINK_UP) {
+		/* Some inconsistent status might be retrieved from the driver, i.e. interface status is
+		 * up and the link status is not up. In this case, we force reporting the interface's
+		 * status being down */
+		if_status = IF_DOWN;
+	}
+	blobmsg_add_string(bb, "status", dsl_if_status_str(if_status));
+	blobmsg_add_u8(bb, "upstream", line->upstream);
+	blobmsg_add_string(bb, "firmware_version", line->firmware_version);
+	blobmsg_add_string(bb, "link_status", dsl_link_status_str(line->link_status));
+	blobmsg_add_string(bb, "current_profile", fast_profile_str(line->current_profile));
+	blobmsg_add_string(bb, "power_management_state", dsl_power_state_str(line->power_management_state));
+
+	// max_bit_rate
+	unsigned long rates[] = { line->max_bit_rate.us, line->max_bit_rate.ds };
+	dsl_add_usds_to_blob("max_bit_rate", false, rates, bb);
+
+	// allowed_profiles
+	array = blobmsg_open_array(bb, "allowed_profiles");
+	for (opt = (unsigned long)FAST_106a; opt <= (unsigned long)FAST_212a; opt <<= 1) {
+		if (line->allowed_profiles & opt)
+			blobmsg_add_string(bb, "", fast_profile_str(opt));
+	}
+	blobmsg_close_array(bb, array);
+
+	blobmsg_add_u32(bb, "success_failure_cause", line->success_failure_cause);
+	blobmsg_add_u32(bb, "upbokler", line->upbokler);
+
+	// last_transmitted_signal
+	long signals[] = { line->last_transmitted_signal.us, line->last_transmitted_signal.ds };
+	dsl_add_usds_to_blob("last_transmitted_signal", true, signals, bb);
+
+
+	blobmsg_add_u32(bb, "upbokle", line->upbokle);
+	dsl_add_int_to_blob("line_number", line->line_number, bb);
+
+	// noise_margin
+	long margins[] = { line->noise_margin.us, line->noise_margin.ds };
+	dsl_add_usds_to_blob("noise_margin", true, margins, bb);
+
+	// attenuation
+	long attenuations[] = { line->attenuation.us, line->attenuation.ds };
+	dsl_add_usds_to_blob("attenuation", true, attenuations, bb);
+
+	// power
+	long powers[] = { line->power.us, line->power.ds };
+	dsl_add_usds_to_blob("power", true, powers, bb);
+
+	// snrm_rmc
+	long rmc[] = { line->snrm_rmc.us, line->snrm_rmc.ds };
+	dsl_add_usds_to_blob("snrm_rmc", true, rmc, bb);
+
+	// bits_rmc_ps
+	dsl_add_sequence_to_blob("bits_rmc_ps", false, line->bits_rmc_ps.count,
+				(const long *)line->bits_rmc_ps.elements, bb);
+
+	// fext_to_cancel_enable
+	void *table = blobmsg_open_table(bb, "fext_to_cancel_enable");
+	blobmsg_add_u8(bb, "us", line->fext_to_cancel_enable.us);
+	blobmsg_add_u8(bb, "ds", line->fext_to_cancel_enable.ds);
+	blobmsg_close_table(bb, table);
+
+	// etr
+	unsigned long etr[] = { line->etr.us, line->etr.ds };
+	dsl_add_usds_to_blob("etr", false, etr, bb);
+
+	// att_etr
+	unsigned long att_etr[] = { line->att_etr.us, line->att_etr.ds };
+	dsl_add_usds_to_blob("att_etr", false, att_etr, bb);
+
+	// min_eftr
+	unsigned long min_eftr[] = { line->min_eftr.us, line->min_eftr.ds };
+	dsl_add_usds_to_blob("min_eftr", false, min_eftr, bb);
+}
+
+int fast_line_status(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method, struct blob_attr *msg)
+{
+	static struct blob_buf bb;
+	struct fast_line line;
+	int retval = UBUS_STATUS_OK;
+	int num = -1;
+
+	// Initialize the buffer
+	memset(&bb, 0, sizeof(bb));
+	blob_buf_init(&bb, 0);
+
+	// Get line status
+	sscanf(obj->name, "fast.line.%d", &num);
+	if (xdsl_ops.get_fast_line_info == NULL || (*xdsl_ops.get_fast_line_info)(num, &line) != 0) {
+		retval = UBUS_STATUS_UNKNOWN_ERROR;
+		goto __ret;
+	}
+	fast_line_status_to_blob(&line, &bb);
+
+	// Send the reply
+	ubus_send_reply(ctx, req, bb.head);
+
+__ret:
+	blob_buf_free(&bb);
+	return retval;
+}
+
+static void fast_line_stats_interval_to_blob(const struct fast_line_stats_interval *stats, struct blob_buf *bb)
+{
+	blobmsg_add_u64(bb, "errored_secs", stats->errored_secs);
+	blobmsg_add_u64(bb, "severely_errored_secs", stats->severely_errored_secs);
+	blobmsg_add_u64(bb, "loss", stats->loss);
+	blobmsg_add_u64(bb, "lors", stats->lors);
+	blobmsg_add_u64(bb, "uas", stats->uas);
+	blobmsg_add_u64(bb, "rtx_uc", stats->rtx_uc);
+	blobmsg_add_u64(bb, "rtx_tx", stats->rtx_tx);
+	blobmsg_add_u64(bb, "success_bsw", stats->success_bsw);
+	blobmsg_add_u64(bb, "success_sra", stats->success_sra);
+	blobmsg_add_u64(bb, "success_fra", stats->success_fra);
+	blobmsg_add_u64(bb, "success_rpa", stats->success_rpa);
+	blobmsg_add_u64(bb, "success_tiga", stats->success_tiga);
+}
+
+int fast_line_stats_handler(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method, struct blob_attr *msg)
+{
+	static struct blob_buf bb;
+	struct blob_attr *tb[__DSL_STATS_MAX];
+	enum dsl_stats_type type = DSL_STATS_QUARTERHOUR + 1;
+	struct fast_line_stats stats;
+	struct fast_line_stats_interval stats_interval;
+	int retval = UBUS_STATUS_OK;
+	int num = -1;
+	int i, j;
+	void *table;
+
+	// Parse and validation check the interval type if any
+	blobmsg_parse(dsl_stats_policy, __DSL_STATS_MAX, tb, blob_data(msg), blob_len(msg));
+	if (tb[DSL_STATS_INTERVAL]) {
+		const char *st = blobmsg_data(tb[DSL_STATS_INTERVAL]);
+
+		for (i = 0; i < ARRAY_SIZE(dsl_stats_types); i++) {
+			if (strcasecmp(st, dsl_stats_types[i].text) == 0) {
+				type = dsl_stats_types[i].value;
+				break;
+			}
+		}
+
+		if (i >= ARRAY_SIZE(dsl_stats_types)) {
+			DSLMNGR_LOG(LOG_ERR, "Wrong argument for interval statistics type\n");
+			return UBUS_STATUS_INVALID_ARGUMENT;
+		}
+	}
+
+	// Initialize the buffer
+	memset(&bb, 0, sizeof(bb));
+	blob_buf_init(&bb, 0);
+
+	// Get line number
+	sscanf(obj->name, "fast.line.%d", &num);
+
+	// Get line interval statistics
+	if (type >= DSL_STATS_TOTAL && type <= DSL_STATS_QUARTERHOUR) {
+		if (xdsl_ops.get_fast_line_stats_interval == NULL || (*xdsl_ops.get_fast_line_stats_interval)
+			(num, type, &stats_interval) != 0) {
+			retval = UBUS_STATUS_UNKNOWN_ERROR;
+			goto __ret;
+		}
+		fast_line_stats_interval_to_blob(&stats_interval, &bb);
+	} else {
+		// Get line statistics
+		if (xdsl_ops.get_fast_line_stats == NULL || (*xdsl_ops.get_fast_line_stats)(num, &stats) != 0) {
+			retval = UBUS_STATUS_UNKNOWN_ERROR;
+			goto __ret;
+		}
+		dsl_stats_to_blob(&stats, &bb);
+
+		// Get all interval statistics
+		for (j = 0; j < ARRAY_SIZE(dsl_stats_types); j++) {
+			table = blobmsg_open_table(&bb, dsl_stats_types[j].text);
+
+			if (xdsl_ops.get_fast_line_stats_interval == NULL || (*xdsl_ops.get_fast_line_stats_interval)
+				(num, dsl_stats_types[j].value, &stats_interval) != 0) {
+				retval = UBUS_STATUS_UNKNOWN_ERROR;
+				goto __ret;
+			}
+			fast_line_stats_interval_to_blob(&stats_interval, &bb);
+
+			blobmsg_close_table(&bb, table);
+		}
+	}
+
+	// Send the reply
+	ubus_send_reply(ctx, req, bb.head);
+
+__ret:
+	blob_buf_free(&bb);
+	return retval;
+}
+
+static struct ubus_method fast_line_methods[] = {
+	{ .name = "status", .handler = fast_line_status },
+	UBUS_METHOD("stats", fast_line_stats_handler, dsl_stats_policy )
+};
+
+static struct ubus_object_type fast_line_type = UBUS_OBJECT_TYPE("fast.line", fast_line_methods);
+
+static const char *atm_link_type_str(enum atm_link_type type)
+{
+	const char *str = dsl_get_string_value(atm_link_types, type);
+
+	if (!str)
+		return "unknown";
+
+	return str;
+}
+
+static const char *atm_encap_str(enum atm_encapsulation encap)
+{
+	const char *str = dsl_get_string_value(atm_encapsulations, encap);
+
+	if (!str)
+		return "unknown";
+
+	return str;
+}
+
+static const char *atm_aal_str(enum atm_aal aal)
+{
+	switch (aal) {
+	case ATM_AAL1: return "aal1";
+	case ATM_AAL2: return "aal2";
+	case ATM_AAL3: return "aal3";
+	case ATM_AAL4: return "aal4";
+	case ATM_AAL5: return "aal5";
+	default: return "unknown";
+	}
+}
+
+static const char *atm_qos_class_str(enum atm_qos_class class)
+{
+	const char *str = dsl_get_string_value(atm_qos_classes, class);
+
+	if (!str)
+		return "unknown";
+
+	return str;
+}
+
+static void atm_add_dest_addr_to_blob(const struct atm_dest_addr *dest_addr, struct blob_buf *bb)
+{
+	void *table = blobmsg_open_table(bb, "dest_addr");
+	blobmsg_add_u32(bb, "vpi", dest_addr->vpi);
+	blobmsg_add_u32(bb, "vci", dest_addr->vci);
+	blobmsg_close_table(bb, table);
+}
+
+static void atm_link_status_to_blob(const struct atm_link *link, const struct atm_link_qos *qos, struct blob_buf *bb)
+{
+	void *array, *table;
+	int i;
+
+	blobmsg_add_string(bb, "status", dsl_if_status_str(link->status));
+	blobmsg_add_string(bb, "link_type", atm_link_type_str(link->link_type));
+	blobmsg_add_u8(bb, "auto_config", link->auto_config);
+	atm_add_dest_addr_to_blob(&link->dest_addr, bb);
+	blobmsg_add_string(bb, "encapsulation", atm_encap_str(link->encapsulation));
+	blobmsg_add_u8(bb, "fcs_preserved", link->fcs_preserved);
+
+	array = blobmsg_open_array(bb, "vc_search_list");
+	for (i = 0; i < link->vc_list_count; i++) {
+		atm_add_dest_addr_to_blob(&link->vc_search_list[i], bb);
+	}
+	blobmsg_close_array(bb, array);
+
+	blobmsg_add_string(bb, "aal", atm_aal_str(link->aal));
+
+	table = blobmsg_open_table(bb, "qos");
+	blobmsg_add_string(bb, "qos_class", atm_qos_class_str(qos->qos_class));
+	blobmsg_add_u32(bb, "peak_cell_rate", qos->peak_cell_rate);
+	blobmsg_add_u32(bb, "max_burst_size", qos->max_burst_size);
+	blobmsg_add_u32(bb, "sustainable_cell_rate", qos->sustainable_cell_rate);
+	blobmsg_close_table(bb, table);
+}
+
+int atm_link_status(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method, struct blob_attr *msg)
+{
+	static struct blob_buf bb;
+	struct atm_link link;
+	struct atm_link_qos qos;
+	int retval = UBUS_STATUS_OK;
+	int num = -1;
+
+	// Initialize the buffer
+	memset(&bb, 0, sizeof(bb));
+	blob_buf_init(&bb, 0);
+
+	// Get line status
+	sscanf(obj->name, "atm.link.%d", &num);
+	if (atm_funcs.get_link_info == NULL || (*atm_funcs.get_link_info)(num, &link, &qos) != 0) {
+		retval = UBUS_STATUS_UNKNOWN_ERROR;
+		goto __ret;
+	}
+	atm_link_status_to_blob(&link, &qos, &bb);
+
+	// Send the reply
+	ubus_send_reply(ctx, req, bb.head);
+
+__ret:
+	blob_buf_free(&bb);
+	return retval;
+}
+
+static void atm_link_stats_to_blob(const struct atm_link_stats *stats, struct blob_buf *bb)
+{
+	blobmsg_add_u64(bb, "transmitted_blocks", stats->transmitted_blocks);
+	blobmsg_add_u64(bb, "received_blocks", stats->received_blocks);
+	blobmsg_add_u64(bb, "crc_errors", stats->crc_errors);
+}
+
+int atm_link_stats_handler(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method, struct blob_attr *msg)
+{
+	static struct blob_buf bb;
+	struct atm_link_stats stats;
+	int retval = UBUS_STATUS_OK;
+	int num = -1;
+
+	// Initialize the buffer
+	memset(&bb, 0, sizeof(bb));
+	blob_buf_init(&bb, 0);
+
+	// Get line status
+	sscanf(obj->name, "atm.link.%d", &num);
+	if (atm_funcs.get_link_stats == NULL || (*atm_funcs.get_link_stats)(num, &stats) != 0) {
+		retval = UBUS_STATUS_UNKNOWN_ERROR;
+		goto __ret;
+	}
+	atm_link_stats_to_blob(&stats, &bb);
+
+	// Send the reply
+	ubus_send_reply(ctx, req, bb.head);
+
+
+__ret:
+	blob_buf_free(&bb);
+	return retval;
+}
+
+enum {
+	ATM_CONFIGURE_LINK_TYPE,
+	ATM_CONFIGURE_VPI,
+	ATM_CONFIGURE_VCI,
+	ATM_CONFIGURE_ENCAPSULATION,
+	ATM_CONFIGURE_QOS_CLASS,
+	ATM_CONFIGURE_PEAK_CELL_RATE,
+	ATM_CONFIGURE_MAX_BURST_SIZE,
+	ATM_CONFIGURE_SUSTAINABLE_CELL_RATE,
+	__ATM_CONFIGURE_MAX
+};
+
+static const struct blobmsg_policy atm_configure_policy[] = {
+	[ATM_CONFIGURE_LINK_TYPE] = { .name = "link_type", .type = BLOBMSG_TYPE_STRING },
+	[ATM_CONFIGURE_VPI] = { .name = "vpi", .type = BLOBMSG_TYPE_INT32 },
+	[ATM_CONFIGURE_VCI] = { .name = "vci", .type = BLOBMSG_TYPE_INT32 },
+	[ATM_CONFIGURE_ENCAPSULATION] = { .name = "encapsulation", .type = BLOBMSG_TYPE_STRING },
+	[ATM_CONFIGURE_QOS_CLASS] = { .name = "qos_class", .type = BLOBMSG_TYPE_STRING },
+	[ATM_CONFIGURE_PEAK_CELL_RATE] = { .name = "peak_cell_rate", .type = BLOBMSG_TYPE_INT32 },
+	[ATM_CONFIGURE_MAX_BURST_SIZE] = { .name = "max_burst_size", .type = BLOBMSG_TYPE_INT32 },
+	[ATM_CONFIGURE_SUSTAINABLE_CELL_RATE] = { .name = "sustainable_cell_rate", .type = BLOBMSG_TYPE_INT32 }
+};
+
+/**
+ * Handler of UBUS call "atm.link.x configure"
+ *
+ * Calling example
+ *
+ * ubus call atm.link.0 configure "{'link_type':'eoa','vpi':8,'vci':35,'encapsulation':'llc',\
+    'qos_class':'ubr','peak_cell_rate':10240,'max_burst_size':8124,'sustainable_cell_rate':9600}"
+ *
+ */
+int atm_link_configure(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method, struct blob_attr *msg)
+{
+	struct blob_attr *tb[__ATM_CONFIGURE_MAX];
+	struct atm_link link;
+	struct atm_link_qos qos;
+	int link_num = -1;
+
+	memset(&link, 0, sizeof(link));
+	memset(&qos, 0, sizeof(qos));
+
+	// Parse and validation check the input parameters
+	if (blobmsg_parse(atm_configure_policy, __ATM_CONFIGURE_MAX, tb, blob_data(msg), blob_len(msg)) != 0)
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	// link_type
+	if (tb[ATM_CONFIGURE_LINK_TYPE]) {
+		const char *type_str = blobmsg_data(tb[ATM_CONFIGURE_LINK_TYPE]);
+		int type_enum = dsl_get_enum_value(atm_link_types, type_str);
+
+		if (type_enum == -1) {
+			DSLMNGR_LOG(LOG_ERR,
+				"Wrong argument for link_type. It should be like \"eoa\"\n");
+			return UBUS_STATUS_INVALID_ARGUMENT;
+		}
+		link.link_type = type_enum;
+
+		DSLMNGR_LOG(LOG_DEBUG, "link.link_type = %d(%s)\n", link.link_type, type_str);
+	}
+
+	// vpi & vci
+	if (tb[ATM_CONFIGURE_VPI] && tb[ATM_CONFIGURE_VCI]) {
+		link.dest_addr.vpi = blobmsg_get_u32(tb[ATM_CONFIGURE_VPI]);
+		link.dest_addr.vci = blobmsg_get_u32(tb[ATM_CONFIGURE_VCI]);
+
+		DSLMNGR_LOG(LOG_DEBUG, "link.dest_addr = { %d, %d }\n", link.dest_addr.vpi, link.dest_addr.vci);
+	}
+
+	// encapsulation
+	if (tb[ATM_CONFIGURE_ENCAPSULATION]) {
+		const char *encap_str = blobmsg_data(tb[ATM_CONFIGURE_ENCAPSULATION]);
+		int encap_enum = dsl_get_enum_value(atm_encapsulations, encap_str);
+
+		if (encap_enum == -1) {
+			DSLMNGR_LOG(LOG_ERR,
+				"Wrong argument for encapsulation. It should be like \"llc\"\n");
+			return UBUS_STATUS_INVALID_ARGUMENT;
+		}
+		link.encapsulation = encap_enum;
+
+		DSLMNGR_LOG(LOG_DEBUG, "link.encapsulation = %d(%s)\n", link.encapsulation, encap_str);
+	}
+
+	// qos_class
+	if (tb[ATM_CONFIGURE_QOS_CLASS]) {
+		const char *class_str = blobmsg_data(tb[ATM_CONFIGURE_QOS_CLASS]);
+		int class_enum = dsl_get_enum_value(atm_qos_classes, class_str);
+
+		if (class_enum == -1) {
+			DSLMNGR_LOG(LOG_ERR,
+				"Wrong argument for qos_class. It should be like \"ubr\"\n");
+			return UBUS_STATUS_INVALID_ARGUMENT;
+		}
+		qos.qos_class = class_enum;
+
+		DSLMNGR_LOG(LOG_DEBUG, "qos.qos_class = %d(%s)\n", qos.qos_class, class_str);
+	}
+
+	// peak_cell_rate
+	if (tb[ATM_CONFIGURE_PEAK_CELL_RATE]) {
+		qos.peak_cell_rate = blobmsg_get_u32(tb[ATM_CONFIGURE_PEAK_CELL_RATE]);
+
+		DSLMNGR_LOG(LOG_DEBUG, "qos.peak_cell_rate = %u\n", qos.peak_cell_rate);
+	}
+
+	// max_burst_size
+	if (tb[ATM_CONFIGURE_MAX_BURST_SIZE]) {
+		qos.max_burst_size = blobmsg_get_u32(tb[ATM_CONFIGURE_MAX_BURST_SIZE]);
+
+		DSLMNGR_LOG(LOG_DEBUG, "qos.max_burst_size = %u\n", qos.max_burst_size);
+	}
+
+	// sustainable_cell_rate
+	if (tb[ATM_CONFIGURE_SUSTAINABLE_CELL_RATE]) {
+		qos.sustainable_cell_rate = blobmsg_get_u32(tb[ATM_CONFIGURE_SUSTAINABLE_CELL_RATE]);
+
+		DSLMNGR_LOG(LOG_DEBUG, "qos.sustainable_cell_rate = %u\n", qos.sustainable_cell_rate);
+	}
+
+	// Get link number and call libdsl API
+	sscanf(obj->name, "atm.link.%d", &link_num);
+	if (atm_funcs.configure(link_num, &link, &qos) != 0) {
+		DSLMNGR_LOG(LOG_ERR, "ATM link %d confuration failed\n", link_num);
+		return UBUS_STATUS_UNKNOWN_ERROR;
+	}
+
+	return 0;
+}
+
+static struct ubus_method atm_link_methods[] = {
+	{ .name = "status", .handler = atm_link_status },
+	{ .name = "stats",  .handler = atm_link_stats_handler },
+	UBUS_METHOD("configure", atm_link_configure,  atm_configure_policy)
+};
+
+static struct ubus_object_type atm_link_type = UBUS_OBJECT_TYPE("atm.link", atm_link_methods);
+
+static void ptm_link_status_to_blob(const struct ptm_link *link, struct blob_buf *bb)
+{
+	char mac[18];
+
+	blobmsg_add_string(bb, "status", dsl_if_status_str(link->status));
+	snprintf(mac, sizeof(mac), "%02x:%02x:%02x:%02x:%02x:%02x",
+			link->mac_addr[0], link->mac_addr[1], link->mac_addr[2],
+			link->mac_addr[3], link->mac_addr[4], link->mac_addr[5]);
+	blobmsg_add_string(bb, "mac_addr", mac);
+}
+
+int ptm_link_status(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method, struct blob_attr *msg)
+{
+	static struct blob_buf bb;
+	struct ptm_link link;
+	int retval = UBUS_STATUS_OK;
+	int num = -1;
+
+	// Initialize the buffer
+	memset(&bb, 0, sizeof(bb));
+	blob_buf_init(&bb, 0);
+
+	// Get line status
+	sscanf(obj->name, "ptm.link.%d", &num);
+	if (ptm_funcs.get_link_info == NULL || (*ptm_funcs.get_link_info)(num, &link) != 0) {
+		retval = UBUS_STATUS_UNKNOWN_ERROR;
+		goto __ret;
+	}
+	ptm_link_status_to_blob(&link, &bb);
+
+	// Send the reply
+	ubus_send_reply(ctx, req, bb.head);
+
+__ret:
+	blob_buf_free(&bb);
+	return retval;
+}
+
+static struct ubus_method ptm_link_methods[] = {
+	{ .name = "status", .handler = ptm_link_status }
+};
+
+static struct ubus_object_type ptm_link_type = UBUS_OBJECT_TYPE("ptm.link", ptm_link_methods);
+
+/**
+ * Handler of UBUS call "dsl.line.x configure"
+ *
+ * Calling example
+ *
+ * ubus call dsl.line.0 configure "{'xtse':'01,02,ab,cd,41,52,f8,6e',\
+    'vdsl2_profiles':'8a,8b,8c,8d,17a,30a,35b',\
+    'fast_profiles':'106a,212a','data_gathering':true,'limit_mask':255,'us0_mask':511}"
+ *
+ */
+int dsl_line_configure(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method, struct blob_attr *msg)
+{
+	struct blob_attr *tb[__DSL_CONFIGURE_MAX];
+	struct dsl_config_params cfg_params;
+	int line_num = -1, i;
+
+	if (!xdsl_ops.configure) {
+		DSLMNGR_LOG(LOG_ERR, "This function is not supported on the current platform yet\n");
+		return UBUS_STATUS_NOT_SUPPORTED;
+	}
+
+	memset(&cfg_params, 0, sizeof(cfg_params));
+
+	// Parse and validation check the input parameters
+	if (blobmsg_parse(dsl_configure_policy, __DSL_CONFIGURE_MAX, tb, blob_data(msg), blob_len(msg)) != 0)
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	// XTSE
+	if (tb[DSL_CONFIGURE_XTSE]) {
+		const char *xtse_str = blobmsg_data(tb[DSL_CONFIGURE_XTSE]);
+
+		if (!xtse_str || !*xtse_str ||
+			sscanf(xtse_str, "%02hhx,%02hhx,%02hhx,%02hhx,%02hhx,%02hhx,%02hhx,%02hhx",
+					&cfg_params.xtse[0],&cfg_params.xtse[1],&cfg_params.xtse[2],&cfg_params.xtse[3],
+					&cfg_params.xtse[4],&cfg_params.xtse[5],&cfg_params.xtse[6],&cfg_params.xtse[7]) != 8) {
+			DSLMNGR_LOG(LOG_ERR, "Wrong argument for xtse. It should be like \"01,02,ab,cd,41,52,f8,6e\"\n");
+			return UBUS_STATUS_INVALID_ARGUMENT;
+		}
+		DSLMNGR_LOG(LOG_DEBUG, "cfg_params.xtse = {%02hhx,%02hhx,%02hhx,%02hhx,%02hhx,%02hhx,%02hhx,%02hhx}\n",
+				cfg_params.xtse[0],cfg_params.xtse[1],cfg_params.xtse[2],cfg_params.xtse[3],
+				cfg_params.xtse[4],cfg_params.xtse[5],cfg_params.xtse[6],cfg_params.xtse[7]);
+	}
+
+	// VDSL2 profiles
+	if (tb[DSL_CONFIGURE_VDSL2_PROFILES]) {
+		const char *profiles_str = blobmsg_data(tb[DSL_CONFIGURE_VDSL2_PROFILES]);
+		char *dup, *token, *saveptr;
+
+		if (!profiles_str || !*profiles_str) {
+			DSLMNGR_LOG(LOG_ERR,
+				"Wrong argument for vdsl2_profiles. It should be like \"8a,8b,8c,8d,17a,30a,35b\"\n");
+			return UBUS_STATUS_INVALID_ARGUMENT;
+		}
+
+		dup = alloca(strlen(profiles_str) + 1);
+		strcpy(dup, profiles_str);
+		for (token = strtok_r(dup, ",", &saveptr); token != NULL; token = strtok_r(NULL, ",", &saveptr)) {
+			int profile = dsl_get_enum_value(vdsl2_profiles, token);
+			if (profile != -1)
+				cfg_params.vdsl2_profiles |= profile;
+			else {
+				DSLMNGR_LOG(LOG_ERR,
+					"Wrong argument for vdsl2_profiles. It should be like \"8a,8b,8c,8d,17a,30a,35b\"\n");
+				return UBUS_STATUS_INVALID_ARGUMENT;
+			}
+		}
+
+		DSLMNGR_LOG(LOG_DEBUG, "cfg_params.vdsl2_profiles = 0x%lx(%s)\n", cfg_params.vdsl2_profiles, profiles_str);
+	}
+
+	// FAST profiles
+	if (tb[DSL_CONFIGURE_FAST_PROFILES]) {
+		const char *profiles_str = blobmsg_data(tb[DSL_CONFIGURE_FAST_PROFILES]);
+		char *dup, *token, *saveptr;
+
+		if (!profiles_str || !*profiles_str) {
+			DSLMNGR_LOG(LOG_ERR,
+				"Wrong argument for fast_profiles. It should be like \"106a,212a\"\n");
+			return UBUS_STATUS_INVALID_ARGUMENT;
+		}
+
+		dup = alloca(strlen(profiles_str) + 1);
+		strcpy(dup, profiles_str);
+		for (token = strtok_r(dup, ",", &saveptr); token != NULL; token = strtok_r(NULL, ",", &saveptr)) {
+			int profile = dsl_get_enum_value(fast_profiles, token);
+			if (profile != -1)
+				cfg_params.fast_profiles |= profile;
+			else {
+				DSLMNGR_LOG(LOG_ERR,
+					"Wrong argument for fast_profiles. It should be like \"106a,212a\"\n");
+				return UBUS_STATUS_INVALID_ARGUMENT;
+			}
+		}
+
+		DSLMNGR_LOG(LOG_DEBUG, "cfg_params.fast_profiles = 0x%lx(%s)\n", cfg_params.fast_profiles, profiles_str);
+	}
+
+	// enable_data_gathering
+	if (tb[DSL_CONFIGURE_ENABLE_DATA_GATHERING]) {
+		uint8_t enabled = blobmsg_get_u8(tb[DSL_CONFIGURE_ENABLE_DATA_GATHERING]);
+
+		cfg_params.enable_data_gathering = !!enabled;
+
+		DSLMNGR_LOG(LOG_DEBUG, "cfg_params.enable_data_gathering = %d\n", cfg_params.enable_data_gathering);
+	}
+
+	// limit_mask
+	if (tb[DSL_CONFIGURE_LIMIT_MASK]) {
+		cfg_params.limit_mask = blobmsg_get_u32(tb[DSL_CONFIGURE_LIMIT_MASK]);
+
+		DSLMNGR_LOG(LOG_DEBUG, "cfg_params.limit_mask = 0x%x\n", cfg_params.limit_mask);
+	}
+
+	// limit_mask
+	if (tb[DSL_CONFIGURE_US0_MASK]) {
+		cfg_params.us0_mask = blobmsg_get_u32(tb[DSL_CONFIGURE_US0_MASK]);
+
+		DSLMNGR_LOG(LOG_DEBUG, "cfg_params.us0_mask = 0x%x\n", cfg_params.us0_mask);
+	}
+
+	// Get line number
+	sscanf(obj->name, "dsl.line.%d", &line_num);
+	if (xdsl_ops.configure(line_num, &cfg_params) != 0) {
+		DSLMNGR_LOG(LOG_ERR, "DSL line %d confuration failed\n", line_num);
+		return UBUS_STATUS_UNKNOWN_ERROR;
+	}
+
+	return 0;
+}
+
 int dsl_add_ubus_objects(struct ubus_context *ctx)
 {
 	struct ubus_object *line_objects = NULL;
 	struct ubus_object *channel_objects = NULL;
+	struct ubus_object *fast_objects = NULL;
+	struct ubus_object *atm_objects = NULL;
+	struct ubus_object *ptm_objects = NULL;
 	int ret, max_line, max_channel, i;
 
-	ret = ubus_add_object(ctx, &dsl_main_object);
+	// Add objects dsl
+	ret = ubus_add_object(ctx, &dsl_object);
 	if (ret) {
 		DSLMNGR_LOG(LOG_ERR, "Failed to add UBUS object '%s', %s\n",
-				dsl_main_object.name, ubus_strerror(ret));
+				dsl_object.name, ubus_strerror(ret));
 		return -1;
 	}
 
@@ -963,6 +1664,94 @@ int dsl_add_ubus_objects(struct ubus_context *ctx)
 		}
 	}
 
+	// Add objects fast.line.x if supported
+	if (xdsl_ops.get_fast_line_info && xdsl_ops.get_fast_line_stats &&
+		xdsl_ops.get_fast_line_stats_interval) {
+		fast_objects = calloc(max_line, sizeof(struct ubus_object));
+		if (!fast_objects) {
+			DSLMNGR_LOG(LOG_ERR, "Out of memory\n");
+			return -1;
+		}
+		for (i = 0; i < max_line; i++) {
+			char *obj_name;
+
+			if (asprintf(&obj_name, "fast.line.%d", i) <= 0) {
+				DSLMNGR_LOG(LOG_ERR, "Out of memory\n");
+				return -1;
+			}
+
+			fast_objects[i].name = obj_name;
+			fast_objects[i].type = &fast_line_type;
+			fast_objects[i].methods = fast_line_methods;
+			fast_objects[i].n_methods = ARRAY_SIZE(fast_line_methods);
+
+			ret = ubus_add_object(ctx, &fast_objects[i]);
+			if (ret) {
+				DSLMNGR_LOG(LOG_ERR, "Failed to add UBUS object '%s', %s\n",
+						obj_name, ubus_strerror(ret));
+				return -1;
+			}
+		}
+	}
+
+	// Add objects atm.link.x if supported
+	if (atm_funcs.get_link_info && atm_funcs.get_link_stats && atm_funcs.configure) {
+		atm_objects = calloc(max_line, sizeof(struct ubus_object));
+		if (!atm_objects) {
+			DSLMNGR_LOG(LOG_ERR, "Out of memory\n");
+			return -1;
+		}
+		for (i = 0; i < max_line; i++) {
+			char *obj_name;
+
+			if (asprintf(&obj_name, "atm.link.%d", i) <= 0) {
+				DSLMNGR_LOG(LOG_ERR, "Out of memory\n");
+				return -1;
+			}
+
+			atm_objects[i].name = obj_name;
+			atm_objects[i].type = &atm_link_type;
+			atm_objects[i].methods = atm_link_methods;
+			atm_objects[i].n_methods = ARRAY_SIZE(atm_link_methods);
+
+			ret = ubus_add_object(ctx, &atm_objects[i]);
+			if (ret) {
+				DSLMNGR_LOG(LOG_ERR, "Failed to add UBUS object '%s', %s\n",
+						obj_name, ubus_strerror(ret));
+				return -1;
+			}
+		}
+	}
+
+	// Add objects ptm.link.x if supported
+	if (ptm_funcs.get_link_info) {
+		ptm_objects = calloc(max_line, sizeof(struct ubus_object));
+		if (!ptm_objects) {
+			DSLMNGR_LOG(LOG_ERR, "Out of memory\n");
+			return -1;
+		}
+		for (i = 0; i < max_line; i++) {
+			char *obj_name;
+
+			if (asprintf(&obj_name, "ptm.link.%d", i) <= 0) {
+				DSLMNGR_LOG(LOG_ERR, "Out of memory\n");
+				return -1;
+			}
+
+			ptm_objects[i].name = obj_name;
+			ptm_objects[i].type = &ptm_link_type;
+			ptm_objects[i].methods = ptm_link_methods;
+			ptm_objects[i].n_methods = ARRAY_SIZE(ptm_link_methods);
+
+			ret = ubus_add_object(ctx, &ptm_objects[i]);
+			if (ret) {
+				DSLMNGR_LOG(LOG_ERR, "Failed to add UBUS object '%s', %s\n",
+						obj_name, ubus_strerror(ret));
+				return -1;
+			}
+		}
+	}
+
 	// Returns on success
 	return 0;
 
@@ -971,5 +1760,12 @@ __error_ret:
 		free(line_objects);
 	if (channel_objects)
 		free(channel_objects);
+	if (fast_objects)
+		free(fast_objects);
+	if (atm_objects)
+		free(atm_objects);
+	if (ptm_objects)
+		free(ptm_objects);
+
 	return -1;
 }
diff --git a/dslmngr.h b/dslmngr.h
index 56a113676ef68f86955995118f16965405c402c8..358c4870915772e337405c4c189af4a0480be0a5 100644
--- a/dslmngr.h
+++ b/dslmngr.h
@@ -31,7 +31,12 @@ extern "C" {
 #include <syslog.h>
 #include <libubus.h>
 
-#define DSLMNGR_LOG(log_level, format...) fprintf(stderr, ##format)
+extern int current_log_level;
+
+#define DSLMNGR_LOG(log_level, format...) do { \
+		if (log_level <= current_log_level) \
+			fprintf(stderr, ##format); \
+	} while(0)
 
 #define CHECK_POINT() printf("Check point at %s@%s:%d\n", __func__, __FILE__, __LINE__)
 
@@ -50,6 +55,22 @@ int dsl_channel_stats(struct ubus_context *ctx, struct ubus_object *obj,
 		struct ubus_request_data *req, const char *method, struct blob_attr *msg);
 int dsl_stats_all(struct ubus_context *ctx, struct ubus_object *obj,
 		struct ubus_request_data *req, const char *method, struct blob_attr *msg);
+int fast_line_status(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method, struct blob_attr *msg);
+int fast_line_stats_handler(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method, struct blob_attr *msg);
+
+int atm_link_status(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method, struct blob_attr *msg);
+int atm_link_stats_handler(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method, struct blob_attr *msg);
+int ptm_link_status(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method, struct blob_attr *msg);
+
+int dsl_line_configure(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method, struct blob_attr *msg);
+int atm_link_configure(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method, struct blob_attr *msg);
 
 #ifdef __cplusplus
 }
diff --git a/schemas/ubus/atm.link_stats.json b/schemas/ubus/atm.link_stats.json
new file mode 100644
index 0000000000000000000000000000000000000000..3fd822fa7badb60562b8b21606f8b079632b812b
--- /dev/null
+++ b/schemas/ubus/atm.link_stats.json
@@ -0,0 +1,32 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "$id": "https://www.iopsys.eu/atm.link_stats.json",
+  "title": "JSON Schema for the output of the UBUS call: atm.link.x stats",
+
+  "definitions": {
+    "stats_counter": {
+      "type": "integer",
+      "minimum": 0,
+      "maximum": 4294967295
+    },
+
+    "atm_link_stats": {
+      "$id": "#atm_link_stats",
+      "type": "object",
+
+      "properties" : {
+      	"transmitted_blocks": { "$ref": "#/definitions/stats_counter" },
+      	"received_blocks": { "$ref": "#/definitions/stats_counter" },
+      	"crc_errors": { "$ref": "#/definitions/stats_counter" }
+      },
+
+      "required": [
+        "transmitted_blocks",
+        "received_blocks",
+        "crc_errors"
+      ]
+    }
+  },
+
+  "$ref": "#atm_link_stats"
+}
diff --git a/schemas/ubus/atm.link_status.json b/schemas/ubus/atm.link_status.json
new file mode 100644
index 0000000000000000000000000000000000000000..e71322fa767aecf8826109aede49ca9ec43be15a
--- /dev/null
+++ b/schemas/ubus/atm.link_status.json
@@ -0,0 +1,82 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "$id": "https://www.iopsys.eu/atm.link_status.json",
+  "title": "JSON Schema for the output of the UBUS call: atm.link.x status",
+
+  "definitions": {
+
+    "if_status": {
+      "type": "string",
+      "enum": [ "up", "down", "dormant", "not_present", "lower_layer_down", "error", "unknown" ]
+    },
+
+    "atm_link_type": {
+      "type": "string",
+      "enum": [ "unconfigured", "eoa", "ipoa", "pppoa", "cip", "unknown" ]
+    },
+
+    "destination": {
+      "type": "object",
+      "properties": {
+        "vpi": { "type": "integer" },
+        "vci": { "type": "integer" }
+      },
+      "required": [ "vpi", "vci" ]
+    },
+
+    "atm_link_status": {
+      "$id": "#atm_link_status",
+      "type": "object",
+
+      "properties" : {
+
+        "status": { "$ref": "#/definitions/if_status" },
+        "link_type": { "$ref": "#/definitions/atm_link_type" },
+        "auto_config": {"type": "boolean" },
+        "dest_addr": { "$ref": "#/definitions/destination" },
+        "encapsulation": {
+          "type": "string",
+          "enum": [ "llc", "vcmux" ]
+        },
+        "fcs_preserved": { "type": "boolean" },
+        "vc_search_list": {
+          "type": "array",
+          "minItems": 0,
+          "Items": { "$ref": "#/definitions/destination" }
+        },
+        "aal": {
+          "type": "string",
+          "enum": [ "aal1", "aal2", "aal3", "aal4", "aal5" ]
+        },
+
+        "qos": {
+          "type": "object",
+          "properties": {
+            "qos_class": {
+              "type": "string",
+              "enum": [ "ubr", "cbr", "gfr", "vbr_nrt", "vbr_rt", "ubr_plus", "abr" ]
+            },
+            "peak_cell_rate": { "$ref": "http://json-schema.org/draft-07/schema#/definitions/nonNegativeInteger" },
+            "max_burst_size": { "$ref": "http://json-schema.org/draft-07/schema#/definitions/nonNegativeInteger" },
+            "sustainable_cell_rate": { "$ref": "http://json-schema.org/draft-07/schema#/definitions/nonNegativeInteger" }
+          },
+          "required": [ "qos_class", "peak_cell_rate", "max_burst_size", "sustainable_cell_rate" ]
+        }
+      },
+
+      "required": [
+        "status",
+        "link_type",
+        "auto_config",
+        "dest_addr",
+        "encapsulation",
+        "fcs_preserved",
+        "vc_search_list",
+        "aal",
+        "qos"
+      ]
+    }
+  },
+
+  "$ref": "#atm_link_status"
+}
diff --git a/schemas/ubus/fast.line_stats.json b/schemas/ubus/fast.line_stats.json
new file mode 100644
index 0000000000000000000000000000000000000000..62a351713448b186d9ea1e557758809a2f57abc0
--- /dev/null
+++ b/schemas/ubus/fast.line_stats.json
@@ -0,0 +1,82 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "$id": "https://www.iopsys.eu/fast.line_stats.json",
+  "title": "JSON Schema for the output of the UBUS call: fast.line.x stats",
+
+  "definitions": {
+    "stats_counter": {
+      "type": "integer",
+      "minimum": 0,
+      "maximum": 4294967295
+    },
+
+    "line_stats_interval" : {
+      "$id": "#line_stats_interval",
+      "type": "object",
+
+      "properties": {
+        "errored_secs": { "$ref": "#/definitions/stats_counter" },
+        "severely_errored_secs": { "$ref": "#/definitions/stats_counter" },
+        "loss": { "$ref": "#/definitions/stats_counter" },
+        "lors": { "$ref": "#/definitions/stats_counter" },
+        "uas": { "$ref": "#/definitions/stats_counter" },
+        "rtx_uc": { "$ref": "#/definitions/stats_counter" },
+        "rtx_tx": { "$ref": "#/definitions/stats_counter" },
+        "success_bsw": { "$ref": "#/definitions/stats_counter" },
+        "success_sra": { "$ref": "#/definitions/stats_counter" },
+        "success_fra": { "$ref": "#/definitions/stats_counter" },
+        "success_rpa": { "$ref": "#/definitions/stats_counter" },
+        "success_tiga": { "$ref": "#/definitions/stats_counter" }
+      },
+
+      "required": [
+        "errored_secs",
+        "severely_errored_secs",
+        "loss",
+        "lors",
+        "uas",
+        "rtx_uc",
+        "rtx_tx",
+        "success_bsw",
+        "success_sra",
+        "success_fra",
+        "success_rpa",
+        "success_tiga"
+      ]
+    },
+
+    "line_stats": {
+      "$id": "#line_stats",
+      "type": "object",
+
+      "properties" : {
+        "total_start": { "$ref": "http://json-schema.org/draft-07/schema#/definitions/nonNegativeInteger" },
+      	"showtime_start": { "$ref": "http://json-schema.org/draft-07/schema#/definitions/nonNegativeInteger" },
+      	"last_showtime_start": { "$ref": "http://json-schema.org/draft-07/schema#/definitions/nonNegativeInteger" },
+      	"current_day_start": { "$ref": "http://json-schema.org/draft-07/schema#/definitions/nonNegativeInteger" },
+      	"quarter_hour_start": { "$ref": "http://json-schema.org/draft-07/schema#/definitions/nonNegativeInteger" },
+
+      	"total": { "$ref": "#line_stats_interval" },
+      	"showtime": { "$ref": "#line_stats_interval" },
+      	"lastshowtime": { "$ref": "#line_stats_interval" },
+      	"currentday": { "$ref": "#line_stats_interval" },
+      	"quarterhour": { "$ref": "#line_stats_interval" }
+      },
+
+      "required": [
+        "total_start",
+        "showtime_start",
+        "last_showtime_start",
+        "current_day_start",
+        "quarter_hour_start",
+        "total",
+        "showtime",
+        "lastshowtime",
+        "currentday",
+        "quarterhour"
+      ]
+    }
+  },
+
+  "$ref": "#line_stats"
+}
diff --git a/schemas/ubus/fast.line_stats_interval.json b/schemas/ubus/fast.line_stats_interval.json
new file mode 100644
index 0000000000000000000000000000000000000000..77ff0bb959b11e06b89cc3599da49b690e8ce04f
--- /dev/null
+++ b/schemas/ubus/fast.line_stats_interval.json
@@ -0,0 +1,50 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "$id": "https://www.iopsys.eu/fast.line_stats_interval.json",
+  "title": "JSON Schema for the output of the UBUS call: fast.line.x stats <interval>",
+
+  "definitions": {
+    "stats_counter": {
+      "type": "integer",
+      "minimum": 0,
+      "maximum": 4294967295
+    },
+
+    "line_stats_interval" : {
+      "$id": "#line_stats_interval",
+      "type": "object",
+
+      "properties": {
+        "errored_secs": { "$ref": "#/definitions/stats_counter" },
+        "severely_errored_secs": { "$ref": "#/definitions/stats_counter" },
+        "loss": { "$ref": "#/definitions/stats_counter" },
+        "lors": { "$ref": "#/definitions/stats_counter" },
+        "uas": { "$ref": "#/definitions/stats_counter" },
+        "rtx_uc": { "$ref": "#/definitions/stats_counter" },
+        "rtx_tx": { "$ref": "#/definitions/stats_counter" },
+        "success_bsw": { "$ref": "#/definitions/stats_counter" },
+        "success_sra": { "$ref": "#/definitions/stats_counter" },
+        "success_fra": { "$ref": "#/definitions/stats_counter" },
+        "success_rpa": { "$ref": "#/definitions/stats_counter" },
+        "success_tiga": { "$ref": "#/definitions/stats_counter" }
+      },
+
+      "required": [
+        "errored_secs",
+        "severely_errored_secs",
+        "loss",
+        "lors",
+        "uas",
+        "rtx_uc",
+        "rtx_tx",
+        "success_bsw",
+        "success_sra",
+        "success_fra",
+        "success_rpa",
+        "success_tiga"
+      ]
+    }
+  },
+
+  "$ref": "#line_stats_interval"
+}
diff --git a/schemas/ubus/fast.line_status.json b/schemas/ubus/fast.line_status.json
new file mode 100644
index 0000000000000000000000000000000000000000..498ac009a466cf41412e4136c74c686f8a567c0e
--- /dev/null
+++ b/schemas/ubus/fast.line_status.json
@@ -0,0 +1,122 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "$id": "https://www.iopsys.eu/fast.line_status.json",
+  "title": "JSON Schema for the output of the UBUS call: fast.line.x status",
+
+  "definitions": {
+
+    "if_status": {
+      "type": "string",
+      "enum": [ "up", "down", "dormant", "not_present", "lower_layer_down", "error", "unknown" ]
+    },
+
+    "link_status": {
+      "type": "string",
+      "enum": [ "up", "initializing", "establishing", "no_signal", "disabled", "error", "unknown" ]
+    },
+
+    "fast_profile": {
+      "type": "string",
+      "enum": [ "106a", "212a", "unknown" ]
+    },
+
+    "power_mgmt_state": {
+      "type": "string",
+      "enum": [ "l0", "l2_1", "l2_2", "l3", "unknown" ]
+    },
+
+    "integer_array": {
+      "type": "array",
+      "items": { "type": "integer" },
+      "minItems": 0
+    },
+
+    "bidirectional_integers": {
+      "type": "object",
+      "properties": {
+        "us": { "type": "integer" },
+        "ds": { "type": "integer" }
+      },
+      "required": [ "us", "ds" ]
+    },
+
+    "bidirectional_bools": {
+      "type": "object",
+      "properties": {
+        "us": { "type": "boolean" },
+        "ds": { "type": "boolean" }
+      },
+      "required": [ "us", "ds" ]
+    },
+
+    "line_status": {
+      "$id": "#line_status",
+      "type": "object",
+
+      "properties" : {
+
+        "status": { "$ref": "#/definitions/if_status" },
+        "upstream": { "type": "boolean" },
+        "firmware_version": {"type": "string" },
+        "link_status": { "$ref": "#/definitions/link_status" },
+        "current_profile": { "$ref": "#/definitions/fast_profile" },
+        "power_management_state": { "$ref": "#/definitions/power_mgmt_state" },
+        "max_bit_rate": { "$ref": "#/definitions/bidirectional_integers" },
+
+        "allowed_profiles": {
+          "type": "array",
+          "items": { "$ref": "#/definitions/fast_profile" },
+          "minItems": 0
+        },
+
+        "success_failure_cause": { "type": "integer" },
+        "upbokler": { "type": "integer" },
+        "last_transmitted_signal": { "$ref": "#/definitions/bidirectional_integers" },
+        "upbokle": { "type": "integer" },
+        "line_number": { "type": "integer" },
+        
+        
+        "noise_margin": { "$ref": "#/definitions/bidirectional_integers" },
+        "last_state_transmitted": { "$ref": "#/definitions/bidirectional_integers" },
+        "attenuation": { "type": "integer" },
+        "trellis": { "$ref": "#/definitions/bidirectional_integers" },
+        "power": { "$ref": "#/definitions/bidirectional_integers" },
+        
+        "snrm_rmc": { "$ref": "#/definitions/bidirectional_integers" },
+        "bits_rmc_ps": { "$ref": "#/definitions/integer_array" },
+        "attenuation": { "$ref": "#/definitions/bidirectional_integers" },
+        "fext_to_cancel_enable": { "$ref": "#/definitions/bidirectional_bools" },
+        "etr": { "$ref": "#/definitions/bidirectional_integers" },
+        "att_etr": { "$ref": "#/definitions/bidirectional_integers" },
+        "min_eftr": { "$ref": "#/definitions/bidirectional_integers" }
+      },
+
+      "required": [
+        "status",
+        "upstream",
+        "firmware_version",
+        "link_status",
+        "current_profile",
+        "power_management_state",
+        "max_bit_rate",
+        "allowed_profiles",
+        "success_failure_cause",
+        "upbokler",
+        "last_transmitted_signal",
+        "upbokle",
+        "line_number",
+        "noise_margin",
+        "attenuation",
+        "power",
+        "snrm_rmc",
+        "bits_rmc_ps",
+        "fext_to_cancel_enable",
+        "etr",
+        "att_etr",
+        "min_eftr"
+      ]
+    }
+  },
+
+  "$ref": "#line_status"
+}
diff --git a/schemas/ubus/ptm.link_status.json b/schemas/ubus/ptm.link_status.json
new file mode 100644
index 0000000000000000000000000000000000000000..9e7474b1b7f2c45343b0ddd8fcb79c7f69366282
--- /dev/null
+++ b/schemas/ubus/ptm.link_status.json
@@ -0,0 +1,37 @@
+{
+  "$schema": "http://json-schema.org/draft-07/schema#",
+  "$id": "https://www.iopsys.eu/ptm.link_status.json",
+  "title": "JSON Schema for the output of the UBUS call: ptm.link.x status",
+
+  "definitions": {
+
+    "if_status": {
+      "type": "string",
+      "enum": [ "up", "down", "dormant", "not_present", "lower_layer_down", "error", "unknown" ]
+    },
+
+    "mac_address": {
+      "type": "string",
+      "pattern": "[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}",
+      "minLength": 17,
+      "maxLength": 17
+    },
+
+    "ptm_link_status": {
+      "$id": "#ptm_link_status",
+      "type": "object",
+
+      "properties" : {
+        "status": { "$ref": "#/definitions/if_status" },
+        "mac_addr": { "$ref": "#/definitions/mac_address" }
+      },
+
+      "required": [
+        "status",
+        "mac_addr"
+      ]
+    }
+  },
+
+  "$ref": "#ptm_link_status"
+}
diff --git a/test/api/json/atm.link.validation.json b/test/api/json/atm.link.validation.json
new file mode 100644
index 0000000000000000000000000000000000000000..519ea6823296132ea58544214dd8e16112904eff
--- /dev/null
+++ b/test/api/json/atm.link.validation.json
@@ -0,0 +1,30 @@
+{
+  "object": "atm.link.0",
+
+  "methods": [
+    {
+      "method": "status",
+      "rc": 0
+    },
+
+    {
+      "method": "stats",
+      "rc": 0
+    },
+
+    {
+      "method": "configure",
+      "args": {
+        "link_type": "eoa",
+        "vpi": 8,
+        "vci": 35,
+        "encapsulation": "llc",
+        "qos_class": "ubr"
+      },
+      "rc": 0
+    }
+  ]
+}
+
+ubus call atm.link.0 configure "{'link_type':'eoa','vpi':8,'vci':35,'encapsulation':'llc',\
+    'qos_class':'ubr','peak_cell_rate':10240,'max_burst_size':8124,'sustainable_cell_rate':9600}"
diff --git a/test/api/json/dsl.line.validation.json b/test/api/json/dsl.line.validation.json
index f7358f457dacb4d462156c7cbe6c42c5940dad72..b420b8804b45c4368feb9f74472458547873ba5b 100644
--- a/test/api/json/dsl.line.validation.json
+++ b/test/api/json/dsl.line.validation.json
@@ -51,5 +51,18 @@
       },
       "rc": 0
     },
+
+    {
+      "method": "configure",
+      "args": {
+        "xtse": "01,02,ab,cd,41,52,f8,6e",
+        "vdsl2_profiles": "8a,8b,8c,8d,17a,30a,35b",
+        "fast_profiles": "106a,212a",
+        "data_gathering": true,
+        "limit_mask": 7,
+        "us0_mask": 3
+      },
+      "rc": 0
+    }
   ]
 }
diff --git a/test/api/json/fast.line.validation.json b/test/api/json/fast.line.validation.json
new file mode 100644
index 0000000000000000000000000000000000000000..df93e2879280466555956ed1c8a5cdb6893d63dc
--- /dev/null
+++ b/test/api/json/fast.line.validation.json
@@ -0,0 +1,55 @@
+{
+  "object": "fast.line.0",
+
+  "methods": [
+    {
+      "method": "status",
+      "rc": 0
+    },
+
+    {
+      "method": "stats",
+      "rc": 0
+    },
+
+    {
+      "method": "stats",
+      "args": {
+        "interval": "total"
+      },
+      "rc": 0
+    },
+
+    {
+      "method": "stats",
+      "args": {
+        "interval": "showtime"
+      },
+      "rc": 0
+    },
+
+    {
+      "method": "stats",
+      "args": {
+        "interval": "lastshowtime"
+      },
+      "rc": 0
+    },
+
+    {
+      "method": "stats",
+      "args": {
+        "interval": "currentday"
+      },
+      "rc": 0
+    },
+
+    {
+      "method": "stats",
+      "args": {
+        "interval": "quarterhour"
+      },
+      "rc": 0
+    }
+  ]
+}
diff --git a/test/api/json/ptm.link.validation.json b/test/api/json/ptm.link.validation.json
new file mode 100644
index 0000000000000000000000000000000000000000..e5e973ee811d5543db23887e4f3ac50d5e793998
--- /dev/null
+++ b/test/api/json/ptm.link.validation.json
@@ -0,0 +1,10 @@
+{
+  "object": "ptm.link.0",
+
+  "methods": [
+    {
+      "method": "status",
+      "rc": 0
+    }
+  ]
+}
diff --git a/test/cmocka/unit_test_dslmngr.c b/test/cmocka/unit_test_dslmngr.c
index 465a80afffa58112187a87c94ca3f7b05a576c29..4099e4ce0b8b061ebcdc40e52e09b1a2d99c9ce5 100644
--- a/test/cmocka/unit_test_dslmngr.c
+++ b/test/cmocka/unit_test_dslmngr.c
@@ -19,9 +19,15 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  * 02110-1301 USA
  */
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
 #include <stdarg.h>
 #include <stddef.h>
 #include <setjmp.h>
+#include <errno.h>
 #include <cmocka.h>
 
 #include <libubus.h>
@@ -36,11 +42,14 @@
 #include "dslmngr.h"
 #include "utils.h"
 
+#define LIBDSL_LOG_INPUT_PARAMS "/tmp/libdsl-input-params.log"
+
 struct test_ctx {
 	struct blob_buf bb;
 	struct ubus_object dsl;
 	struct ubus_object dsl_line;
 	struct ubus_object dsl_channel;
+	struct ubus_object atm_link;
 };
 
 /* Overload ubus_send_reply to prevent segment fault*/
@@ -66,6 +75,9 @@ static int setup(void **state)
 
 	blob_buf_init(&ctx->bb, 0);
 
+	// Delete the log file for libdsl input parameters dump
+	unlink(LIBDSL_LOG_INPUT_PARAMS);
+
 	return 0;
 }
 
@@ -89,6 +101,7 @@ static int group_setup(void **state)
 	ctx->dsl.name = "dsl";
 	ctx->dsl_line.name = "dsl.line.0";
 	ctx->dsl_channel.name = "dsl.channel.0";
+	ctx->atm_link.name = "atm.link.0";
 	memset(&ctx->bb, 0, sizeof(struct blob_buf));
 	*state = ctx;
 
@@ -223,6 +236,210 @@ static void test_api_dsl_stats(void **state)
 	validate_dsl_stats(json_output);
 }
 
+static struct json_object *get_json_obj_from_log()
+{
+	int fd = -1;
+	char *str = NULL;
+
+	// Put the output of ubus call into a string
+	fd = open(LIBDSL_LOG_INPUT_PARAMS, O_RDONLY);
+	assert_return_code(fd, errno);
+
+	struct stat st;
+	int rc = fstat(fd, &st);
+	assert_true(rc == 0 && st.st_size > 0);
+
+	str = calloc(1, (size_t)st.st_size + 1);
+	assert_non_null(str);
+
+	ssize_t read_len = read(fd, str, (size_t)st.st_size);
+	assert_int_equal((int)read_len, (int)st.st_size);
+
+	// Parse the string to a json_object
+	char *start = strchr(str, '{');
+	assert_non_null(start);
+	//puts(start);
+	struct json_object *obj = json_tokener_parse(start);
+
+	if (fd >= 0)
+		close(fd);
+	if (str)
+		free(str);
+
+	return obj;
+}
+
+static void test_api_dsl_configure(void **state)
+{
+	const char *xtse_val = "01,02,ab,cd,41,52,f8,6e";
+	const char *vdsl2_profiles_val = "8a,8b,8c,8d,17a,30a,35b";
+	const char *fast_profiles_val = "106a,212a";
+	const bool data_gathering_val = true;
+	const unsigned int limit_mask_val = 7;
+	const unsigned int us0_mask_val = 3;
+
+	struct test_ctx *ctx = (struct test_ctx *) *state;
+	struct blob_buf *bb = &ctx->bb;
+	struct ubus_object *obj = &ctx->dsl_line;
+
+	// Prepare the input parameters
+	blobmsg_add_string(bb, "xtse", xtse_val);
+	blobmsg_add_string(bb, "vdsl2_profiles", vdsl2_profiles_val);
+	blobmsg_add_string(bb, "fast_profiles", fast_profiles_val);
+	blobmsg_add_u8(bb, "data_gathering", data_gathering_val);
+	blobmsg_add_u32(bb, "limit_mask", limit_mask_val);
+	blobmsg_add_u32(bb, "us0_mask", us0_mask_val);
+
+	// Call the function to be tested
+	int res = dsl_line_configure(NULL, obj, NULL, NULL, bb->head);
+	assert_true(res == UBUS_STATUS_OK);
+
+	// Check the results
+	struct json_object *jobj = get_json_obj_from_log();
+	assert_non_null(jobj);
+
+	struct json_object *tmp = json_object_get_by_string(jobj, "xtse");
+	assert_string_equal(json_object_get_string(tmp), xtse_val);
+
+	tmp = json_object_get_by_string(jobj, "vdsl2_profiles");
+	assert_string_equal(json_object_get_string(tmp), vdsl2_profiles_val);
+
+	tmp = json_object_get_by_string(jobj, "fast_profiles");
+	assert_string_equal(json_object_get_string(tmp), fast_profiles_val);
+
+	tmp = json_object_get_by_string(jobj, "limit_mask");
+	assert_int_equal(json_object_get_int(tmp), limit_mask_val);
+
+	tmp = json_object_get_by_string(jobj, "us0_mask");
+	assert_int_equal(json_object_get_int(tmp), us0_mask_val);
+
+	// Free the memory
+	json_object_put(jobj);
+}
+
+static void test_api_dsl_configure_fail(void **state)
+{
+	const char *xtse_val = "00,00,00,00,00,00,00,00"; // invalid
+	const char *vdsl2_profiles_val = "30a,35b";
+	const char *fast_profiles_val = "106a";
+
+	struct test_ctx *ctx = (struct test_ctx *) *state;
+	struct blob_buf *bb = &ctx->bb;
+	struct ubus_object *obj = &ctx->dsl_line;
+
+	// Prepare the input parameters
+	blobmsg_add_string(bb, "xtse", xtse_val);
+	blobmsg_add_string(bb, "vdsl2_profiles", vdsl2_profiles_val);
+	blobmsg_add_string(bb, "fast_profiles", fast_profiles_val);
+
+	// Call the function to be tested
+	int res = dsl_line_configure(NULL, obj, NULL, NULL, bb->head);
+	assert_true(res != UBUS_STATUS_OK);
+
+	// Check the results
+	struct json_object *jobj = get_json_obj_from_log();
+	assert_non_null(jobj);
+
+	struct json_object *tmp = json_object_get_by_string(jobj, "xtse");
+	assert_string_equal(json_object_get_string(tmp), xtse_val);
+
+	tmp = json_object_get_by_string(jobj, "vdsl2_profiles");
+	assert_string_equal(json_object_get_string(tmp), vdsl2_profiles_val);
+
+	tmp = json_object_get_by_string(jobj, "fast_profiles");
+	assert_string_equal(json_object_get_string(tmp), fast_profiles_val);
+
+	// Free the memory
+	json_object_put(jobj);
+}
+
+static void test_api_atm_configure(void **state)
+{
+	const char *link_type_val = "eoa";
+	const unsigned int vpi_val = 8; // invalid
+	const unsigned int vci_val = 35;
+	const char *qos_class_val = "ubr";
+	const unsigned int max_burst_size_val = 8124;
+
+	struct test_ctx *ctx = (struct test_ctx *) *state;
+	struct blob_buf *bb = &ctx->bb;
+	struct ubus_object *obj = &ctx->atm_link;
+
+	// Prepare the input parameters
+	blobmsg_add_string(bb, "link_type", link_type_val);
+	blobmsg_add_u32(bb, "vpi", vpi_val);
+	blobmsg_add_u32(bb, "vci", vci_val);
+	blobmsg_add_string(bb, "qos_class", qos_class_val);
+	blobmsg_add_u32(bb, "max_burst_size", max_burst_size_val);
+
+	// Call the function to be tested
+	int res = atm_link_configure(NULL, obj, NULL, NULL, bb->head);
+	assert_true(res == UBUS_STATUS_OK);
+
+	// Check the results
+	struct json_object *jobj = get_json_obj_from_log();
+	assert_non_null(jobj);
+
+	struct json_object *tmp = json_object_get_by_string(jobj, "link_type");
+	assert_string_equal(json_object_get_string(tmp), link_type_val);
+
+	tmp = json_object_get_by_string(jobj, "vpi");
+	assert_int_equal(json_object_get_int(tmp), vpi_val);
+
+	tmp = json_object_get_by_string(jobj, "vci");
+	assert_int_equal(json_object_get_int(tmp), vci_val);
+
+	tmp = json_object_get_by_string(jobj, "qos_class");
+	assert_string_equal(json_object_get_string(tmp), qos_class_val);
+
+	tmp = json_object_get_by_string(jobj, "max_burst_size");
+	assert_int_equal(json_object_get_int(tmp), max_burst_size_val);
+
+	// Free the memory
+	json_object_put(jobj);
+}
+
+static void test_api_atm_configure_fail(void **state)
+{
+	const char *link_type_val = "eoa";
+	const unsigned int vpi_val = 0; // invalid
+	const unsigned int vci_val = 35;
+	const char *qos_class_val = "ubr";
+
+	struct test_ctx *ctx = (struct test_ctx *) *state;
+	struct blob_buf *bb = &ctx->bb;
+	struct ubus_object *obj = &ctx->atm_link;
+
+	// Prepare the input parameters
+	blobmsg_add_string(bb, "link_type", link_type_val);
+	blobmsg_add_u32(bb, "vpi", vpi_val);
+	blobmsg_add_u32(bb, "vci", vci_val);
+	blobmsg_add_string(bb, "qos_class", qos_class_val);
+
+	// Call the function to be tested
+	int res = atm_link_configure(NULL, obj, NULL, NULL, bb->head);
+	assert_true(res != UBUS_STATUS_OK);
+
+	// Check the results
+	struct json_object *jobj = get_json_obj_from_log();
+	assert_non_null(jobj);
+
+	struct json_object *tmp = json_object_get_by_string(jobj, "link_type");
+	assert_string_equal(json_object_get_string(tmp), link_type_val);
+
+	tmp = json_object_get_by_string(jobj, "vpi");
+	assert_int_equal(json_object_get_int(tmp), vpi_val);
+
+	tmp = json_object_get_by_string(jobj, "vci");
+	assert_int_equal(json_object_get_int(tmp), vci_val);
+
+	tmp = json_object_get_by_string(jobj, "qos_class");
+	assert_string_equal(json_object_get_string(tmp), qos_class_val);
+
+	// Free the memory
+	json_object_put(jobj);
+}
+
 int main(void)
 {
 	const struct CMUnitTest tests[] = {
@@ -233,7 +450,11 @@ int main(void)
 		cmocka_unit_test_setup_teardown(test_api_dsl_line_stats_interval, setup, teardown),
 		cmocka_unit_test_setup_teardown(test_api_dsl_channel_stats, setup, teardown),
 		cmocka_unit_test_setup_teardown(test_api_dsl_channel_stats_interval, setup, teardown),
-		cmocka_unit_test_setup_teardown(test_api_dsl_stats, setup, teardown)
+		cmocka_unit_test_setup_teardown(test_api_dsl_stats, setup, teardown),
+		cmocka_unit_test_setup_teardown(test_api_dsl_configure, setup, teardown),
+		cmocka_unit_test_setup_teardown(test_api_dsl_configure_fail, setup, teardown),
+		cmocka_unit_test_setup_teardown(test_api_atm_configure, setup, teardown),
+		cmocka_unit_test_setup_teardown(test_api_atm_configure_fail, setup, teardown)
 	};
 
 	return cmocka_run_group_tests(tests, group_setup, group_teardown);