ltq-*-app: extend ubus metrics/statistics
[openwrt/staging/dedeckeh.git] / package / network / config / ltq-vdsl-vr9-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 /* These values are exported via ubus and backwards compability
137 * needs to be kept!
138 */
139 enum {
140 RAMODE_MAP_UNKNOWN = -1,
141 RAMODE_MAP_MANUAL,
142 RAMODE_MAP_AT_INIT,
143 RAMODE_MAP_DYNAMIC,
144 RAMODE_MAP_DYNAMIC_SOS,
145 };
146
147 static DSL_CPE_ThreadCtrl_t thread;
148 static struct ubus_context *ctx;
149 static struct blob_buf b;
150
151 static inline void m_null() {
152 blobmsg_add_field(&b, BLOBMSG_TYPE_UNSPEC, "", NULL, 0);
153 }
154
155 static inline void m_double(const char *id, double value) {
156 blobmsg_add_double(&b, id, value);
157 }
158
159 static inline void m_bool(const char *id, bool value) {
160 blobmsg_add_u8(&b, id, value);
161 }
162
163 static inline void m_u32(const char *id, uint32_t value) {
164 blobmsg_add_u64(&b, id, value);
165 }
166
167 static inline void m_str(const char *id, const char *value) {
168 blobmsg_add_string(&b, id, value);
169 }
170
171 static inline void m_db(const char *id, int value, int invalid) {
172 if (value != invalid)
173 m_double(id, (double)value / 10);
174 }
175
176 static inline void m_array(const char *id, const uint8_t *value, size_t len) {
177 void *c = blobmsg_open_array(&b, id);
178
179 for (size_t i = 0; i < len; ++i)
180 blobmsg_add_u16(&b, "", value[i]);
181
182 blobmsg_close_array(&b, c);
183 }
184
185 static inline void m_array_u16(const char *id, const uint16_t *value, size_t len) {
186 void *c = blobmsg_open_array(&b, id);
187
188 for (size_t i = 0; i < len; ++i)
189 blobmsg_add_u16(&b, "", value[i]);
190
191 blobmsg_close_array(&b, c);
192 }
193
194 static void m_vendor(const char *id, const uint8_t *value) {
195 // ITU-T T.35: U.S.
196 if (U16(value[0], value[1]) != 0xb500)
197 return;
198
199 const char *str = NULL;
200 switch (U32(value[2], value[3], value[4], value[5])) {
201 STR_CASE(0x414C4342, "Alcatel")
202 STR_CASE(0x414E4456, "Analog Devices")
203 STR_CASE(0x4244434D, "Broadcom")
204 STR_CASE(0x43454E54, "Centillium")
205 STR_CASE(0x4753504E, "Globespan")
206 STR_CASE(0x494B4E53, "Ikanos")
207 STR_CASE(0x4946544E, "Infineon")
208 STR_CASE(0x54535443, "Texas Instruments")
209 STR_CASE(0x544D4D42, "Thomson MultiMedia Broadband")
210 STR_CASE(0x5443544E, "Trend Chip Technologies")
211 STR_CASE(0x53544D49, "ST Micro")
212 };
213
214 if (!str)
215 return;
216
217 if ((value[6] == 0) && (value[7] == 0)) {
218 m_str(id, str);
219 return;
220 }
221
222 char buf[64];
223 sprintf(buf, "%s %d.%d", str, value[6], value[7]);
224 m_str(id, buf);
225
226 return;
227 }
228
229 annex_t get_annex(const uint8_t *xtse) {
230 if ((xtse[0] & XTSE_1_01_A_T1_413) ||
231 (xtse[0] & XTSE_1_03_A_1_NO) ||
232 (xtse[0] & XTSE_1_04_A_1_O) ||
233 (xtse[1] & XTSE_2_01_A_2_NO) ||
234 (xtse[2] & XTSE_3_03_A_3_NO) ||
235 (xtse[2] & XTSE_3_04_A_3_O) ||
236 (xtse[3] & XTSE_4_01_A_4_NO) ||
237 (xtse[3] & XTSE_4_02_A_4_O) ||
238 (xtse[5] & XTSE_6_01_A_5_NO) ||
239 (xtse[5] & XTSE_6_02_A_5_O) ||
240 (xtse[7] & XTSE_8_01_A))
241 return ANNEX_A;
242
243 if ((xtse[0] & XTSE_1_05_B_1_NO) ||
244 (xtse[0] & XTSE_1_06_B_1_O) ||
245 (xtse[1] & XTSE_2_02_B_2_O) ||
246 (xtse[2] & XTSE_3_05_B_3_NO) ||
247 (xtse[2] & XTSE_3_06_B_3_O) ||
248 (xtse[5] & XTSE_6_03_B_5_NO) ||
249 (xtse[5] & XTSE_6_04_B_5_O) ||
250 (xtse[7] & XTSE_8_02_B))
251 return ANNEX_B;
252
253 if ((xtse[0] & XTSE_1_02_C_TS_101388) ||
254 (xtse[0] & XTSE_1_07_C_1_NO) ||
255 (xtse[0] & XTSE_1_08_C_1_O) ||
256 (xtse[1] & XTSE_2_03_C_2_NO) ||
257 (xtse[1] & XTSE_2_04_C_2_O) ||
258 (xtse[7] & XTSE_8_03_C))
259 return ANNEX_C;
260
261 if ((xtse[3] & XTSE_4_05_I_3_NO) ||
262 (xtse[3] & XTSE_4_06_I_3_O) ||
263 (xtse[4] & XTSE_5_01_I_4_NO) ||
264 (xtse[4] & XTSE_5_02_I_4_O) ||
265 (xtse[5] & XTSE_6_07_I_5_NO) ||
266 (xtse[5] & XTSE_6_08_I_5_O))
267 return ANNEX_I;
268
269 if ((xtse[3] & XTSE_4_07_J_3_NO) ||
270 (xtse[3] & XTSE_4_08_J_3_O) ||
271 (xtse[6] & XTSE_7_01_J_5_NO) ||
272 (xtse[6] & XTSE_7_02_J_5_O))
273 return ANNEX_J;
274
275 if ((xtse[4] & XTSE_5_03_L_3_NO) ||
276 (xtse[4] & XTSE_5_04_L_3_NO) ||
277 (xtse[4] & XTSE_5_05_L_3_O) ||
278 (xtse[4] & XTSE_5_06_L_3_O))
279 return ANNEX_L;
280
281 if ((xtse[4] & XTSE_5_07_M_3_NO) ||
282 (xtse[4] & XTSE_5_08_M_3_O) ||
283 (xtse[6] & XTSE_7_03_M_5_NO) ||
284 (xtse[6] & XTSE_7_04_M_5_O))
285 return ANNEX_M;
286
287 return ANNEX_UNKNOWN;
288 }
289
290 static standard_t get_standard(const uint8_t *xtse) {
291 if (xtse[0] & XTSE_1_01_A_T1_413)
292 return STD_T1_413;
293
294 if (xtse[0] & XTSE_1_02_C_TS_101388)
295 return STD_TS_101_388;
296
297 if ((xtse[0] & XTSE_1_03_A_1_NO) ||
298 (xtse[0] & XTSE_1_04_A_1_O) ||
299 (xtse[0] & XTSE_1_05_B_1_NO) ||
300 (xtse[0] & XTSE_1_06_B_1_O) ||
301 (xtse[0] & XTSE_1_07_C_1_NO) ||
302 (xtse[0] & XTSE_1_08_C_1_O))
303 return STD_G_992_1;
304
305 if ((xtse[1] & XTSE_2_01_A_2_NO) ||
306 (xtse[1] & XTSE_2_02_B_2_O) ||
307 (xtse[1] & XTSE_2_03_C_2_NO) ||
308 (xtse[1] & XTSE_2_04_C_2_O))
309 return STD_G_992_2;
310
311 if ((xtse[2] & XTSE_3_03_A_3_NO) ||
312 (xtse[2] & XTSE_3_04_A_3_O) ||
313 (xtse[2] & XTSE_3_05_B_3_NO) ||
314 (xtse[2] & XTSE_3_06_B_3_O) ||
315 (xtse[3] & XTSE_4_05_I_3_NO) ||
316 (xtse[3] & XTSE_4_06_I_3_O) ||
317 (xtse[3] & XTSE_4_07_J_3_NO) ||
318 (xtse[3] & XTSE_4_08_J_3_O) ||
319 (xtse[4] & XTSE_5_03_L_3_NO) ||
320 (xtse[4] & XTSE_5_04_L_3_NO) ||
321 (xtse[4] & XTSE_5_05_L_3_O) ||
322 (xtse[4] & XTSE_5_06_L_3_O) ||
323 (xtse[4] & XTSE_5_07_M_3_NO) ||
324 (xtse[4] & XTSE_5_08_M_3_O))
325 return STD_G_992_3;
326
327 if ((xtse[3] & XTSE_4_01_A_4_NO) ||
328 (xtse[3] & XTSE_4_02_A_4_O) ||
329 (xtse[4] & XTSE_5_01_I_4_NO) ||
330 (xtse[4] & XTSE_5_02_I_4_O))
331 return STD_G_992_4;
332
333 if ((xtse[5] & XTSE_6_01_A_5_NO) ||
334 (xtse[5] & XTSE_6_02_A_5_O) ||
335 (xtse[5] & XTSE_6_03_B_5_NO) ||
336 (xtse[5] & XTSE_6_04_B_5_O) ||
337 (xtse[5] & XTSE_6_07_I_5_NO) ||
338 (xtse[5] & XTSE_6_08_I_5_O) ||
339 (xtse[6] & XTSE_7_01_J_5_NO) ||
340 (xtse[6] & XTSE_7_02_J_5_O) ||
341 (xtse[6] & XTSE_7_03_M_5_NO) ||
342 (xtse[6] & XTSE_7_04_M_5_O))
343 return STD_G_992_5;
344
345 if (xtse[7] & XTSE_8_08)
346 return STD_G_993_1;
347
348 if ((xtse[7] & XTSE_8_01_A) ||
349 (xtse[7] & XTSE_8_02_B) ||
350 (xtse[7] & XTSE_8_03_C))
351 return STD_G_993_2;
352
353 return STD_UNKNOWN;
354 }
355
356 static void version_information(int fd) {
357 IOCTL(DSL_VersionInformation_t, DSL_FIO_VERSION_INFORMATION_GET)
358
359 m_str("api_version", out.data.DSL_DriverVersionApi);
360 m_str("firmware_version", out.data.DSL_ChipSetFWVersion);
361 m_str("chipset", out.data.DSL_ChipSetType);
362 m_str("driver_version", out.data.DSL_DriverVersionMeiBsp);
363 }
364
365 static void line_state(int fd) {
366 IOCTL(DSL_LineState_t, DSL_FIO_LINE_STATE_GET)
367
368 int map = LSTATE_MAP_UNKNOWN;
369 const char *str;
370 switch (out.data.nLineState) {
371 STR_CASE_MAP(DSL_LINESTATE_NOT_INITIALIZED, "Not initialized", LSTATE_MAP_NOT_INITIALIZED)
372 STR_CASE_MAP(DSL_LINESTATE_EXCEPTION, "Exception", LSTATE_MAP_EXCEPTION)
373 STR_CASE(DSL_LINESTATE_NOT_UPDATED, "Not updated")
374 STR_CASE(DSL_LINESTATE_IDLE_REQUEST, "Idle request")
375 STR_CASE_MAP(DSL_LINESTATE_IDLE, "Idle", LSTATE_MAP_IDLE)
376 STR_CASE(DSL_LINESTATE_SILENT_REQUEST, "Silent request")
377 STR_CASE_MAP(DSL_LINESTATE_SILENT, "Silent", LSTATE_MAP_SILENT)
378 STR_CASE_MAP(DSL_LINESTATE_HANDSHAKE, "Handshake", LSTATE_MAP_HANDSHAKE)
379 STR_CASE(DSL_LINESTATE_BONDING_CLR, "Bonding CLR")
380 STR_CASE_MAP(DSL_LINESTATE_FULL_INIT, "Full init", LSTATE_MAP_FULL_INIT)
381 STR_CASE(DSL_LINESTATE_SHORT_INIT_ENTRY, "Short init entry")
382 STR_CASE(DSL_LINESTATE_DISCOVERY, "Discovery")
383 STR_CASE(DSL_LINESTATE_TRAINING, "Training")
384 STR_CASE(DSL_LINESTATE_ANALYSIS, "Analysis")
385 STR_CASE(DSL_LINESTATE_EXCHANGE, "Exchange")
386 STR_CASE_MAP(DSL_LINESTATE_SHOWTIME_NO_SYNC, "Showtime without TC-Layer sync", LSTATE_MAP_SHOWTIME_NO_SYNC)
387 STR_CASE_MAP(DSL_LINESTATE_SHOWTIME_TC_SYNC, "Showtime with TC-Layer sync", LSTATE_MAP_SHOWTIME_TC_SYNC)
388 STR_CASE(DSL_LINESTATE_FASTRETRAIN, "Fastretrain")
389 STR_CASE(DSL_LINESTATE_LOWPOWER_L2, "Lowpower L2")
390 STR_CASE(DSL_LINESTATE_LOOPDIAGNOSTIC_ACTIVE, "Loopdiagnostic active")
391 STR_CASE(DSL_LINESTATE_LOOPDIAGNOSTIC_DATA_EXCHANGE, "Loopdiagnostic data exchange")
392 STR_CASE(DSL_LINESTATE_LOOPDIAGNOSTIC_DATA_REQUEST, "Loopdiagnostic data request")
393 STR_CASE(DSL_LINESTATE_LOOPDIAGNOSTIC_COMPLETE, "Loopdiagnostic complete")
394 STR_CASE_MAP(DSL_LINESTATE_RESYNC, "Resync", LSTATE_MAP_RESYNC)
395 STR_CASE(DSL_LINESTATE_TEST, "Test")
396 STR_CASE(DSL_LINESTATE_TEST_LOOP, "Test loop")
397 STR_CASE(DSL_LINESTATE_TEST_REVERB, "Test reverb")
398 STR_CASE(DSL_LINESTATE_TEST_MEDLEY, "Test medley")
399 STR_CASE(DSL_LINESTATE_TEST_SHOWTIME_LOCK, "Showtime lock")
400 STR_CASE(DSL_LINESTATE_TEST_QUIET, "Quiet")
401 STR_CASE(DSL_LINESTATE_LOWPOWER_L3, "Lowpower L3")
402 #ifndef INCLUDE_DSL_CPE_API_DANUBE
403 STR_CASE(DSL_LINESTATE_DISABLED, "Disabled")
404 STR_CASE(DSL_LINESTATE_T1413, "T1413")
405 STR_CASE(DSL_LINESTATE_ORDERLY_SHUTDOWN_REQUEST, "Orderly shutdown request")
406 STR_CASE(DSL_LINESTATE_ORDERLY_SHUTDOWN, "Orderly shutdown")
407 STR_CASE(DSL_LINESTATE_TEST_FILTERDETECTION_ACTIVE, "Test filterdetection active")
408 STR_CASE(DSL_LINESTATE_TEST_FILTERDETECTION_COMPLETE, "Test filterdetection complete")
409 #endif
410 default:
411 str = NULL;
412 break;
413 };
414
415 if (str)
416 m_str("state", str);
417
418 if (map != LSTATE_MAP_UNKNOWN )
419 m_u32("state_num", map);
420
421 m_bool("up", out.data.nLineState == DSL_LINESTATE_SHOWTIME_TC_SYNC);
422 }
423
424 static void pm_channel_counters_showtime(int fd) {
425 IOCTL_DIR(DSL_PM_ChannelCounters_t, DSL_FIO_PM_CHANNEL_COUNTERS_SHOWTIME_GET, DSL_NEAR_END);
426
427 m_u32("uptime", out.interval.nElapsedTime);
428 }
429
430 static void g997_line_inventory(int fd) {
431 IOCTL_DIR(DSL_G997_LineInventory_t, DSL_FIO_G997_LINE_INVENTORY_GET, DSL_DOWNSTREAM)
432
433 m_array("vendor_id", out.data.G994VendorID, DSL_G997_LI_MAXLEN_VENDOR_ID);
434 m_vendor("vendor", out.data.G994VendorID);
435 m_array("system_vendor_id", out.data.SystemVendorID, DSL_G997_LI_MAXLEN_VENDOR_ID);
436 m_vendor("system_vendor", out.data.SystemVendorID);
437 m_array("version", out.data.VersionNumber, DSL_G997_LI_MAXLEN_VERSION);
438 m_array("serial", out.data.SerialNumber, DSL_G997_LI_MAXLEN_SERIAL);
439 }
440
441 static void pilot_tones_status(int fd) {
442 #ifndef INCLUDE_DSL_CPE_API_DANUBE
443 IOCTL(DSL_PilotTonesStatus_t, DSL_FIO_PILOT_TONES_STATUS_GET);
444
445 m_array_u16("pilot_tones", out.data.nPilotTone, out.data.nNumData);
446 #endif
447 }
448
449 static void band_border_status(int fd, DSL_AccessDir_t direction) {
450 IOCTL(DSL_BandBorderStatus_t, DSL_FIO_BAND_BORDER_STATUS_GET);
451
452 void *c, *c2;
453
454 c = blobmsg_open_array(&b, "limits");
455
456 for (size_t i = 0; i < out.data.nNumData; i++) {
457 c2 = blobmsg_open_table(&b, "");
458 blobmsg_add_u16(&b, "first", out.data.nBandLimits[i].nFirstToneIndex);
459 blobmsg_add_u16(&b, "last", out.data.nBandLimits[i].nLastToneIndex);
460 blobmsg_close_table(&b, c2);
461 }
462
463 blobmsg_close_array(&b, c);
464 }
465
466 static void g977_get_bit_allocation(int fd, DSL_AccessDir_t direction) {
467 IOCTL_DIR(DSL_G997_BitAllocationNsc_t, DSL_FIO_G997_BIT_ALLOCATION_NSC_GET, direction);
468
469 // create default value to obtain consistent JSON structure
470 m_u32("groupsize", 1);
471 m_u32("groups", out.data.bitAllocationNsc.nNumData);
472 m_array("data", out.data.bitAllocationNsc.nNSCData, out.data.bitAllocationNsc.nNumData);
473 }
474
475 static void g977_get_snr(int fd, DSL_AccessDir_t direction) {
476 IOCTL_DIR_DELT(DSL_G997_DeltSnr_t, DSL_FIO_G997_DELT_SNR_GET, direction, DSL_DELT_DATA_SHOWTIME);
477
478 m_u32("groupsize", out.data.nGroupSize);
479 m_u32("groups", out.data.deltSnr.nNumData);
480
481 void *c = blobmsg_open_array(&b, "data");
482
483 // SNR -32 ... 95 dB
484 for (uint16_t i = 0 ; i < out.data.deltSnr.nNumData ; i++)
485 if (out.data.deltSnr.nNSCData[i] != 255 && out.data.deltSnr.nNSCData[i] != 0)
486 m_double("", -32 + (double)out.data.deltSnr.nNSCData[i] / 2);
487 else
488 m_null();
489
490 blobmsg_close_array(&b, c);
491 }
492
493 static void g977_get_qln(int fd, DSL_AccessDir_t direction) {
494 IOCTL_DIR_DELT(DSL_G997_DeltQln_t, DSL_FIO_G997_DELT_QLN_GET, direction, DSL_DELT_DATA_SHOWTIME);
495
496 m_u32("groupsize", out.data.nGroupSize);
497 m_u32("groups", out.data.deltQln.nNumData);
498
499 void *c = blobmsg_open_array(&b, "data");
500
501 // QLN -150 ... -23 dBm/Hz
502 for (uint16_t i = 0 ; i < out.data.deltQln.nNumData ; i++)
503 if (out.data.deltQln.nNSCData[i] != 255 && out.data.deltQln.nNSCData[i] != 0)
504 m_double("", -23 - (double)out.data.deltQln.nNSCData[i] / 2);
505 else
506 m_null();
507
508 blobmsg_close_array(&b, c);
509 }
510
511 static void g977_get_hlog(int fd, DSL_AccessDir_t direction) {
512 IOCTL_DIR_DELT(DSL_G997_DeltHlog_t, DSL_FIO_G997_DELT_HLOG_GET, direction, DSL_DELT_DATA_SHOWTIME);
513
514 m_u32("groupsize", out.data.nGroupSize);
515 m_u32("groups", out.data.deltHlog.nNumData);
516
517 void *c = blobmsg_open_array(&b, "data");
518
519 // HLOG +6 ... -96 dB
520 for (uint16_t i = 0 ; i < out.data.deltHlog.nNumData ; i++)
521 if (out.data.deltHlog.nNSCData[i] != 1023 && out.data.deltHlog.nNSCData[i] != 0)
522 m_double("", 6 - (double)out.data.deltHlog.nNSCData[i] / 10);
523 else
524 m_null();
525
526 blobmsg_close_array(&b, c);
527 }
528
529 static void g997_power_management_status(int fd) {
530 IOCTL(DSL_G997_PowerManagementStatus_t, DSL_FIO_G997_POWER_MANAGEMENT_STATUS_GET)
531
532 int map = PSTATE_MAP_UNKNOWN;
533 const char *str;
534 switch (out.data.nPowerManagementStatus) {
535 STR_CASE_MAP(DSL_G997_PMS_NA, "Power management state is not available", PSTATE_MAP_NA)
536 STR_CASE_MAP(DSL_G997_PMS_L0, "L0 - Synchronized", PSTATE_MAP_L0)
537 STR_CASE_MAP(DSL_G997_PMS_L1, "L1 - Power Down Data transmission (G.992.2)", PSTATE_MAP_L1)
538 STR_CASE_MAP(DSL_G997_PMS_L2, "L2 - Power Down Data transmission (G.992.3 and G.992.4)", PSTATE_MAP_L2)
539 STR_CASE_MAP(DSL_G997_PMS_L3, "L3 - No power", PSTATE_MAP_L3)
540 default:
541 str = NULL;
542 break;
543 };
544
545 if (str)
546 m_str("power_state", str);
547
548 if (map != PSTATE_MAP_UNKNOWN)
549 m_u32("power_state_num", map);
550 }
551
552 static void g997_xtu_system_enabling(int fd, standard_t *standard) {
553 IOCTL(DSL_G997_XTUSystemEnabling_t, DSL_FIO_G997_XTU_SYSTEM_ENABLING_STATUS_GET)
554
555 m_array("xtse", out.data.XTSE, DSL_G997_NUM_XTSE_OCTETS);
556
557 const char *str;
558 switch (get_annex(out.data.XTSE)) {
559 STR_CASE(ANNEX_A, "A")
560 STR_CASE(ANNEX_B, "B")
561 STR_CASE(ANNEX_C, "C")
562 STR_CASE(ANNEX_I, "I")
563 STR_CASE(ANNEX_J, "J")
564 STR_CASE(ANNEX_L, "L")
565 STR_CASE(ANNEX_M, "M")
566 default:
567 str = NULL;
568 break;
569 };
570 if (str)
571 m_str("annex", str);
572
573 *standard = get_standard(out.data.XTSE);
574
575 switch (*standard) {
576 STR_CASE(STD_T1_413, "T1.413")
577 STR_CASE(STD_TS_101_388, "TS 101 388")
578 STR_CASE(STD_G_992_1, "G.992.1")
579 STR_CASE(STD_G_992_2, "G.992.2")
580 STR_CASE(STD_G_992_3, "G.992.3")
581 STR_CASE(STD_G_992_4, "G.992.4")
582 STR_CASE(STD_G_992_5, "G.992.5")
583 STR_CASE(STD_G_993_1, "G.993.1")
584 STR_CASE(STD_G_993_2, "G.993.2")
585 default:
586 str = NULL;
587 break;
588 }
589 if (str)
590 m_str("standard", str);
591 }
592
593 static void get_vector_status(int fd, vector_t *status) {
594 *status = VECTOR_UNKNOWN;
595
596 #ifdef INCLUDE_DSL_CPE_API_VRX
597 if (fd < 0)
598 return;
599
600 IOCTL(IOCTL_MEI_dsmStatus_t, FIO_MEI_DSM_STATUS_GET);
601
602 switch (out.eVectorStatus) {
603 case e_MEI_VECTOR_STAT_OFF:
604 *status = VECTOR_OFF;
605 break;
606 case e_MEI_VECTOR_STAT_ON_DS:
607 *status = VECTOR_ON_DS;
608 break;
609 case e_MEI_VECTOR_STAT_ON_DS_US:
610 *status = VECTOR_ON_DS_US;
611 break;
612 default:
613 break;
614 };
615 #endif
616 }
617
618 static void vector_erb(int fd) {
619 #ifdef INCLUDE_DSL_CPE_API_VRX
620 if (fd < 0)
621 return;
622
623 IOCTL(IOCTL_MEI_dsmStatistics_t, FIO_MEI_DSM_STATISTICS_GET);
624
625 m_u32("sent", out.n_processed);
626 m_u32("discarded", out.n_fw_dropped_size + out.n_mei_dropped_size + out.n_mei_dropped_no_pp_cb + out.n_pp_dropped);
627 #endif
628 }
629
630 static void band_plan_status(int fd, profile_t *profile) {
631 #if (INCLUDE_DSL_CPE_API_VDSL_SUPPORT == 1)
632 IOCTL(DSL_BandPlanStatus_t, DSL_FIO_BAND_PLAN_STATUS_GET)
633
634 switch (out.data.nProfile) {
635 case DSL_PROFILE_8A:
636 *profile = PROFILE_8A;
637 break;
638 case DSL_PROFILE_8B:
639 *profile = PROFILE_8B;
640 break;
641 case DSL_PROFILE_8C:
642 *profile = PROFILE_8C;
643 break;
644 case DSL_PROFILE_8D:
645 *profile = PROFILE_8D;
646 break;
647 case DSL_PROFILE_12A:
648 *profile = PROFILE_12A;
649 break;
650 case DSL_PROFILE_12B:
651 *profile = PROFILE_12B;
652 break;
653 case DSL_PROFILE_17A:
654 *profile = PROFILE_17A;
655 break;
656 case DSL_PROFILE_30A:
657 *profile = PROFILE_30A;
658 break;
659 case DSL_PROFILE_35B:
660 *profile = PROFILE_35B;
661 break;
662 default:
663 *profile = PROFILE_UNKNOWN;
664 break;
665 };
666
667 const char *str;
668 switch (*profile) {
669 STR_CASE(PROFILE_8A, "8a")
670 STR_CASE(PROFILE_8B, "8b")
671 STR_CASE(PROFILE_8C, "8c")
672 STR_CASE(PROFILE_8D, "8d")
673 STR_CASE(PROFILE_12A, "12a")
674 STR_CASE(PROFILE_12B, "12b")
675 STR_CASE(PROFILE_17A, "17a")
676 STR_CASE(PROFILE_30A, "30a")
677 STR_CASE(PROFILE_35B, "35b")
678 default:
679 str = NULL;
680 break;
681 };
682 if (str)
683 m_str("profile", str);
684 #endif
685 }
686
687 static void line_feature_config(int fd, DSL_AccessDir_t direction, bool *retx) {
688 IOCTL_DIR(DSL_LineFeature_t, DSL_FIO_LINE_FEATURE_STATUS_GET, direction)
689
690 m_bool("trellis", out.data.bTrellisEnable);
691 m_bool("bitswap", out.data.bBitswapEnable);
692 m_bool("retx", out.data.bReTxEnable);
693 m_bool("virtual_noise", out.data.bVirtualNoiseSupport);
694
695 *retx = out.data.bReTxEnable;
696 }
697
698 static void g997_rate_adaptation_status(int fd, DSL_AccessDir_t direction) {
699 #ifndef INCLUDE_DSL_CPE_API_DANUBE
700 IOCTL_DIR(DSL_G997_RateAdaptationStatus_t, DSL_FIO_G997_RATE_ADAPTATION_STATUS_GET, direction);
701
702 int map = RAMODE_MAP_UNKNOWN;
703 const char *str;
704 switch (out.data.RA_MODE) {
705 STR_CASE_MAP(DSL_G997_RA_MODE_MANUAL, "Manual", RAMODE_MAP_MANUAL)
706 STR_CASE_MAP(DSL_G997_RA_MODE_AT_INIT, "At initialization", RAMODE_MAP_AT_INIT)
707 STR_CASE_MAP(DSL_G997_RA_MODE_DYNAMIC, "Dynamic", RAMODE_MAP_DYNAMIC)
708 STR_CASE_MAP(DSL_G997_RA_MODE_DYNAMIC_SOS, "Dynamic with SOS", RAMODE_MAP_DYNAMIC_SOS)
709 default:
710 str = NULL;
711 break;
712 };
713
714 if (str)
715 m_str("ra_mode", str);
716
717 if (map != PSTATE_MAP_UNKNOWN)
718 m_u32("ra_mode_num", map);
719 #endif
720 }
721
722 static void g997_channel_status(int fd, DSL_AccessDir_t direction) {
723 IOCTL_DIR(DSL_G997_ChannelStatus_t, DSL_FIO_G997_CHANNEL_STATUS_GET, direction);
724
725 m_u32("interleave_delay", out.data.ActualInterleaveDelay * 10);
726 m_double("inp", (double)out.data.ActualImpulseNoiseProtection / 10);
727 #ifndef INCLUDE_DSL_CPE_API_DANUBE
728 // prefer ACTNDR, see comments in drv_dsl_cpe_api_g997.h
729 m_u32("data_rate", out.data.ActualNetDataRate);
730 #else
731 m_u32("data_rate", out.data.ActualDataRate);
732 #endif
733 }
734
735 static void g997_line_status(int fd, DSL_AccessDir_t direction) {
736 IOCTL_DIR_DELT(DSL_G997_LineStatus_t, DSL_FIO_G997_LINE_STATUS_GET, direction, DSL_DELT_DATA_SHOWTIME);
737
738 // invalid value indicators taken from drv_dsl_cpe_api_g997.h
739 m_db("latn", out.data.LATN, 1271);
740 m_db("satn", out.data.SATN, 1271);
741 m_db("snr", out.data.SNR, -641);
742 m_db("actps", out.data.ACTPS, -901);
743 m_db("actatp", out.data.ACTATP, -512);
744 m_u32("attndr", out.data.ATTNDR);
745 }
746
747 static void pm_retx_counters_showtime(int fd, DSL_XTUDir_t direction) {
748 #ifdef INCLUDE_DSL_CPE_PM_RETX_COUNTERS
749 IOCTL_DIR(DSL_PM_ReTxCounters_t, DSL_FIO_PM_RETX_COUNTERS_SHOWTIME_GET, direction);
750
751 m_u32("mineftr", out.data.nEftrMin);
752 #endif
753 }
754
755 #ifndef INCLUDE_DSL_CPE_API_DANUBE
756 static void olr_statistics(int fd, DSL_AccessDir_t direction) {
757 IOCTL_DIR(DSL_OlrStatistics_t, DSL_FIO_OLR_STATISTICS_GET, direction)
758
759 void *c = blobmsg_open_table(&b, "bitswap");
760 m_u32("requested", out.data.nBitswapRequested + out.data.nBitswapRequested);
761 m_u32("executed", out.data.nBitswapExecuted);
762 m_u32("rejected", out.data.nBitswapRejected);
763 m_u32("timeout", out.data.nBitswapTimeout);
764 blobmsg_close_table(&b, c);
765
766 c = blobmsg_open_table(&b, "sra");
767 m_u32("requested", out.data.nSraRequested);
768 m_u32("executed", out.data.nSraExecuted);
769 m_u32("rejected", out.data.nSraRejected);
770 m_u32("timeout", out.data.nSraTimeout);
771 blobmsg_close_table(&b, c);
772
773 c = blobmsg_open_table(&b, "sos");
774 m_u32("requested", out.data.nSosRequested);
775 m_u32("executed", out.data.nSosExecuted);
776 m_u32("rejected", out.data.nSosRejected);
777 m_u32("timeout", out.data.nSosTimeout);
778 blobmsg_close_table(&b, c);
779 }
780 #endif
781
782 static void pm_line_sec_counters_total(int fd, DSL_XTUDir_t direction) {
783 IOCTL_DIR(DSL_PM_LineSecCountersTotal_t, DSL_FIO_PM_LINE_SEC_COUNTERS_TOTAL_GET, direction)
784
785 m_u32("es", out.data.nES);
786 m_u32("ses", out.data.nSES);
787 m_u32("loss", out.data.nLOSS);
788 m_u32("uas", out.data.nUAS);
789 m_u32("lofs", out.data.nLOFS);
790 #ifndef INCLUDE_DSL_CPE_API_DANUBE
791 m_u32("fecs", out.data.nFECS);
792 #endif
793 }
794
795 static void pm_retx_counters_total(int fd, DSL_XTUDir_t direction) {
796 #ifdef INCLUDE_DSL_CPE_PM_RETX_COUNTERS
797 IOCTL_DIR(DSL_PM_ReTxCountersTotal_t, DSL_FIO_PM_RETX_COUNTERS_TOTAL_GET, direction);
798
799 m_u32("leftrs", out.data.nLeftr);
800 #endif
801 }
802
803 static void pm_channel_counters_total(int fd, DSL_XTUDir_t direction) {
804 IOCTL_DIR(DSL_PM_ChannelCountersTotal_t, DSL_FIO_PM_CHANNEL_COUNTERS_TOTAL_GET, direction);
805
806 m_u32("cv_c", out.data.nCodeViolations);
807 m_u32("fec_c", out.data.nFEC);
808 }
809
810 static void pm_data_path_counters_total(int fd, DSL_XTUDir_t direction) {
811 IOCTL_DIR(DSL_PM_DataPathCountersTotal_t, DSL_FIO_PM_DATA_PATH_COUNTERS_TOTAL_GET, direction);
812
813 m_u32("hec", out.data.nHEC);
814 m_u32("ibe", out.data.nIBE);
815 m_u32("crc_p", out.data.nCRC_P);
816 m_u32("crcp_p", out.data.nCRCP_P);
817 m_u32("cv_p", out.data.nCV_P);
818 m_u32("cvp_p", out.data.nCVP_P);
819 }
820
821 static void retx_statistics(int fd, DSL_XTUDir_t direction) {
822 #ifdef INCLUDE_DSL_CPE_PM_RETX_COUNTERS
823 #ifdef INCLUDE_DSL_CPE_PM_RETX_THRESHOLDS
824 IOCTL_DIR(DSL_ReTxStatistics_t, DSL_FIO_RETX_STATISTICS_GET, direction);
825
826 m_u32("rx_corrupted", out.data.nRxCorruptedTotal);
827 m_u32("rx_uncorrected_protected", out.data.nRxUncorrectedProtected);
828 m_u32("rx_retransmitted", out.data.nRxRetransmitted);
829 m_u32("rx_corrected", out.data.nRxCorrected);
830 m_u32("tx_retransmitted", out.data.nTxRetransmitted);
831 #endif
832 #endif
833 }
834
835 static void describe_mode(standard_t standard, profile_t profile, vector_t vector) {
836 char buf[128];
837
838 switch (standard) {
839 case STD_T1_413:
840 strcpy(buf, "T1.413");
841 break;
842 case STD_TS_101_388:
843 strcpy(buf, "TS 101 388");
844 break;
845 case STD_G_992_1:
846 strcpy(buf, "G.992.1 (ADSL)");
847 break;
848 case STD_G_992_2:
849 strcpy(buf, "G.992.2 (ADSL lite)");
850 break;
851 case STD_G_992_3:
852 strcpy(buf, "G.992.3 (ADSL2)");
853 break;
854 case STD_G_992_4:
855 strcpy(buf, "G.992.4 (ADSL2 lite)");
856 break;
857 case STD_G_992_5:
858 strcpy(buf, "G.992.5 (ADSL2+)");
859 break;
860 case STD_G_993_1:
861 strcpy(buf, "G.993.1 (VDSL)");
862 break;
863 case STD_G_993_2:
864 strcpy(buf, "G.993.2 (VDSL2");
865
866 switch (profile) {
867 case PROFILE_8A:
868 strcat(buf, ", Profile 8a");
869 break;
870 case PROFILE_8B:
871 strcat(buf, ", Profile 8b");
872 break;
873 case PROFILE_8C:
874 strcat(buf, ", Profile 8c");
875 break;
876 case PROFILE_8D:
877 strcat(buf, ", Profile 8d");
878 break;
879 case PROFILE_12A:
880 strcat(buf, ", Profile 12a");
881 break;
882 case PROFILE_12B:
883 strcat(buf, ", Profile 12b");
884 break;
885 case PROFILE_17A:
886 strcat(buf, ", Profile 17a");
887 break;
888 case PROFILE_30A:
889 strcat(buf, ", Profile 30a");
890 break;
891 case PROFILE_35B:
892 strcat(buf, ", Profile 35b");
893 break;
894 default:
895 break;
896 };
897
898 switch (vector) {
899 case VECTOR_ON_DS:
900 strcat(buf, ", with downstream vectoring");
901 break;
902 case VECTOR_ON_DS_US:
903 strcat(buf, ", with down- and upstream vectoring");
904 break;
905 default:
906 break;
907 };
908
909 strcat(buf, ")");
910 break;
911 default:
912 return;
913 };
914
915 m_str("mode", buf);
916 }
917
918 static int line_statistics(struct ubus_context *ctx, struct ubus_object *obj,
919 struct ubus_request_data *req, const char *method,
920 struct blob_attr *msg)
921 {
922 int fd;
923 void *c, *c2;
924
925 #ifndef INCLUDE_DSL_CPE_API_DANUBE
926 fd = open(DSL_CPE_DEVICE_NAME "/0", O_RDWR, 0644);
927 #else
928 fd = open(DSL_CPE_DEVICE_NAME, O_RDWR, 0644);
929 #endif
930 if (fd < 0)
931 return UBUS_STATUS_UNKNOWN_ERROR;
932
933 blob_buf_init(&b, 0);
934
935 pilot_tones_status(fd);
936
937 c = blobmsg_open_table(&b, "bands");
938 c2 = blobmsg_open_table(&b, "downstream");
939 band_border_status(fd, DSL_DOWNSTREAM);
940 blobmsg_close_table(&b, c2);
941 c2 = blobmsg_open_table(&b, "upstream");
942 band_border_status(fd, DSL_UPSTREAM);
943 blobmsg_close_table(&b, c2);
944 blobmsg_close_table(&b, c);
945
946 c = blobmsg_open_table(&b, "bits");
947 c2 = blobmsg_open_table(&b, "downstream");
948 g977_get_bit_allocation(fd, DSL_DOWNSTREAM);
949 blobmsg_close_table(&b, c2);
950 c2 = blobmsg_open_table(&b, "upstream");
951 g977_get_bit_allocation(fd, DSL_UPSTREAM);
952 blobmsg_close_table(&b, c2);
953 blobmsg_close_table(&b, c);
954
955 c = blobmsg_open_table(&b, "snr");
956 c2 = blobmsg_open_table(&b, "downstream");
957 g977_get_snr(fd, DSL_DOWNSTREAM);
958 blobmsg_close_table(&b, c2);
959 c2 = blobmsg_open_table(&b, "upstream");
960 g977_get_snr(fd, DSL_UPSTREAM);
961 blobmsg_close_table(&b, c2);
962 blobmsg_close_table(&b, c);
963
964 c = blobmsg_open_table(&b, "qln");
965 c2 = blobmsg_open_table(&b, "downstream");
966 g977_get_qln(fd, DSL_DOWNSTREAM);
967 blobmsg_close_table(&b, c2);
968 c2 = blobmsg_open_table(&b, "upstream");
969 g977_get_qln(fd, DSL_UPSTREAM);
970 blobmsg_close_table(&b, c2);
971 blobmsg_close_table(&b, c);
972
973 c = blobmsg_open_table(&b, "hlog");
974 c2 = blobmsg_open_table(&b, "downstream");
975 g977_get_hlog(fd, DSL_DOWNSTREAM);
976 blobmsg_close_table(&b, c2);
977 c2 = blobmsg_open_table(&b, "upstream");
978 g977_get_hlog(fd, DSL_UPSTREAM);
979 blobmsg_close_table(&b, c2);
980 blobmsg_close_table(&b, c);
981
982 ubus_send_reply(ctx, req, b.head);
983
984 close(fd);
985
986 return 0;
987 }
988
989 static int metrics(struct ubus_context *ctx, struct ubus_object *obj,
990 struct ubus_request_data *req, const char *method,
991 struct blob_attr *msg)
992 {
993 int fd, fd_mei;
994 void *c, *c2;
995 standard_t standard = STD_UNKNOWN;
996 profile_t profile = PROFILE_UNKNOWN;
997 vector_t vector = VECTOR_UNKNOWN;
998 bool retx_up = false, retx_down = false;
999
1000 #ifndef INCLUDE_DSL_CPE_API_DANUBE
1001 fd = open(DSL_CPE_DEVICE_NAME "/0", O_RDWR, 0644);
1002 #else
1003 fd = open(DSL_CPE_DEVICE_NAME, O_RDWR, 0644);
1004 #endif
1005 if (fd < 0)
1006 return UBUS_STATUS_UNKNOWN_ERROR;
1007
1008 #ifdef INCLUDE_DSL_CPE_API_VRX
1009 fd_mei = open(DSL_CPE_DSL_LOW_DEV "/0", O_RDWR, 0644);
1010 #else
1011 fd_mei = -1;
1012 #endif
1013
1014 blob_buf_init(&b, 0);
1015
1016 version_information(fd);
1017 line_state(fd);
1018 pm_channel_counters_showtime(fd);
1019
1020 c = blobmsg_open_table(&b, "atu_c");
1021 g997_line_inventory(fd);
1022 blobmsg_close_table(&b, c);
1023
1024 g997_power_management_status(fd);
1025 g997_xtu_system_enabling(fd, &standard);
1026
1027 if (standard == STD_G_993_2) {
1028 band_plan_status(fd, &profile);
1029 get_vector_status(fd_mei, &vector);
1030 }
1031
1032 describe_mode(standard, profile, vector);
1033
1034 c = blobmsg_open_table(&b, "upstream");
1035 switch (vector) {
1036 case VECTOR_OFF:
1037 m_bool("vector", false);
1038 break;
1039 case VECTOR_ON_DS_US:
1040 m_bool("vector", true);
1041 break;
1042 default:
1043 break;
1044 };
1045 line_feature_config(fd, DSL_UPSTREAM, &retx_up);
1046 g997_rate_adaptation_status(fd, DSL_UPSTREAM);
1047 g997_channel_status(fd, DSL_UPSTREAM);
1048 g997_line_status(fd, DSL_UPSTREAM);
1049 if (retx_up)
1050 pm_retx_counters_showtime(fd, DSL_FAR_END);
1051 blobmsg_close_table(&b, c);
1052
1053 c = blobmsg_open_table(&b, "downstream");
1054 switch (vector) {
1055 case VECTOR_OFF:
1056 m_bool("vector", false);
1057 break;
1058 case VECTOR_ON_DS:
1059 case VECTOR_ON_DS_US:
1060 m_bool("vector", true);
1061 break;
1062 default:
1063 break;
1064 };
1065 line_feature_config(fd, DSL_DOWNSTREAM, &retx_down);
1066 g997_rate_adaptation_status(fd, DSL_DOWNSTREAM);
1067 g997_channel_status(fd, DSL_DOWNSTREAM);
1068 g997_line_status(fd, DSL_DOWNSTREAM);
1069 if (retx_down)
1070 pm_retx_counters_showtime(fd, DSL_NEAR_END);
1071 blobmsg_close_table(&b, c);
1072
1073 #ifndef INCLUDE_DSL_CPE_API_DANUBE
1074 c = blobmsg_open_table(&b, "olr");
1075 c2 = blobmsg_open_table(&b, "downstream");
1076 olr_statistics(fd, DSL_DOWNSTREAM);
1077 blobmsg_close_table(&b, c2);
1078 c2 = blobmsg_open_table(&b, "upstream");
1079 olr_statistics(fd, DSL_UPSTREAM);
1080 blobmsg_close_table(&b, c2);
1081 blobmsg_close_table(&b, c);
1082 #endif
1083
1084 c = blobmsg_open_table(&b, "errors");
1085 c2 = blobmsg_open_table(&b, "near");
1086 pm_line_sec_counters_total(fd, DSL_NEAR_END);
1087 if (retx_down)
1088 pm_retx_counters_total(fd, DSL_NEAR_END);
1089 pm_channel_counters_total(fd, DSL_NEAR_END);
1090 pm_data_path_counters_total(fd, DSL_NEAR_END);
1091 retx_statistics(fd, DSL_NEAR_END);
1092 blobmsg_close_table(&b, c2);
1093
1094 c2 = blobmsg_open_table(&b, "far");
1095 pm_line_sec_counters_total(fd, DSL_FAR_END);
1096 if (retx_up)
1097 pm_retx_counters_total(fd, DSL_FAR_END);
1098 pm_channel_counters_total(fd, DSL_FAR_END);
1099 pm_data_path_counters_total(fd, DSL_FAR_END);
1100 retx_statistics(fd, DSL_FAR_END);
1101 blobmsg_close_table(&b, c2);
1102 blobmsg_close_table(&b, c);
1103
1104 switch (vector) {
1105 case VECTOR_ON_DS:
1106 case VECTOR_ON_DS_US:
1107 c = blobmsg_open_table(&b, "erb");
1108 vector_erb(fd_mei);
1109 blobmsg_close_table(&b, c);
1110 break;
1111 default:
1112 break;
1113 };
1114
1115 ubus_send_reply(ctx, req, b.head);
1116
1117 if (fd_mei >= 0)
1118 close(fd_mei);
1119 close(fd);
1120
1121 return 0;
1122 }
1123
1124 static const struct ubus_method dsl_methods[] = {
1125 UBUS_METHOD_NOARG("metrics", metrics),
1126 UBUS_METHOD_NOARG("statistics", line_statistics)
1127 };
1128
1129 static struct ubus_object_type dsl_object_type =
1130 UBUS_OBJECT_TYPE("dsl", dsl_methods);
1131
1132 static struct ubus_object dsl_object = {
1133 .name = "dsl",
1134 .type = &dsl_object_type,
1135 .methods = dsl_methods,
1136 .n_methods = ARRAY_SIZE(dsl_methods),
1137 };
1138
1139 static DSL_int_t ubus_main(DSL_CPE_Thread_Params_t *params) {
1140 uloop_run();
1141 return 0;
1142 }
1143
1144 void ubus_init() {
1145 uloop_init();
1146
1147 ctx = ubus_connect(NULL);
1148 if (!ctx)
1149 return;
1150
1151 if (ubus_add_object(ctx, &dsl_object)) {
1152 ubus_free(ctx);
1153 ctx = NULL;
1154 return;
1155 }
1156
1157 ubus_add_uloop(ctx);
1158
1159 DSL_CPE_ThreadInit(&thread, "ubus", ubus_main, DSL_CPE_PIPE_STACK_SIZE, DSL_CPE_PIPE_PRIORITY, 0, 0);
1160 }
1161
1162 void ubus_deinit() {
1163 if (!ctx)
1164 return;
1165
1166 ubus_free(ctx);
1167 uloop_done();
1168
1169 DSL_CPE_ThreadShutdown(&thread, 1000);
1170 }