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; }