ltq-vdsl-app: extent dsl metrics with state_num and power_state_num
[openwrt/staging/mkresin.git] / package / network / config / ltq-vdsl-app / src / src / dsl_cpe_ubus.c
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (C) 2020 Andre Heider <a.heider@gmail.com>
4 */
5
6 #include <sys/ioctl.h>
7 #include <sys/stat.h>
8 #include <sys/types.h>
9 #include <fcntl.h>
10 #include <libubus.h>
11 #include <stdint.h>
12 #include <stdio.h>
13 #include <string.h>
14 #include <unistd.h>
15
16 #include "dsl_cpe_control.h"
17 #include <drv_dsl_cpe_api_ioctl.h>
18 #ifdef INCLUDE_DSL_CPE_API_VRX
19 #include <drv_mei_cpe_interface.h>
20 #endif
21
22 #define U16(v1, v2) ( \
23 ((uint16_t)(v1) << 8) | \
24 ((uint16_t)(v2)))
25
26 #define U32(v1, v2, v3, v4) ( \
27 ((uint32_t)(v1) << 24) | \
28 ((uint32_t)(v2) << 16) | \
29 ((uint32_t)(v3) << 8) | \
30 ((uint32_t)(v4)))
31
32 #define STR_CASE(id, text) \
33 case id: \
34 str = text; \
35 break;
36
37 #define STR_CASE_MAP(id, text, number) \
38 case id: \
39 str = text; \
40 map = number; \
41 break;
42
43 #define IOCTL(type, request) \
44 type out; \
45 memset(&out, 0, sizeof(type)); \
46 if (ioctl(fd, request, &out)) \
47 return;
48
49 #define IOCTL_DIR(type, request, dir) \
50 type out; \
51 memset(&out, 0, sizeof(type)); \
52 out.nDirection = dir; \
53 if (ioctl(fd, request, &out)) \
54 return;
55
56 #define IOCTL_DIR_DELT(type, request, dir, delt) \
57 type out; \
58 memset(&out, 0, sizeof(type)); \
59 out.nDirection = dir; \
60 out.nDeltDataType = delt; \
61 if (ioctl(fd, request, &out)) \
62 return;
63
64 typedef enum {
65 ANNEX_UNKNOWN = 0,
66 ANNEX_A,
67 ANNEX_B,
68 ANNEX_C,
69 ANNEX_I,
70 ANNEX_J,
71 ANNEX_L,
72 ANNEX_M,
73 } annex_t;
74
75 typedef enum {
76 STD_UNKNOWN = 0,
77 STD_T1_413,
78 STD_TS_101_388,
79 STD_G_992_1,
80 STD_G_992_2,
81 STD_G_992_3,
82 STD_G_992_4,
83 STD_G_992_5,
84 STD_G_993_1,
85 STD_G_993_2,
86 } standard_t;
87
88 typedef enum {
89 VECTOR_UNKNOWN = 0,
90 VECTOR_OFF,
91 VECTOR_ON_DS,
92 VECTOR_ON_DS_US,
93 } vector_t;
94
95 typedef enum {
96 PROFILE_UNKNOWN = 0,
97 PROFILE_8A,
98 PROFILE_8B,
99 PROFILE_8C,
100 PROFILE_8D,
101 PROFILE_12A,
102 PROFILE_12B,
103 PROFILE_17A,
104 PROFILE_30A,
105 PROFILE_35B,
106 } profile_t;
107
108 /* These values are exported via ubus and backwards compability
109 * needs to be kept!
110 */
111 enum {
112 LSTATE_MAP_UNKNOWN = -1,
113 LSTATE_MAP_NOT_INITIALIZED,
114 LSTATE_MAP_EXCEPTION,
115 LSTATE_MAP_IDLE,
116 LSTATE_MAP_SILENT,
117 LSTATE_MAP_HANDSHAKE,
118 LSTATE_MAP_FULL_INIT,
119 LSTATE_MAP_SHOWTIME_NO_SYNC,
120 LSTATE_MAP_SHOWTIME_TC_SYNC,
121 LSTATE_MAP_RESYNC,
122 };
123
124 /* These values are exported via ubus and backwards compability
125 * needs to be kept!
126 */
127 enum {
128 PSTATE_MAP_UNKNOWN = -2,
129 PSTATE_MAP_NA,
130 PSTATE_MAP_L0,
131 PSTATE_MAP_L1,
132 PSTATE_MAP_L2,
133 PSTATE_MAP_L3,
134 };
135
136 static DSL_CPE_ThreadCtrl_t thread;
137 static struct ubus_context *ctx;
138 static struct blob_buf b;
139
140 static inline void m_double(const char *id, double value) {
141 blobmsg_add_double(&b, id, value);
142 }
143
144 static inline void m_bool(const char *id, bool value) {
145 blobmsg_add_u8(&b, id, value);
146 }
147
148 static inline void m_u32(const char *id, uint32_t value) {
149 blobmsg_add_u32(&b, id, value);
150 }
151
152 static inline void m_str(const char *id, const char *value) {
153 blobmsg_add_string(&b, id, value);
154 }
155
156 static inline void m_db(const char *id, int value) {
157 m_double(id, (double)value / 10);
158 }
159
160 static inline void m_array(const char *id, const uint8_t *value, uint8_t len) {
161 void *c = blobmsg_open_array(&b, id);
162
163 for (uint8_t i = 0; i < len; ++i)
164 blobmsg_add_u16(&b, "", value[i]);
165
166 blobmsg_close_array(&b, c);
167 }
168
169 static void m_vendor(const char *id, const uint8_t *value) {
170 // ITU-T T.35: U.S.
171 if (U16(value[0], value[1]) != 0xb500)
172 return;
173
174 const char *str = NULL;
175 switch (U32(value[2], value[3], value[4], value[5])) {
176 STR_CASE(0x414C4342, "Alcatel")
177 STR_CASE(0x414E4456, "Analog Devices")
178 STR_CASE(0x4244434D, "Broadcom")
179 STR_CASE(0x43454E54, "Centillium")
180 STR_CASE(0x4753504E, "Globespan")
181 STR_CASE(0x494B4E53, "Ikanos")
182 STR_CASE(0x4946544E, "Infineon")
183 STR_CASE(0x54535443, "Texas Instruments")
184 STR_CASE(0x544D4D42, "Thomson MultiMedia Broadband")
185 STR_CASE(0x5443544E, "Trend Chip Technologies")
186 STR_CASE(0x53544D49, "ST Micro")
187 };
188
189 if (!str)
190 return;
191
192 if ((value[6] == 0) && (value[7] == 0)) {
193 m_str(id, str);
194 return;
195 }
196
197 char buf[64];
198 sprintf(buf, "%s %d.%d", str, value[6], value[7]);
199 m_str(id, buf);
200
201 return;
202 }
203
204 annex_t get_annex(const uint8_t *xtse) {
205 if ((xtse[0] & XTSE_1_01_A_T1_413) ||
206 (xtse[0] & XTSE_1_03_A_1_NO) ||
207 (xtse[0] & XTSE_1_04_A_1_O) ||
208 (xtse[1] & XTSE_2_01_A_2_NO) ||
209 (xtse[2] & XTSE_3_03_A_3_NO) ||
210 (xtse[2] & XTSE_3_04_A_3_O) ||
211 (xtse[3] & XTSE_4_01_A_4_NO) ||
212 (xtse[3] & XTSE_4_02_A_4_O) ||
213 (xtse[5] & XTSE_6_01_A_5_NO) ||
214 (xtse[5] & XTSE_6_02_A_5_O) ||
215 (xtse[7] & XTSE_8_01_A))
216 return ANNEX_A;
217
218 if ((xtse[0] & XTSE_1_05_B_1_NO) ||
219 (xtse[0] & XTSE_1_06_B_1_O) ||
220 (xtse[1] & XTSE_2_02_B_2_O) ||
221 (xtse[2] & XTSE_3_05_B_3_NO) ||
222 (xtse[2] & XTSE_3_06_B_3_O) ||
223 (xtse[5] & XTSE_6_03_B_5_NO) ||
224 (xtse[5] & XTSE_6_04_B_5_O) ||
225 (xtse[7] & XTSE_8_02_B))
226 return ANNEX_B;
227
228 if ((xtse[0] & XTSE_1_02_C_TS_101388) ||
229 (xtse[0] & XTSE_1_07_C_1_NO) ||
230 (xtse[0] & XTSE_1_08_C_1_O) ||
231 (xtse[1] & XTSE_2_03_C_2_NO) ||
232 (xtse[1] & XTSE_2_04_C_2_O) ||
233 (xtse[7] & XTSE_8_03_C))
234 return ANNEX_C;
235
236 if ((xtse[3] & XTSE_4_05_I_3_NO) ||
237 (xtse[3] & XTSE_4_06_I_3_O) ||
238 (xtse[4] & XTSE_5_01_I_4_NO) ||
239 (xtse[4] & XTSE_5_02_I_4_O) ||
240 (xtse[5] & XTSE_6_07_I_5_NO) ||
241 (xtse[5] & XTSE_6_08_I_5_O))
242 return ANNEX_I;
243
244 if ((xtse[3] & XTSE_4_07_J_3_NO) ||
245 (xtse[3] & XTSE_4_08_J_3_O) ||
246 (xtse[6] & XTSE_7_01_J_5_NO) ||
247 (xtse[6] & XTSE_7_02_J_5_O))
248 return ANNEX_J;
249
250 if ((xtse[4] & XTSE_5_03_L_3_NO) ||
251 (xtse[4] & XTSE_5_04_L_3_NO) ||
252 (xtse[4] & XTSE_5_05_L_3_O) ||
253 (xtse[4] & XTSE_5_06_L_3_O))
254 return ANNEX_L;
255
256 if ((xtse[4] & XTSE_5_07_M_3_NO) ||
257 (xtse[4] & XTSE_5_08_M_3_O) ||
258 (xtse[6] & XTSE_7_03_M_5_NO) ||
259 (xtse[6] & XTSE_7_04_M_5_O))
260 return ANNEX_M;
261
262 return ANNEX_UNKNOWN;
263 }
264
265 static standard_t get_standard(const uint8_t *xtse) {
266 if (xtse[0] & XTSE_1_01_A_T1_413)
267 return STD_T1_413;
268
269 if (xtse[0] & XTSE_1_02_C_TS_101388)
270 return STD_TS_101_388;
271
272 if ((xtse[0] & XTSE_1_03_A_1_NO) ||
273 (xtse[0] & XTSE_1_04_A_1_O) ||
274 (xtse[0] & XTSE_1_05_B_1_NO) ||
275 (xtse[0] & XTSE_1_06_B_1_O) ||
276 (xtse[0] & XTSE_1_07_C_1_NO) ||
277 (xtse[0] & XTSE_1_08_C_1_O))
278 return STD_G_992_1;
279
280 if ((xtse[1] & XTSE_2_01_A_2_NO) ||
281 (xtse[1] & XTSE_2_02_B_2_O) ||
282 (xtse[1] & XTSE_2_03_C_2_NO) ||
283 (xtse[1] & XTSE_2_04_C_2_O))
284 return STD_G_992_2;
285
286 if ((xtse[2] & XTSE_3_03_A_3_NO) ||
287 (xtse[2] & XTSE_3_04_A_3_O) ||
288 (xtse[2] & XTSE_3_05_B_3_NO) ||
289 (xtse[2] & XTSE_3_06_B_3_O) ||
290 (xtse[3] & XTSE_4_05_I_3_NO) ||
291 (xtse[3] & XTSE_4_06_I_3_O) ||
292 (xtse[3] & XTSE_4_07_J_3_NO) ||
293 (xtse[3] & XTSE_4_08_J_3_O) ||
294 (xtse[4] & XTSE_5_03_L_3_NO) ||
295 (xtse[4] & XTSE_5_04_L_3_NO) ||
296 (xtse[4] & XTSE_5_05_L_3_O) ||
297 (xtse[4] & XTSE_5_06_L_3_O) ||
298 (xtse[4] & XTSE_5_07_M_3_NO) ||
299 (xtse[4] & XTSE_5_08_M_3_O))
300 return STD_G_992_3;
301
302 if ((xtse[3] & XTSE_4_01_A_4_NO) ||
303 (xtse[3] & XTSE_4_02_A_4_O) ||
304 (xtse[4] & XTSE_5_01_I_4_NO) ||
305 (xtse[4] & XTSE_5_02_I_4_O))
306 return STD_G_992_4;
307
308 if ((xtse[5] & XTSE_6_01_A_5_NO) ||
309 (xtse[5] & XTSE_6_02_A_5_O) ||
310 (xtse[5] & XTSE_6_03_B_5_NO) ||
311 (xtse[5] & XTSE_6_04_B_5_O) ||
312 (xtse[5] & XTSE_6_07_I_5_NO) ||
313 (xtse[5] & XTSE_6_08_I_5_O) ||
314 (xtse[6] & XTSE_7_01_J_5_NO) ||
315 (xtse[6] & XTSE_7_02_J_5_O) ||
316 (xtse[6] & XTSE_7_03_M_5_NO) ||
317 (xtse[6] & XTSE_7_04_M_5_O))
318 return STD_G_992_5;
319
320 if (xtse[7] & XTSE_8_08)
321 return STD_G_993_1;
322
323 if ((xtse[7] & XTSE_8_01_A) ||
324 (xtse[7] & XTSE_8_02_B) ||
325 (xtse[7] & XTSE_8_03_C))
326 return STD_G_993_2;
327
328 return STD_UNKNOWN;
329 }
330
331 static void version_information(int fd) {
332 IOCTL(DSL_VersionInformation_t, DSL_FIO_VERSION_INFORMATION_GET)
333
334 m_str("api_version", out.data.DSL_DriverVersionApi);
335 m_str("firmware_version", out.data.DSL_ChipSetFWVersion);
336 m_str("chipset", out.data.DSL_ChipSetType);
337 m_str("driver_version", out.data.DSL_DriverVersionMeiBsp);
338 }
339
340 static void line_state(int fd) {
341 IOCTL(DSL_LineState_t, DSL_FIO_LINE_STATE_GET)
342
343 int map = LSTATE_MAP_UNKNOWN;
344 const char *str;
345 switch (out.data.nLineState) {
346 STR_CASE_MAP(DSL_LINESTATE_NOT_INITIALIZED, "Not initialized", LSTATE_MAP_NOT_INITIALIZED)
347 STR_CASE_MAP(DSL_LINESTATE_EXCEPTION, "Exception", LSTATE_MAP_EXCEPTION)
348 STR_CASE(DSL_LINESTATE_NOT_UPDATED, "Not updated")
349 STR_CASE(DSL_LINESTATE_IDLE_REQUEST, "Idle request")
350 STR_CASE_MAP(DSL_LINESTATE_IDLE, "Idle", LSTATE_MAP_IDLE)
351 STR_CASE(DSL_LINESTATE_SILENT_REQUEST, "Silent request")
352 STR_CASE_MAP(DSL_LINESTATE_SILENT, "Silent", LSTATE_MAP_SILENT)
353 STR_CASE_MAP(DSL_LINESTATE_HANDSHAKE, "Handshake", LSTATE_MAP_HANDSHAKE)
354 STR_CASE(DSL_LINESTATE_BONDING_CLR, "Bonding CLR")
355 STR_CASE_MAP(DSL_LINESTATE_FULL_INIT, "Full init", LSTATE_MAP_FULL_INIT)
356 STR_CASE(DSL_LINESTATE_SHORT_INIT_ENTRY, "Short init entry")
357 STR_CASE(DSL_LINESTATE_DISCOVERY, "Discovery")
358 STR_CASE(DSL_LINESTATE_TRAINING, "Training")
359 STR_CASE(DSL_LINESTATE_ANALYSIS, "Analysis")
360 STR_CASE(DSL_LINESTATE_EXCHANGE, "Exchange")
361 STR_CASE_MAP(DSL_LINESTATE_SHOWTIME_NO_SYNC, "Showtime without TC-Layer sync", LSTATE_MAP_SHOWTIME_NO_SYNC)
362 STR_CASE_MAP(DSL_LINESTATE_SHOWTIME_TC_SYNC, "Showtime with TC-Layer sync", LSTATE_MAP_SHOWTIME_TC_SYNC)
363 STR_CASE(DSL_LINESTATE_FASTRETRAIN, "Fastretrain")
364 STR_CASE(DSL_LINESTATE_LOWPOWER_L2, "Lowpower L2")
365 STR_CASE(DSL_LINESTATE_LOOPDIAGNOSTIC_ACTIVE, "Loopdiagnostic active")
366 STR_CASE(DSL_LINESTATE_LOOPDIAGNOSTIC_DATA_EXCHANGE, "Loopdiagnostic data exchange")
367 STR_CASE(DSL_LINESTATE_LOOPDIAGNOSTIC_DATA_REQUEST, "Loopdiagnostic data request")
368 STR_CASE(DSL_LINESTATE_LOOPDIAGNOSTIC_COMPLETE, "Loopdiagnostic complete")
369 STR_CASE_MAP(DSL_LINESTATE_RESYNC, "Resync", LSTATE_MAP_RESYNC)
370 STR_CASE(DSL_LINESTATE_TEST, "Test")
371 STR_CASE(DSL_LINESTATE_TEST_LOOP, "Test loop")
372 STR_CASE(DSL_LINESTATE_TEST_REVERB, "Test reverb")
373 STR_CASE(DSL_LINESTATE_TEST_MEDLEY, "Test medley")
374 STR_CASE(DSL_LINESTATE_TEST_SHOWTIME_LOCK, "Showtime lock")
375 STR_CASE(DSL_LINESTATE_TEST_QUIET, "Quiet")
376 STR_CASE(DSL_LINESTATE_LOWPOWER_L3, "Lowpower L3")
377 #ifndef INCLUDE_DSL_CPE_API_DANUBE
378 STR_CASE(DSL_LINESTATE_DISABLED, "Disabled")
379 STR_CASE(DSL_LINESTATE_T1413, "T1413")
380 STR_CASE(DSL_LINESTATE_ORDERLY_SHUTDOWN_REQUEST, "Orderly shutdown request")
381 STR_CASE(DSL_LINESTATE_ORDERLY_SHUTDOWN, "Orderly shutdown")
382 STR_CASE(DSL_LINESTATE_TEST_FILTERDETECTION_ACTIVE, "Test filterdetection active")
383 STR_CASE(DSL_LINESTATE_TEST_FILTERDETECTION_COMPLETE, "Test filterdetection complete")
384 #endif
385 default:
386 str = NULL;
387 break;
388 };
389
390 if (str)
391 m_str("state", str);
392
393 if (map != LSTATE_MAP_UNKNOWN )
394 m_u32("state_num", map);
395
396 m_bool("up", out.data.nLineState == DSL_LINESTATE_SHOWTIME_TC_SYNC);
397 }
398
399 static void pm_channel_counters_showtime(int fd) {
400 IOCTL_DIR(DSL_PM_ChannelCounters_t, DSL_FIO_PM_CHANNEL_COUNTERS_SHOWTIME_GET, DSL_NEAR_END);
401
402 m_u32("uptime", out.interval.nElapsedTime);
403 }
404
405 static void g997_line_inventory(int fd) {
406 IOCTL_DIR(DSL_G997_LineInventory_t, DSL_FIO_G997_LINE_INVENTORY_GET, DSL_DOWNSTREAM)
407
408 m_array("vendor_id", out.data.G994VendorID, DSL_G997_LI_MAXLEN_VENDOR_ID);
409 m_vendor("vendor", out.data.G994VendorID);
410 m_array("system_vendor_id", out.data.SystemVendorID, DSL_G997_LI_MAXLEN_VENDOR_ID);
411 m_vendor("system_vendor", out.data.SystemVendorID);
412 m_array("version", out.data.VersionNumber, DSL_G997_LI_MAXLEN_VERSION);
413 m_array("serial", out.data.SerialNumber, DSL_G997_LI_MAXLEN_SERIAL);
414 }
415
416 static void g997_power_management_status(int fd) {
417 IOCTL(DSL_G997_PowerManagementStatus_t, DSL_FIO_G997_POWER_MANAGEMENT_STATUS_GET)
418
419 int map = PSTATE_MAP_UNKNOWN;
420 const char *str;
421 switch (out.data.nPowerManagementStatus) {
422 STR_CASE_MAP(DSL_G997_PMS_NA, "Power management state is not available", PSTATE_MAP_NA)
423 STR_CASE_MAP(DSL_G997_PMS_L0, "L0 - Synchronized", PSTATE_MAP_L0)
424 STR_CASE_MAP(DSL_G997_PMS_L1, "L1 - Power Down Data transmission (G.992.2)", PSTATE_MAP_L1)
425 STR_CASE_MAP(DSL_G997_PMS_L2, "L2 - Power Down Data transmission (G.992.3 and G.992.4)", PSTATE_MAP_L2)
426 STR_CASE_MAP(DSL_G997_PMS_L3, "L3 - No power", PSTATE_MAP_L3)
427 default:
428 str = NULL;
429 break;
430 };
431
432 if (str)
433 m_str("power_state", str);
434
435 if (map != PSTATE_MAP_UNKNOWN)
436 m_u32("power_state_num", map);
437 }
438
439 static void g997_xtu_system_enabling(int fd, standard_t *standard) {
440 IOCTL(DSL_G997_XTUSystemEnabling_t, DSL_FIO_G997_XTU_SYSTEM_ENABLING_STATUS_GET)
441
442 m_array("xtse", out.data.XTSE, DSL_G997_NUM_XTSE_OCTETS);
443
444 const char *str;
445 switch (get_annex(out.data.XTSE)) {
446 STR_CASE(ANNEX_A, "A")
447 STR_CASE(ANNEX_B, "B")
448 STR_CASE(ANNEX_C, "C")
449 STR_CASE(ANNEX_I, "I")
450 STR_CASE(ANNEX_J, "J")
451 STR_CASE(ANNEX_L, "L")
452 STR_CASE(ANNEX_M, "M")
453 default:
454 str = NULL;
455 break;
456 };
457 if (str)
458 m_str("annex", str);
459
460 *standard = get_standard(out.data.XTSE);
461
462 switch (*standard) {
463 STR_CASE(STD_T1_413, "T1.413")
464 STR_CASE(STD_TS_101_388, "TS 101 388")
465 STR_CASE(STD_G_992_1, "G.992.1")
466 STR_CASE(STD_G_992_2, "G.992.2")
467 STR_CASE(STD_G_992_3, "G.992.3")
468 STR_CASE(STD_G_992_4, "G.992.4")
469 STR_CASE(STD_G_992_5, "G.992.5")
470 STR_CASE(STD_G_993_1, "G.993.1")
471 STR_CASE(STD_G_993_2, "G.993.2")
472 default:
473 str = NULL;
474 break;
475 }
476 if (str)
477 m_str("standard", str);
478 }
479
480 static vector_t get_vector_status() {
481 #ifdef INCLUDE_DSL_CPE_API_VRX
482 int fd = open(DSL_CPE_DSL_LOW_DEV "/0", O_RDWR, 0644);
483 if (fd < 0)
484 return VECTOR_UNKNOWN;
485
486 IOCTL_MEI_dsmStatus_t out;
487 memset(&out, 0, sizeof(IOCTL_MEI_dsmStatus_t));
488 int ret = ioctl(fd, FIO_MEI_DSM_STATUS_GET, &out);
489 close(fd);
490
491 if (ret)
492 return VECTOR_UNKNOWN;
493
494 switch (out.eVectorStatus) {
495 case e_MEI_VECTOR_STAT_OFF:
496 return VECTOR_OFF;
497 case e_MEI_VECTOR_STAT_ON_DS:
498 return VECTOR_ON_DS;
499 case e_MEI_VECTOR_STAT_ON_DS_US:
500 return VECTOR_ON_DS_US;
501 default:
502 return VECTOR_UNKNOWN;
503 };
504 #else
505 return VECTOR_UNKNOWN;
506 #endif
507 }
508
509 static void band_plan_status(int fd, profile_t *profile) {
510 #if (INCLUDE_DSL_CPE_API_VDSL_SUPPORT == 1)
511 IOCTL(DSL_BandPlanStatus_t, DSL_FIO_BAND_PLAN_STATUS_GET)
512
513 switch (out.data.nProfile) {
514 case DSL_PROFILE_8A:
515 *profile = PROFILE_8A;
516 break;
517 case DSL_PROFILE_8B:
518 *profile = PROFILE_8B;
519 break;
520 case DSL_PROFILE_8C:
521 *profile = PROFILE_8C;
522 break;
523 case DSL_PROFILE_8D:
524 *profile = PROFILE_8D;
525 break;
526 case DSL_PROFILE_12A:
527 *profile = PROFILE_12A;
528 break;
529 case DSL_PROFILE_12B:
530 *profile = PROFILE_12B;
531 break;
532 case DSL_PROFILE_17A:
533 *profile = PROFILE_17A;
534 break;
535 case DSL_PROFILE_30A:
536 *profile = PROFILE_30A;
537 break;
538 case DSL_PROFILE_35B:
539 *profile = PROFILE_35B;
540 break;
541 default:
542 *profile = PROFILE_UNKNOWN;
543 break;
544 };
545
546 const char *str;
547 switch (*profile) {
548 STR_CASE(PROFILE_8A, "8a")
549 STR_CASE(PROFILE_8B, "8b")
550 STR_CASE(PROFILE_8C, "8c")
551 STR_CASE(PROFILE_8D, "8d")
552 STR_CASE(PROFILE_12A, "12a")
553 STR_CASE(PROFILE_12B, "12b")
554 STR_CASE(PROFILE_17A, "17a")
555 STR_CASE(PROFILE_30A, "30a")
556 STR_CASE(PROFILE_35B, "35b")
557 default:
558 str = NULL;
559 break;
560 };
561 if (str)
562 m_str("profile", str);
563 #endif
564 }
565
566 static void line_feature_config(int fd, DSL_AccessDir_t direction) {
567 IOCTL_DIR(DSL_LineFeature_t, DSL_FIO_LINE_FEATURE_STATUS_GET, direction)
568
569 m_bool("trellis", out.data.bTrellisEnable);
570 m_bool("bitswap", out.data.bBitswapEnable);
571 m_bool("retx", out.data.bReTxEnable);
572 m_bool("virtual_noise", out.data.bVirtualNoiseSupport);
573 }
574
575 static void g997_channel_status(int fd, DSL_AccessDir_t direction) {
576 IOCTL_DIR(DSL_G997_ChannelStatus_t, DSL_FIO_G997_CHANNEL_STATUS_GET, direction);
577
578 m_u32("interleave_delay", out.data.ActualInterleaveDelay * 10);
579 #ifndef INCLUDE_DSL_CPE_API_DANUBE
580 // prefer ACTNDR, see comments in drv_dsl_cpe_api_g997.h
581 m_u32("data_rate", out.data.ActualNetDataRate);
582 #else
583 m_u32("data_rate", out.data.ActualDataRate);
584 #endif
585 }
586
587 static void g997_line_status(int fd, DSL_AccessDir_t direction) {
588 IOCTL_DIR_DELT(DSL_G997_LineStatus_t, DSL_FIO_G997_LINE_STATUS_GET, direction, DSL_DELT_DATA_SHOWTIME);
589
590 m_db("latn", out.data.LATN);
591 m_db("satn", out.data.SATN);
592 m_db("snr", out.data.SNR);
593 m_db("actps", out.data.ACTPS);
594 m_db("actatp", out.data.ACTATP);
595 m_u32("attndr", out.data.ATTNDR);
596 }
597
598 static void pm_line_sec_counters_total(int fd, DSL_XTUDir_t direction) {
599 IOCTL_DIR(DSL_PM_LineSecCountersTotal_t, DSL_FIO_PM_LINE_SEC_COUNTERS_TOTAL_GET, direction)
600
601 m_u32("es", out.data.nES);
602 m_u32("ses", out.data.nSES);
603 m_u32("loss", out.data.nLOSS);
604 m_u32("uas", out.data.nUAS);
605 m_u32("lofs", out.data.nLOFS);
606 #ifndef INCLUDE_DSL_CPE_API_DANUBE
607 m_u32("fecs", out.data.nFECS);
608 #endif
609 }
610
611 static void pm_data_path_counters_total(int fd, DSL_XTUDir_t direction) {
612 IOCTL_DIR(DSL_PM_DataPathCountersTotal_t, DSL_FIO_PM_DATA_PATH_COUNTERS_TOTAL_GET, direction);
613
614 m_u32("hec", out.data.nHEC);
615 m_u32("ibe", out.data.nIBE);
616 m_u32("crc_p", out.data.nCRC_P);
617 m_u32("crcp_p", out.data.nCRCP_P);
618 m_u32("cv_p", out.data.nCV_P);
619 m_u32("cvp_p", out.data.nCVP_P);
620 }
621
622 static void retx_statistics(int fd, DSL_XTUDir_t direction) {
623 #ifdef INCLUDE_DSL_CPE_PM_RETX_COUNTERS
624 #ifdef INCLUDE_DSL_CPE_PM_RETX_THRESHOLDS
625 IOCTL_DIR(DSL_ReTxStatistics_t, DSL_FIO_RETX_STATISTICS_GET, direction);
626
627 m_u32("rx_corrupted", out.data.nRxCorruptedTotal);
628 m_u32("rx_uncorrected_protected", out.data.nRxUncorrectedProtected);
629 m_u32("rx_retransmitted", out.data.nRxRetransmitted);
630 m_u32("rx_corrected", out.data.nRxCorrected);
631 m_u32("tx_retransmitted", out.data.nTxRetransmitted);
632 #endif
633 #endif
634 }
635
636 static void describe_mode(standard_t standard, profile_t profile, vector_t vector) {
637 char buf[128];
638
639 switch (standard) {
640 case STD_T1_413:
641 strcpy(buf, "T1.413");
642 break;
643 case STD_TS_101_388:
644 strcpy(buf, "TS 101 388");
645 break;
646 case STD_G_992_1:
647 strcpy(buf, "G.992.1 (ADSL)");
648 break;
649 case STD_G_992_2:
650 strcpy(buf, "G.992.2 (ADSL lite)");
651 break;
652 case STD_G_992_3:
653 strcpy(buf, "G.992.3 (ADSL2)");
654 break;
655 case STD_G_992_4:
656 strcpy(buf, "G.992.4 (ADSL2 lite)");
657 break;
658 case STD_G_992_5:
659 strcpy(buf, "G.992.5 (ADSL2+)");
660 break;
661 case STD_G_993_1:
662 strcpy(buf, "G.993.1 (VDSL)");
663 break;
664 case STD_G_993_2:
665 strcpy(buf, "G.993.2 (VDSL2");
666
667 switch (profile) {
668 case PROFILE_8A:
669 strcat(buf, ", Profile 8a");
670 break;
671 case PROFILE_8B:
672 strcat(buf, ", Profile 8b");
673 break;
674 case PROFILE_8C:
675 strcat(buf, ", Profile 8c");
676 break;
677 case PROFILE_8D:
678 strcat(buf, ", Profile 8d");
679 break;
680 case PROFILE_12A:
681 strcat(buf, ", Profile 12a");
682 break;
683 case PROFILE_12B:
684 strcat(buf, ", Profile 12b");
685 break;
686 case PROFILE_17A:
687 strcat(buf, ", Profile 17a");
688 break;
689 case PROFILE_30A:
690 strcat(buf, ", Profile 30a");
691 break;
692 case PROFILE_35B:
693 strcat(buf, ", Profile 35b");
694 break;
695 default:
696 break;
697 };
698
699 switch (vector) {
700 case VECTOR_ON_DS:
701 strcat(buf, ", with downstream vectoring");
702 break;
703 case VECTOR_ON_DS_US:
704 strcat(buf, ", with down- and upstream vectoring");
705 break;
706 default:
707 break;
708 };
709
710 strcat(buf, ")");
711 break;
712 default:
713 return;
714 };
715
716 m_str("mode", buf);
717 }
718
719 static int metrics(struct ubus_context *ctx, struct ubus_object *obj,
720 struct ubus_request_data *req, const char *method,
721 struct blob_attr *msg)
722 {
723 int fd;
724 void *c, *c2;
725 standard_t standard = STD_UNKNOWN;
726 profile_t profile = PROFILE_UNKNOWN;
727 vector_t vector = VECTOR_UNKNOWN;
728
729 #ifndef INCLUDE_DSL_CPE_API_DANUBE
730 fd = open(DSL_CPE_DEVICE_NAME "0", O_RDWR, 0644);
731 #else
732 fd = open(DSL_CPE_DEVICE_NAME, O_RDWR, 0644);
733 #endif
734 if (fd < 0)
735 return UBUS_STATUS_UNKNOWN_ERROR;
736
737 blob_buf_init(&b, 0);
738
739 version_information(fd);
740 line_state(fd);
741 pm_channel_counters_showtime(fd);
742
743 c = blobmsg_open_table(&b, "atu_c");
744 g997_line_inventory(fd);
745 blobmsg_close_table(&b, c);
746
747 g997_power_management_status(fd);
748 g997_xtu_system_enabling(fd, &standard);
749
750 if (standard == STD_G_993_2) {
751 band_plan_status(fd, &profile);
752 vector = get_vector_status();
753 }
754
755 describe_mode(standard, profile, vector);
756
757 c = blobmsg_open_table(&b, "upstream");
758 switch (vector) {
759 case VECTOR_OFF:
760 m_bool("vector", false);
761 break;
762 case VECTOR_ON_DS_US:
763 m_bool("vector", true);
764 break;
765 default:
766 break;
767 };
768 line_feature_config(fd, DSL_UPSTREAM);
769 g997_channel_status(fd, DSL_UPSTREAM);
770 g997_line_status(fd, DSL_UPSTREAM);
771 blobmsg_close_table(&b, c);
772
773 c = blobmsg_open_table(&b, "downstream");
774 switch (vector) {
775 case VECTOR_OFF:
776 m_bool("vector", false);
777 break;
778 case VECTOR_ON_DS:
779 case VECTOR_ON_DS_US:
780 m_bool("vector", true);
781 break;
782 default:
783 break;
784 };
785 line_feature_config(fd, DSL_DOWNSTREAM);
786 g997_channel_status(fd, DSL_DOWNSTREAM);
787 g997_line_status(fd, DSL_DOWNSTREAM);
788 blobmsg_close_table(&b, c);
789
790 c = blobmsg_open_table(&b, "errors");
791 c2 = blobmsg_open_table(&b, "near");
792 pm_line_sec_counters_total(fd, DSL_NEAR_END);
793 pm_data_path_counters_total(fd, DSL_NEAR_END);
794 retx_statistics(fd, DSL_NEAR_END);
795 blobmsg_close_table(&b, c2);
796
797 c2 = blobmsg_open_table(&b, "far");
798 pm_line_sec_counters_total(fd, DSL_FAR_END);
799 pm_data_path_counters_total(fd, DSL_FAR_END);
800 retx_statistics(fd, DSL_FAR_END);
801 blobmsg_close_table(&b, c2);
802 blobmsg_close_table(&b, c);
803
804 ubus_send_reply(ctx, req, b.head);
805
806 close(fd);
807
808 return 0;
809 }
810
811 static const struct ubus_method dsl_methods[] = {
812 UBUS_METHOD_NOARG("metrics", metrics),
813 };
814
815 static struct ubus_object_type dsl_object_type =
816 UBUS_OBJECT_TYPE("dsl", dsl_methods);
817
818 static struct ubus_object dsl_object = {
819 .name = "dsl",
820 .type = &dsl_object_type,
821 .methods = dsl_methods,
822 .n_methods = ARRAY_SIZE(dsl_methods),
823 };
824
825 static DSL_int_t ubus_main(DSL_CPE_Thread_Params_t *params) {
826 uloop_run();
827 return 0;
828 }
829
830 void ubus_init() {
831 uloop_init();
832
833 ctx = ubus_connect(NULL);
834 if (!ctx)
835 return;
836
837 if (ubus_add_object(ctx, &dsl_object)) {
838 ubus_free(ctx);
839 ctx = NULL;
840 return;
841 }
842
843 ubus_add_uloop(ctx);
844
845 DSL_CPE_ThreadInit(&thread, "ubus", ubus_main, DSL_CPE_PIPE_STACK_SIZE, DSL_CPE_PIPE_PRIORITY, 0, 0);
846 }
847
848 void ubus_deinit() {
849 if (!ctx)
850 return;
851
852 ubus_free(ctx);
853 uloop_done();
854
855 DSL_CPE_ThreadShutdown(&thread, 1000);
856 }