diff --git a/Makefile b/Makefile
index a25ab0d229fa8dadc635839e4a8073cf9c6c223e..76415d730d0aab8aa0698a35a08fd41aa2e951fb 100644
--- a/Makefile
+++ b/Makefile
@@ -7,7 +7,7 @@ OBJS += dslmngr_nl.o
CODECOVERAGE_SRC = dslmngr.c
PROG_CFLAGS = $(CFLAGS) -fstrict-aliasing -fPIC
-PROG_LDFLAGS = $(LDFLAGS) -ldsl
+PROG_LDFLAGS = $(LDFLAGS) -ldsl -leasy
PROG_LDFLAGS += -pthread -luci -lubus -lubox -lblobmsg_json -lnl-genl-3 -lnl-3
ifeq ($(TARGET_PLATFORM),INTEL)
diff --git a/dslmngr.c b/dslmngr.c
index 5a30ae154d03f22fd4c23b518c357a1f06fbed46..02e52b3430ae34ed28e0b7d70b780845d080cd4a 100644
--- a/dslmngr.c
+++ b/dslmngr.c
@@ -30,6 +30,8 @@
#include <libubox/ustream.h>
#include <libubox/utils.h>
#include <uci.h>
+#include <net/if.h>
+#include <easy/easy.h>
#include "xdsl.h"
#include "xtm.h"
@@ -569,6 +571,18 @@ static struct value2text dsl_stats_types[] = {
{ DSL_STATS_QUARTERHOUR, "quarterhour" }
};
+static void dsl_if_stats_to_blob(const struct if_stats *stats, struct blob_buf *bb)
+{
+ blobmsg_add_u64(bb, "bytes_sent", stats->tx_bytes);
+ blobmsg_add_u64(bb, "bytes_received", stats->rx_bytes);
+ blobmsg_add_u64(bb, "packets_sent", stats->tx_packets);
+ blobmsg_add_u64(bb, "packets_received", stats->rx_packets);
+ blobmsg_add_u64(bb, "errors_sent", stats->tx_errors);
+ blobmsg_add_u64(bb, "errors_received", stats->rx_errors);
+ blobmsg_add_u64(bb, "discard_packets_sent", stats->tx_dropped);
+ blobmsg_add_u64(bb, "discard_packets_received", stats->rx_dropped);
+}
+
static void dsl_stats_to_blob(const struct dsl_line_channel_stats *stats, struct blob_buf *bb)
{
blobmsg_add_u64(bb, "total_start", stats->total_start);
@@ -594,12 +608,16 @@ static void dsl_stats_channel_interval_to_blob(const struct dsl_channel_stats_in
blobmsg_add_u64(bb, "xtuc_crc_errors", stats->xtuc_crc_errors);
}
+static int uci_get_ifname(char *ifname, size_t len, bool is_fast);
+
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;
+ char ifname[IFNAMSIZ];
+ struct if_stats if_stats;
struct dsl_line_channel_stats stats;
struct dsl_line_stats_interval line_stats_interval;
struct dsl_channel_stats_interval channel_stats_interval;
@@ -622,6 +640,9 @@ int dsl_stats_all(struct ubus_context *ctx, struct ubus_object *obj,
// Line statistics
blobmsg_add_u32(&bb, "id", (unsigned int)i + 1);
+ if (uci_get_ifname(ifname, sizeof(ifname), false) == 0 &&
+ if_getstats(ifname, &if_stats) == 0)
+ dsl_if_stats_to_blob(&if_stats, &bb);
dsl_stats_to_blob(&stats, &bb);
// Line interval statistics
@@ -730,6 +751,8 @@ int dsl_line_stats(struct ubus_context *ctx, struct ubus_object *obj,
static struct blob_buf bb;
struct blob_attr *tb[__DSL_STATS_MAX];
enum dsl_stats_type type = DSL_STATS_QUARTERHOUR + 1;
+ char ifname[IFNAMSIZ];
+ struct if_stats if_stats;
struct dsl_line_channel_stats stats;
struct dsl_line_stats_interval line_stats_interval;
int retval = UBUS_STATUS_OK;
@@ -772,6 +795,10 @@ int dsl_line_stats(struct ubus_context *ctx, struct ubus_object *obj,
}
dsl_stats_line_interval_to_blob(&line_stats_interval, &bb);
} else {
+ // Get interface counters
+ if (uci_get_ifname(ifname, sizeof(ifname), false) == 0 &&
+ if_getstats(ifname, &if_stats) == 0)
+ dsl_if_stats_to_blob(&if_stats, &bb);
// Get line statistics
if (xdsl_ops.get_line_stats == NULL || (*xdsl_ops.get_line_stats)(num, &stats) != 0) {
retval = UBUS_STATUS_UNKNOWN_ERROR;
@@ -846,6 +873,8 @@ int dsl_channel_stats(struct ubus_context *ctx, struct ubus_object *obj,
static struct blob_buf bb;
struct blob_attr *tb[__DSL_STATS_MAX];
enum dsl_stats_type type = DSL_STATS_QUARTERHOUR + 1;
+ char ifname[IFNAMSIZ];
+ struct if_stats if_stats;
struct dsl_line_channel_stats stats;
struct dsl_channel_stats_interval channel_stats_interval;
int retval = UBUS_STATUS_OK;
@@ -888,6 +917,10 @@ int dsl_channel_stats(struct ubus_context *ctx, struct ubus_object *obj,
}
dsl_stats_channel_interval_to_blob(&channel_stats_interval, &bb);
} else {
+ // Get interface counters
+ if (uci_get_ifname(ifname, sizeof(ifname), false) == 0 &&
+ if_getstats(ifname, &if_stats) == 0)
+ dsl_if_stats_to_blob(&if_stats, &bb);
// Get channel statistics
if (xdsl_ops.get_channel_stats == NULL || (*xdsl_ops.get_channel_stats)(num, &stats) != 0) {
retval = UBUS_STATUS_UNKNOWN_ERROR;
@@ -1078,6 +1111,8 @@ int fast_stats_all(struct ubus_context *ctx, struct ubus_object *obj,
struct fast_line_stats_interval line_stats_interval;
int i, j, max_line;
void *array_line, *table_line, *table_interval;
+ char ifname[IFNAMSIZ];
+ struct if_stats if_stats;
// Initialize the buffer
memset(&bb, 0, sizeof(bb));
@@ -1095,6 +1130,9 @@ int fast_stats_all(struct ubus_context *ctx, struct ubus_object *obj,
// Line statistics
blobmsg_add_u32(&bb, "id", (unsigned int)i + 1);
+ if (uci_get_ifname(ifname, sizeof(ifname), true) == 0 &&
+ if_getstats(ifname, &if_stats) == 0)
+ dsl_if_stats_to_blob(&if_stats, &bb);
dsl_stats_to_blob(&stats, &bb);
// Line interval statistics
@@ -1179,6 +1217,8 @@ int fast_line_stats_handler(struct ubus_context *ctx, struct ubus_object *obj,
int num = -1;
int i, j;
void *table;
+ char ifname[IFNAMSIZ];
+ struct if_stats if_stats;
// Parse and validation check the interval type if any
blobmsg_parse(dsl_stats_policy, __DSL_STATS_MAX, tb, blob_data(msg), blob_len(msg));
@@ -1215,6 +1255,10 @@ int fast_line_stats_handler(struct ubus_context *ctx, struct ubus_object *obj,
}
fast_line_stats_interval_to_blob(&stats_interval, &bb);
} else {
+ // Get interface counters
+ if (uci_get_ifname(ifname, sizeof(ifname), false) == 0 &&
+ if_getstats(ifname, &if_stats) == 0)
+ dsl_if_stats_to_blob(&if_stats, &bb);
// Get line statistics
if (xdsl_ops.get_fast_line_stats == NULL || (*xdsl_ops.get_fast_line_stats)(num, &stats) != 0) {
retval = UBUS_STATUS_UNKNOWN_ERROR;
@@ -1908,6 +1952,66 @@ __error_ret:
return -1;
}
+static int uci_get_ifname(char *ifname, size_t len, bool is_fast)
+{
+ struct uci_context *ctx;
+ struct uci_package *pkg;
+ struct uci_element *e;
+ const char *value;
+ bool use_ptm = is_fast;
+ int i = 0; // always check line 0 for now
+
+ /* First, we need to check if we are running ADSL or not */
+ if (!is_fast) {
+ struct dsl_line line;
+ if (xdsl_ops.get_line_info == NULL || (*xdsl_ops.get_line_info)(i, &line) != 0) {
+ return -1;
+ }
+ if (line.standard_used.use_xtse) {
+ if (XTSE_BIT_GET(line.standard_used.xtse, G_993_2_EUROPE) ||
+ XTSE_BIT_GET(line.standard_used.xtse, G_993_2_JAPAN) ||
+ XTSE_BIT_GET(line.standard_used.xtse, G_993_2_NORTH_AMERICA))
+ use_ptm= true;
+ } else {
+ if (line.standard_used.mode &
+ (MOD_G_993_1 | MOD_G_993_1_Annex_A |
+ MOD_G_993_2_Annex_A | MOD_G_993_2_Annex_B |
+ MOD_G_993_2_Annex_C))
+ use_ptm= true;
+ }
+ }
+
+ ctx = uci_alloc_context();
+ if (!ctx)
+ return -1;
+
+ if (uci_load(ctx, "dsl", &pkg)) {
+ uci_free_context(ctx);
+ return -1;
+ }
+
+ uci_foreach_element(&pkg->sections, e) {
+ struct uci_section *s = uci_to_section(e);
+ if (!strcmp(s->type, use_ptm ? "ptm-device" : "atm-device")) {
+ value = uci_lookup_option_string(ctx, s, "device");
+ if (value) {
+ if (snprintf(ifname, len, "%s", value) >= len) {
+ // truncated
+ uci_free_context(ctx);
+ return -2;
+ }
+ // success
+ uci_free_context(ctx);
+ return 0;
+ }
+ }
+ }
+
+ // not found
+ uci_free_context(ctx);
+ return -1;
+}
+
static int uci_get_oem_params(char *vendor_id, char *sw_version, char *serial_nr)
{
struct uci_context *ctx;