diff --git a/Makefile b/Makefile
index 375683dc4a15999e1383c1a0b623cf144074484c..8172bce395a549b795283dce38511977688fb9fd 100644
--- a/Makefile
+++ b/Makefile
@@ -1,21 +1,21 @@
 PROG = dslmngr
-OBJS = dslmngr.o dslmngr_nl.o main.o
+OBJS = dslmngr.o main.o
 
-PROG_CFLAGS = $(CFLAGS) -fstrict-aliasing -I./libdsl
-PROG_LDFLAGS = $(LDFLAGS) -L. -L./libdsl -ldsl -pthread
-PROG_LDFLAGS += -luci -lubus -lubox -lblobmsg_json -lnl-genl-3 -lnl-3
+PROG_CFLAGS = $(CFLAGS) -fstrict-aliasing
+PROG_LDFLAGS = $(LDFLAGS) -ldsl
+PROG_LDFLAGS += -pthread -luci -lubus -lubox -lblobmsg_json -lnl-genl-3 -lnl-3
+
+ifeq ($(TARGET_PLATFORM),INTEL)
+PROG_LDFLAGS += -L/opt/intel/usr/lib -ldslfapi -lhelper -lsysfapi
+endif
 
 %.o: %.c
 	$(CC) $(PROG_CFLAGS) $(FPIC) -c -o $@ $<
 
-all: libdsl.so dslmngr
-
 dslmngr: $(OBJS)
 	$(CC) $(PROG_LDFLAGS) -o $@ $^
 
-libdsl.so:
-	$(MAKE) -C libdsl $@
-
 clean:
-	$(MAKE) -C libdsl clean
 	rm -f *.o $(PROG)
+
+.PHONY: clean
diff --git a/README b/README
index 0b0923753ff98eed0656fe9813b15439444b707f..d2d0fcc8d26f34c6ec5cb74d8270848ee6570a8c 100644
--- a/README
+++ b/README
@@ -1,12 +1,10 @@
-PrplWrt DSL PoC consists of two parts.
-
 libdsl: SoC independent DSL API covering functions to configure DSL and gather stats.
 
 dsmngr: Userspace application to configure DSL from UCI options and provide ubus interface to start/stop DSL and gather stats. dslmngr links with libdsl and utilizes the libdsl functions.
 
 
      -----------------
-    |xdsl object @ubus|
+    |dsl object @ubus|
      -----------------
 	   ||
 	 -------
@@ -20,3 +18,529 @@ dsmngr: Userspace application to configure DSL from UCI options and provide ubus
        ----------
       |DSL Driver|
        ----------
+
+ -----------------------------------------------------------------------
+|				UBUS Data Model				|
+ -----------------------------------------------------------------------
+ubus call dsl status
+{
+	"line": [
+		{
+			"id": 0,
+			"status": "up",
+			"upstream": true,
+			"firmware_version": "8.11.0.15.0.7",
+			"link_status": "up",
+			"xtse_used": [
+				"00",
+				"00",
+				"00",
+				"00",
+				"00",
+				"00",
+				"00",
+				"01"
+			],
+			"current_profile": "17a",
+			"power_management_state": "l0",
+			"max_bit_rate": {
+				"us": 65067,
+				"ds": 141161
+			},
+			"line_encoding": "dmt",
+			"xtse": [
+				"15",
+				"00",
+				"04",
+				"00",
+				"0c",
+				"05",
+				"05",
+				"07"
+			],
+			"allowed_profiles": [
+				"8a",
+				"8b",
+				"8c",
+				"8b",
+				"12a",
+				"12b",
+				"17a",
+				"30a",
+				"35b"
+			],
+			"success_failure_cause": 0,
+			"upbokler_pb": [
+				2,
+				15,
+				12,
+				2048,
+				2048
+			],
+			"rxthrsh_ds": [
+				18,
+				18,
+				2048,
+				2048,
+				2048
+			],
+			"act_ra_mode": {
+				"us": 3,
+				"ds": 3
+			},
+			"snr_mroc_us": 0,
+			"last_state_transmitted": {
+				"us": 0,
+				"ds": 0
+			},
+			"us0_mask": 62451,
+			"trellis": {
+				"us": 1,
+				"ds": 1
+			},
+			"act_snr_mode": {
+				"us": 0,
+				"ds": 0
+			},
+			"line_number": 0,
+			"noise_margin": {
+				"us": 139,
+				"ds": 184
+			},
+			"snr_mpb_us": [
+				99,
+				182,
+				123,
+				-32768,
+				-32768
+			],
+			"snr_mpb_ds": [
+				184,
+				182,
+				186,
+				-32768,
+				-32768
+			],
+			"attenuation": {
+				"us": 38,
+				"ds": 35
+			},
+			"power": {
+				"us": 133,
+				"ds": 125
+			},
+			"xtur_vendor": "4946544E",
+			"xtur_country": "B500",
+			"xtur_ansi_std": 0,
+			"xtur_ansi_rev": 0,
+			"xtuc_vendor": "4244434D",
+			"xtuc_country": "B500",
+			"xtuc_ansi_std": 0,
+			"xtuc_ansi_rev": 0,
+			"channel": [
+				{
+					"id": 0,
+					"status": "up",
+					"link_encapsulation_used": "vdsl2_ptm",
+					"curr_rate": {
+						"us": 59998,
+						"ds": 100000
+					},
+					"actndr": {
+						"us": 59998,
+						"ds": 100000
+					},
+					"link_encapsulation_supported": [
+						"adsl2_atm",
+						"vdsl2_ptm"
+					],
+					"lpath": 0,
+					"intlvdepth": 1,
+					"intlvblock": 255,
+					"actual_interleaving_delay": 0,
+					"actinp": 0,
+					"inpreport": false,
+					"nfec": 255,
+					"rfec": 16,
+					"lsymb": 26823,
+					"actinprein": {
+						"us": 0,
+						"ds": 0
+					}
+				}
+			]
+		}
+	]
+}
+ubus call dsl stats
+{
+	"line": [
+		{
+			"id": 0,
+			"total_start": 193,
+			"showtime_start": 86,
+			"last_showtime_start": 0,
+			"current_day_start": 32512,
+			"quarter_hour_start": 112,
+			"total": {
+				"errored_secs": 0,
+				"severely_errored_secs": 0
+			},
+			"showtime": {
+				"errored_secs": 0,
+				"severely_errored_secs": 0
+			},
+			"lastshowtime": {
+				"errored_secs": 0,
+				"severely_errored_secs": 0
+			},
+			"currentday": {
+				"errored_secs": 0,
+				"severely_errored_secs": 0
+			},
+			"quarterhour": {
+				"errored_secs": 0,
+				"severely_errored_secs": 0
+			},
+			"channel": [
+				{
+					"id": 0,
+					"total_start": 193,
+					"showtime_start": 86,
+					"last_showtime_start": 0,
+					"current_day_start": 32512,
+					"quarter_hour_start": 112,
+					"total": {
+						"xtur_fec_errors": 0,
+						"xtuc_fec_errors": 0,
+						"xtur_hec_errors": 0,
+						"xtuc_hec_errors": 0,
+						"xtur_crc_errors": 0,
+						"xtuc_crc_errors": 0
+					},
+					"showtime": {
+						"xtur_fec_errors": 0,
+						"xtuc_fec_errors": 0,
+						"xtur_hec_errors": 0,
+						"xtuc_hec_errors": 0,
+						"xtur_crc_errors": 0,
+						"xtuc_crc_errors": 0
+					},
+					"lastshowtime": {
+						"xtur_fec_errors": 0,
+						"xtuc_fec_errors": 0,
+						"xtur_hec_errors": 0,
+						"xtuc_hec_errors": 0,
+						"xtur_crc_errors": 0,
+						"xtuc_crc_errors": 0
+					},
+					"currentday": {
+						"xtur_fec_errors": 0,
+						"xtuc_fec_errors": 0,
+						"xtur_hec_errors": 0,
+						"xtuc_hec_errors": 0,
+						"xtur_crc_errors": 0,
+						"xtuc_crc_errors": 0
+					},
+					"quarterhour": {
+						"xtur_fec_errors": 0,
+						"xtuc_fec_errors": 0,
+						"xtur_hec_errors": 0,
+						"xtuc_hec_errors": 0,
+						"xtur_crc_errors": 0,
+						"xtuc_crc_errors": 0
+					}
+				}
+			]
+		}
+	]
+}
+ubus call dsl.line.0 status
+{
+	"status": "up",
+	"upstream": true,
+	"firmware_version": "8.11.0.15.0.7",
+	"link_status": "up",
+	"xtse_used": [
+		"00",
+		"00",
+		"00",
+		"00",
+		"00",
+		"00",
+		"00",
+		"01"
+	],
+	"current_profile": "17a",
+	"power_management_state": "l0",
+	"max_bit_rate": {
+		"us": 65067,
+		"ds": 141209
+	},
+	"line_encoding": "dmt",
+	"xtse": [
+		"15",
+		"00",
+		"04",
+		"00",
+		"0c",
+		"05",
+		"05",
+		"07"
+	],
+	"allowed_profiles": [
+		"8a",
+		"8b",
+		"8c",
+		"8b",
+		"12a",
+		"12b",
+		"17a",
+		"30a",
+		"35b"
+	],
+	"success_failure_cause": 0,
+	"upbokler_pb": [
+		2,
+		15,
+		12,
+		2048,
+		2048
+	],
+	"rxthrsh_ds": [
+		18,
+		18,
+		2048,
+		2048,
+		2048
+	],
+	"act_ra_mode": {
+		"us": 3,
+		"ds": 3
+	},
+	"snr_mroc_us": 0,
+	"last_state_transmitted": {
+		"us": 0,
+		"ds": 0
+	},
+	"us0_mask": 62451,
+	"trellis": {
+		"us": 1,
+		"ds": 1
+	},
+	"act_snr_mode": {
+		"us": 0,
+		"ds": 0
+	},
+	"line_number": 0,
+	"noise_margin": {
+		"us": 139,
+		"ds": 184
+	},
+	"snr_mpb_us": [
+		101,
+		183,
+		124,
+		-32768,
+		-32768
+	],
+	"snr_mpb_ds": [
+		184,
+		182,
+		186,
+		-32768,
+		-32768
+	],
+	"attenuation": {
+		"us": 38,
+		"ds": 35
+	},
+	"power": {
+		"us": 133,
+		"ds": 125
+	},
+	"xtur_vendor": "4946544E",
+	"xtur_country": "B500",
+	"xtur_ansi_std": 0,
+	"xtur_ansi_rev": 0,
+	"xtuc_vendor": "4244434D",
+	"xtuc_country": "B500",
+	"xtuc_ansi_std": 0,
+	"xtuc_ansi_rev": 0
+}
+ubus call dsl.line.0 stats
+{
+	"total_start": 193,
+	"showtime_start": 86,
+	"last_showtime_start": 0,
+	"current_day_start": 32512,
+	"quarter_hour_start": 112,
+	"total": {
+		"errored_secs": 0,
+		"severely_errored_secs": 0
+	},
+	"showtime": {
+		"errored_secs": 0,
+		"severely_errored_secs": 0
+	},
+	"lastshowtime": {
+		"errored_secs": 0,
+		"severely_errored_secs": 0
+	},
+	"currentday": {
+		"errored_secs": 0,
+		"severely_errored_secs": 0
+	},
+	"quarterhour": {
+		"errored_secs": 0,
+		"severely_errored_secs": 0
+	}
+}
+ubus call dsl.line.0 stats "{'interval':'total'}"
+{
+	"errored_secs": 0,
+	"severely_errored_secs": 0
+}
+ubus call dsl.line.0 stats "{'interval':'showtime'}"
+{
+	"errored_secs": 0,
+	"severely_errored_secs": 0
+}
+ubus call dsl.line.0 stats "{'interval':'lastshowtime'}"
+{
+	"errored_secs": 0,
+	"severely_errored_secs": 0
+}
+ubus call dsl.line.0 stats "{'interval':'currentday'}"
+{
+	"errored_secs": 0,
+	"severely_errored_secs": 0
+}
+ubus call dsl.line.0 stats "{'interval':'quarterhour'}"
+{
+	"errored_secs": 0,
+	"severely_errored_secs": 0
+}
+ubus call dsl.channel.0 status
+{
+	"status": "up",
+	"link_encapsulation_used": "vdsl2_ptm",
+	"curr_rate": {
+		"us": 59998,
+		"ds": 100000
+	},
+	"actndr": {
+		"us": 59998,
+		"ds": 100000
+	},
+	"link_encapsulation_supported": [
+		"adsl2_atm",
+		"vdsl2_ptm"
+	],
+	"lpath": 0,
+	"intlvdepth": 1,
+	"intlvblock": 255,
+	"actual_interleaving_delay": 0,
+	"actinp": 0,
+	"inpreport": false,
+	"nfec": 255,
+	"rfec": 16,
+	"lsymb": 26823,
+	"actinprein": {
+		"us": 0,
+		"ds": 0
+	}
+}
+ubus call dsl.channel.0 stats
+{
+	"total_start": 193,
+	"showtime_start": 86,
+	"last_showtime_start": 0,
+	"current_day_start": 32512,
+	"quarter_hour_start": 112,
+	"total": {
+		"xtur_fec_errors": 0,
+		"xtuc_fec_errors": 0,
+		"xtur_hec_errors": 0,
+		"xtuc_hec_errors": 0,
+		"xtur_crc_errors": 0,
+		"xtuc_crc_errors": 0
+	},
+	"showtime": {
+		"xtur_fec_errors": 0,
+		"xtuc_fec_errors": 0,
+		"xtur_hec_errors": 0,
+		"xtuc_hec_errors": 0,
+		"xtur_crc_errors": 0,
+		"xtuc_crc_errors": 0
+	},
+	"lastshowtime": {
+		"xtur_fec_errors": 0,
+		"xtuc_fec_errors": 0,
+		"xtur_hec_errors": 0,
+		"xtuc_hec_errors": 0,
+		"xtur_crc_errors": 0,
+		"xtuc_crc_errors": 0
+	},
+	"currentday": {
+		"xtur_fec_errors": 0,
+		"xtuc_fec_errors": 0,
+		"xtur_hec_errors": 0,
+		"xtuc_hec_errors": 0,
+		"xtur_crc_errors": 0,
+		"xtuc_crc_errors": 0
+	},
+	"quarterhour": {
+		"xtur_fec_errors": 0,
+		"xtuc_fec_errors": 0,
+		"xtur_hec_errors": 0,
+		"xtuc_hec_errors": 0,
+		"xtur_crc_errors": 0,
+		"xtuc_crc_errors": 0
+	}
+}
+ubus call dsl.channel.0 stats "{'interval':'total'}"
+{
+	"xtur_fec_errors": 0,
+	"xtuc_fec_errors": 0,
+	"xtur_hec_errors": 0,
+	"xtuc_hec_errors": 0,
+	"xtur_crc_errors": 0,
+	"xtuc_crc_errors": 0
+}
+ubus call dsl.channel.0 stats "{'interval':'showtime'}"
+{
+	"xtur_fec_errors": 0,
+	"xtuc_fec_errors": 0,
+	"xtur_hec_errors": 0,
+	"xtuc_hec_errors": 0,
+	"xtur_crc_errors": 0,
+	"xtuc_crc_errors": 0
+}
+ubus call dsl.channel.0 stats "{'interval':'lastshowtime'}"
+{
+	"xtur_fec_errors": 0,
+	"xtuc_fec_errors": 0,
+	"xtur_hec_errors": 0,
+	"xtuc_hec_errors": 0,
+	"xtur_crc_errors": 0,
+	"xtuc_crc_errors": 0
+}
+ubus call dsl.channel.0 stats "{'interval':'currentday'}"
+{
+	"xtur_fec_errors": 0,
+	"xtuc_fec_errors": 0,
+	"xtur_hec_errors": 0,
+	"xtuc_hec_errors": 0,
+	"xtur_crc_errors": 0,
+	"xtuc_crc_errors": 0
+}
+ubus call dsl.channel.0 stats "{'interval':'quarterhour'}"
+{
+	"xtur_fec_errors": 0,
+	"xtuc_fec_errors": 0,
+	"xtur_hec_errors": 0,
+	"xtuc_hec_errors": 0,
+	"xtur_crc_errors": 0,
+	"xtuc_crc_errors": 0
+}
diff --git a/dslmngr.c b/dslmngr.c
index 5c9a9837abf5940098750598f1af8c2667b1ccb1..52a0c5677e69d8f4f3ccc3fba4e2063c4c9508d5 100644
--- a/dslmngr.c
+++ b/dslmngr.c
@@ -1,9 +1,10 @@
 /*
- * dslmngr.c - provides "xdsl" UBUS object
+ * dslmngr.c - provides "dsl" UBUS object
  *
- * Copyright (C) 2018 Inteno Broadband Technology AB. All rights reserved.
+ * Copyright (C) 2019 iopsys Software Solutions AB. All rights reserved.
  *
- * Author: anjan.chanda@inteno.se
+ * Author: anjan.chanda@iopsys.eu
+ *         yalu.zhang@iopsys.eu
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -25,471 +26,834 @@
 #include <libubox/uloop.h>
 #include <libubox/ustream.h>
 #include <libubox/utils.h>
-#include <libubus.h>
 #include <uci.h>
 
-#include <xdsl.h>
-
+#include "xdsl.h"
 #include "dslmngr.h"
 
-enum {
-	DSL_STATS_TYPE,
-	__DSL_STATS_MAX,
-};
+#define DSL_OBJECT_LINE "line"
+#define DSL_OBJECT_CHANNEL "channel"
 
-static const struct blobmsg_policy dsl_stats_policy[__DSL_STATS_MAX] = {
-	[DSL_STATS_TYPE] = { .name = "type", .type = BLOBMSG_TYPE_STRING },
+struct value2text {
+	int value;
+	char *text;
 };
 
 enum {
-	DSL_STATUS_LINE_ID,
-	__DSL_STATUS_MAX,
+	DSL_STATS_INTERVAL,
+	__DSL_STATS_MAX,
 };
 
-static const struct blobmsg_policy dsl_status_policy[__DSL_STATUS_MAX] = {
-	[DSL_STATUS_LINE_ID] = { .name = "line", .type = BLOBMSG_TYPE_INT32 },
+static const struct blobmsg_policy dsl_stats_policy[__DSL_STATS_MAX] = {
+	[DSL_STATS_INTERVAL] = { .name = "interval", .type = BLOBMSG_TYPE_STRING },
 };
 
+static const char *dsl_if_status_str(enum dsl_if_status status)
+{
+	switch (status) {
+	case IF_UP: return "up";
+	case IF_DOWN: return "down";
+	case IF_DORMANT: return "dormant";
+	case IF_NOTPRESENT: return "not_present";
+	case IF_LLDOWN: return "lower_layer_down";
+	case IF_ERROR: return "error";
+	case IF_UNKNOWN:
+	default: return "unknown";
+	}
+}
+
+static const char *dsl_link_status_str(enum dsl_link_status status)
+{
+	switch (status) {
+	case LINK_UP: return "up";
+	case LINK_INITIALIZING: return "initializing";
+	case LINK_ESTABLISHING: return "establishing";
+	case LINK_NOSIGNAL: return "no_signal";
+	case LINK_DISABLED: return "disabled";
+	case LINK_ERROR: return "error";
+	default: return "unknown";
+	}
+}
 
+static const char *dsl_mod_str(enum dsl_modtype mod)
+{
+	switch (mod) {
+	case MOD_G_922_1_ANNEX_A: return "gdmt_annexa";
+	case MOD_G_922_1_ANNEX_B: return "gdmt_annexb";
+	case MOD_G_922_1_ANNEX_C: return "gdmt_annexc";
+	case MOD_T1_413: return "t1413";
+	case MOD_T1_413i2: return "t1413_i2";
+	case MOD_ETSI_101_388: return "etsi_101_388";
+	case MOD_G_992_2: return "glite";
+	case MOD_G_992_3_Annex_A: return "adsl2_annexa";
+	case MOD_G_992_3_Annex_B: return "adsl2_annexb";
+	case MOD_G_992_3_Annex_C: return "adsl2_annexc";
+	case MOD_G_992_3_Annex_I: return "adsl2_annexi";
+	case MOD_G_992_3_Annex_J: return "adsl2_annexj";
+	case MOD_G_992_3_Annex_L: return "adsl2_annexl";
+	case MOD_G_992_3_Annex_M: return "adsl2_annexm";
+	case MOD_G_992_4: return "splitterless_adsl2";
+	case MOD_G_992_5_Annex_A: return "adsl2p_annexa";
+	case MOD_G_992_5_Annex_B: return "adsl2p_annexb";
+	case MOD_G_992_5_Annex_C: return "adsl2p_annexc";
+	case MOD_G_992_5_Annex_I: return "adsl2p_annexi";
+	case MOD_G_992_5_Annex_J: return "adsl2p_annexj";
+	case MOD_G_992_5_Annex_M: return "adsl2p_annexm";
+	case MOD_G_993_1: return "vdsl";
+	case MOD_G_993_1_Annex_A: return "vdsl_annexa";
+	case MOD_G_993_2_Annex_A: return "vdsl2_annexa";
+	case MOD_G_993_2_Annex_B: return "vdsl2_annexb";
+	case MOD_G_993_2_Annex_C: return "vdsl2_annexc";
+	default: return "unknown";
+	}
+}
 
-const char *dsl_mode_str(enum dsl_modtype v)
+static const char *dsl_line_encoding_str(enum dsl_line_encoding encoding)
 {
-#define E2S(v)	case v: return #v
-	switch(v) {
-	E2S(MOD_GDMT);
-	E2S(MOD_T1413);
-	E2S(MOD_GLITE);
-	E2S(MOD_ADSL2);
-	E2S(MOD_ADSL2P);
-	E2S(MOD_READSL2);
-	E2S(MOD_VDSL);
-	E2S(MOD_VDSL2);
-	E2S(MOD_VDSL2P);
-	E2S(MOD_GFAST);
-	E2S(MOD_UNDEFINED);
-	default:
-		return "MOD_Undefined";
+	switch (encoding) {
+	case LE_DMT: return "dmt";
+	case LE_CAP: return "cap";
+	case LE_2B1Q: return "2b1q";
+	case LE_43BT: return "43bt";
+	case LE_PAM: return "pam";
+	case LE_QAM: return "qam";
+	default: return "unknown";
 	}
-};
+}
 
-const char *dsl_tc_str(enum dsl_traffictype v)
+static const char *dsl_profile_str(enum dsl_profile profile)
 {
-#define E2S(v)	case v: return #v
-	switch(v) {
-	E2S(TC_PTM);
-	E2S(TC_ATM);
-	E2S(TC_RAW);
-	E2S(TC_NOT_CONNECTED);
-	default:
-		return "TC_Undefined";
+	switch (profile) {
+	case VDSL2_8a: return "8a";
+	case VDSL2_8b: return "8b";
+	case VDSL2_8c: return "8c";
+	case VDSL2_8d: return "8b";
+	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 *dsl_pwr_state_str(enum dsl_powerstate v)
+static const char *dsl_power_state_str(enum dsl_power_state power_state)
 {
-#define E2S(v)	case v: return #v
-	switch(v) {
-	E2S(L0);
-	E2S(L1);
-	E2S(L2);
-	E2S(L3);
-	default:
-		return "Unknown";
+	switch (power_state) {
+	case DSL_L0: return "l0";
+	case DSL_L1: return "l1";
+	case DSL_L2: return "l2";
+	case DSL_L3: return "l3";
+	case DSL_L4: return "l4";
+	default: return "unknown";
 	}
 };
 
-const char *dsl_line_status_str(enum dsl_linestate v)
+static void dsl_add_sequence_to_blob(const char *name, bool is_signed, size_t count,
+				const long *head, struct blob_buf *bb)
 {
-#define E2S(v)	case v: return #v
-	switch(v) {
-	E2S(LINE_DOWN);
-	E2S(LINE_HANDSHAKING);
-	E2S(LINE_TRAINING);
-	E2S(LINE_SHOWTIME);
-	default:
-		return "LINE_Unknown";
+	void *array;
+	size_t i;
+
+	array = blobmsg_open_array(bb, name);
+	for (i = 0; i < count; i++) {
+		if (is_signed)
+			blobmsg_add_u32(bb, "", (uint32_t)head[i]);
+		else
+			blobmsg_add_u64(bb, "", (uint64_t)head[i]);
 	}
-};
+	blobmsg_close_array(bb, array);
+}
 
-const char *dsl_stattype_str(enum dsl_stattype t)
+static void dsl_add_usds_to_blob(const char *name, bool is_signed, const long *head, struct blob_buf *bb)
 {
-	switch (t) {
-	case STAT_CURR_LINK:
-		return "since linkup";
-	case STAT_CURR_15MINS:
-		return "current 15 mins";
-	case STAT_PREV_15MINS:
-		return "previous 15 mins";
-	case STAT_CURR_24HRS:
-		return "current day";
-	case STAT_PREV_24HRS:
-		return "previous day";
-	case STAT_TOTAL:
-		return "total";
-	default:
-		return "";
+	void *table;
+	int i;
+
+	table = blobmsg_open_table(bb, name);
+	for (i = 0; i < 2; i++) {
+		if (is_signed)
+			blobmsg_add_u32(bb, i == 0 ? "us" : "ds", (uint32_t)head[i]);
+		else
+			blobmsg_add_u64(bb, i == 0 ? "us" : "ds", (uint64_t)head[i]);
 	}
+	blobmsg_close_table(bb, table);
 }
 
-void dslstats_to_blob_buffer(struct dsl_perfcounters *perf, struct blob_buf *b)
+static void dsl_add_int_to_blob(const char *name, long int value, struct blob_buf *bb)
 {
-	//blobmsg_add_string(b, "type", dsl_stattype_str(perf->type));
-	blobmsg_add_u64(b, "es_down", perf->es.ds);
-	blobmsg_add_u64(b, "es_up", perf->es.us);
-	blobmsg_add_u64(b, "ses_down", perf->ses.ds);
-	blobmsg_add_u64(b, "ses_up", perf->ses.us);
-	blobmsg_add_u64(b, "uas_down", perf->uas.ds);
-	blobmsg_add_u64(b, "uas_up", perf->uas.us);
+	blobmsg_add_u32(bb, name, (uint32_t)value);
 }
 
-void dslinfo_to_blob_buffer(struct dsl_info *info, int lineid, struct blob_buf *b)
+static void dsl_status_line_to_blob(const struct dsl_line *line, struct blob_buf *bb)
 {
-	void *array, *obj;
-	struct dsl_link *link = &info->link;
+	void *array;
 	int i;
+	unsigned long opt;
+	char str[64];
+
+	/*
+	 * Put most important information at the beginning
+	 */
+	blobmsg_add_string(bb, "status", dsl_if_status_str(line->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));
+	// standard_used
+	if (line->standard_used.use_xtse) {
+		array = blobmsg_open_array(bb, "xtse_used");
+		for (i = 0; i < ARRAY_SIZE(line->standard_used.xtse); i++) {
+			snprintf(str, sizeof(str), "%02x", line->standard_used.xtse[i]);
+			blobmsg_add_string(bb, "", str);
+		}
+		blobmsg_close_array(bb, array);
+	} else {
+		for (opt = (unsigned long)MOD_G_922_1_ANNEX_A;
+			 opt <= (unsigned long)MOD_G_993_2_Annex_C;
+			 opt <<= 1) {
+			if (line->standard_used.mode & opt) {
+				blobmsg_add_string(bb, "standard_used", dsl_mod_str(opt));
+				break;
+			}
+		}
+	}
+	// current_profile
+	blobmsg_add_string(bb, "current_profile", dsl_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);
+
+	blobmsg_add_string(bb, "line_encoding", dsl_line_encoding_str(line->line_encoding));
+
+	// standards_supported
+	if (line->standard_supported.use_xtse) {
+		array = blobmsg_open_array(bb, "xtse");
+		for (i = 0; i < ARRAY_SIZE(line->standard_supported.xtse); i++) {
+			snprintf(str, sizeof(str), "%02x", line->standard_supported.xtse[i]);
+			blobmsg_add_string(bb, "", str);
+		}
+		blobmsg_close_array(bb, array);
+	} else {
+		array = blobmsg_open_array(bb, "standards_supported");
+		for (opt = (unsigned long)MOD_G_922_1_ANNEX_A;
+			 opt <= (unsigned long)MOD_G_993_2_Annex_C;
+			 opt <<= 1) {
+			if (line->standard_supported.mode & opt)
+				blobmsg_add_string(bb, "", dsl_mod_str(opt));
+		}
+		blobmsg_close_array(bb, array);
+	}
+
+	// allowed_profiles
+	array = blobmsg_open_array(bb, "allowed_profiles");
+	for (opt = (unsigned long)VDSL2_8a; opt <= (unsigned long)VDSL2_35b; opt <<= 1) {
+		if (line->allowed_profiles & opt)
+			blobmsg_add_string(bb, "", dsl_profile_str(opt));
+	}
+	blobmsg_close_array(bb, array);
+
+	blobmsg_add_u32(bb, "success_failure_cause", line->success_failure_cause);
+
+	// upbokler_pb
+	dsl_add_sequence_to_blob("upbokler_pb", false, line->upbokler_pb.count,
+			(const long *)line->upbokler_pb.array, bb);
+
+	// rxthrsh_ds
+	dsl_add_sequence_to_blob("rxthrsh_ds", false, line->rxthrsh_ds.count,
+			(const long *)line->rxthrsh_ds.array, bb);
+
+	// act_ra_mode
+	unsigned long ra_modes[] = { line->act_ra_mode.us, line->act_ra_mode.ds };
+	dsl_add_usds_to_blob("act_ra_mode", false, ra_modes, bb);
+
+	blobmsg_add_u64(bb, "snr_mroc_us", line->snr_mroc_us);
+
+	// last_state_transmitted
+	unsigned long lst[] = { line->last_state_transmitted.us, line->last_state_transmitted.ds };
+	dsl_add_usds_to_blob("last_state_transmitted", false, lst, bb);
+
+	// us0_mask
+	blobmsg_add_u64(bb, "us0_mask", line->us0_mask);
+
+	// trellis
+	long trellis[] = { line->trellis.us, line->trellis.ds };
+	dsl_add_usds_to_blob("trellis", true, trellis, bb);
+
+	// act_snr_mode
+	unsigned long snr_modes[] = { line->act_snr_mode.us, line->act_snr_mode.ds };
+	dsl_add_usds_to_blob("act_snr_mode", false, snr_modes, bb);
 
-	blobmsg_add_string(b, "mode", dsl_mode_str(link->mode) + 4);
-	blobmsg_add_string(b, "traffic", dsl_tc_str(link->tc_type) + 3);
-	//blobmsg_add_string(b, "status", link->status);
-	blobmsg_add_string(b, "link_power_state",
-				dsl_pwr_state_str(link->pwr_state));
-	blobmsg_add_string(b, "line_status",
-			dsl_line_status_str(link->training_status) + 5);
-	blobmsg_add_u8(b, "trellis_up", link->trellis_enabled.us);
-	blobmsg_add_u8(b, "trellis_down", link->trellis_enabled.ds);
-	blobmsg_add_u32(b, "snr_up_x10", link->snr_margin.us);
-	blobmsg_add_u32(b, "snr_down_x10", link->snr_margin.ds);
-	blobmsg_add_u32(b, "pwr_up_x10", link->power.us);
-	blobmsg_add_u32(b, "pwr_down_x10", link->power.ds);
-	blobmsg_add_u32(b, "attn_up_x10", link->attn.us);
-	blobmsg_add_u32(b, "attn_down_x10", link->attn.ds);
-	blobmsg_add_u32(b, "max_rate_up", link->rate_kbps_max.us);
-	blobmsg_add_u32(b, "max_rate_down", link->rate_kbps_max.ds);
-
-	if (lineid == -1)
-		array = blobmsg_open_array(b, "line");
-
-	for (i = 0; i < info->num_lines; i++) {
-		struct dsl_line *line = &info->line[i];
-		struct dsl_line_params *p = &line->param;
-
-		if (lineid != -1 && lineid != i)
-			continue;
-
-			obj = blobmsg_open_table(b, NULL);
-				blobmsg_add_u32(b, "id", i);
-				blobmsg_add_u32(b, "rate_up", line->rate_kbps.us);
-				blobmsg_add_u32(b, "rate_down", line->rate_kbps.ds);
-				blobmsg_add_u32(b, "msgc_up", p->msgc.us);
-				blobmsg_add_u32(b, "msgc_down", p->msgc.ds);
-				blobmsg_add_u32(b, "b_down", p->b.ds);
-				blobmsg_add_u32(b, "b_up", p->b.us);
-				blobmsg_add_u32(b, "m_down", p->m.ds);
-				blobmsg_add_u32(b, "m_up", p->m.us);
-				blobmsg_add_u32(b, "t_down", p->t.ds);
-				blobmsg_add_u32(b, "t_up", p->t.us);
-				blobmsg_add_u32(b, "r_down", p->r.ds);
-				blobmsg_add_u32(b, "r_up", p->r.us);
-				blobmsg_add_u32(b, "s_down_x10000", p->s.ds * 10000);
-				blobmsg_add_u32(b, "s_up_x10000", p->s.us * 10000);
-				blobmsg_add_u32(b, "l_down", p->l.ds);
-				blobmsg_add_u32(b, "l_up", p->l.us);
-				blobmsg_add_u32(b, "d_down", p->d.ds);
-				blobmsg_add_u32(b, "d_up", p->d.us);
-				blobmsg_add_u32(b, "delay_down", p->delay.ds);
-				blobmsg_add_u32(b, "delay_up", p->delay.us);
-				blobmsg_add_u32(b, "inp_down_x100", p->inp.ds * 100);
-				blobmsg_add_u32(b, "inp_up_x100", p->inp.us * 100);
-				blobmsg_add_u64(b, "sf_down", line->cnts.sf.ds);
-				blobmsg_add_u64(b, "sf_up", line->cnts.sf.us);
-				blobmsg_add_u64(b, "sf_err_down", line->cnts.sferr.ds);
-				blobmsg_add_u64(b, "sf_err_up", line->cnts.sferr.us);
-				blobmsg_add_u64(b, "rs_down", line->cnts.rs.ds);
-				blobmsg_add_u64(b, "rs_up", line->cnts.rs.us);
-				blobmsg_add_u64(b, "rs_corr_down", line->cnts.rscorr.ds);
-				blobmsg_add_u64(b, "rs_corr_up", line->cnts.rscorr.us);
-				blobmsg_add_u64(b, "rs_uncorr_down", line->cnts.rsuncorr.ds);
-				blobmsg_add_u64(b, "rs_uncorr_up", line->cnts.rsuncorr.us);
-				blobmsg_add_u64(b, "hec_down", line->err.hec.ds);
-				blobmsg_add_u64(b, "hec_up", line->err.hec.us);
-				blobmsg_add_u64(b, "ocd_down", line->err.ocd.ds);
-				blobmsg_add_u64(b, "ocd_up", line->err.ocd.us);
-				blobmsg_add_u64(b, "lcd_down", line->err.lcd.ds);
-				blobmsg_add_u64(b, "lcd_up", line->err.lcd.us);
-				blobmsg_add_u64(b, "fec_down", line->err.fec.ds);
-				blobmsg_add_u64(b, "fec_up", line->err.fec.us);
-				blobmsg_add_u64(b, "crc_down", line->err.crc.ds);
-				blobmsg_add_u64(b, "crc_up", line->err.crc.us);
-			blobmsg_close_table(b, obj);
+	// line_number
+	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);
+
+	// snr_mpb_us
+	dsl_add_sequence_to_blob("snr_mpb_us", true, line->snr_mpb_us.count,
+			(const long *)line->snr_mpb_us.array, bb);
+
+	// snr_mpb_ds
+	dsl_add_sequence_to_blob("snr_mpb_ds", true, line->snr_mpb_ds.count,
+			(const long *)line->snr_mpb_ds.array, 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);
+
+	blobmsg_add_string(bb, "xtur_vendor", line->xtur_vendor);
+	blobmsg_add_string(bb, "xtur_country", line->xtur_country);
+	blobmsg_add_u64(bb, "xtur_ansi_std", line->xtur_ansi_std);
+	blobmsg_add_u64(bb, "xtur_ansi_rev", line->xtur_ansi_rev);
+
+	blobmsg_add_string(bb, "xtuc_vendor", line->xtuc_vendor);
+	blobmsg_add_string(bb, "xtuc_country", line->xtuc_country);
+	blobmsg_add_u64(bb, "xtuc_ansi_std", line->xtuc_ansi_std);
+	blobmsg_add_u64(bb, "xtuc_ansi_rev", line->xtuc_ansi_rev);
+}
+
+static const char *dsl_link_encap_str(enum dsl_link_encapsulation encap)
+{
+	switch (encap) {
+	case G_992_3_ANNEK_K_ATM: return "adsl2_atm";
+	case G_992_3_ANNEK_K_PTM: return "adsl2_ptm";
+	case G_993_2_ANNEK_K_ATM: return "vdsl2_atm";
+	case G_993_2_ANNEK_K_PTM: return "vdsl2_ptm";
+	case G_994_1_AUTO: return "auto";
+	default: return "unknown";
+	}
+};
+
+static void dsl_status_channel_to_blob(const struct dsl_channel *channel, struct blob_buf *bb)
+{
+	void *array;
+	unsigned long opt;
+
+	blobmsg_add_string(bb, "status", dsl_if_status_str(channel->status));
+	blobmsg_add_string(bb, "link_encapsulation_used", dsl_link_encap_str(channel->link_encapsulation_used));
+
+	// curr_rate
+	unsigned long curr_rates[] = { channel->curr_rate.us, channel->curr_rate.ds };
+	dsl_add_usds_to_blob("curr_rate", false, curr_rates, bb);
+
+	// actndr
+	unsigned long act_rates[] = { channel->actndr.us, channel->actndr.ds };
+	dsl_add_usds_to_blob("actndr", false, act_rates, bb);
+
+	// link_encapsulation_supported
+	array = blobmsg_open_array(bb, "link_encapsulation_supported");
+	for (opt = (unsigned long)G_992_3_ANNEK_K_ATM; opt <= (unsigned long)G_994_1_AUTO; opt <<= 1) {
+		if (channel->link_encapsulation_supported & opt)
+			blobmsg_add_string(bb, "", dsl_link_encap_str(opt));
 	}
-	if (lineid == -1)
-		blobmsg_close_array(b, array);
-
-	array = blobmsg_open_table(b, "counters");
-		obj = blobmsg_open_table(b, "total");
-			blobmsg_add_u64(b, "es_down", link->perf_cnts.es.ds);
-			blobmsg_add_u64(b, "es_up", link->perf_cnts.es.us);
-			blobmsg_add_u64(b, "ses_down", link->perf_cnts.ses.ds);
-			blobmsg_add_u64(b, "ses_up", link->perf_cnts.ses.us);
-			blobmsg_add_u64(b, "uas_down", link->perf_cnts.uas.ds);
-			blobmsg_add_u64(b, "uas_up", link->perf_cnts.uas.us);
-		blobmsg_close_table(b, obj);
-	blobmsg_close_array(b, array);
+	blobmsg_close_array(bb, array);
+
+	blobmsg_add_u64(bb, "lpath", channel->lpath);
+	blobmsg_add_u64(bb, "intlvdepth", channel->intlvdepth);
+	dsl_add_int_to_blob("intlvblock", channel->intlvblock, bb);
+	blobmsg_add_u64(bb, "actual_interleaving_delay", channel->actual_interleaving_delay);
+	dsl_add_int_to_blob("actinp", channel->actinp, bb);
+	blobmsg_add_u8(bb, "inpreport", channel->inpreport);
+	dsl_add_int_to_blob("nfec", channel->nfec, bb);
+	dsl_add_int_to_blob("rfec", channel->rfec, bb);
+	dsl_add_int_to_blob("lsymb", channel->lsymb, bb);
+
+	// actinprein
+	unsigned long act_inps[] = { channel->actinprein.us, channel->actinprein.ds };
+	dsl_add_usds_to_blob("actinprein", false, act_inps, bb);
 }
 
-static int uci_get_dsl_type(char *type)
+static int dsl_status_all(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method, struct blob_attr *msg)
 {
-	static struct uci_context *ctx = NULL;
-	static struct uci_package *pkg = NULL;
-	struct uci_element *e;
-	int ret = 0;
+	static struct blob_buf bb;
+	struct dsl_line line;
+	struct dsl_channel channel;
+	int retval = UBUS_STATUS_OK;
+	int i, max_line;
+	void *array_line, *array_chan, *table_line, *table_chan;
+
+	// Initialize the buffer
+	memset(&bb, 0, sizeof(bb));
+	blob_buf_init(&bb, 0);
 
-	ctx = uci_alloc_context();
-	if (uci_load(ctx, "dsl", &pkg))
-		return -1;
+	array_line = blobmsg_open_array(&bb, DSL_OBJECT_LINE);
+	for (i = 0, max_line = dsl_get_line_number(); i < max_line; i++) {
+		if (xdsl_ops.get_line_info == NULL || (*xdsl_ops.get_line_info)(i, &line) != 0 ||
+			xdsl_ops.get_channel_info == NULL || (*xdsl_ops.get_channel_info)(i, &channel) != 0) {
+			retval = UBUS_STATUS_UNKNOWN_ERROR;
+			goto __ret;
+		}
 
-	uci_foreach_element(&pkg->sections, e) {
-		struct uci_section *s = uci_to_section(e);
-		const char *dsl_type;
+		// Line table
+		table_line = blobmsg_open_table(&bb, "");
 
-		if (strcmp(s->type, "dsl-line"))
-			continue;
+		// Line parameters
+		blobmsg_add_u32(&bb, "id", (unsigned int)i);
+		dsl_status_line_to_blob(&line, &bb);
 
-		dsl_type = uci_lookup_option_string(ctx, s, "type");
-		if (dsl_type)
-			sprintf(type, "%s", dsl_type);
-		else
-			ret = -1;
+		// Embed channel(s) inside a line in the format channel: [{},{}...]
+		array_chan = blobmsg_open_array(&bb, DSL_OBJECT_CHANNEL);
+		table_chan = blobmsg_open_table(&bb, "");
+		// Channel parameters
+		blobmsg_add_u32(&bb, "id", 0);
+		dsl_status_channel_to_blob(&channel, &bb);
+		blobmsg_close_table(&bb, table_chan);
+		blobmsg_close_array(&bb, array_chan);
+
+		blobmsg_close_table(&bb, table_line);
 	}
-	uci_free_context(ctx);
-	return ret;
+	blobmsg_close_array(&bb, array_line);
+
+	// Send the reply
+	ubus_send_reply(ctx, req, bb.head);
+
+__ret:
+	blob_buf_free(&bb);
+	return retval;
 }
 
-static int uci_get_dsl_config(struct dsl_config *cfg)
+static struct value2text dsl_stats_types[] = {
+	{ DSL_STATS_TOTAL, "total" },
+	{ DSL_STATS_SHOWTIME, "showtime" },
+	{ DSL_STATS_LASTSHOWTIME, "lastshowtime" },
+	{ DSL_STATS_CURRENTDAY, "currentday" },
+	{ DSL_STATS_QUARTERHOUR, "quarterhour" }
+};
+
+static void dsl_stats_to_blob(const struct dsl_line_channel_stats *stats, struct blob_buf *bb)
 {
-	static struct uci_context *ctx = NULL;
-	static struct uci_package *pkg = NULL;
-	struct uci_element *e;
+	blobmsg_add_u64(bb, "total_start", stats->total_start);
+	blobmsg_add_u64(bb, "showtime_start", stats->showtime_start);
+	blobmsg_add_u64(bb, "last_showtime_start", stats->last_showtime_start);
+	blobmsg_add_u64(bb, "current_day_start", stats->current_day_start);
+	blobmsg_add_u64(bb, "quarter_hour_start", stats->quarter_hour_start);
+}
 
-	memset(cfg, 0, sizeof(struct dsl_config));
+static void dsl_stats_line_interval_to_blob(const struct dsl_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);
+}
 
-	ctx = uci_alloc_context();
-	if (uci_load(ctx, "dsl", &pkg))
-		return -1;
+static void dsl_stats_channel_interval_to_blob(const struct dsl_channel_stats_interval *stats, struct blob_buf *bb)
+{
+	blobmsg_add_u64(bb, "xtur_fec_errors", stats->xtur_fec_errors);
+	blobmsg_add_u64(bb, "xtuc_fec_errors", stats->xtuc_fec_errors);
+	blobmsg_add_u64(bb, "xtur_hec_errors", stats->xtur_hec_errors);
+	blobmsg_add_u64(bb, "xtuc_hec_errors", stats->xtuc_hec_errors);
+	blobmsg_add_u64(bb, "xtur_crc_errors", stats->xtur_crc_errors);
+	blobmsg_add_u64(bb, "xtuc_crc_errors", stats->xtuc_crc_errors);
+}
 
-	uci_foreach_element(&pkg->sections, e) {
-		struct uci_section *s = uci_to_section(e);
-		struct uci_option *o;
-		struct uci_ptr ptr;
-		char mode_path[64] = {0};
-		char profile_path[64] = {0};
-		const char *bitswap, *sra, *us0, *trellis;
-
-		if (strcmp(s->type, "dsl-line"))
-			continue;
-
-		sprintf(mode_path, "dsl.%s.mode", s->e.name);
-		if (uci_lookup_ptr(ctx, &ptr, mode_path, true) == UCI_OK) {
-			struct uci_element *ent;
-			o = ptr.o;
-			if (o->type == UCI_TYPE_LIST) {
-				uci_foreach_element(&o->v.list, ent) {
-					if (!strcmp(ent->name, "gdmt"))
-						cfg->mode |= (1 << MOD_GDMT);
-					if (!strcmp(ent->name, "glite"))
-						cfg->mode |= (1 << MOD_GLITE);
-					if (!strcmp(ent->name, "t1413"))
-						cfg->mode |= (1 << MOD_T1413);
-					if (!strcmp(ent->name, "adsl2"))
-						cfg->mode |= (1 << MOD_ADSL2);
-					if (!strcmp(ent->name, "adsl2p"))
-						cfg->mode |= (1 << MOD_ADSL2P);
-					if (!strcmp(ent->name, "vdsl2"))
-						cfg->mode |= (1 << MOD_VDSL2);
-					if (!strcmp(ent->name, "gfast"))
-						cfg->mode |= (1 << MOD_GFAST);
-				}
-			}
+static 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 retval = UBUS_STATUS_OK;
+	static struct blob_buf bb;
+	enum dsl_stats_type type;
+	struct dsl_line_channel_stats stats;
+	struct dsl_line_stats_interval line_stats_interval;
+	struct dsl_channel_stats_interval channel_stats_interval;
+	int i, j, max_line;
+	void *array_line, *array_chan, *table_line, *table_interval, *table_chan;
+
+	// Initialize the buffer
+	memset(&bb, 0, sizeof(bb));
+	blob_buf_init(&bb, 0);
+
+	array_line = blobmsg_open_array(&bb, DSL_OBJECT_LINE);
+	for (i = 0, max_line = dsl_get_line_number(); i < max_line; i++) {
+		if (xdsl_ops.get_line_stats == NULL || (*xdsl_ops.get_line_stats)(i, &stats) != 0) {
+			retval = UBUS_STATUS_UNKNOWN_ERROR;
+			goto __ret;
 		}
 
-		sprintf(profile_path, "dsl.%s.profile", s->e.name);
-		if (uci_lookup_ptr(ctx, &ptr, profile_path, true) == UCI_OK) {
-			struct uci_element *ent;
-			o = ptr.o;
-			if (o->type == UCI_TYPE_LIST) {
-				uci_foreach_element(&o->v.list, ent) {
-					if (!strcmp(ent->name, "8a"))
-						cfg->vdsl2_profile |= VDSL2_8a;
-					if (!strcmp(ent->name, "8b"))
-						cfg->vdsl2_profile |= VDSL2_8b;
-					if (!strcmp(ent->name, "8c"))
-						cfg->vdsl2_profile |= VDSL2_8c;
-					if (!strcmp(ent->name, "8d"))
-						cfg->vdsl2_profile |= VDSL2_8d;
-					if (!strcmp(ent->name, "12a"))
-						cfg->vdsl2_profile |= VDSL2_12a;
-					if (!strcmp(ent->name, "12b"))
-						cfg->vdsl2_profile |= VDSL2_12b;
-					if (!strcmp(ent->name, "17a"))
-						cfg->vdsl2_profile |= VDSL2_17a;
-					if (!strcmp(ent->name, "30a"))
-						cfg->vdsl2_profile |= VDSL2_30a;
-					if (!strcmp(ent->name, "35b"))
-						cfg->vdsl2_profile |= VDSL2_35b;
-				}
+		// Line table
+		table_line = blobmsg_open_table(&bb, "");
+
+		// Line statistics
+		blobmsg_add_u32(&bb, "id", (unsigned int)i);
+		dsl_stats_to_blob(&stats, &bb);
+
+		// Line interval statistics
+		for (j = 0; j < ARRAY_SIZE(dsl_stats_types); j++) {
+			table_interval = blobmsg_open_table(&bb, dsl_stats_types[j].text);
+
+			if (xdsl_ops.get_line_stats_interval == NULL || (*xdsl_ops.get_line_stats_interval)
+				(i, dsl_stats_types[j].value, &line_stats_interval) != 0) {
+				retval = UBUS_STATUS_UNKNOWN_ERROR;
+				goto __ret;
 			}
+			dsl_stats_line_interval_to_blob(&line_stats_interval, &bb);
+
+			blobmsg_close_table(&bb, table_interval);
 		}
 
-		trellis = uci_lookup_option_string(ctx, s, "trellis");
-		bitswap = uci_lookup_option_string(ctx, s, "bitswap");
-		sra = uci_lookup_option_string(ctx, s, "sra");
-		us0 = uci_lookup_option_string(ctx, s, "us0");
+		// Embed channel(s) inside a line in the format channel: [{},{}...]
+		array_chan = blobmsg_open_array(&bb, DSL_OBJECT_CHANNEL);
+		table_chan = blobmsg_open_table(&bb, "");
 
-		if (trellis && atoi(trellis) == 1)
-			cfg->trellis = 1;
+		// Channel statistics
+		blobmsg_add_u32(&bb, "id", 0);
+		if (xdsl_ops.get_channel_stats == NULL || (*xdsl_ops.get_channel_stats)(i, &stats) != 0) {
+			retval = UBUS_STATUS_UNKNOWN_ERROR;
+			goto __ret;
+		}
+		dsl_stats_to_blob(&stats, &bb);
 
-		if (bitswap && atoi(bitswap) == 1)
-			cfg->bitswap = 1;
+		// Line interval statistics
+		for (j = 0; j < ARRAY_SIZE(dsl_stats_types); j++) {
+			table_interval = blobmsg_open_table(&bb, dsl_stats_types[j].text);
 
-		if (sra && atoi(sra) == 1)
-			cfg->sra = 1;
+			if (xdsl_ops.get_channel_stats_interval == NULL || (*xdsl_ops.get_channel_stats_interval)
+				(i, dsl_stats_types[j].value, &channel_stats_interval) != 0) {
+				retval = UBUS_STATUS_UNKNOWN_ERROR;
+				goto __ret;
+			}
+			dsl_stats_channel_interval_to_blob(&channel_stats_interval, &bb);
 
-		if (us0 && atoi(us0) == 1)
-			cfg->us0 = 1;
-	}
-	uci_free_context(ctx);
-	return 0;
-}
+			blobmsg_close_table(&bb, table_interval);
+		}
 
-int dslmngr_dsl_start(struct ubus_context *ctx, struct ubus_object *obj,
-		struct ubus_request_data *req, const char *method,
-		struct blob_attr *msg)
-{
-	struct dsl_config cfg, *cfgptr = NULL;
-	char type[128] = {0};
+		// Close the tables and arrays for the channel
+		blobmsg_close_table(&bb, table_chan);
+		blobmsg_close_array(&bb, array_chan);
 
-	if (uci_get_dsl_type(type) == -1)
-		return UBUS_STATUS_UNKNOWN_ERROR;
+		// Close the table for one line
+		blobmsg_close_table(&bb, table_line);
+	}
+	blobmsg_close_array(&bb, array_line);
 
-	if (uci_get_dsl_config(&cfg) == 0)
-		cfgptr = &cfg;
+	// Send the reply
+	ubus_send_reply(ctx, req, bb.head);
 
-	if (dsl_start(type, cfgptr) < 0)
-		return UBUS_STATUS_UNKNOWN_ERROR;
+__ret:
+	blob_buf_free(&bb);
 
-	return UBUS_STATUS_OK;
+	return retval;
 }
 
-int dslmngr_dsl_stop(struct ubus_context *ctx, struct ubus_object *obj,
-		struct ubus_request_data *req, const char *method,
-		struct blob_attr *msg)
+static struct ubus_method dsl_main_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 = {
+	.name = "dsl",
+	.type = &dsl_main_type,
+	.methods = dsl_main_methods,
+	.n_methods = ARRAY_SIZE(dsl_main_methods),
+};
+
+static int dsl_line_status(struct ubus_context *ctx, struct ubus_object *obj,
+		struct ubus_request_data *req, const char *method, struct blob_attr *msg)
 {
-	char type[128] = {0};
+	static struct blob_buf bb;
+	struct dsl_line line;
+	int retval = UBUS_STATUS_OK;
+	int num = -1;
 
-	if (uci_get_dsl_type(type) == -1)
-		return UBUS_STATUS_UNKNOWN_ERROR;
+	// Initialize the buffer
+	memset(&bb, 0, sizeof(bb));
+	blob_buf_init(&bb, 0);
 
-	if (dsl_stop(type) < 0)
-		return UBUS_STATUS_UNKNOWN_ERROR;
+	// Get line status
+	sscanf(obj->name, "dsl.line.%d", &num);
+	if (xdsl_ops.get_line_info == NULL || (*xdsl_ops.get_line_info)(num, &line) != 0) {
+		retval = UBUS_STATUS_UNKNOWN_ERROR;
+		goto __ret;
+	}
+	dsl_status_line_to_blob(&line, &bb);
 
-	return UBUS_STATUS_OK;
+	// Send the reply
+	ubus_send_reply(ctx, req, bb.head);
+
+__ret:
+	blob_buf_free(&bb);
+	return retval;
 }
 
-int dslmngr_dump_dslstats(struct ubus_context *ctx, struct ubus_object *obj,
-		struct ubus_request_data *req, const char *method,
-		struct blob_attr *msg)
+static int dsl_line_stats(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];
-	struct dsl_perfcounters stats;
-	enum dsl_stattype type = STAT_CURR_LINK;
-	char dsltype[128] = {0};
-
-	blobmsg_parse(dsl_stats_policy, __DSL_STATS_MAX, tb,
-					blob_data(msg), blob_len(msg));
-
-	memset(&stats, 0, sizeof(struct dsl_perfcounters));
-        if ((tb[DSL_STATS_TYPE])) {
-		char st[64] = {0};
-
-		strncpy(st, blobmsg_data(tb[DSL_STATS_TYPE]), sizeof(st)-1);
-		if (!strncasecmp(st, "now15", 5))
-			type = STAT_CURR_15MINS;
-		else if (!strncasecmp(st, "prev15", 6))
-			type = STAT_PREV_15MINS;
-		else if (!strncasecmp(st, "now24", 6))
-			type = STAT_CURR_24HRS;
-		else if (!strncasecmp(st, "prev24", 6))
-			type = STAT_PREV_24HRS;
-		else if (!strncasecmp(st, "total", 6))
-			type = STAT_TOTAL;
-		else if (!strncasecmp(st, "link", 6))
-			type = STAT_CURR_LINK;
-		else
+	enum dsl_stats_type type = DSL_STATS_QUARTERHOUR + 1;
+	struct dsl_line_channel_stats stats;
+	struct dsl_line_stats_interval line_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, "dsl.line.%d", &num);
+
+	// Get line interval statistics
+	if (type >= DSL_STATS_TOTAL && type <= DSL_STATS_QUARTERHOUR) {
+		if (xdsl_ops.get_line_stats_interval == NULL || (*xdsl_ops.get_line_stats_interval)
+			(num, type, &line_stats_interval) != 0) {
+			retval = UBUS_STATUS_UNKNOWN_ERROR;
+			goto __ret;
+		}
+		dsl_stats_line_interval_to_blob(&line_stats_interval, &bb);
+	} else {
+		// Get line statistics
+		if (xdsl_ops.get_line_stats == NULL || (*xdsl_ops.get_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_line_stats_interval == NULL || (*xdsl_ops.get_line_stats_interval)
+				(num, dsl_stats_types[j].value, &line_stats_interval) != 0) {
+				retval = UBUS_STATUS_UNKNOWN_ERROR;
+				goto __ret;
+			}
+			dsl_stats_line_interval_to_blob(&line_stats_interval, &bb);
+
+			blobmsg_close_table(&bb, table);
+		}
 	}
 
-	if (uci_get_dsl_type(dsltype) == -1)
-		return UBUS_STATUS_UNKNOWN_ERROR;
+	// Send the reply
+	ubus_send_reply(ctx, req, bb.head);
+
+__ret:
+	blob_buf_free(&bb);
+	return retval;
+}
 
-	if (dsl_get_stats(dsltype, type, &stats) < 0)
-		return UBUS_STATUS_UNKNOWN_ERROR;
+static struct ubus_method dsl_line_methods[] = {
+	{ .name = "status", .handler = dsl_line_status },
+	UBUS_METHOD("stats", dsl_line_stats, dsl_stats_policy )
+};
+
+static struct ubus_object_type dsl_line_type = UBUS_OBJECT_TYPE("dsl.line", dsl_line_methods);
+
+static int dsl_channel_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 dsl_channel channel;
+	int retval = UBUS_STATUS_OK;
+	int num = -1;
 
+	// Initialize the buffer
+	memset(&bb, 0, sizeof(bb));
 	blob_buf_init(&bb, 0);
-	dslstats_to_blob_buffer(&stats, &bb);
 
+	// Get channel status
+	sscanf(obj->name, "dsl.channel.%d", &num);
+	if (xdsl_ops.get_channel_info == NULL || (*xdsl_ops.get_channel_info)(num, &channel) != 0) {
+		retval = UBUS_STATUS_UNKNOWN_ERROR;
+		goto __ret;
+	}
+	dsl_status_channel_to_blob(&channel, &bb);
+
+	// Send the reply
 	ubus_send_reply(ctx, req, bb.head);
 
-	return UBUS_STATUS_OK;
+__ret:
+	blob_buf_free(&bb);
+	return retval;
 }
 
-int dslmngr_dump_dslstatus(struct ubus_context *ctx, struct ubus_object *obj,
-		struct ubus_request_data *req, const char *method,
-		struct blob_attr *msg)
+static int dsl_channel_stats(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 dsl_info dslinfo;
-	struct blob_attr *tb[__DSL_STATUS_MAX];
-	int ret;
-	int lineid = -1;
-	char type[128] = {0};
-
-	blobmsg_parse(dsl_status_policy, __DSL_STATUS_MAX, tb,
-					blob_data(msg), blob_len(msg));
-
-        if (tb[DSL_STATUS_LINE_ID]) {
-		lineid = blobmsg_get_u32(tb[DSL_STATUS_LINE_ID]);
-		if (lineid < 0 || lineid > XDSL_MAX_LINES)
+	struct blob_attr *tb[__DSL_STATS_MAX];
+	enum dsl_stats_type type = DSL_STATS_QUARTERHOUR + 1;
+	struct dsl_line_channel_stats stats;
+	struct dsl_channel_stats_interval channel_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;
+		}
 	}
 
-	if (uci_get_dsl_type(type) == -1)
-		return UBUS_STATUS_UNKNOWN_ERROR;
+	// Initialize the buffer
+	memset(&bb, 0, sizeof(bb));
+	blob_buf_init(&bb, 0);
 
-	memset(&dslinfo, 0, sizeof(dslinfo));
-	ret = dsl_get_status(type, &dslinfo);
-	if (ret != 0)
-		return UBUS_STATUS_UNKNOWN_ERROR;
+	// Get channel number
+	sscanf(obj->name, "dsl.channel.%d", &num);
 
-	blob_buf_init(&bb, 0);
-	dslinfo_to_blob_buffer(&dslinfo, lineid, &bb);
+	// Get channel interval statistics
+	if (type >= DSL_STATS_TOTAL && type <= DSL_STATS_QUARTERHOUR) {
+		if (xdsl_ops.get_channel_stats_interval == NULL || (*xdsl_ops.get_channel_stats_interval)
+			(num, type, &channel_stats_interval) != 0) {
+			retval = UBUS_STATUS_UNKNOWN_ERROR;
+			goto __ret;
+		}
+		dsl_stats_channel_interval_to_blob(&channel_stats_interval, &bb);
+	} else {
+		// Get channel statistics
+		if (xdsl_ops.get_channel_stats == NULL || (*xdsl_ops.get_channel_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_channel_stats_interval == NULL || (*xdsl_ops.get_channel_stats_interval)
+				(num, dsl_stats_types[j].value, &channel_stats_interval) != 0) {
+				retval = UBUS_STATUS_UNKNOWN_ERROR;
+				goto __ret;
+			}
+			dsl_stats_channel_interval_to_blob(&channel_stats_interval, &bb);
+
+			blobmsg_close_table(&bb, table);
+		}
+	}
+
+	// Send the reply
 	ubus_send_reply(ctx, req, bb.head);
-	return UBUS_STATUS_OK;
+
+__ret:
+	blob_buf_free(&bb);
+	return retval;
 }
 
-struct ubus_method dsl_methods[] = {
-	UBUS_METHOD("status", dslmngr_dump_dslstatus, dsl_status_policy),
-	UBUS_METHOD_NOARG("start", dslmngr_dsl_start),
-	UBUS_METHOD_NOARG("stop", dslmngr_dsl_stop),
-	UBUS_METHOD("stats", dslmngr_dump_dslstats, dsl_stats_policy),
+static struct ubus_method dsl_channel_methods[] = {
+	{ .name = "status", .handler = dsl_channel_status },
+	UBUS_METHOD("stats", dsl_channel_stats, dsl_stats_policy )
 };
 
-struct ubus_object_type dsl_type = UBUS_OBJECT_TYPE("xdsl", dsl_methods);
+static struct ubus_object_type dsl_channel_type = UBUS_OBJECT_TYPE("dsl.channel", dsl_channel_methods);
 
-struct ubus_object dsl_object = {
-	.name = "xdsl",
-	.type = &dsl_type,
-	.methods = dsl_methods,
-	.n_methods = ARRAY_SIZE(dsl_methods),
-};
+int dsl_add_ubus_objects(struct ubus_context *ctx)
+{
+	struct ubus_object *line_objects = NULL;
+	struct ubus_object *channel_objects = NULL;
+	int ret, max_line, max_channel, i;
+
+	ret = ubus_add_object(ctx, &dsl_main_object);
+	if (ret) {
+		DSLMNGR_LOG(LOG_ERR, "Failed to add UBUS object '%s', %s\n",
+				dsl_main_object.name, ubus_strerror(ret));
+		return -1;
+	}
+
+	// Add objects dsl.line.x
+	max_line = dsl_get_line_number();
+	line_objects = calloc(max_line, sizeof(struct ubus_object));
+	if (!line_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, "dsl.line.%d", i) <= 0) {
+			DSLMNGR_LOG(LOG_ERR, "Out of memory\n");
+			return -1;
+		}
+
+		line_objects[i].name = obj_name;
+		line_objects[i].type = &dsl_line_type;
+		line_objects[i].methods = dsl_line_methods;
+		line_objects[i].n_methods = ARRAY_SIZE(dsl_line_methods);
+
+		ret = ubus_add_object(ctx, &line_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 dsl.channel.x
+	max_channel = dsl_get_channel_number();
+	channel_objects = calloc(max_channel, sizeof(struct ubus_object));
+	if (!channel_objects) {
+		DSLMNGR_LOG(LOG_ERR, "Out of memory\n");
+		return -1;
+	}
+	for (i = 0; i < max_channel; i++) {
+		char *obj_name;
+
+		if (asprintf(&obj_name, "dsl.channel.%d", i) <= 0) {
+			DSLMNGR_LOG(LOG_ERR, "Out of memory\n");
+			return -1;
+		}
+
+		channel_objects[i].name = obj_name;
+		channel_objects[i].type = &dsl_channel_type;
+		channel_objects[i].methods = dsl_channel_methods;
+		channel_objects[i].n_methods = ARRAY_SIZE(dsl_channel_methods);
+
+		ret = ubus_add_object(ctx, &channel_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;
+
+__error_ret:
+	if (line_objects)
+		free(line_objects);
+	if (channel_objects)
+		free(channel_objects);
+	return -1;
+}
diff --git a/dslmngr.h b/dslmngr.h
index eb23fd138a1e1a0009ae557fa0fe33578bd164bb..bfd0c41019198446b00f548aca847ec166157333 100644
--- a/dslmngr.h
+++ b/dslmngr.h
@@ -1,10 +1,43 @@
-#ifndef DSLMNGR_H
-#define DSLMNGR_H
+/*
+ * dslmngr header file
+ *
+ * Copyright (C) 2019 iopsys Software Solutions AB. All rights reserved.
+ *
+ * Author: anjan.chanda@iopsys.eu
+ *         yalu.zhang@iopsys.eu
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#ifndef _DSLMNGR_H
+#define _DSLMNGR_H
 
-/* ubus published objects */
-extern struct ubus_object dsl_object;
+#ifdef __cplusplus
+extern "C" {
+#endif
 
+#include <stdio.h>
+#include <syslog.h>
+#include <libubus.h>
 
-extern int dslmngr_nl_msgs_handler(struct ubus_context *ctx);
+#define DSLMNGR_LOG(log_level, format...) fprintf(stderr, ##format)
 
-#endif /* DSLMNGR_H */
+#define CHECK_POINT() printf("Check point at %s@%s:%d\n", __func__, __FILE__, __LINE__)
+
+int dsl_add_ubus_objects(struct ubus_context *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _DSLMNGR_H */
diff --git a/dslmngr_nl.c b/dslmngr_nl.c
index fac3cb173711ad5ab294bd9c3201e7c3e9fcf5f2..3c4607f6809f130f3549e0f18b453b2805334851 100644
--- a/dslmngr_nl.c
+++ b/dslmngr_nl.c
@@ -1,9 +1,10 @@
 /*
  * dslmngr_nl.c - converts netlink messages to UBUS events
  *
- * Copyright (C) 2018 Inteno Broadband Technology AB. All rights reserved.
+ * Copyright (C) 2019 iopsys Software Solutions AB. All rights reserved.
  *
- * Author: anjan.chanda@inteno.se
+ * Author: anjan.chanda@iopsys.eu
+ *         yalu.zhang@iopsys.eu
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -19,24 +20,22 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  * 02110-1301 USA
  */
-
 #include <stdio.h>
 #include <stdlib.h>
 #include <time.h>
 #include <signal.h>
-
 #include <netlink/netlink.h>
 #include <netlink/socket.h>
 #include <netlink/genl/ctrl.h>
 #include <netlink/genl/genl.h>
-
 #include <netlink/attr.h>
-
-#include <libubox/blobmsg_json.h>
+#include "libubox/blobmsg_json.h"
 #include "libubus.h"
 
-#define XDSL_GENL_NAME	"xdsl"
-#define XDSL_GENL_GRP	"notify"
+#define NETLINK_FAMILY_NAME "easysoc"
+#define NETLINK_GROUP_NAME  "notify"
+
+#define MAX_MSG 128
 
 /* nl attributes */
 enum {
@@ -44,8 +43,6 @@ enum {
 	XDSL_NL_MSG,
 	__XDSL_NL_MAX,
 };
-#define XDSL_NL_MAX (__XDSL_NL_MAX - 1)
-#define MAX_MSG 128
 
 static struct nla_policy nl_notify_policy[__XDSL_NL_MAX] = {
 	[XDSL_NL_MSG] = { .type = NLA_STRING },
@@ -115,12 +112,8 @@ int dslmngr_nl_msgs_handler(struct ubus_context *ctx)
 	}
 
 	if ((grp = genl_ctrl_resolve_grp(sock,
-					XDSL_GENL_NAME,
-					XDSL_GENL_GRP)) < 0) {
-		/* fprintf(stderr, "Error: %s (%s grp %s)\n",
-				nl_geterror(grp),
-				XDSL_GENL_NAME,
-				XDSL_GENL_GRP); */
+					NETLINK_FAMILY_NAME,
+					NETLINK_GROUP_NAME)) < 0) {
 		return -1;
 	}
 
@@ -131,8 +124,8 @@ int dslmngr_nl_msgs_handler(struct ubus_context *ctx)
 		if (err < 0) {
 			fprintf(stderr, "Error: %s (%s grp %s)\n",
 					nl_geterror(err),
-					XDSL_GENL_NAME,
-					XDSL_GENL_GRP);
+					NETLINK_FAMILY_NAME,
+					NETLINK_GROUP_NAME);
 		}
 	}
 
diff --git a/libdsl/Makefile b/libdsl/Makefile
index 8921e20043c253a1ec8728bd601eb952ff41e57a..96daaea0cb229fe2a43137f72742b3cd68c86ef6 100644
--- a/libdsl/Makefile
+++ b/libdsl/Makefile
@@ -1,10 +1,11 @@
 LIBDSL = libdsl.so
-OBJS = dsl.o
 
-ifneq ($(INTELCPE),)
-  OBJS += intel.o
-  LIBDSL_CFLAGS += -DINCLUDE_DSL_CPE_API_VRX
+if ($(PLATFORM),INTEL)
+SRCS := $(shell ls intel/*.c)
+else
+$(error Unknown PLATFORM: $(PLATFORM))
 endif
+OBJS := $(SRCS:.c=.o)
 
 all: $(LIBDSL)
 
@@ -16,3 +17,12 @@ libdsl.so: $(OBJS)
 
 clean:
 	rm -f *.o $(LIBDSL)
+
+export SRCS OBJS CFLAGS LOCAL_CFLAGS
+debug:
+	@echo "PLATFORM = $$PLATFORM"
+	@echo "SRCS = $$SRCS"
+	@echo "OBJS = $$OBJS"
+	@echo "CFLAGS = $$CFLAGS"
+
+.PHONY: all clean debug
diff --git a/libdsl/dsl.c b/libdsl/dsl.c
deleted file mode 100644
index 89c15e180ad31d0dcd90ca6fd62ea75e2033100e..0000000000000000000000000000000000000000
--- a/libdsl/dsl.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * dsl.c - glue file for backend implementations
- *
- * Copyright (C) 2018 Inteno Broadband Technology AB. All rights reserved.
- *
- * Author: anjan.chanda@inteno.se
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "xdsl.h"
-
-#ifdef INTELCPE
-extern const struct dsl_ops intel_xdsl_ops;
-#endif
-
-const struct dsl_ops *dsl_backends[] = {
-#ifdef INTELCPE
-	&intel_xdsl_ops,
-#endif
-};
-
-const struct dsl_ops *get_dsl_backend(char *name)
-{
-	int i;
-
-	for (i = 0; i < sizeof(dsl_backends)/sizeof(dsl_backends[0]); i++)
-		if (!strncmp(dsl_backends[i]->name, name,
-					strlen(dsl_backends[i]->name)))
-			return dsl_backends[i];
-
-	return NULL;
-}
-
-int dsl_start(char *name, struct dsl_config *cfg)
-{
-	const struct dsl_ops *dsl = get_dsl_backend(name);
-
-	if (dsl && dsl->start)
-		return dsl->start(name, cfg);
-
-	return -1;
-}
-
-int dsl_stop(char *name)
-{
-	const struct dsl_ops *dsl = get_dsl_backend(name);
-
-	if (dsl && dsl->stop)
-		return dsl->stop(name);
-
-	return -1;
-}
-
-int dsl_get_max_bitrate(char *name, dsl_long_t *max_rate_kbps)
-{
-	const struct dsl_ops *dsl = get_dsl_backend(name);
-
-	if (dsl && dsl->get_max_bitrate)
-		return dsl->get_max_bitrate(name, max_rate_kbps);
-
-	return -1;
-}
-
-int dsl_get_bitrate(char *name, dsl_long_t *rate_kbps)
-{
-	const struct dsl_ops *dsl = get_dsl_backend(name);
-
-	if (dsl && dsl->get_bitrate)
-		return dsl->get_bitrate(name, rate_kbps);
-
-	return -1;
-}
-
-int dsl_get_status(char *name, struct dsl_info *info)
-{
-	const struct dsl_ops *dsl = get_dsl_backend(name);
-
-	if (dsl && dsl->get_status)
-		return dsl->get_status(name, info);
-
-	return -1;
-}
-
-int dsl_get_stats(char *name, enum dsl_stattype type,
-				struct dsl_perfcounters *c)
-{
-	const struct dsl_ops *dsl = get_dsl_backend(name);
-
-	if (dsl && dsl->get_stats)
-		return dsl->get_stats(name, type, c);
-
-	return -1;
-}
diff --git a/libdsl/intel/intel_dsl_api.c b/libdsl/intel/intel_dsl_api.c
new file mode 100644
index 0000000000000000000000000000000000000000..85cedff44c6ce020ece72e787a1fc0b8a2d45011
--- /dev/null
+++ b/libdsl/intel/intel_dsl_api.c
@@ -0,0 +1,600 @@
+/*
+ * Copyright (C) 2019 iopsys Software Solutions AB. All rights reserved.
+ *
+ * Author: anjan.chanda@iopsys.eu
+ *         yalu.zhang@iopsys.eu
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <net/if.h>
+#include <stdbool.h>
+#include <syslog.h>
+
+#define INCLUDE_DSL_CPE_API_VRX // This is needed by drv_dsl_cpe_api.h
+#include "drv_dsl_cpe_api/drv_dsl_cpe_api_ioctl.h"
+#include "drv_dsl_cpe_api/drv_dsl_cpe_api.h"
+#include "dsl-fapi/dsl_fapi.h"
+
+#include "xdsl.h"
+#include "utils.h"
+
+/**
+ * Mappings among string values and enum ones
+ */
+struct str_enum_map {
+	char *val_str;
+	int val_enum;
+};
+
+const struct dsl_ops xdsl_ops = {
+	.get_line_info = dsl_get_line_info,
+	.get_line_stats = dsl_get_line_stats,
+	.get_line_stats_interval = dsl_get_line_stats_interval,
+	.get_channel_info = dsl_get_channel_info,
+	.get_channel_stats = dsl_get_channel_stats,
+	.get_channel_stats_interval = dsl_get_channel_stats_interval
+};
+
+// TODO: this needs to be updated when supporting DSL bonding
+static int max_line_num = 1;
+static int max_chan_num = 1;
+
+int dsl_get_line_number(void)
+{
+	return max_line_num;
+}
+
+int dsl_get_channel_number(void)
+{
+	return max_chan_num;
+}
+
+/**
+	This function converts a string value to the corresponding enum value.
+
+	\param mappings
+		The mapping arrays whose element contains a string value and an enum one.
+		This parameter must end with { NULL, -1 }.
+
+	\param str_value
+		The string value to be searched.
+
+	\return
+		Returns 0 on success. Otherwise a negative value is returned.
+*/
+static int dsl_get_enum_value(const struct str_enum_map *mappings, const char *str_value)
+{
+	const struct str_enum_map *element;
+
+	for (element = mappings; element->val_str != NULL; element++) {
+		if (strcasecmp(element->val_str, str_value) == 0)
+			return element->val_enum;
+	}
+
+	return -1;
+}
+
+#define OPEN_DSL_FAPI_CTX(dev_num) do { \
+				if (dev_num < 0 || dev_num >= max_line_num) \
+					return -1; \
+				fapi_ctx = fapi_dsl_open(0); \
+				if (!fapi_ctx) { \
+					LIBDSL_LOG(LOG_ERR, "fapi_dsl_open() failed\n"); \
+					return -1; \
+				} \
+			} while (0)
+
+static const struct str_enum_map if_status[] = {
+	{ "Up", IF_UP },
+	{ "Down", IF_DOWN },
+	{ "Unknown", IF_UNKNOWN },
+	{ "Dormant", IF_DORMANT },
+	{ "NotPresent", IF_NOTPRESENT },
+	{ "LowerLayerDown", IF_LLDOWN },
+	{ "Error", IF_ERROR },
+	{ NULL, -1 }
+};
+
+static enum dsl_if_status ifstatus_str2enum(const char *status_str)
+{
+	int status = dsl_get_enum_value(if_status, status_str);
+
+	if (status >= 0)
+		return (enum dsl_if_status)status;
+
+	return IF_ERROR;
+}
+
+static const struct str_enum_map link_status[] = {
+	{ "Up", LINK_UP },
+	{ "Initializing", LINK_INITIALIZING },
+	{ "EstablishingLink", LINK_ESTABLISHING },
+	{ "NoSignal", LINK_NOSIGNAL },
+	{ "Disabled", LINK_DISABLED },
+	{ "Error", LINK_ERROR },
+	{ NULL, -1 }
+};
+
+static enum dsl_link_status linkstatus_str2enum(const char *status_str)
+{
+	int status = dsl_get_enum_value(link_status, status_str);
+
+	if (status >= 0)
+		return (enum dsl_link_status)status;
+
+	return LINK_ERROR;
+}
+
+static const struct str_enum_map profiles[] = {
+	{ "8a", VDSL2_8a },
+	{ "8b", VDSL2_8b },
+	{ "8c", VDSL2_8c },
+	{ "8d", VDSL2_8d },
+	{ "12a", VDSL2_12a },
+	{ "12b", VDSL2_12b },
+	{ "17a", VDSL2_17a },
+	{ "30a", VDSL2_30a },
+	{ "35b", VDSL2_35b },
+	{ NULL, -1 }
+};
+
+static enum dsl_profile profile_str2enum(const char *prof_str)
+{
+	int profile = dsl_get_enum_value(profiles, prof_str);
+
+	if (profile >= 0)
+		return (enum dsl_profile)profile;
+
+	return (enum dsl_profile)0;
+}
+
+static const struct str_enum_map power_states[] = {
+	{ "L0", DSL_L0},
+	{ "L1", DSL_L1},
+	{ "L2", DSL_L2},
+	{ "L3", DSL_L3},
+	{ "L4", DSL_L4},
+	{ NULL, -1 }
+};
+
+static enum dsl_power_state powerstate_str2enum(const char *power_state)
+{
+	int state = dsl_get_enum_value(power_states, power_state);
+
+	if (state >= 0)
+		return (enum dsl_power_state)state;
+
+	return (enum dsl_power_state)0;
+}
+
+int dsl_get_line_info(int line_num, struct dsl_line *line)
+{
+	int retval = 0;
+	struct fapi_dsl_ctx *fapi_ctx;
+	struct dsl_fapi_line_obj obj;
+	char *token, *saveptr;
+	int num, i;
+
+	// Open the DSL FAPI context
+	OPEN_DSL_FAPI_CTX(line_num);
+
+	// Get the data
+	memset(&obj, 0, sizeof(obj));
+	if (fapi_dsl_line_get(fapi_ctx, &obj) != FAPI_DSL_STATUS_SUCCESS) {
+		LIBDSL_LOG(LOG_ERR, "fapi_dsl_line_get() failed\n");
+		retval = -1;
+		goto __ret;
+	}
+
+	// Initialize the output buffer
+	memset(line, 0, sizeof(*line));
+
+	/**
+	 *  Convert the values
+	 */
+	line->status = ifstatus_str2enum(obj.status);
+	line->upstream = obj.upstream;
+	strncpy(line->firmware_version, obj.firmware_version, sizeof(line->firmware_version) - 1);
+	line->link_status = linkstatus_str2enum(obj.link_status);
+
+	// Supported standards and currently used standard
+	line->standard_supported.use_xtse = true;
+	memcpy(line->standard_supported.xtse, obj.xtse, sizeof(line->standard_supported.xtse));
+	line->standard_used.use_xtse = true;
+	memcpy(line->standard_used.xtse, obj.xtse_used, sizeof(line->standard_used.xtse));
+
+	// Line encoding, it is always DMT for Intel
+	line->line_encoding = LE_DMT;
+
+	// Allowed profiles and the currently used profile
+	token = strtok_r(obj.allowed_profiles, ",", &saveptr);
+	while (token != NULL) {
+		line->allowed_profiles |= profile_str2enum(token);
+		// Move to the next token
+		token = strtok_r(NULL, ",", &saveptr);
+	}
+	line->current_profile = profile_str2enum(obj.current_profile);
+
+	line->power_management_state = powerstate_str2enum(obj.power_management_state);
+	line->success_failure_cause = obj.success_failure_cause;
+
+	// upbokler_pb
+	token = strtok_r(obj.upbokler_pb, ",", &saveptr);
+	for (num = sizeof (line->upbokler_pb.array) / sizeof (line->upbokler_pb.array[0]);
+		 line->upbokler_pb.count < num && token != NULL;
+		 line->upbokler_pb.count++, token = strtok_r(NULL, ",", &saveptr)) {
+		line->upbokler_pb.array[line->upbokler_pb.count] = atoi(token);
+	}
+
+	// rxthrsh_ds
+	token = strtok_r(obj.rxthrsh_ds, ",", &saveptr);
+	for (num = sizeof (line->rxthrsh_ds.array) / sizeof (line->rxthrsh_ds.array[0]);
+		 line->rxthrsh_ds.count < num && token != NULL;
+		 line->rxthrsh_ds.count++, token = strtok_r(NULL, ",", &saveptr)) {
+		line->rxthrsh_ds.array[line->rxthrsh_ds.count] = atoi(token);
+	}
+
+	line->act_ra_mode.us = obj.act_ra_mode_us;
+	line->act_ra_mode.ds = obj.act_ra_mode_ds;
+
+	line->snr_mroc_us = obj.snr_mroc_us;
+
+	line->last_state_transmitted.us = obj.last_state_transmitted_upstream;
+	line->last_state_transmitted.ds = obj.last_state_transmitted_downstream;
+
+	line->us0_mask = obj.us0_mask;
+
+	line->trellis.us = obj.trellis_us;
+	line->trellis.ds = obj.trellis_ds;
+
+	line->act_snr_mode.us = obj.act_snr_mode_us;
+	line->act_snr_mode.ds = obj.act_snr_mode_ds;
+
+	line->line_number = obj.line_number;
+
+	/* Note that there is a mistake in DSL FAPI which uses bps instead of kbps */
+	line->max_bit_rate.us = obj.upstream_max_bit_rate / 1000;
+	line->max_bit_rate.ds = obj.downstream_max_bit_rate / 1000;
+
+	line->noise_margin.us = obj.upstream_noise_margin;
+	line->noise_margin.ds = obj.downstream_noise_margin;
+
+	// snr_mpb_us
+	token = strtok_r(obj.snr_mpb_us, ",", &saveptr);
+	for (num = sizeof (line->snr_mpb_us.array) / sizeof (line->snr_mpb_us.array[0]);
+		 line->snr_mpb_us.count < num && token != NULL;
+		 line->snr_mpb_us.count++, token = strtok_r(NULL, ",", &saveptr)) {
+		line->snr_mpb_us.array[line->snr_mpb_us.count] = atoi(token);
+	}
+
+	// snr_mpb_ds
+	token = strtok_r(obj.snr_mpb_ds, ",", &saveptr);
+	for (num = sizeof (line->snr_mpb_ds.array) / sizeof (line->snr_mpb_ds.array[0]);
+		 line->snr_mpb_ds.count < num && token != NULL;
+		 line->snr_mpb_ds.count++, token = strtok_r(NULL, ",", &saveptr)) {
+		line->snr_mpb_ds.array[line->snr_mpb_ds.count] = atoi(token);
+	}
+
+	line->attenuation.us = obj.upstream_attenuation;
+	line->attenuation.ds = obj.downstream_attenuation;
+
+	line->power.us = obj.upstream_power;
+	line->power.ds = obj.downstream_power;
+
+	// XTU-R vendor ID
+	num = (sizeof(line->xtur_vendor) / 2) < sizeof(obj.xtur_vendor) ?
+			(sizeof(line->xtur_vendor) / 2) : sizeof(obj.xtur_vendor);
+	for (i = 0; i < num; i++)
+		sprintf(line->xtur_vendor + i * 2, "%02X", obj.xtur_vendor[i]);
+
+	// XTU-R country
+	num = (sizeof(line->xtur_country) / 2) < sizeof(obj.xtur_country) ?
+			(sizeof(line->xtur_country) / 2) : sizeof(obj.xtur_country);
+	for (i = 0; i < num; i++)
+		sprintf(line->xtur_country + i * 2, "%02X", obj.xtur_country[i]);
+
+	line->xtur_ansi_std = obj.xtur_ansi_std;
+	line->xtur_ansi_rev = obj.xtur_ansi_rev;
+
+	// XTU-C vendor ID
+	num = (sizeof(line->xtuc_vendor) / 2) < (sizeof(obj.xtuc_vendor) / sizeof(obj.xtuc_vendor[0]))?
+			(sizeof(line->xtuc_vendor) / 2) : (sizeof(obj.xtuc_vendor) / sizeof(obj.xtuc_vendor[0]));
+	for (i = 0; i < num; i++)
+		sprintf(line->xtuc_vendor + i * 2, "%02X", obj.xtuc_vendor[i]);
+
+	// XTU-C country
+	num = (sizeof(line->xtuc_country) / 2) < sizeof(obj.xtuc_country) ?
+			(sizeof(line->xtuc_country) / 2) : (sizeof(obj.xtuc_country) / sizeof(obj.xtuc_country[0]));
+	for (i = 0; i < num; i++)
+		sprintf(line->xtuc_country + i * 2, "%02X", obj.xtuc_country[i]);
+
+	line->xtuc_ansi_std = obj.xtuc_ansi_std;
+	line->xtuc_ansi_rev = obj.xtuc_ansi_rev;
+
+__ret:
+	if (fapi_ctx)
+		fapi_dsl_close(fapi_ctx);
+	return retval;
+}
+
+int dsl_get_line_stats(int line_num, struct dsl_line_channel_stats *stats)
+{
+	int retval = 0;
+	struct fapi_dsl_ctx *fapi_ctx;
+	struct dsl_fapi_line_stats_obj obj;
+
+	// Open the DSL FAPI context
+	OPEN_DSL_FAPI_CTX(line_num);
+
+	// Get the data
+	memset(&obj, 0, sizeof(obj));
+	if (fapi_dsl_line_stats_get(fapi_ctx, &obj) != FAPI_DSL_STATUS_SUCCESS) {
+		LIBDSL_LOG(LOG_ERR, "fapi_dsl_line_stats_get() failed\n");
+		retval = -1;
+		goto __ret;
+	}
+
+	// Initialize the output buffer
+	memset(stats, 0, sizeof(*stats));
+
+	// Fill in the output parameter
+	stats->total_start = obj.total_start;
+	stats->showtime_start = obj.showtime_start;
+	stats->last_showtime_start = obj.last_showtime_start;
+	stats->current_day_start = obj.current_day_start;
+	stats->quarter_hour_start = obj.quarter_hour_start;
+
+__ret:
+	if (fapi_ctx)
+		fapi_dsl_close(fapi_ctx);
+	return retval;
+}
+
+int dsl_get_line_stats_interval(int line_num, enum dsl_stats_type type, struct dsl_line_stats_interval *stats)
+{
+	int retval = 0;
+	struct fapi_dsl_ctx *fapi_ctx;
+	struct dsl_fapi_line_stats_interval_obj obj;
+	enum fapi_dsl_status status;
+
+	// Open the DSL FAPI context
+	OPEN_DSL_FAPI_CTX(line_num);
+
+	// Get the data
+	memset(&obj, 0, sizeof(obj));
+	switch (type) {
+	case DSL_STATS_TOTAL:
+		status = fapi_dsl_line_stats_total_get(fapi_ctx, &obj);
+		break;
+	case DSL_STATS_SHOWTIME:
+		status = fapi_dsl_line_stats_showtime_get(fapi_ctx, &obj);
+		break;
+	case DSL_STATS_LASTSHOWTIME:
+		status = fapi_dsl_line_stats_last_showtime_get(fapi_ctx, &obj);
+		break;
+	case DSL_STATS_CURRENTDAY:
+		status = fapi_dsl_line_stats_current_day_get(fapi_ctx, &obj);
+		break;
+	case DSL_STATS_QUARTERHOUR:
+		status = fapi_dsl_line_stats_quarter_hour_get(fapi_ctx, &obj);
+		break;
+	default:
+		LIBDSL_LOG(LOG_ERR, "Unknown interval type for DSL line statistics, %d\n", type);
+		retval = -1;
+		goto __ret;
+	}
+
+	if (status != FAPI_DSL_STATUS_SUCCESS) {
+		LIBDSL_LOG(LOG_ERR,
+			"Failed to call DSL FAPI to retrieve the DSL line statistics interval %d\n", type);
+		retval = -1;
+		goto __ret;
+	}
+
+	// Initialize the output buffer
+	memset(stats, 0, sizeof(*stats));
+
+	// Fill in the output parameter
+	stats->errored_secs = obj.errored_secs;
+	stats->severely_errored_secs = obj.severely_errored_secs;
+
+__ret:
+	if (fapi_ctx)
+		fapi_dsl_close(fapi_ctx);
+	return retval;
+}
+
+static const struct str_enum_map link_encaps[] = {
+	{ "G.992.3_Annex_K_ATM", G_992_3_ANNEK_K_ATM },
+	{ "G.992.3_Annex_K_PTM", G_992_3_ANNEK_K_PTM },
+	{ "G.993.2_Annex_K_ATM", G_993_2_ANNEK_K_ATM },
+	{ "G.993.2_Annex_K_PTM", G_993_2_ANNEK_K_PTM},
+	{ "G.994.1 (Auto)", G_994_1_AUTO },
+	{ NULL, -1 }
+};
+
+static enum dsl_link_encapsulation linkencap_str2enum(const char *link_encap)
+{
+	int encap = dsl_get_enum_value(link_encaps, link_encap);
+
+	if (encap >= 0)
+		return (enum dsl_link_encapsulation)encap;
+
+	return (enum dsl_link_encapsulation)0;
+}
+
+int dsl_get_channel_info(int chan_num, struct dsl_channel *channel)
+{
+	int retval = 0;
+	struct fapi_dsl_ctx *fapi_ctx;
+	struct dsl_fapi_channel_obj obj;
+	char *token, *saveptr;
+
+	// Open the DSL FAPI context
+	OPEN_DSL_FAPI_CTX(chan_num);
+
+	// Get the data
+	memset(&obj, 0, sizeof(obj));
+	if (fapi_dsl_channel_get(fapi_ctx, &obj) != FAPI_DSL_STATUS_SUCCESS) {
+		LIBDSL_LOG(LOG_ERR, "fapi_dsl_channel_get() failed\n");
+		retval = -1;
+		goto __ret;
+	}
+
+	// Initialize the output buffer
+	memset(channel, 0, sizeof(*channel));
+
+	/**
+	 *  Fill in the output parameter
+	 */
+	channel->status = ifstatus_str2enum(obj.status);
+
+	// link_encapsulation_supported and link_encapsulation_used
+	token = strtok_r(obj.link_encapsulation_supported, ",", &saveptr);
+	while (token != NULL) {
+		channel->link_encapsulation_supported |= linkencap_str2enum(token);;
+		// Move to the next token
+		token = strtok_r(NULL, ",", &saveptr);
+	}
+	channel->link_encapsulation_used = linkencap_str2enum(obj.link_encapsulation_used);
+
+	channel->lpath = obj.lpath;
+	channel->intlvdepth = obj.intlvdepth;
+	channel->intlvblock = obj.intlvblock;
+	channel->actual_interleaving_delay = obj.actual_interleaving_delay;
+	channel->actinp = obj.actinp;
+	channel->inpreport = obj.inpreport;
+	channel->nfec = obj.nfec;
+	channel->rfec = obj.rfec;
+	channel->lsymb = obj.lsymb;
+
+	/* Note that there is a mistake in DSL FAPI which uses bps instead of kbps */
+	channel->curr_rate.us = obj.upstream_curr_rate / 1000;
+	channel->curr_rate.ds = obj.downstream_curr_rate / 1000;
+	channel->actndr.us = obj.actndr_us / 1000;
+	channel->actndr.ds = obj.actndr_ds / 1000;
+
+	channel->actinprein.us = obj.actinprein_us;
+	channel->actinprein.ds = obj.actinprein_ds;
+
+__ret:
+	if (fapi_ctx)
+		fapi_dsl_close(fapi_ctx);
+	return retval;
+}
+
+int dsl_get_channel_stats(int chan_num, struct dsl_line_channel_stats *stats)
+{
+	int retval = 0;
+	struct fapi_dsl_ctx *fapi_ctx;
+	struct dsl_fapi_channel_stats_obj obj;
+
+	// Open the DSL FAPI context
+	OPEN_DSL_FAPI_CTX(chan_num);
+
+	// Get the data
+	memset(&obj, 0, sizeof(obj));
+	if (fapi_dsl_channel_stats_get(fapi_ctx, &obj) != FAPI_DSL_STATUS_SUCCESS) {
+		LIBDSL_LOG(LOG_ERR, "fapi_dsl_channel_stats_get() failed\n");
+		retval = -1;
+		goto __ret;
+	}
+
+	// Initialize the output buffer
+	memset(stats, 0, sizeof(*stats));
+
+	// Fill in the output parameter
+	stats->total_start = obj.total_start;
+	stats->showtime_start = obj.showtime_start;
+	stats->last_showtime_start = obj.last_showtime_start;
+	stats->current_day_start = obj.current_day_start;
+	stats->quarter_hour_start = obj.quarter_hour_start;
+
+__ret:
+	if (fapi_ctx)
+		fapi_dsl_close(fapi_ctx);
+	return retval;
+}
+
+int dsl_get_channel_stats_interval(int chan_num, enum dsl_stats_type type, struct dsl_channel_stats_interval *stats)
+{
+	int retval = 0;
+	struct fapi_dsl_ctx *fapi_ctx;
+	struct dsl_fapi_channel_stats_interval_obj obj;
+	enum fapi_dsl_status status;
+
+	// Open the DSL FAPI context
+	OPEN_DSL_FAPI_CTX(chan_num);
+
+	// Get the data
+	memset(&obj, 0, sizeof(obj));
+	switch (type) {
+	case DSL_STATS_TOTAL:
+		status = fapi_dsl_channel_stats_total_get(fapi_ctx, &obj);
+		break;
+	case DSL_STATS_SHOWTIME:
+		status = fapi_dsl_channel_stats_showtime_get(fapi_ctx, &obj);
+		break;
+	case DSL_STATS_LASTSHOWTIME:
+		status = fapi_dsl_channel_stats_last_showtime_get(fapi_ctx, &obj);
+		break;
+	case DSL_STATS_CURRENTDAY:
+		status = fapi_dsl_channel_stats_current_day_get(fapi_ctx, &obj);
+		break;
+	case DSL_STATS_QUARTERHOUR:
+		status = fapi_dsl_channel_stats_quarter_hour_get(fapi_ctx, &obj);
+		break;
+	default:
+		LIBDSL_LOG(LOG_ERR, "Unknown interval type for DSL channel statistics, %d\n", type);
+		retval = -1;
+		goto __ret;
+	}
+
+	if (status != FAPI_DSL_STATUS_SUCCESS) {
+		LIBDSL_LOG(LOG_ERR,
+			"Failed to call DSL FAPI to retrieve the channel statistics interval %d\n", type);
+		retval = -1;
+		goto __ret;
+	}
+
+	// Initialize the output buffer
+	memset(stats, 0, sizeof(*stats));
+
+	// Fill in the output parameter
+	stats->xtur_fec_errors = obj.xtu_rfec_errors;
+	stats->xtuc_fec_errors = obj.xtu_cfec_errors;
+
+	stats->xtur_hec_errors = obj.xtu_rhec_errors;
+	stats->xtuc_hec_errors = obj.xtu_chec_errors;
+
+	stats->xtur_crc_errors = obj.xtu_rcrc_errors;
+	stats->xtuc_crc_errors = obj.xtu_ccrc_errors;
+
+__ret:
+	if (fapi_ctx)
+		fapi_dsl_close(fapi_ctx);
+	return retval;
+}
diff --git a/libdsl/utils.h b/libdsl/utils.h
new file mode 100644
index 0000000000000000000000000000000000000000..05b5de460b6be49732b89b93e270687c0824c5a3
--- /dev/null
+++ b/libdsl/utils.h
@@ -0,0 +1,36 @@
+/*
+ * utils.h - private header file
+ *
+ * Copyright (C) 2019 iopsys Software Solutions AB. All rights reserved.
+ *
+ * Author: yalu.zhang@iopsys.eu
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+#ifndef _UTILS_H
+#define _UTILS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+
+#define LIBDSL_LOG(log_level, format...) fprintf(stderr, ##format)
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _UTILS_H */
diff --git a/libdsl/xdsl.h b/libdsl/xdsl.h
index 7e6fb8f6d0127ef50c7757f1682d79899f3ce141..8fe02cd1dcc6e47a90a8030b8ad1d231d632a626 100644
--- a/libdsl/xdsl.h
+++ b/libdsl/xdsl.h
@@ -1,9 +1,12 @@
 /*
- * xdsl.h - XDSL library header file
+ * xdsl.h - library header file
+ * This file provides definition for the libdsl APIs and related
+ * structures.
  *
- * Copyright (C) 2018 Inteno Broadband Technology AB. All rights reserved.
+ * Copyright (C) 2019 iopsys Software Solutions AB. All rights reserved.
  *
- * Author: anjan.chanda@inteno.se
+ * Author: anjan.chanda@iopsys.eu
+ *         yalu.zhang@iopsys.eu
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -22,271 +25,469 @@
 #ifndef _XDSL_H
 #define _XDSL_H
 
-#include <stdint.h>
-#include <stdbool.h>
-
 #ifdef __cplusplus
 extern "C" {
 #endif
 
-typedef struct dsl_long_data { long us; long ds; } dsl_long_t;
-typedef struct dsl_bool_data { bool us; bool ds; } dsl_bool_t;
+#include <stdint.h>
+#include <stdbool.h>
 
-enum {
-	trellis_off,
-	trellis_on,
-};
+/** Common definitions */
+#define XDSL_MAX_LINES	1
 
-/** enum dsl_modetype - dsl modes */
-enum dsl_modtype {
-	MOD_GDMT,    /* G.992.1 */
-	MOD_T1413,   /* T1.413 */
-	MOD_GLITE,   /* G.992.2 */
-	MOD_ADSL2,   /* G.992.3 */
-	MOD_ADSL2P,  /* G.992.5 */
-	MOD_READSL2, /* G.992.3 Annex L */
-	MOD_VDSL,    /* G.993.1 */
-	MOD_VDSL2,   /* G.993.2 */
-	MOD_VDSL2P,  /* G.993.2 Annex Q */
-	MOD_GFAST,   /* G.9700, G.9701 */
-	MOD_UNDEFINED
-};
+typedef struct { long us; long ds; } dsl_long_t;
+typedef struct { unsigned long us; unsigned long ds; } dsl_ulong_t;
+typedef struct { bool us; bool ds; } dsl_bool_t;
+typedef struct { long array[24]; int count; } dsl_long_sequence_t;
+typedef struct { unsigned long array[24]; int count; } dsl_ulong_sequence_t;
 
-#define is_adsl(m)	(m >= MOD_GDMT && m < MOD_ADSL2)
-#define is_adsl2(m)	(m >= MOD_ADSL2 && m < MOD_VDSL)
-#define is_vdsl2(m)	(m > MOD_VDSL && m <= MOD_VDSL2P)
-#define is_gfast(m)	(m == MOD_GFAST)
-
-/** enum dsl_linestatus - line status */
-enum dsl_linestatus {
-	LINE_UP,
-	LINE_INITING,
-	LINE_ESTABLISHING,
-	LINE_NOSIGNAL,
-	LINE_ERROR,
+/** enum dsl_status - operational status of a line or channel */
+enum dsl_if_status {
+	/* Starts with non-zero in order to distinguish from an uninitialized value which is usually 0 */
+	IF_UP = 1,
+	IF_DOWN,
+	IF_UNKNOWN,
+	IF_DORMANT,
+	IF_NOTPRESENT,
+	IF_LLDOWN,
+	IF_ERROR
 };
 
-/** enum dsl_linestate - physical line state */
-enum dsl_linestate {
-	LINE_DOWN,        /* no sync */
-	LINE_HANDSHAKING, /* hello exchange phase */
-	LINE_TRAINING,    /* establishing sync */
-	LINE_SHOWTIME,    /* successfully synced */
-	LINE_UNKNOWN,     /* unknown state */
+/** enum dsl_link_status - link status */
+enum dsl_link_status {
+	/* Starts with non-zero in order to distinguish from an uninitialized value which is usually 0 */
+	LINK_UP = 1,
+	LINK_INITIALIZING,
+	LINK_ESTABLISHING,
+	LINK_NOSIGNAL,
+	LINK_DISABLED,
+	LINK_ERROR
 };
 
-/** enum dsl_vdsl2_profile - vdsl2 profiles */
-enum dsl_vdsl2_profile {
-	VDSL2_8a    = 1<<0,
-	VDSL2_8b    = 1<<1,
-	VDSL2_8c    = 1<<2,
-	VDSL2_8d    = 1<<3,
-	VDSL2_12a   = 1<<4,
-	VDSL2_12b   = 1<<5,
-	VDSL2_17a   = 1<<6,
-	VDSL2_30a   = 1<<7,
-	VDSL2_35b   = 1<<8,
+/** enum dsl_modtype - DSL modes */
+enum dsl_modtype {
+	MOD_G_922_1_ANNEX_A = 1,
+	MOD_G_922_1_ANNEX_B = 1 << 1,
+	MOD_G_922_1_ANNEX_C = 1 << 2,
+	MOD_T1_413          = 1 << 3,
+	MOD_T1_413i2        = 1 << 4,
+	MOD_ETSI_101_388    = 1 << 5,
+	MOD_G_992_2         = 1 << 6,
+	MOD_G_992_3_Annex_A = 1 << 7,
+	MOD_G_992_3_Annex_B = 1 << 8,
+	MOD_G_992_3_Annex_C = 1 << 9,
+	MOD_G_992_3_Annex_I = 1 << 10,
+	MOD_G_992_3_Annex_J = 1 << 11,
+	MOD_G_992_3_Annex_L = 1 << 12,
+	MOD_G_992_3_Annex_M = 1 << 13,
+	MOD_G_992_4         = 1 << 14,
+	MOD_G_992_5_Annex_A = 1 << 15,
+	MOD_G_992_5_Annex_B = 1 << 16,
+	MOD_G_992_5_Annex_C = 1 << 17,
+	MOD_G_992_5_Annex_I = 1 << 18,
+	MOD_G_992_5_Annex_J = 1 << 19,
+	MOD_G_992_5_Annex_M = 1 << 20,
+	MOD_G_993_1         = 1 << 21,
+	MOD_G_993_1_Annex_A = 1 << 22,
+	MOD_G_993_2_Annex_A = 1 << 23,
+	MOD_G_993_2_Annex_B = 1 << 24,
+	MOD_G_993_2_Annex_C = 1 << 25
 };
 
-/** struct dsl_caps - dsl capabiltities */
-struct dsl_caps {
-	uint32_t stds;            /** bitmap of STD_* */
-	uint32_t modes;           /** bitmap of MOD_* */
-	uint32_t profiles;        /** bitmap of PROFILE_ * */
-	dsl_long_t rate_kbps_max; /** max bitrate in Kbps */
-};
+/** enum dsl_xtse_bit - XTSE bit definition. Refer to dsl_line.xtse for details */
+enum dsl_xtse_bit {
+	/* Octet 1 - ADSL, i.e. g.dmt */
+	T1_413							= 1,
+	ETSI_101_388					= 2,
+	G_992_1_POTS_NON_OVERLAPPED		= 3, /* Annex A */
+	G_992_1_POTS_OVERLAPPED			= 4, /* Annex A */
+	G_992_1_ISDN_NON_OVERLAPPED		= 5, /* Annex B */
+	G_992_1_ISDN_OVERLAPPED			= 6, /* Annex B */
+	G_992_1_TCM_ISDN_NON_OVERLAPPED	= 7, /* Annex C */
+	G_992_1_TCM_ISDN_OVERLAPPED		= 8, /* Annex C */
 
-/** enum dsl_stattype - type of collected statistics */
-enum dsl_stattype {
-	STAT_CURR_LINK,     /** since latest linkup */
-	STAT_CURR_15MINS,   /** latest 15 mins stats */
-	STAT_PREV_15MINS,   /** previous 15 mins stats */
-	STAT_CURR_24HRS,    /** current day's stats */
-	STAT_PREV_24HRS,    /** previous day's stats */
-	STAT_TOTAL,         /** total stats since power up */
-};
+	/* Octet 2 - Splitter-less ADSL, i.e. g.lite */
+	G_992_2_POTS_NON_OVERLAPPED		= 9, /* Annex A */
+	G_992_2_POTS_OVERLAPPED			= 10, /* Annex B */
+	G_992_2_TCM_ISDN_NON_OVERLAPPED	= 11, /* Annex C */
+	G_992_2_TCM_ISDN_OVERLAPPED		= 12, /* Annex C */
+	/* Bits 13 - 16 are reserved */
 
-/** struct dsl_counters - dsl statistics counters */
-struct dsl_counters {
-	unsigned long tx_bytes;
-	unsigned long rx_bytes;
-	unsigned long tx_packets;
-	unsigned long rx_packets;
+	/* Octet 3 - ADSL2 */
+	/* Bits 17 - 18 are reserved */
+	G_992_3_POTS_NON_OVERLAPPED		= 19, /* Annex A */
+	G_992_3_POTS_OVERLAPPED			= 20, /* Annex A */
+	G_992_3_ISDN_NON_OVERLAPPED		= 21, /* Annex B */
+	G_992_3_ISDN_OVERLAPPED			= 22, /* Annex B */
+	G_992_3_TCM_ISDN_NON_OVERLAPPED	= 23, /* Annex C */
+	G_992_3_TCM_ISDN_OVERLAPPED		= 24, /* Annex C */
 
-	/** packets dropped due to packets */
-	unsigned long tx_error_packets;
-	unsigned long rx_error_packets;
+	/* Octet 4 - Splitter-less ADSL2 and ADSL2 */
+	G_992_4_POTS_NON_OVERLAPPED		= 25, /* Annex A */
+	G_992_4_POTS_OVERLAPPED			= 26, /* Annex A */
+	/* Bits 27 - 28 are reserved */
+	G_992_3_ANNEX_I_NON_OVERLAPPED	= 29, /* All digital mode */
+	G_992_3_ANNEX_I_OVERLAPPED		= 30, /* All digital mode */
+	G_992_3_ANNEX_J_NON_OVERLAPPED	= 31, /* All digital mode */
+	G_992_3_ANNEX_J_OVERLAPPED		= 32, /* All digital mode */
 
-	/** no-error packets dropped due to other factors */
-	unsigned long tx_dropped_packets;
-	unsigned long rx_dropped_pcakets;
-};
 
-/* Traffic type */
-enum dsl_traffictype {
-	TC_PTM,
-	TC_ATM,
-	TC_RAW,
-	TC_NOT_CONNECTED,
+	/* Octet 5 - Splitter-less ADSL2 and ADSL2 */
+	G_992_4_ANNEX_I_NON_OVERLAPPED	= 33, /* All digital mode */
+	G_992_4_ANNEX_I_OVERLAPPED		= 34, /* All digital mode */
+	G_992_3_POTS_MODE_1				= 35, /* Annex L, non-overlapped, wide upstream */
+	G_992_3_POTS_MODE_2				= 36, /* Annex L, non-overlapped, narrow upstream */
+	G_992_3_POTS_MODE_3				= 37, /* Annex L, overlapped, wide upstream */
+	G_992_3_POTS_MODE_4				= 38, /* Annex L, overlapped, narrow upstream */
+	G_992_3_EXT_POTS_NON_OVERLAPPED	= 39, /* Annex M */
+	G_992_3_EXT_POTS_OVERLAPPED		= 40, /* Annex M */
+
+	/* Octet 6 - ADSL2+ */
+	G_992_5_POTS_NON_OVERLAPPED		= 41, /* Annex A */
+	G_992_5_POTS_OVERLAPPED			= 42, /* Annex A */
+	G_992_5_ISDN_NON_OVERLAPPED		= 43, /* Annex B */
+	G_992_5_ISDN_OVERLAPPED			= 44, /* Annex B */
+	G_992_5_TCM_ISDN_NON_OVERLAPPED	= 45, /* Annex C */
+	G_992_5_TCM_ISDN_OVERLAPPED		= 46, /* Annex C */
+	G_992_5_ANNEX_I_NON_OVERLAPPED	= 47, /* All digital mode */
+	G_992_5_ANNEX_I_OVERLAPPED		= 48, /* All digital mode */
+
+	/* Octet 7 - ADSL2+ */
+	G_992_5_ANNEX_J_NON_OVERLAPPED	= 49, /* All digital mode */
+	G_992_5_ANNEX_J_OVERLAPPED		= 50, /* All digital mode */
+	G_992_5_EXT_POTS_NON_OVERLAPPED	= 51, /* Annex M */
+	G_992_5_EXT_POTS_OVERLAPPED		= 52, /* Annex M */
+	/* Bits 53 - 56 are reserved */
+
+	/* Octet 8 - VDSL2 */
+	G_993_2_NORTH_AMERICA			= 57, /* Annex A */
+	G_993_2_EUROPE					= 58, /* Annex B */
+	G_993_2_JAPAN					= 59, /* Annex C */
+	/* Bits 60 - 64 are reserved */
 };
 
-/**enum dsl_powerstate - power states */
-enum dsl_powerstate {
-	L0,
-	L1,
-	L2,
-	L3,
+/**
+ * This macro determines whether a XTSE bit is set
+ *
+ * @param[in] xtse unsigned char[8] as defined in dsl_line.xtse
+ * @param[in] bit Bit number as defined in G.997.1 clause 7.3.1.1.1 XTU transmission system enabling (XTSE)
+ *
+ * @return A non-zero value is the bit is set. Otherwise 0
+ */
+#define XTSE_BIT_GET(xtse, bit) (xtse[((bit) - 1) / 8] & (1 << (((bit) - 1) % 8)))
+
+/** struct dsl_standard - DSL standards */
+struct dsl_standard {
+	bool use_xtse; /* true if xtse is used. false if mode is used */
+	union {
+		/** Bit maps defined in dsl_modtype */
+		unsigned long mode;
+		/** Transmission system types to be allowed by the xTU on this line instance */
+		unsigned char xtse[8];
+	};
 };
 
-/** struct dsl_line_params - dsl line parameters */
-struct dsl_line_params {
-	dsl_long_t msgc;    /** # of bytes in OH channel message */
-	dsl_long_t k;       /** # of bytes in DMT frame */
-	dsl_long_t b;       /** # of bytes in Mux data frame */
-	dsl_long_t t;       /** # of Mux data frames in OH subframe */
-	dsl_long_t r;       /** # of check bytes in FEC data frames (RFEC) */
-	dsl_long_t s;       /** ratio of FEC over PMD data frame */
-	dsl_long_t l;       /** # of bits in PMD data frame (LSYMB) */
-	dsl_long_t d;       /** interleave depth (INTLVDEPTH)*/
-	dsl_long_t m;       /** # of Mux frames per FEC data frame */
-	dsl_long_t i;
-	dsl_long_t n;       /** length of code word (NFEC) */
-	dsl_long_t q;       /** # of RS code words per DTU */
-	dsl_long_t v;       /** # of padding octets per DTU */
-	dsl_long_t delay;   /** delay in msecs due to interleaving */
-	dsl_long_t inp;     /** actual Impulse Noise Protection (DMT symbol) */
-	dsl_long_t inprein; /** actual INP against REIN noise (ACTINPREIN) */
+/** enum dsl_line_encoding - Line encoding */
+enum dsl_line_encoding {
+	/* Starts with non-zero in order to distinguish from an uninitialized value which is usually 0 */
+	LE_DMT = 1,
+	LE_CAP,
+	LE_2B1Q,
+	LE_43BT,
+	LE_PAM,
+	LE_QAM
 };
 
-/** struct dsl_line_errors - dsl line errors */
-struct dsl_line_errors {
-	dsl_long_t sferr;
-	dsl_long_t rs_corr;
-	dsl_long_t rs_uncorr;
-	dsl_long_t hec;
-	dsl_long_t ocd;
-	dsl_long_t lcd;
-	dsl_long_t fec;
-	dsl_long_t crc;
-	dsl_long_t ohf;
-	dsl_long_t lof;
-	dsl_long_t lol;
-	dsl_long_t lom;
-	dsl_long_t los;
-	dsl_long_t lop;
+/** enum dsl_profile - DSL profiles */
+enum dsl_profile {
+	VDSL2_8a	= 1,
+	VDSL2_8b	= 1 << 1,
+	VDSL2_8c	= 1 << 2,
+	VDSL2_8d	= 1 << 3,
+	VDSL2_12a	= 1 << 4,
+	VDSL2_12b	= 1 << 5,
+	VDSL2_17a	= 1 << 6,
+	VDSL2_30a	= 1 << 7,
+	VDSL2_35b	= 1 << 8,
 };
 
-/** struct dsl_perfcounters - dsl performance counters */
-struct dsl_perfcounters {
-	enum dsl_stattype type; /** stats type */
-	unsigned long secs;     /** stats collected duration (in seconds) */
-	dsl_long_t es;          /** errored seconds */
-	dsl_long_t ses;         /** severly errored seconds */
-	dsl_long_t uas;         /** unavailable seconds */
-	dsl_long_t as;          /** available seconds */
+/** enum dsl_power_state - power states */
+enum dsl_power_state {
+	/* Starts with non-zero in order to distinguish from an uninitialized value which is usually 0 */
+	DSL_L0 = 1,
+	DSL_L1,
+	DSL_L2,
+	DSL_L3,
+	DSL_L4
 };
 
-/** struct dsl_line_counters - stats counters */
-struct dsl_line_counters {
-	dsl_long_t sf;         /** super frames */
-	dsl_long_t sferr;      /** super frame errors TODO: move */
-	dsl_long_t rs;         /** total RS codewords tx/rx */
-	dsl_long_t rscorr;     /** RS correctable errors TODO: move */
-	dsl_long_t rsuncorr;   /** RS uncorrectable errors TODO: move */
+/** struct dsl_line - DSL line parameters */
+struct dsl_line {
+	/** The current operational state of the DSL line */
+	enum dsl_if_status status;
+	/** Whether the interface points towards the Internet (true) or towards End Devices (false) */
+	bool upstream;
+	/** The version of the modem firmware currently installed for this interface */
+	char firmware_version[64];
+	/** Status of the DSL physical link */
+	enum dsl_link_status link_status;
+	/** The transmission system types or standards supported */
+	struct dsl_standard standard_supported;
+	/** The currently used transmission system type, or the standard on this line instance */
+	struct dsl_standard standard_used;
+	/** The line encoding method used in establishing the Layer 1 DSL connection between the CPE and the DSLAM */
+	enum dsl_line_encoding line_encoding;
+	/** VDSL2 profiles are allowed on the line. The bitmap is defined in enum dsl_profile */
+	unsigned long allowed_profiles;
+	/** VDSL2 profile is currently in use on the line */
+	enum dsl_profile current_profile;
+	/** The power management state of the line */
+	enum dsl_power_state power_management_state;
+	/** The success failure cause of the initialization */
+	unsigned int success_failure_cause;
+	/** VTU-R estimated upstream power back-off electrical length per band */
+	dsl_ulong_sequence_t upbokler_pb;
+	/** Downstream receiver signal level threshold */
+	dsl_ulong_sequence_t rxthrsh_ds;
+	/** The actual active rate adaptation mode in both directions */
+	dsl_ulong_t act_ra_mode;
+	/** The actual signal-to-noise margin of the robust overhead channel (ROC) */
+	unsigned int snr_mroc_us;
+	/** The last successful transmitted initialization state in both directions */
+	dsl_ulong_t last_state_transmitted;
+	/** The allowed VDSL2 US0 PSD masks for Annex A operation */
+	unsigned int us0_mask;
+	/** Whether trellis coding is enabled in the downstream and upstream directions */
+	dsl_long_t trellis;
+	/** Whether the OPTIONAL virtual noise mechanism is in use in both directions */
+	dsl_ulong_t act_snr_mode;
+	/** The line pair that the modem is using to connection */
+	int line_number;
+	/** The current maximum attainable data rate in both directions (expressed in Kbps) */
+	dsl_ulong_t max_bit_rate;
+	/** The current signal-to-noise ratio margin (expressed in 0.1dB) in both directions */
+	dsl_long_t noise_margin;
+	/** The current signal-to-noise ratio margin of each upstream band */
+	dsl_long_sequence_t snr_mpb_us;
+	/** The current signal-to-noise ratio margin of each downstream band */
+	dsl_long_sequence_t snr_mpb_ds;
+	/** The current upstream and downstream signal loss (expressed in 0.1dB). */
+	dsl_long_t attenuation;
+	/** The current output and received power at the CPE's DSL line (expressed in 0.1dBmV) */
+	dsl_long_t power;
+	/** xTU-R vendor identifier as defined in G.994.1 and T1.413 in hex binary format */
+	char xtur_vendor[16 + 1]; // Adding '\0' in the end for convenient manipulation
+	/** T.35 country code of the xTU-R vendor as defined in G.994.1 in hex binary format */
+	char xtur_country[4 + 1]; // Adding '\0' in the end for convenient manipulation
+	/** xTU-R T1.413 Revision Number as defined in T1.413 Issue 2 */
+	unsigned int xtur_ansi_std;
+	/** xTU-R Vendor Revision Number as defined in T1.413 Issue 2 */
+	unsigned int xtur_ansi_rev;
+	/** xTU-C vendor identifier as defined in G.994.1 and T1.413 in hex binary format */
+	char xtuc_vendor[16 + 1]; // Adding '\0' in the end for convenient manipulation
+	/** T.35 country code of the xTU-C vendor as defined in G.994.1 in hex binary format */
+	char xtuc_country[4 + 1]; // Adding '\0' in the end for convenient manipulation
+	/** xTU-C T1.413 Revision Number as defined in T1.413 Issue 2 */
+	unsigned int xtuc_ansi_std;
+	/** xTU-C Vendor Revision Number as defined in T1.413 Issue 2 */
+	unsigned int xtuc_ansi_rev;
 };
 
-/** struct dsl_line_rtxcounters - retransmit counters */
-struct dsl_line_rtxcounters {
-	dsl_long_t tx;      /** # of retransmitted DTUs */
-	dsl_long_t corr;    /** # of corrected retransmissions */
-	dsl_long_t uncorr;  /** # of DTU errors which couldnot be corrected */
+/** struct dsl_line_channel_stats - Statistics counters for DSL line and channel */
+struct dsl_line_channel_stats {
+	/** The number of seconds since the beginning of the period used for collection of Total statistics */
+	unsigned int total_start;
+	/** The number of seconds since the most recent DSL Showtime */
+	unsigned int showtime_start;
+	/** The number of seconds since the second most recent DSL Showtime-the beginning of the period used for
+	 *  collection of LastShowtime statistics */
+	unsigned int last_showtime_start;
+	/** The number of seconds since the beginning of the period used for collection of CurrentDay statistics */
+	unsigned int current_day_start;
+	/** The number of seconds since the beginning of the period used for collection of QuarterHour statistics */
+	unsigned int quarter_hour_start;
 };
 
-/** struct dsl_link - xdsl link information */
-struct dsl_link {
-	char name[64];                      /** real name */
-	char alias[64];                     /** name alias */
-	char fw_version[64];                /** firmware version */
-	enum dsl_linestate linestate;
-	enum dsl_powerstate pwr_state;      /** L0..L3 */
-	enum dsl_traffictype tc_type;       /** Traffic type */
-	enum dsl_modtype mode;              /** dsl mode adsl, vdsl2, etc. */
-	int annex_info;			    /* TODO: xdsl_mode-> annex_info */
-	unsigned int vdsl2_profile;         /** 8a,.. 30a, 35b */
-	dsl_long_t rate_kbps_max;           /** max attainable rate in Kbps */
-	dsl_bool_t trellis_enabled;         /** whether trellis coding used */
-	dsl_long_t snr_margin;              /** snr margin in 0.1 dB */
-	dsl_long_t attn;                    /** attenuation in 0.1 dB */
-	dsl_long_t power;                   /** power in 0.1 dBmV */
-	long status;
-	unsigned int training_status;
-	unsigned long uptime;               /** seconds since link up */
-	struct dsl_perfcounters perf_cnts;  /** perforamce stats */
+/** struct dsl_line_stats_interval - This is a common structure for all interval statistics */
+struct dsl_line_stats_interval {
+	/** Number of errored seconds */
+	unsigned int errored_secs;
+	/** Number of severely errored seconds */
+	unsigned int severely_errored_secs;
 };
 
-/** struct dsl_line - dsl line information structure */
-struct dsl_line {
-	dsl_long_t rate_kbps;                 /** rate in Kbps */
-	struct dsl_line_counters cnts;        /** line stats */
-	struct dsl_line_rtxcounters rtx_cnts; /** line retransmit counters */
-	struct dsl_line_params param;         /** line parameters */
-	struct dsl_line_errors err;           /** line errors */
+/**
+ *	enum dsl_stats_type - Type of DSL interval statistics
+ */
+enum dsl_stats_type {
+	/* Starts with non-zero in order to distinguish from an uninitialized value which is usually 0 */
+	DSL_STATS_TOTAL = 1,
+	DSL_STATS_SHOWTIME,
+	DSL_STATS_LASTSHOWTIME,
+	DSL_STATS_CURRENTDAY,
+	DSL_STATS_QUARTERHOUR
 };
 
-#define XDSL_MAX_LINES	2
+/** enum dsl_link_encapsulation - Type of link encapsulation method defineds as bit maps */
+enum dsl_link_encapsulation {
+	G_992_3_ANNEK_K_ATM	= 1,
+	G_992_3_ANNEK_K_PTM	= 1 << 1,
+	G_993_2_ANNEK_K_ATM	= 1 << 2,
+	G_993_2_ANNEK_K_PTM	= 1 << 3,
+	G_994_1_AUTO		= 1 << 4
+};
 
-/** struct dsl_info - dsl information structure */
-struct dsl_info {
-	struct dsl_link link;                 /** dsl link informantion */
-	uint32_t num_lines;                   /** # of phy lines */
-	struct dsl_line line[XDSL_MAX_LINES]; /** dsl lines */
+/** struct dsl_channel - DSL channel parameters */
+struct dsl_channel {
+	/** The current operational state of the DSL channel */
+	enum dsl_if_status status;
+	/** Which link encapsulation standards and recommendations are supported by the channel */
+	unsigned long link_encapsulation_supported;
+	/** The link encapsulation standard that the channel instance is using for the connection. */
+	enum dsl_link_encapsulation link_encapsulation_used;
+	/** The index of the latency path supporting the bearer channel */
+	unsigned int lpath;
+	/** The interleaver depth D for the latency path indicated in lpath */
+	unsigned int intlvdepth;
+	/** The interleaver block length in use on the latency path indicated in lpath */
+	int intlvblock;
+	/** The actual delay, in milliseconds, of the latency path due to interleaving */
+	unsigned int actual_interleaving_delay;
+	/** The actual impulse noise protection (INP) provided by the latency path indicated in lpath */
+	int actinp;
+	/** Whether the value reported in actinp was computed assuming the receiver does not use erasure decoding */
+	bool inpreport;
+	/** Reports the size, in octets, of the Reed-Solomon codeword in use on the latency path indicated in lpath */
+	int nfec;
+	/** The number of redundancy bytes per Reed-Solomon codeword on the latency path indicated in lpath */
+	int rfec;
+	/** The number of bits per symbol assigned to the latency path indicated in lpath */
+	int lsymb;
+	/** The current physical layer aggregate data rate (expressed in Kbps) in both directions. */
+	dsl_ulong_t curr_rate;
+	/** Actual net data rate expressed in Kbps in both directions */
+	dsl_ulong_t actndr;
+	/** Actual impulse noise protection in both directions against REIN, expressed in 0.1 DMT symbols */
+	dsl_ulong_t actinprein;
 };
 
-struct dsl_config {
-	unsigned int mode;	/** bitmap of modes */
-	unsigned int vdsl2_profile;
-	int us0;
-	int trellis;
-	int bitswap;
-	int sra;
+/** This value shall be used if any of elements defined in "struct dsl_channel_stats_interval" is unavailable */
+#define DSL_INVALID_STATS_COUNTER 4294967295
+/**
+ *  struct dsl_channel_stats_interval - This is a common structure for all interval statistics
+ */
+struct dsl_channel_stats_interval {
+	/** Number of FEC errors */
+	unsigned int xtur_fec_errors;
+	/** Number of FEC errors detected by the ATU-C */
+	unsigned int xtuc_fec_errors;
+	/** Number of HEC errors */
+	unsigned int xtur_hec_errors;
+	/** Number of HEC errors detected by the ATU-C */
+	unsigned int xtuc_hec_errors;
+	/** Number of CRC errors */
+	unsigned int xtur_crc_errors;
+	/** Number of CRC errors detected by the ATU-C */
+	unsigned int xtuc_crc_errors;
 };
 
+/**
+ * This function gets the number of DSL lines
+ *
+ * @return the number of DSL lines on success. Otherwise a negative value is returned.
+ *
+ * Note that this API must be implemented on all platforms on which libdsl is enabled.
+ */
+int dsl_get_line_number(void);
+
+/**
+ * This function gets the number of DSL channels
+ *
+ * @return the number of DSL channels on success. Otherwise a negative value is returned.
+ *
+ * Note that this API must be implemented on all platforms on which libdsl is enabled.
+ */
+int dsl_get_channel_number(void);
+
+/**
+ * This function gets the DSL line information
+ *
+ * @param[in] line_num - The line number which starts with 0
+ * @param[out] line - The output parameter to receive the data
+ *
+ * @return 0 on success. Otherwise a negative value is returned
+ */
+int dsl_get_line_info(int line_num, struct dsl_line *line);
+
+/**
+ * This function gets the statistics counters of a DSL line
+ *
+ * @param[in] line_num - The line number which starts with 0
+ * @param[out] stats The output parameter to receive the data
+ *
+ * @return 0 on success. Otherwise a negative value is returned
+ */
+int dsl_get_line_stats(int line_num, struct dsl_line_channel_stats *stats);
+
+/**
+ * This function gets the interval statistics counters of a DSL line
+ *
+ * @param[in] line_num - The line number which starts with 0
+ * @param[in] type The type of interval statistics
+ * @param[out] stats The output parameter to receive the data
+ *
+ * @return 0 on success. Otherwise a negative value is returned
+ */
+int dsl_get_line_stats_interval(int line_num, enum dsl_stats_type type, struct dsl_line_stats_interval *stats);
+
+/**
+ * This function gets the DSL channel information
+ *
+ * @param[in] chan_num - The channel number which starts with 0
+ * @param[out] channel The output parameter to receive the data
+ *
+ * @return 0 on success. Otherwise a negative value is returned
+ */
+int dsl_get_channel_info(int chan_num, struct dsl_channel *channel);
+
+/**
+ * This function gets the statistics counters of a DSL channel
+ *
+ * @param[in] chan_num - The channel number which starts with 0
+ * @param[out] stats The output parameter to receive the data
+ *
+ * @return 0 on success. Otherwise a negative value is returned
+ */
+int dsl_get_channel_stats(int chan_num, struct dsl_line_channel_stats *stats);
+
+/**
+ * This function gets the interval statistics counters of a DSL channel
+ *
+ * @param[in] chan_num - The channel number which starts with 0
+ * @param[in] type The type of interval statistics
+ * @param[out] stats The output parameter to receive the data
+ *
+ * @return 0 on success. Otherwise a negative value is returned
+ */
+int dsl_get_channel_stats_interval(int chan_num, enum dsl_stats_type type, struct dsl_channel_stats_interval *stats);
+
+/**
+ *  struct dsl_ops - This structure defines the DSL operations.
+ *  A function pointer shall be NULL if the operation
+ */
 struct dsl_ops {
-	/** name to match dsl backend */
-	const char *name;
-
-	int (*start)(char *name, struct dsl_config *cfg);
-	int (*stop)(char *name);
-	int (*set_alias)(char *name, char *alias);
-	int (*get_mode)(char *name, enum dsl_modtype *m);
-	int (*get_supported_standards)(char *name, uint32_t *std);
-	int (*get_active_standards)(char *name, uint32_t *std);
-	int (*get_line_status)(char *name, enum dsl_linestatus *s);
-	int (*get_supported_profiles)(char *name, uint32_t *p);
-	int (*get_active_profiles)(char *name, uint32_t *p);
-	int (*get_max_bitrate)(char *name, dsl_long_t *max_rate_kbps);
-	int (*get_bitrate)(char *name, dsl_long_t *rate_kbps);
-	int (*get_stats)(char *name, enum dsl_stattype type,
-				struct dsl_perfcounters *c);
-	int (*get_status)(char *name, struct dsl_info *info);
+	int (*get_line_info)(int line_num, struct dsl_line *line);
+	int (*get_line_stats)(int line_num, struct dsl_line_channel_stats *stats);
+	int (*get_line_stats_interval)(int line_num, enum dsl_stats_type type,
+			struct dsl_line_stats_interval *stats);
+	int (*get_channel_info)(int chan_num, struct dsl_channel *channel);
+	int (*get_channel_stats)(int chan_num, struct dsl_line_channel_stats *stats);
+	int (*get_channel_stats_interval)(int chan_num, enum dsl_stats_type type,
+			struct dsl_channel_stats_interval *stats);
 };
 
-
-/* API list */
-int dsl_start(char *name, struct dsl_config *cfg);
-int dsl_stop(char *name);
-int dsl_set_alias(char *name, char *alias);
-int dsl_get_mode(char *name, enum dsl_modtype *m);
-int dsl_get_supported_standards(char *name, uint32_t *std);
-int dsl_get_active_standards(char *name, uint32_t *std);
-int dsl_get_line_status(char *name, enum dsl_linestatus *s);
-int dsl_get_supported_profiles(char *name, uint32_t *p);
-int dsl_get_active_profiles(char *name, uint32_t *p);
-int dsl_get_max_bitrate(char *name, dsl_long_t *max_rate_kbps);
-int dsl_get_bitrate(char *name, dsl_long_t *rate_kbps);
-int dsl_get_stats(char *name, enum dsl_stattype type,
-			struct dsl_perfcounters *c);
-int dsl_get_status(char *name, struct dsl_info *info);
+/** This global variable must be defined for each platform specific implementation */
+extern const struct dsl_ops xdsl_ops;
 
 #ifdef __cplusplus
 }
diff --git a/main.c b/main.c
index 36570fb3822076091a7ada221987443cc5c09d07..6d515343aec8cbd909fef031ea587755cad3da31 100644
--- a/main.c
+++ b/main.c
@@ -1,9 +1,10 @@
 /*
  * main.c - dslmngr application
  *
- * Copyright (C) 2018 Inteno Broadband Technology AB. All rights reserved.
+ * Copyright (C) 2019 iopsys Software Solutions AB. All rights reserved.
  *
- * Author: anjan.chanda@inteno.se
+ * Author: anjan.chanda@iopsys.eu
+ *         yalu.zhang@iopsys.eu
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
@@ -27,7 +28,6 @@
 #define _GNU_SOURCE
 #endif
 #include <pthread.h>
-
 #include <libubox/blobmsg.h>
 #include <libubox/blobmsg_json.h>
 #include <libubox/uloop.h>
@@ -37,39 +37,28 @@
 
 #include "dslmngr.h"
 
-#define DSLMGR_EVENT_THREAD	"dslmngr_eventd"
-
-
-static void dslmngr_cmd_main(struct ubus_context *ctx)
-{
-	int ret;
-
-	ret = ubus_add_object(ctx, &dsl_object);
-	if (ret)
-		fprintf(stderr, "Failed to add 'xdsl' object: %s\n",
-				ubus_strerror(ret));
-
-	uloop_run();
-}
-
+#if 0 // Converting netlink to UBUS is done by inbd for now
 void *dslmngr_event_main(void *arg)
 {
 	struct ubus_context *ctx = (struct ubus_context *)arg;
 
 	pthread_t me = pthread_self();
-	pthread_setname_np(me, DSLMGR_EVENT_THREAD);
+	pthread_setname_np(me, "dslmngr_eventd");
 
 	dslmngr_nl_msgs_handler(ctx);
 	return NULL;
 }
+#endif
 
 int main(int argc, char **argv)
 {
 	const char *ubus_socket = NULL;
-	int ch;
-	pthread_t evtid;
-	pthread_attr_t attr, *pattr = NULL;
 	struct ubus_context *ctx = NULL;
+	int ch, ret;
+#if 0
+	pthread_t evtid;
+	pthread_attr_t attr;
+#endif
 
 	while ((ch = getopt(argc, argv, "cs:")) != -1) {
 		switch (ch) {
@@ -80,19 +69,10 @@ int main(int argc, char **argv)
 			break;
 		}
 	}
-
 	argc -= optind;
 	argv += optind;
 
-	uloop_init();
-	ctx = ubus_connect(ubus_socket);
-	if (!ctx) {
-		fprintf(stderr, "Failed to connect to ubus\n");
-		return -1;
-	}
-
-	ubus_add_uloop(ctx);
-
+#if 0 // Converting netlink to UBUS is done by inbd for now
 	if (pthread_attr_init(&attr) == 0) {
 		struct sched_param sp;
 
@@ -100,17 +80,31 @@ int main(int argc, char **argv)
 		pthread_attr_setschedpolicy(&attr, SCHED_RR);
 		sp.sched_priority = 99;
 		pthread_attr_setschedparam(&attr, &sp);
-		pattr = &attr;
 	}
 
-	if (pthread_create(&evtid, pattr, &dslmngr_event_main, ctx) != 0)
+	if (pthread_create(&evtid, &attr, &dslmngr_event_main, ctx) != 0)
 		fprintf(stderr, "pthread_create error!\n");
 
 	dslmngr_cmd_main(ctx);
+#endif
+
+	uloop_init();
+	ctx = ubus_connect(ubus_socket);
+	if (!ctx) {
+		DSLMNGR_LOG(LOG_ERR, "Failed to connect to ubus\n");
+		return -1;
+	}
+
+	ubus_add_uloop(ctx);
+
+	if (dsl_add_ubus_objects(ctx) != 0)
+		goto __ret;
 
 	uloop_run();
+
+__ret:
 	ubus_free(ctx);
 	uloop_done();
 
-	return 0;
+	return ret;
 }